docs(plans): batch S32 plan updates (2026-09-23)
What this changes
This wave of S32 plan updates records five Status rows and two sets of cross-step obligations. The first set came from the review of Step 11 (!2842 (merged)), and the second from the review of Step 12 (!2900 (merged)). A step branch cannot edit the plan, so each one goes on the entry of the step that owns it.
- Step 14 names
oci.NewVirtualResolutionin theManifestMaxPayloadfield comment inremote_operations.go. That comment says both constructors take their bounds fromociRemoteManifestBodyBounds. Step 14 builds the facade from the same selector, so the sentence goes stale at that step. The comment is a 22-line block that predates the comment caps, and the entry says so. - Steps 15 and 16 answer a malformed digest with
400 DIGEST_INVALIDbefore any resolution runs. The manifest route usesreadReferenceDigestInvalid, and the blob route usesgateRemoteBlobDigest. Step 11's mapping answersErrVirtualHostedReferencewith500and relies on this check. Without the check, a client can drive 500s at ERROR with a bad digest. - Step 17 appends
namespace_idandrepository_idto the request's context logger in both virtual handlers. Step 11's error mapping writes no repository identity, so an operator can tie a virtual503to its repository only by acorrelation_idjoin. - Status table: rows 4, 10a, 10b, 11, and 12 now record !2756 (merged), !2831 (merged), !2836 (merged), !2842 (merged), and !2900 (merged).
From the Step 12 review, the virtual download record that !2907 (merged) adds to S32:
- Step 12 records a delivered read's download on the supplying position. Its Files entry adds
virtual_assembly.go,virtual_assembly_test.go,emit.go, anddocs/dev/storage-accounting.md, which !2900 (merged) already changes. It also addsremote_download.go, whose header lists the callers ofrecord. !2900 (merged) does not change that file yet. - Step 14 carries the cache surface Steps 15 and 16 read on
ociVirtualWiring: anoci.RemoteReadCacheForand theremoteStalenessWindow(remoteCfg)value each virtual arm hands it. It also booksVirtualPosition.RemoteRepository, the winner's remote row that the factory takes. Neither route step can declare a wiring field. - Steps 15 and 16 fill
virtualServeRead.rowswith the winning remote repository'sRemoteReadCache, never the Phase 1 memo. Their builders handvirtualServeHandler.countersthe process'sCounterSink. Without the cache surface, the serve answers a remote winner500. Without the sink, a hosted supplier books no download. - Step 17 adds the virtual serve to the
downloads_countdispatchers named indocs/dev/observability.md.
Merge timing
Merge this after !2907 (merged), because Step 12's scope cites the download rule that !2907 (merged) adds to S32. Merge it before the Step 15 and Step 16 MRs open, because their entries gain an Acceptance criterion and the serve wiring here. !2917 (merged) gates the same two steps with the single_flight_wait_timeout budget term. The two MRs share no lines, so either can merge first.
Status rows 14 to 18 go in a later wave, once those MRs open.
Related to #291 (closed)