Files
hq/04-ISSUES/155-two-records-may-share-a-number-and-nothing-says-so/00-report.md
T
jschoubben 47909c6b71 The records pointed at branches that no longer exist, and two fixes had no sequel
Three issues named the branch that fixed them, and a branch is deleted
when it merges — so every `fixed-by:` was a pointer that resolved to
nothing by the time anyone followed it. They name commits and pull
requests now, and playbook 03 says to.

Two records were missing the thing a reader arrives for. 146 did not say
that one of its fixes crash-looped the control plane on a running mesh,
which is the whole reason the delivery subject carries the stream and the
raise path was the only one exercised. 151 did not say that 152 removed
the false reasons its roster moved, or that it stays open for the real
ones.

ADR 0080 enumerates what cycle.py enforces and named four things; it
enforces five. A progressive insight names the fifth — the decision
stands, the list had gone stale. The checks README and playbook 03 gained
the same rule, and 155 points at all three.
2026-09-30 00:28:35 +02:00

2.8 KiB

status, opened, located-in, fixed-by, amended-design
status opened located-in fixed-by amended-design
resolved 2026-09-29
hq 00-META/checks/cycle.py
hq f89aef9 (PR 192)

155 — Two records may share a number, and every check passes

What was observed

On 2026-09-29 two machines opened issues against this repository within the same hour. Both read main correctly and both took "the next free number", and they collided twice:

one machine opened the other had already used
first 147, 148 147, 148 on an unmerged branch
second 149, 150 149 on an unmerged branch, 150 from renumbering the first collision

The first collision was reconciled by hand before merging. The second was merged into main, and records.py, cycle.py and index.py all reported success over a tree holding 149-a-declaration-that-shrinks-to-empty beside 149-an-adopted-machines-data-cannot-be-placed-where-it-is, and two folders numbered 150.

Why

The number is allocated as max(main) + 1, and main lags every open pull request — seven of them that evening. Two readers of the same main therefore compute the same next number, and neither is doing anything wrong. The existing reconciliation precedent (a second record numbered 127 became 149) assumed a single writer, which stopped being true when a second machine began filing its own findings.

Why it matters

An issue number is how every other record cites this one — fixed-by:, located-in:, a decision record's consequence, a commit message. Two records answering to one number is a citation that resolves to whichever folder the reader happened to open, and the failure is silent on both sides: the citer is not wrong, and the cited record exists.

It is also exactly the class this repository says it does not permit — a rule (00-META/process/03-issues.md: "take the next free number") enforced by nothing.

How it was fixed, and how the fix is checked

cycle.py now refuses a tree in which two issue folders share a leading number, and names both. Proven by adding a duplicate and watching it fail, then removing it and watching it pass.

The colliding records were renumbered 153 and 154, in the branch that landed last — renumbering a branch whose author is still pushing only moves the race.

The check catches the collision; it does not prevent it. Allocating a number still needs the open pull requests read as well as main. That is a habit the check now backstops rather than one it replaces, and playbook 03 now says so at the step where the number is taken.

ADR 0080 enumerates what cycle.py enforces and named four things; it carries a progressive insight naming the fifth. The decision stands — this is one more thing frontmatter and file names can carry, found by its absence.