docs(plans): record the two filed handbook amendment MRs
What this does
Five plan corrections, all fallout from the reviews of the two handbook amendment MRs this plan books.
- Records both amendment MRs, now that both are filed, and corrects how the plan describes the ADR-009 one.
- Rewrites
### Schema facts, which no longer described the repository. - Adds a cross-plan note to Step 2 about its
positioncheck, and what to copy from the npm migration that now precedes it. - Names the two
docs(specs)MRs that close the same claims on the spec side. - Names the open
referrers/:digesterror-code decision on Step 13, which is the step that writes the route.
No code ships here, and no step's scope, acceptance, or sizing changes.
| Amendment | MR |
|---|---|
| ADR-007, container virtual tables | gitlab-com/content-sites/handbook!20928 (merged) |
| ADR-009, virtual container read routes | gitlab-com/content-sites/handbook!20929 (merged) |
| ADR-009, in-use refusal on repository delete | gitlab-com/content-sites/handbook!20941 (merged) |
| S32 spec, deferrable precedent | !2126 (closed) |
| S32 spec, referrers client split | !2127 (closed) (Draft) |
Decisions a reviewer should check first
### Schema facts was wrong before this branch, not only stale. It claimed
grep -ic virtual over structure.sql returns 0 and that no *_virtual_*
table exists. S31's first table was already merged at this branch's own base, so
the count was never 0 here. All three npm virtual tables are on main now, and
the count is 1818 at ddfb0f545. The section is rewritten with the commit named
beside the measurement, so the next reader can tell a stale figure from a wrong
command.
The same paragraph asked which of S31 and S32 would land first and set the
deferrable-constraint precedent. S31 did. structure.sql carries 65
DEFERRABLE lines from e739e728b — the parent constraint plus its 64
partition clones — so Step 2 copies
20260828102654_create_npm_virtual_repository_upstreams.sql rather than
deriving the shape.
The spec still carries the pre-S31 reading, and the plan says so rather than
correcting it silently. ### Schema facts names the divergence and points at
!2126 (closed). That follows the AGENTS.md rule for a plan whose research contradicts its
spec: a reader cross-referencing the two documents can otherwise not tell a
deliberate correction from a transcription error.
Step 2 gains one precedent to copy and one not to. The npm migration's
disallowed-unique-constraint ignore transfers, because neither half of the
rule's own remedy runs on a hash-partitioned parent — PostgreSQL refuses
CREATE UNIQUE INDEX CONCURRENTLY there, and refuses
ALTER TABLE ... ADD CONSTRAINT ... UNIQUE USING INDEX too. Its
prefer-bigint-over-int ignore does not transfer: that one justifies itself
with "positions are unique and ordered but not contiguous", which holds for the
npm column and is false for this one. Carried over wholesale, the directive
argues the opposite of what this table needs, and nothing fails when it does.
The ADR-009 entry counted three widening items. There are four. The
amendment also had to scope its account of the referrers tag-schema fallback to
the clients that take it: crane reads no error code and falls back, while
oras and Notation read a 404 NAME_UNKNOWN as a missing repository and return
an error. Measured against go-containerregistry v0.20.6 and oras-go v2.5.0
and v2.6.0. The spec states the fallback without that qualifier in four places,
and !2127 (closed) corrects them.
Step 2's position check diverges from the npm sibling's, and one S17 write
surface serves both. This table takes CHECK (position >= 1), 1-based and
contiguous, per the spec. The npm virtual table takes position >= 0 and
permits gaps. S17 Phase 6 writes both tables from one surface — Step 39's
junction store and Step 40's handler — which its Step 41 extends with the npm
arm and its Step 42 with the container arm.
The two checks are asymmetric rather than incompatible. S17 fixes one rule over
that surface: position is 1-based and contiguous, and a position below 1
returns 422. Values written under that rule satisfy both checks, so no S17
write path meets two constraints. Only a 0-based helper written against the npm
table alone fails against the container one.
ADR-007 fixes no base or contiguity rule for either table. !20928 therefore states S32's constraint on the container table, leaves the npm table untouched, and leaves the divergence open for the S17 or S13 DRI — arbitrating would change the npm table, which is outside what the spec asked for. Nothing in Step 2 changes.
Step 13 and the open error code
Step 13's Scope writes 404 NAME_UNKNOWN on referrers/:digest, and whether
that is the right code is open in
#1019 (closed).
NAME_UNKNOWN is what stops oras and Notation taking the referrers
tag-schema fallback, and that fallback is the spec's stated reason for
preferring a 404 over an empty 200.
The entry now carries an Open decision this step settles first line. The
Scope keeps NAME_UNKNOWN as its assumption and says what changes if #1019 (closed)
lands on another code, so the step reads correctly either way. tags/list is
unaffected, because neither client library has a tag-listing fallback at any
status.
### ADR findings also had the crane half of the split compressed to the
point of being wrong. It reads no error code, but it does not fall back on
everything: CheckError admits only 200, 404, 400, and 406, so any
other status returns an error and never reaches the fallback arm. The entry now
carries the predicate the code implements, and attributes Notation's behavior to
oras-go rather than listing it beside two libraries it is not one of.
Size
101 insertions, 15 deletions, one file, documentation only. Well inside the reviewable-source ceiling; no justification owed.
Overlap
!2069 (merged) also writes this plan file. Its hunks sit at old lines 787-792 and 1340-1352; this branch's at 910, 1020, and 1612, so the two merge in either order. Whichever lands second should still be rebased before merge.
Checks
pre-commit clean, lychee included. The hook needs
env LYCHEE_VERSION=0.24.2 locally, because git commit exports GIT_DIR and
the hook's own tag detection then resolves against this repository instead of
its cached lychee clone. That is an environment gap rather than anything in this
diff, and the variable short-circuits the detection while still running the link
check.