docs(plans): record the S32 steps 1, 5, 6, 7 and 13 findings

What

Fills five Status rows and corrects the plan text that implementing Steps 1, 5, 6, 7 and 13 falsified. Documentation only; no code ships here.

AGENTS.md guardrail 4 gives docs/plans/2026-08-27-s32-container-virtual.md a single writer, so no step branch may carry these edits. This MR is the catch-all for findings discovered during implementation, which is a different phase from the two open plan MRs: !2063 (merged) books the handbook amendment set found during plan review, and !2069 (merged) corrects the Step 8, 9 and 10b designs. Neither is touched here.

The findings came from the four step sessions. Each one reported against its own branch and did not edit the plan.

Status rows

Step MR
1 !2159 (merged)
5 !2135 (merged)
6 !2136 (merged)
7 !2118 (merged)
13 !2138 (merged)

The MR column is widened to fit the references. An empty cell still means "not yet recorded", not "not started".

Sizing lines keep the estimate and add the actual

Each corrected sizing line now reads ~N estimated, M actual, with the commit the actual was measured at. Every other step still carries a forecast, so a row holding only actuals would be the one row a reader cannot compare against its neighbours, and ### How the ceiling is applied reasons off the estimates. A forecast was true as a forecast on the day it was written; a measurement is what needs its commit named.

Step Estimated Actual Measured at
1 600 / 1,800 / 2,400 650 / 1,382 / 2,032 dc0971c4b
5 450 / 1,280 / 1,730 694 / 2,401 / 3,095 462f86f30
6 400 / 1,360 / 1,760 472 / 2,484 / 2,956 00ad7b62c
13 420 / 1,000 / 1,420 353 / 1,241 / 1,594 ef5fe8738

Step 1's figures exclude the regenerated structure.sql and jet output. Step 5's exclude nothing, and its overrun is mostly comment volume — the two source files are 444 code-only lines.

Corrections a reviewer should check

Step 1. Scope gains the id version CHECK, Files gains docs/specs/S32-container-virtual.md, and Shared seams gains three paths. ADR-007 requires the CHECK, and handbook commit 22ced257 added that rule after this plan merged, which is why the original Scope omitted it. The three extra shared paths are the knownHeadVersion constant, the FK schema guard in repositories_integration_test.go, and lifecycle_reap_repository.md.

Step 5. Two stale measurements of the npm sibling suite, and they disagreed with each other. ### Schema facts-adjacent prose said five files and 913 lines of test; the Step 5 Tests entry said 913 across three files. The suite is 1,300 lines across three test files at 98a7b2612, and the glob also matches a 347-line source file the figure excludes. Both sites are corrected. The _guards_test.go the entry called uncounterparted now has one, a 234-line superset. Acceptance also gains a clause for the duplicate-hit sentinel !2135 (merged) ships.

Step 6. Files gains the predicates sidecar, and two overclaims are narrowed. The freshness agreement holds under a UTC session timezone: freshWithinHoursExpr renders a DST-aware INTERVAL '1 DAY' where freshWithinColumnWindowExpr renders exact hours, so the two diverge by an hour on a DST shift day. Work item #1001 closes that. And conditionalETag is unexported in internal/virtual, so an external test in internal/format/oci cannot call it; the Tests entry now names the exported function the suite actually routes through.

Step 7. The two target-field constants are unexported — virtualTargetImage and virtualTargetTag — matching the npm file the step's Files entry declares it mirrors. The Approach text called them exported.

Step 13. Files gains dispatchSlots, which crosses virtual_slots.go and remote_slots.go and which Step 14's composition root consumes. The handler.go bullet now authorises two renames on merged S16 surface: allowRemoteReadVerbs to allowReadVerbs and isRemoteReadMethod to isReadMethod, because both now serve the virtual arm as well as the remote one. Step 13's Shared seams claims it is the sole writer of that surface, so without this the renames read as scope creep.

Deliberately not here

  • plan:925, on which step chooses the constraint-abbreviation family. It sits one line below !2063 (merged)'s hunk, so an edit here would read as a competing rewrite of the same paragraph. It waits for !2063 (merged).
  • The ceiling-count sentence at the ### How the ceiling is applied paragraph. !2069 (merged) owns that line and rewrites it.
  • Step 13's knowingly-stale comment count in serveRemoteRepository's doc. The decision is MR-level and !2138 (merged) discloses it.
  • Step 14's sizing line, which is byte-identical to Step 13's and may be a copy-paste. Step 14 has not shipped, so there is no actual to add. Worth a look when the batch extends.

Related to #291

Merge request reports

Loading
Loading