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
Dogfooding on skullcaps-native hit a real ADR-0016 double-assignment that the guard reported STATUS=OK for:
docs/blueprint/adrs/0016-in-engine-ui-not-win32-dialogs.md — frontmatter id: ADR-0016, registered in the manifest
docs/adrs/objs-format.md — frontmatter id: ADR-0016, unregistered, and cited as ADR-0016 by two other documents
Both are genuine ADRs. The guard missed it for two compounding reasons:
normalize() derives the number from the NNNN-title.mdbasename (script line ~59), so objs-format.md contributes no number at all.
ADR_DIR resolves to a single directory, so the two claimants were never compared.
The cause is documented inside one of the colliding files — 0016-in-engine-ui-not-win32-dialogs.md:17 records that its author computed "next free slot" from the manifest, not knowing objs-format.md had already self-assigned 0016 in its own frontmatter. That's precisely #1585's branch-time-vs-claim-time race, in a form the shipped guard can't see.
Same repo, same run: INDEX=absent for docs/adrs/, while the other ADR directory's README index listed 8 of 25 ADRs, carried a stale status for one, and offered an awk one-liner as the regeneration recipe whose END block prints a single row regardless of input.
How
1. Detect frontmatter id claims. Union the basename-derived number with a frontmatter id: ADR-NNNN parse. A file claiming a number in frontmatter that a different file claims by filename is the same duplicate_adr_number class already implemented — only the collection step needs widening.
2. Support multiple ADR directories. Accept repeated --adr-dir, or read the set from the manifest. Cross-directory is where this bug lived; a single-directory assumption makes it structurally undetectable. (Relatedly: this repo's ADR ids span docs/adrs/ and docs/blueprint/adrs/, which #1357 already touched from the writer side.)
3. Prefer the manifest as the arbiter.id_registry is the only place that resolves id→path unambiguously; two files can both say ADR-0016 but only one can be registered. Reporting "file X claims ADR-NNNN but the registry maps NNNN to Y" catches this in one comparison and needs no filename convention at all.
4. Generate the index rather than warning about it. A small generator that rebuilds the index table from frontmatter between <!-- adr-index:start --> / <!-- adr-index:end --> markers, with a --check mode for CI. That turns adr_missing_index_row from a warning into a fixable state and removes the hand-maintained table that rotted here.
Status
Working implementation of (4) exists locally (~130 lines, --check mode, wired to pre-commit + CI; regenerates 25 ADRs across two directories). (1)-(3) are small changes to the existing script. Happy to PR either or both with tests matching scripts/tests/.
Not urgent — the collision is fixed downstream by renumbering to ADR-0035. Filing because the guard reported OK on a real collision, which is the kind of false-negative worth closing while the evidence is concrete.
What
Two gaps in the ADR collision guard that shipped for #1585 (
blueprint-adr-validate/scripts/check-adr-numbers.sh):adr_missing_index_rowcan only warn, never repair — and a stale index is what blueprint-plugin: placeholder ADR numbers with merge-time assignment (parallel-PR collision guard) #1585 itself named as how the original0038collision went unnoticed for a week.Why
Dogfooding on
skullcaps-nativehit a real ADR-0016 double-assignment that the guard reportedSTATUS=OKfor:docs/blueprint/adrs/0016-in-engine-ui-not-win32-dialogs.md— frontmatterid: ADR-0016, registered in the manifestdocs/adrs/objs-format.md— frontmatterid: ADR-0016, unregistered, and cited as ADR-0016 by two other documentsBoth are genuine ADRs. The guard missed it for two compounding reasons:
normalize()derives the number from theNNNN-title.mdbasename (script line ~59), soobjs-format.mdcontributes no number at all.ADR_DIRresolves to a single directory, so the two claimants were never compared.The cause is documented inside one of the colliding files —
0016-in-engine-ui-not-win32-dialogs.md:17records that its author computed "next free slot" from the manifest, not knowingobjs-format.mdhad already self-assigned 0016 in its own frontmatter. That's precisely #1585's branch-time-vs-claim-time race, in a form the shipped guard can't see.Same repo, same run:
INDEX=absentfordocs/adrs/, while the other ADR directory's README index listed 8 of 25 ADRs, carried a stale status for one, and offered anawkone-liner as the regeneration recipe whoseENDblock prints a single row regardless of input.How
1. Detect frontmatter id claims. Union the basename-derived number with a frontmatter
id: ADR-NNNNparse. A file claiming a number in frontmatter that a different file claims by filename is the sameduplicate_adr_numberclass already implemented — only the collection step needs widening.2. Support multiple ADR directories. Accept repeated
--adr-dir, or read the set from the manifest. Cross-directory is where this bug lived; a single-directory assumption makes it structurally undetectable. (Relatedly: this repo's ADR ids spandocs/adrs/anddocs/blueprint/adrs/, which #1357 already touched from the writer side.)3. Prefer the manifest as the arbiter.
id_registryis the only place that resolves id→path unambiguously; two files can both say ADR-0016 but only one can be registered. Reporting "file X claims ADR-NNNN but the registry maps NNNN to Y" catches this in one comparison and needs no filename convention at all.4. Generate the index rather than warning about it. A small generator that rebuilds the index table from frontmatter between
<!-- adr-index:start -->/<!-- adr-index:end -->markers, with a--checkmode for CI. That turnsadr_missing_index_rowfrom a warning into a fixable state and removes the hand-maintained table that rotted here.Status
Working implementation of (4) exists locally (~130 lines,
--checkmode, wired to pre-commit + CI; regenerates 25 ADRs across two directories). (1)-(3) are small changes to the existing script. Happy to PR either or both with tests matchingscripts/tests/.Not urgent — the collision is fixed downstream by renumbering to ADR-0035. Filing because the guard reported OK on a real collision, which is the kind of false-negative worth closing while the evidence is concrete.