feat(remote): Fetch seams, short-write guard, and test fakes (S13 Step 7, part 1/4)

📦 What this MR does

Part 1 of 4 of S13 Step 7 (Fetch cache-fill pipeline): the supporting contract every later part builds on.

  • The remote-local BodyKind enum — BodyKindMetadata is the zero value, so an unset kind selects the fail-small 16MB metadata cap, and upstreamhttp aliases this declaration rather than keeping a second enum — and the UpstreamDoer seam. The seam exists because internal/remote/upstreamhttp already imports internal/remote for shared error types, so internal/remote cannot import it back; the production adapter over upstreamhttp.Client is owned by Step 11 (see the plan).
  • The exported ErrCacheFill and ErrFillAbandoned sentinels: errors.Is(err, ErrCacheFill) means the failure originated in the cache-side machinery — opening the staging session on a 200, the 304 freshness bump, the terminal Commit, or the post-Commit cache-row upsert — rather than in the client's transfer or the upstream read. What the client received varies by stage: a Commit or upsert failure leaves an already-complete transfer intact, the 304 bump owed no body, and a session-open failure on a 200 fails the request outright. A client-facing SLI must therefore split on the failing stage rather than treat every ErrCacheFill as client-invisible. ErrFillAbandoned marks a client-side abort before end-of-body.
  • FetchOptions.BodyKind on the Operations.Fetch contract, plus the contract's cache-infrastructure-failure carve-out documentation.
  • The sessionWriter short-write guard (synthesizes io.ErrShortWrite when a storage driver under-reports without an error — a truncated blob would otherwise commit under a digest that matches only the truncated bytes) with its internal tests.
  • remotetest fake upgrades the Fetch test floors need: FakeUpstreamDoer, call-recording on FakeCacheStore/FakeRequestBuilder behind accessors that clone under the fake mutex, clone-per-call request building, and unconditional context honoring in every FakeCacheStore write method (stated as the CacheStore write contract on the interface, so a detached-context assertion cannot pass vacuously and a real implementation has something to conform to).
  • The Step 7 plan amendments (Files/Scope/Tests reconciliation, the work-item 320 spec-amendment note, Step 11's adapter ownership) under the documented drift carve-out.

⚙️ Why stacked

Step 7's full diff is ~2.7k reviewable LoC — far over the 800 LoC acceptable ceiling — so it ships as 4 stacked MRs, each targeting the previous (part 1 targets main), reviewed and merged bottom-up. Part 2 carries the production pipeline; parts 3-4 carry its unit and integration test floors.

  • Plan: docs/plans/2026-07-16-s13-virtual-remote-foundation.md — Step 7
  • Spec: docs/specs/S13-virtual-remote-foundation.md — Fetch, cache freshness model

🔬 e2e scenarios

No scenario added or affected: S13 remote fetch has no e2e catalog yet, and nothing in this stack is reachable from a request path until Step 11 wires the production adapter.

Related to #328 (closed)

📚 Stacked MRs (review/merge bottom-up)

Edited by David Fernandez

Merge request reports

Loading
Loading