docs(plans): fill the wave-one status rows and correct thirteen drifts
Why
The Phase 4 fan-out opened seventeen step MRs in one wave, and Step 7's arrived later, so the table now carries eighteen filled rows. The fill-your-own-row guardrail assumes one step MR at a time, so those rows read as "not started" until each one lands. These land as one batch instead, each pairing verified against the live MR's source branch rather than against the dispatch list.
Thirteen plan-text drifts are corrected alongside, each stated at the point of drift per the plan-contradiction rule:
-
Step 14 cited S17 AC #32 for the marker invisibility obligation. Position 32 is the purger's full-subtree criterion. The obligation the step meets is AC #25 with AC #31.
-
Step 19 read the container tag cap as per-image and enforced on create only. The merged S12 write path counts
container_tagsbycontainer_manifest_idincountTagsForManifest, so a retarget onto a manifest already at its cap is rejected too. Four spots, because the "create only" reading appeared twice. -
The bulk job-enqueue seam is declared once, by whichever of Steps 32, 34, and 37 merges first. The plan read as a three-way tie, and its "four families" is the scaffold's route-family axis rather than the three format families.
-
delete_allon packages and files reads thecreated_atcolumns Step 5 adds, so Steps 33 and 35 sequence behind Step 5's merge even though the dependency graph draws no edge. -
Step 10's attachment inventory said eight referencing tables at six sites. The widening replaces the one-table guard outright rather than growing it, one clause per table in
structure.sql's foreign-key inventory, which is what the plan now names instead of a count. -
Step 17's Files bullet gains
internal/transport/httperror.gofor theDetailsattestation and theCodeServiceUnavailabledoc amendments, which the plan assigned to no step. -
Step 8's dispatch shells key on the
{format}path value and read no store, not on the resolved repository's format as the plan said. -
Steps 20, 21, 23, and 24 glossed AC #32 as subtree invisibility. The Maven pair initiate a removal the purger completes at reap, and the npm pair hard-delete their dist-tags and metadata files in the request, so each gloss now says which half lands where. This closes Tighten the AC #32 glosses on the plan's handle... (#593 - closed) • Hayley Swimelar • 19.3.
-
The eight write-arm steps (20-22, 23-25, 34, 37) owe the repository resolve, the hosted-kind narrowing, and the stored-format comparison against the
{format}segment. The scaffold reads no store, so nothing upstream performs them, and the plan named the obligation nowhere. Step 32 is excluded: it registers bare placeholders and already names its resolve chain. -
Step 8's
-Depends-on read as though no ordering question arose. Registering the write methods widens theAllowheader on the artifact paths Phase 3 already serves, ahead of Steps 1 through 4 declaring them. The window is accepted, not ordered away, because every placeholder answers501with the S01 envelope, soAllowadvertises a method nothing serves. Its Scope also now says thenot_implementedenum entry and itsTestContract_ErrorCodeEnum_MatchesTransportCodesrow ship with Step 3. -
Step 36 said its counter dispatches settle entry by entry, and named only Steps 12 and 35. The Step 9 dispatcher's in-flight cap is per process rather than per caller, so a per-entry burst from one worker sheds its own tail and every concurrent handler's update. Its counter updates now aggregate per batch, and it names Step 9 the way sibling workers 30, 33, and 35 already do.
-
Steps 20 and 21 are the first callers of Step 14's Maven tombstone markers, and inherit an upload-liveness race the plan named nowhere. The Maven upload commit path re-verifies no parent liveness, so a concurrent upload can commit a child under a marked parent. Each step now either closes the race inside
internal/format/maven's upload commit transaction, as a cross-package edit its Files list must name, or records the accepted window with its reasoning. -
Steps 3 and 4 declare selector rejection rules that Step 27's decode enforces, an ordering neither Depends-on named. Step 4 declares four (strict decode, empty list, over cap, and the all-zeros UUID refusal); Step 3 declares the first three. The all-zeros rule cannot be a schema pattern, so the contract prose names the decode as its enforcer, and Step 27 stated the rule nowhere while its canonical-lowercase entry check admits the value. No live window opens, because the routes answer
501until the bulk route steps land and those already depend on Step 27.
Two further amendments carry operator rulings rather than drifts:
-
Steps 20 and 21 own proving that a marked Maven subtree is invisible through the read surface. Step 14 composes the markers, and its acceptance claimed handler-level verification without naming an owner, so each handler step now states that once it has marked a package or version, that resource's metadata read and every file fetch beneath it answer as though it does not exist.
-
The Maven upload-liveness race is closed rather than accepted. Step 20 re-verifies the parent chain inside
commitFileRowand owns that cross-packageinternal/format/mavenedit as the first caller of the markers, with Steps 21 and 33 finding it declared on the first-lands-declares device the bulk enqueue seam already uses. A staged-race test held at theON CONFLICTstatement throughawaitConflictRendezvousproves the window shut, which a serial walk cannot.
Test plan
mise run lint:markdown and mise run lint:vale, both at parity with
main: markdownlint 0 errors, Vale 0 errors and 97 warnings, the same 97
the file already carries on main.
Related to #313 (closed)