Skip to content

docs/adr: three open PRs collide on ADR numbers and all merge clean — ADR-027 twice, ADR-025 against main, and ADR-018 already duplicated for 22 days #1402

Open

Description

@lilyshen0722

Three open PRs are about to add ADR files whose numbers already belong to something else. All of them merge clean, so nothing will go red and nothing will tell a reviewer.

Measured, not argued

main (cf10ee6ec) already carries one duplicate, which is the precedent:

$ git ls-tree --name-only origin/main docs/adr/ | grep -oE '^ADR-[0-9]+' | sort | uniq -d
ADR-018

Two more are queued right now.

Collision 1 — two open PRs both claiming ADR-027, opened three minutes apart:

$ git merge-tree --write-tree --messages refs/remotes/pr/1399 refs/remotes/pr/1401
exit=0
$ git ls-tree --name-only <result> docs/adr/ | grep ADR-027
docs/adr/ADR-027-pm-tool-projection-contract.md
docs/adr/ADR-027-work-claims-and-decision-ledger.md

Collision 2 — #1295 vs a file already merged. ADR-025-connector-substrate.md has been on main since before #1295 was opened; #1295 adds ADR-025-user-scoped-connectors-and-channel-routing.md:

$ git merge-tree --write-tree --messages origin/main refs/remotes/pr/1295
exit=0
$ git ls-tree --name-only <result> docs/adr/ | grep ADR-025
docs/adr/ADR-025-connector-substrate.md
docs/adr/ADR-025-user-scoped-connectors-and-channel-routing.md

(#1256 and #1083 also touch docs/adr/, but they edit existing filenames — those conflict normally and are fine. The defect is specific to adding a new file under a taken number.)

Why it's invisible

Disjoint filenames share no text, so git has nothing to conflict on. docs/adr/ has no index and no numbering check in CI. Highest number on main is ADR-026; every author independently and correctly reasoned "next is 027". Nothing they could have run would have shown them the other PR.

This is not carelessness by any of the three authors. It is a missing guard, and it has already fired once (ADR-018, undetected for 22 days).

Decision needed

Who keeps ADR-027. #1399 has seniority by 3 minutes; renumbering the other to ADR-028 is a filename change plus its internal self-references. Same call for #1295 — either renumber to the next free number, or, if it's genuinely an amendment to the connector substrate, fold it into the existing ADR-025-connector-substrate.md so it conflicts honestly.

Suggested guard

A CI check that fails when two files in docs/adr/ share an ADR-NNN prefix. It is a one-line uniq -d — the same command run above — and it would have caught all three instances, including the one that has been on main for 22 days.

Worth noting for whoever picks this up: #1401 is itself the ADR that documents the ADR-018 duplicate as evidence for a decision ledger. It is about to reproduce its own finding, which is the most concrete argument for the guard that I can offer.

Activity

  1. lilyshen0722 commented on Aug 31, 2026

    @lilyshen0722
    ContributorAuthor

    Correction to the issue body: #1295 is not an open decision. It was already ruled, a day before I filed this.

    I listed three collisions needing a decision. Only one of them does.

    The guard proposal is unaffected, and the correction actually strengthens it. That same comment identifies the identical defect one level down: once #1295 folds, the merged file carries two independent D1…D7 sequences, so "ADR-025 D3" resolves to two different decisions and nothing goes red. A uniq -d on filename prefixes would not catch that — so if anyone builds the guard, the shape worth reaching for is ambiguous decision identifiers, of which duplicate ADR numbers are the coarsest case.

    On how I got it wrong, since it is the same failure this repo keeps paying for: I measured three merge-trees and filed, without reading the PR's existing comments. The record was on the object I was filing against, it was a day old, and it named me in its second sentence. A measurement is not a substitute for reading what is already on the thing you are measuring — and being rigorous about the mechanical part is exactly what made the reading step feel already done.

  2. lilyshen0722 commented on Aug 31, 2026

    @lilyshen0722
    ContributorAuthor

    Ruled. Sam settled the ADR-027 collision (2026-08-31 03:44Z):

    That closes the last open decision in this issue. Recording the reasoning behind the cross-link because it is the part a renumber alone would lose: these two ADRs are not merely adjacent, they are coupled, and the coupling is exactly what the numbering accident obscured. Per the repo's own ADR-status discipline, when two ADRs sit adjacent on a subject the one a reader reaches first must carry a scope-boundary note naming the other.

    Status of all three collisions:

    Collision State
    ADR-027 (#1399 vs #1401) Ruled — #1399 keeps 027, #1401 → 028
    ADR-025 (#1295 vs main) Ruled earlier (fold into one ADR-025); I withdrew my duplicate finding
    ADR-018 (two files on main) Still unguarded, 22 days

    What this issue is now for: the guard, and only the guard. All three collisions were caught by a human reading titles, twice after the fact. Nothing in CI can see any of them, because disjoint filenames have nothing to conflict on.

    Restating the target shape from the earlier correction, since it survives the rulings: the check worth building is ambiguous decision identifiers, of which duplicate ADR-NNN filename prefixes are the coarsest case. A uniq -d on prefixes catches ADR-018 and would have caught both of tonight's — but it will not catch the finer case @pod-architect identified on #1295, where one reconciled file carries two independent D1…D7 sequences and a citation to "ADR-025 D3" resolves to two different decisions.

    I will re-stamp #1401 once the renumber lands; my gate is pinned to a6225e2e and a rename moves the tree.


    (Edited to repair two code spans — ADR-NNN and uniq -d — that my shell ate as backtick command substitution when I posted this inline instead of from a file. They vanished silently rather than erroring, leaving "duplicate filename prefixes". Flagging rather than quietly fixing, since a swallowed span in a spec sentence is the same failure class this issue is about.)

  3. lilyshen0722 commented on Aug 31, 2026

    @lilyshen0722
    ContributorAuthor

    Update: collision 2 has stopped being hypothetical. This issue argued the ADR-025 duplicate would misresolve citations. It now does, in a PR under review.

    #1399's ADR-027 carries three ADR-025 D* citations. Resolved against both files:

    citation #1295's ADR-025 (unmerged) main's ADR-025 (merged)
    D2 — "Transport is kernel; judgment is agent (inherits ADR-025 D2)" "Transport is kernel; curation is agent" — match "Add a conversational outbound verb to the provider contract"
    D3 — "The mapping table IS the router" "Outbound messages carry their pod" "A provider declares its directions"

    The D2 match is verbatim, so the intent is unambiguous: #1399 is written against #1295's numbering, which is not on main. A reader who follows that citation against the merged tree today lands on a different decision. I have corrected my own review on #1399, which had filed this as a future ratification risk rather than a present error.

    So the cost of this issue is no longer "a reviewer might get confused later" — it is one ADR already citing the wrong document, found by @pod-architect and confirmed here against both files.

    One correction to the guard I proposed

    The check in the opening comment is uniq -d over main's docs/adr/. That check cannot see collision 2. Run today it returns ADR-018 only:

    $ git ls-tree --name-only origin/main docs/adr/ | grep -oE 'ADR-[0-9]{3}' | sort | uniq -d
    ADR-018
    

    main holds exactly one ADR-025; the duplicate only exists in the merge result with #1295. A guard that runs against the base branch is structurally blind to the case where a PR adds the colliding file — which is every case that matters, because that is the only moment the collision is still cheap to fix. The guard has to run on the PR's merge result (or equivalently, diff the PR's added ADR filenames against the base's number set). Same class of error as validating a review's sha against the value it was copied from: the two sides agree by construction, so their agreement carries no information.

    Why ADR-018 has survived 22 days

    Worth recording, because it explains the absence of symptoms and it does not generalise:

    $ git show origin/main:docs/adr/ADR-018-agent-identity.md | head -3
    # ADR-018 — Agent identity
    **Status:** Proposed (stub — decision not yet made)
    

    That file has zero D-headings. So all 20+ ADR-018 Dk citations in the codebase resolve unambiguously to ADR-018-agent-attention-claims.md — not because the number is unique, but because only one of the two claimants has any decisions to cite. The moment anyone writes a D1 into the identity stub, every one of those citations becomes ambiguous at once, including CLAUDE.md's own ADR-status-discipline section, which cites ADR-018 D8 while arguing about ADR-018 vs ADR-020.

    That is not a stable state to leave a repo in, and it is not visible to anyone who is not looking for it — the citations keep working right up until they silently don't.

  4. lilyshen0722 commented on Aug 31, 2026

    @lilyshen0722
    ContributorAuthor

    Re-measured against origin/main at cf10ee6e and all 100 open PRs. One of the three collisions in the title has resolved; two are live. Updating so this issue stops carrying a stale claim.

    Every open PR that adds a new ADR file (swept all open PRs, not a sample):

    #1295  docs/adr/ADR-025-user-scoped-connectors-and-channel-routing.md   COLLIDES
    #1399  docs/adr/ADR-027-pm-tool-projection-contract.md                  free
    #1401  docs/adr/ADR-028-work-claims-and-decision-ledger.md              free
    

    ADR numbers on main: 021 022 023 024 025 026. Next free is ADR-029.

    RESOLVED — "ADR-027 twice." #1401 was renumbered to ADR-028 and I re-stamped it at 770fb1fa. 027 is now claimed once, by #1399.

    LIVE — ADR-025 against main. #1295 still adds a second ADR-025-* beside ADR-025-connector-substrate.md. I have now filed a BLOCK on that PR with the renumber-to-029 remedy. Worth recording that this one is a reviewer failure and not only a tooling gap: the substrate ADR landed on main 2026-08-29 18:02 and I passed #1295 fourteen hours later, at 08-30 08:18, without checking its number against the tree. A guard would have caught what I did not.

    LIVE — ADR-018 duplicated on main. Confirmed present today:

    docs/adr/ADR-018-agent-attention-claims.md
    docs/adr/ADR-018-agent-identity.md
    

    This one matters for guard design, and it is the counterexample to my own earlier correction on this issue. I noted before that a uniq -d over main could not detect the #1295 collision because that duplicate exists only in the merge result. Both halves are true and they imply the guard needs both checks, not one:

    A guard with only the first never notices the duplicate that has been sitting on main for weeks; a guard with only the second passes #1295 cleanly. That asymmetry is the actual design requirement here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions