Skip to content

feat(FAFF-368): re-validate ADR numbering at the merge gate, renumber on collision#288

Merged
alechill merged 3 commits into
mainfrom
faff-368-adr-renumber-merge-gate
Jul 7, 2026
Merged

feat(FAFF-368): re-validate ADR numbering at the merge gate, renumber on collision#288
alechill merged 3 commits into
mainfrom
faff-368-adr-renumber-merge-gate

Conversation

@alechill

@alechill alechill commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

What

Adds a mechanical guard so a concurrent-graft ADR-number collision can't reach main (FAFF-368). Two grafts allocate the same ADR number at branch-base time and both merge → duplicate on main reddens faff adr validate on every open PR until an out-of-band hotfix (the live incident: PR #264/#265 both minted ADR-0043).

Changes

  • faff adr renumber <selector> --to <NNNN|next> [--ref-scope f,f…] — the deterministic merge-time collision-repair primitive: move one ADR to a free number, fix its heading + in-ref-scope canonical back-refs, re-validate. git-agnostic (pure fs; the caller stages the rename). Refuses (exit 1) an occupied target, an ambiguous bare number, or a still-red re-validate, leaving no partial move. Ref-scope is bounded to real docs/adr/ ADR files (basename + ADR_FILE_RE) so it never touches a file this PR didn't create.
  • faff adr validate now names every colliding file: duplicate ADR number NNNN — f1, f2 (serves the CI backstop and the graft guard).
  • faff-graft Step 10 gains the ADR-collision merge guard, folded into the concurrent rebase-revalidate before the single CI re-confirm; fail-closed needs-human on pre-existing-broken-main / ambiguous / non-zero-renumber / still-red re-validate.
  • Docs: docs/guide/cli.md + the adr usage line document renumber.
  • Tests: adr --selftest (+12 cases) and test/adr.test.mjs (+6 tests) cover the two-branch collision regression, ref-scope bound (in-scope follows, out-of-scope byte-identical, asymmetric → red exit 1, non-ADR entry ignored), occupied/ambiguous refusals, and the sharpened duplicate message.

Spec: docs/specs/2026-07-07-FAFF-368-adr-renumber-merge-gate-design.md

alechill added 3 commits July 7, 2026 16:02
… on collision

Concurrent grafts allocate the same ADR number at branch-base time and both
merge, landing a duplicate on main that reddens `faff adr validate` on every
open PR until an out-of-band hotfix renumbers one. Add a mechanical guard at
the graft merge gate that detects the duplicate against the merge-target tree
and renumbers the incoming ADR to a free number before ship.

- New `faff adr renumber <selector> --to <NNNN|next> [--ref-scope f,f...]`: the
  deterministic collision-repair primitive — move one ADR to a free number, fix
  its heading + in-`ref-scope` canonical back-refs, re-validate. git-agnostic
  (pure fs; the caller stages the rename). Refuses (exit 1) an occupied target,
  an ambiguous bare number, or a still-red re-validate, leaving no partial move.
- `faff adr validate` now names every colliding file on a duplicate number
  (`duplicate ADR number NNNN — f1, f2`), serving both the CI backstop and the
  graft guard.
- faff-graft Step 10 gains the ADR-collision merge guard, folded into the
  concurrent rebase-revalidate before the single CI re-confirm; fail-closed
  needs-human on pre-existing-broken-main / ambiguous / non-zero-renumber.
- adr --selftest + test/adr.test.mjs cover the two-branch collision regression,
  ref-scope bound (in-scope follows, out-of-scope byte-identical, asymmetric →
  red), occupied/ambiguous refusals, and the sharpened duplicate message.
- docs/guide/cli.md + the `adr` usage line document `renumber`.
…touch a non-ADR path)

Adversarial review flagged that --ref-scope entries were read/rewritten without
verifying they are ADR files, so an arbitrary or path-traversed entry could in
principle be touched. Keep only basenames matching ADR_FILE_RE, so the rewrite
blast radius is bounded to this-PR ADR files under docs/adr/ — upholding the
spec's 'never touch main's untouched files' invariant.
@alechill alechill merged commit a42614b into main Jul 7, 2026
2 checks passed
@alechill alechill deleted the faff-368-adr-renumber-merge-gate branch July 7, 2026 16:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant