docs(specs): correct S16 hoistability, body cap, and credential prose

What

Three corrections to S16. In each one the spec and the implementation disagree, and the spec is the side that is wrong.

  1. The container request builder is not hoistable as written. The S13 Dependencies row said hoisting both the cache store and the request builder to one instance per remote repository was "a pure rewiring". True for the store. Not for the builder, which holds the client's Accept values and a snapshot of the row's url, auth_status, and auth_url, and remote.RequestBuilder.BuildRequest has no per-call channel for either.
  2. The token exchange reads its response under a fixed 64 KiB bound, not body_size_cap_metadata (16 MB). The Oversize acceptance criterion and the body-cap Error Cases row are corrected with it.
  3. A half-set credential pair is refused, not sent anonymously. The prose said "when both are set ... otherwise"; the acceptance criterion already said "When neither ... is set". Refusal answers 500 INTERNAL, with its own Error Cases row and acceptance criterion.

Each correction gets a ## Resolutions entry carrying its reasoning, in the shape that section already uses.

Why each one matters

Item 1 misleads a reader in a different slice. The Dependencies row is where someone composing single-flight looks, and it currently tells them the hoist is free. The failure mode is a builder that compiles, passes every test, and forwards the first request's Accept for the repository's lifetime, plus an unknown auth snapshot that re-runs the discovery HEAD on every fetch and breaks the two memoization criteria the three-state auth_status column exists to keep.

Worth noting for review: the row was the only place that overclaimed. ### Manifest proxy and the media_type resolution both already scope the claim to the cache store and are untouched here, which is what marks the row as a drafting slip rather than a decision being reversed.

Item 2 is not only a wrong number. S13's Client.bodyCap clamps a per-request override against body_size_cap_blob only, and deliberately not against the kind's own default, because that is what lets npm's max_remote_packument_size raise the metadata cap. So an override replaces the metadata cap rather than tightening it. An oversize-token fixture written from the earlier text would sit above 16 MB, exceed both bounds, and pass while asserting nothing about the one that binds.

Item 3 started as a one-clause prose fix and now carries the answer with it. The all-or-none CHECK on container_remote_repositories admits no half-set pair, so reaching that state is a read-side defect rather than an operator configuration, and answering it anonymously would surface upstream as a 401 byte-identical to a wrong password. 500 INTERNAL rather than the token-exchange-failure 503: a 503 is retryable to an OCI client and this fault never clears, and it must not take the cache-fallback path, which S13 scopes to a response the upstream never returned.

Scope

No code changes.

Item 1's deferral is tracked in #596, which carries its own ## Follow-ups bullet cross-linked with item 9 of #320 (closed) and with the Resolutions entry. It is deliberately not a widening of item 9: that item rests on a call-time credential read being free, which does not hold for Accept (not a BuildRequest parameter at all) or for the auth snapshot (a store read per fetch). Item 2 owes no work item — the override semantics it documents are deliberate in S13, not a defect.

Items 2 and 3 were found while implementing S16 Step 12 (container request builder and token-exchange flow), whose MR opens against this text. Per the documentation-pairing table in docs/dev/conventions.md, docs/specs/ ships in its own spec MR rather than with the implementation.

Two changes outside docs/specs/ ship here alongside the corrections:

  • docs/plans/2026-07-30-container-remote.md carried the same "the hoist is free" claim item 1 retracts, in Dependencies, in Step 8, and in Step 12's Template. All three are corrected, and the correction is recorded under Research Findings so the plan says where it contradicted the spec rather than substituting the fact silently. The same file's Acceptance-criterion ownership section gains a row for item 3's new criterion, and a Correction note: its stated total of 111 is four short of the 115 criteria on main, so four criteria from earlier spec MRs have no owner in that table.
  • CLAUDE.md gains two rules under Docs Make Claims a Reader Can Check: naming one file as the home of a list of values is a claim about every value in it, and a claim of scale has to hold at the weak end of the range the same sentence names. Both came out of quantities in this MR's own new text.
Edited by Sylvia Shen

Merge request reports

Loading
Loading