docs(specs): scope S16's cache-miss delivery-mode carve-out to a streamed miss
Why
S16's blob-proxy section says "A cache miss is always proxy delivery",
covering all three miss shapes. Only one of them can be. A streamed full GET
tees the body from the upstream as it arrives, so there is no stored object to
pre-sign. The other two answer after the fill commits, so by the time either
writes a response there is a stored object and the carve-out has nothing to rest
on.
Split out of the Step 15 implementation branch so the contract change is approved on its own, per the plan's rule that merging the spec MR is the approval signal. !1894 (merged) stacks on this branch; see below.
Related MRs
!1894 (merged)
stacks on this branch and implements the narrowed carve-out. This MR merging is
the approval signal for it, per the plan.
!1896 (merged)
is independent of both and targets main directly.
What
The delivery-mode carve-out narrows to a streamed miss. Each of the three miss shapes now reads explicitly:
| Miss shape | Delivery |
|---|---|
Streamed full GET |
Mode-independent, for the reason it always was: nothing stored to point at. |
Cold HEAD |
Never a 307 — but because a HEAD is answered from the row in both modes, not because it is a miss. |
| Ranged miss | Follows the configured mode like any cached ranged read: 206 under proxy, 307 under redirect with the storage backend serving the range. |
The ranged miss is the case the old wording got wrong, and it is reachable: the
arm fetches the whole blob with no Range forwarded, then serves the range out
of local storage. The delivery-mode acceptance criterion carried the same
over-broad claim and is corrected to match.
The download-signal criterion becomes mode-scoped. "A cache miss records
exactly one download, and a miss that serves nothing records none" turns on an
unsatisfiable ranged miss. Under proxy delivery that fills and answers 416,
serving no bytes and recording nothing. Under redirect delivery the same request
answers 307 and records one, because issuing a redirect is the only serve the
arm can observe and satisfiability is the storage backend's to evaluate. Both
are correct under their own mode, so a suite asserting the proxy-mode outcome
has to pin the mode to be asserting anything.
Three coalescing criteria are gated on
#752. The
blob arm composes S13's Fetcher directly and constructs no single-flight
layer, so there is no coalescing to observe and no follower to answer. The gate
says so, and says explicitly not to satisfy it by building a per-request
single-flight instance: one coalesces nothing while compiling and passing, so a
green assertion would establish the opposite of the rule. Recorded alongside it:
the same deferral leaves the fill path with no per-repository in-flight bound,
because resolution.max_concurrent_fills_per_repo is enforced inside that layer
and nowhere else.
The already-gated follower criterion now names both blockers rather than one. Without #752 there is no follower at all; #320 (closed) is what decides where an early-joining follower's answer comes from.
Verification
Every claim was checked against the implementation before it was written:
redirectToCachedBlob returns true, so a 307 does record a download, and
getCachedBlob opens the blob before parsing Range, so an unsatisfiable range
redirects under redirect delivery. No drift found between the corrected text and
the code.
Related to #288