Draft: REFERENCE ONLY, DO NOT MERGE — #433 Fetch seam gaps, combined
🔖 This MR is a reference. Do not merge it.
It holds the whole of #433 as one change, which is how the work was originally written. It ships as three smaller MRs instead, extracted from this one. This MR stays open as a Draft so the combined view is readable while those three are reviewed, and is closed once all three have merged and #433 is fully addressed.
Nothing here should be reviewed for merge. Review the three below.
| MR | Scope | Merge order |
|---|---|---|
| !1806 (merged) | Spec corrections against what main already ships. No code. |
1 |
| !1808 (merged) | FetchOptions.ExpectedDigest reaching the cache-fill commit (#433 gap 1) |
2 |
| !1807 | The upstream Docker-Content-Digest cross-check (#433 gap 2) |
3 |
🤔 Why it was split
#433 came out of an MR review rather than a planned step, so no engineer had focused eyes on it — which is exactly the shape a mistake slips through, past author and reviewer alike. This MR had reached 16 files across four packages carrying three unrelated claims, a signature change, and a set of spec corrections. Each extracted MR reduces to one claim a reviewer can try to falsify:
- !1806 (merged) — every sentence is a fact you can
git grepagainstmain. - !1808 (merged) — the digest the request named reaches the commit, and a mismatch is not a cache-fill failure.
- !1807 — a contradicted fill is discarded before it commits, and an unreadable claim is dropped rather than failed.
⚠️ What this reference contains that will not ship
Two things, both deliberate.
The readable-header half of gap 2. This branch adds a raw flag to FetchResult, a sixth parameter to NewFetchResult, and a second SafeHeaders allowlist exposing Docker-Content-Digest. That has been dropped, not deferred. S16 never reads the upstream's digest: it is "a cross-check only, never the stored value", the response header is "service-generated, not relayed", and a HEAD reports it "from the committed fill, never from the upstream's own". A slice needs the verdict, not the value, and the verdict arrives as the fill's error, whose message names both digests.
That framing came from an earlier design where the handler did the comparing. Once the comparison moved inside the fill, the readability requirement went away with it — nobody noticed because the gap-2 entry still said "exemption plus hook".
Dropping it is what removed every file this work touched outside internal/remote: internal/format/maven, internal/virtual, and internal/remote/remotetest were pure signature churn.
Gap 3. This branch predates FetchResult.ContentLength landing on main with the Maven remote fill work — the "separate channel" alternative #433 itself offered, rather than the allowlist exemption it asked for. An earlier revision of this branch also put Content-Length on the second allowlist, which would have been wrong: newCappedBody resets an over-cap claim to -1 on the field and does not delete the header, so a header read hands back the full declared length for a body truncated at the cap. One source has to win, and it is the scrubbed one. What remains of gap 3 is that ServeResult has no equivalent field, so the length does not cross Standalone.Serve; that is recorded on #433 and in S16's follow-ups.
📄 State of this branch
Rebased onto main and squashed to one signed commit. Full suite green, go vet clean in both tag modes, golangci-lint clean on the touched packages. It was a mergeable change; it is being split for reviewability, not because anything in it is broken.
Related to #433