You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Out-of-scope finding from #6676 / PR #7316 (the ADR-0107 tombstone). Recorded, not claimed. Observation-class: nothing a user hits today, and both halves are deliberately-deferred judgment calls, not defects.
#6676 explicitly deferred its own optional half — "Optionally teach check:adr-anchors to flag future gaps (separate judgment — gaps may be legitimate)" — and that half dies with the card when PR #7316 closes it. This issue carries it forward with the measurement that was missing, plus a second fact PR #7316 introduced. Both would be fixed inside one change ("teach the gate about ADR numbers that are not live decisions"), which is why they are one card rather than two.
Fact 1 — gaps are NOT uniformly illegitimate; measured, four holes, three causes
docs/adr/ holds 119 records with max 0122. The holes, each chased on full history (9,829 commits, clone verified unshallowed):
Hole
Cause
Evidence
0001
Record deleted 2026-02-11 in the permission-protocol rewrite; still cited as history by ADR-0002
9da8e3e72; on UNRESOLVED_ADR_CITATIONS
0075
Drafted only on an unmerged branch — never assigned on main
148f4c8f5, 617f3f8ae; both git merge-base --is-ancestor ... origin/main = false
0083
Never existed, on any branch, at any time; never cited
no path ever matched *0083*; no citations
0107
Landed 2026-07-28 00:25, withdrawn 09:24 the same day
53d37f1ae (#3716) / 3bb382b67 (#3735) — tombstoned by PR #7316
So a blanket "flag every gap" would be wrong: 0075 and 0083 are ordinary, blameless number skips, and 0001 is already grandfathered on purpose. Only the 0107 shape (a number that was a live record) carries the squat risk #6634 is about. Any gate here needs to discriminate, and this table is the discrimination data.
This is the input #6676 asked for, not a request to build the gate. Whether a gap check is worth having at all is the open question.
Fact 2 — a tombstone reads to the gate as a decision that exists
PR #7316 adds the corpus's first tombstone, docs/adr/0107-withdrawn-hook-body-write-set-static-gap.md: a record whose entire content is "this number is withdrawn, do not reuse".
check-adr-anchors.mjs builds its records set from filenames only (auditAdrDirectory), so the tombstone satisfies both the citation audit (intended and wanted — the historical ADR-0107 citations now resolve) and the anchor loop's if (!records.has(...)) guard, which was never meant to accept it. A future scripts/adr-anchors/*.json entry anchoring live code to ADR-0107 would pass.
Consequences are small and bounded today:
nothing anchors ADR-0107, and nothing should;
the anchor schema requires an invariant stating what the ADR decided — unwritable truthfully for a number that decided nothing, so the mistake is caught by a reader, not by the gate;
The gate has no concept of "a record that is not a decision", which is the same missing concept as Fact 1. Options if this is ever taken up: a front-matter status the gate reads; a filename convention (NNNN-withdrawn-*); or an explicit list. All three are contract choices, hence a finding rather than a patch.
Scope discipline: #6676's card said the gate question is "explicitly OPTIONAL and separate… Do not implement it in this PR." Fact 2 was found while implementing it and is recorded here for the same reason.
Refs: #6676, PR #7316, #6634 (the citation audit and the squat failure mode), #5992 (the number-uniqueness audit).
Out-of-scope finding from #6676 / PR #7316 (the ADR-0107 tombstone). Recorded, not claimed. Observation-class: nothing a user hits today, and both halves are deliberately-deferred judgment calls, not defects.
#6676 explicitly deferred its own optional half — "Optionally teach
check:adr-anchorsto flag future gaps (separate judgment — gaps may be legitimate)" — and that half dies with the card when PR #7316 closes it. This issue carries it forward with the measurement that was missing, plus a second fact PR #7316 introduced. Both would be fixed inside one change ("teach the gate about ADR numbers that are not live decisions"), which is why they are one card rather than two.Fact 1 — gaps are NOT uniformly illegitimate; measured, four holes, three causes
docs/adr/holds 119 records with max0122. The holes, each chased on full history (9,829 commits, clone verified unshallowed):00019da8e3e72; onUNRESOLVED_ADR_CITATIONS0075main148f4c8f5,617f3f8ae; bothgit merge-base --is-ancestor ... origin/main= false0083*0083*; no citations010753d37f1ae(#3716) /3bb382b67(#3735) — tombstoned by PR #7316So a blanket "flag every gap" would be wrong:
0075and0083are ordinary, blameless number skips, and0001is already grandfathered on purpose. Only the0107shape (a number that was a live record) carries the squat risk #6634 is about. Any gate here needs to discriminate, and this table is the discrimination data.This is the input #6676 asked for, not a request to build the gate. Whether a gap check is worth having at all is the open question.
Fact 2 — a tombstone reads to the gate as a decision that exists
PR #7316 adds the corpus's first tombstone,
docs/adr/0107-withdrawn-hook-body-write-set-static-gap.md: a record whose entire content is "this number is withdrawn, do not reuse".check-adr-anchors.mjsbuilds itsrecordsset from filenames only (auditAdrDirectory), so the tombstone satisfies both the citation audit (intended and wanted — the historicalADR-0107citations now resolve) and the anchor loop'sif (!records.has(...))guard, which was never meant to accept it. A futurescripts/adr-anchors/*.jsonentry anchoring live code toADR-0107would pass.Consequences are small and bounded today:
ADR-0107, and nothing should;invariantstating what the ADR decided — unwritable truthfully for a number that decided nothing, so the mistake is caught by a reader, not by the gate;The gate has no concept of "a record that is not a decision", which is the same missing concept as Fact 1. Options if this is ever taken up: a front-matter status the gate reads; a filename convention (
NNNN-withdrawn-*); or an explicit list. All three are contract choices, hence a finding rather than a patch.Why this is not in PR #7316
Scope discipline: #6676's card said the gate question is "explicitly OPTIONAL and separate… Do not implement it in this PR." Fact 2 was found while implementing it and is recorded here for the same reason.
Refs: #6676, PR #7316, #6634 (the citation audit and the squat failure mode), #5992 (the number-uniqueness audit).