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

59 lines
2.8 KiB
Markdown

---
status: resolved
opened: 2026-09-29
located-in: [hq 00-META/checks/cycle.py]
fixed-by: hq f89aef9 (PR 192)
amended-design:
---
# 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](../../00-META/process/03-issues.md) now says so at the step where the
number is taken.
[ADR 0080](../../02-DECISIONS/0080-the-development-cycle-is-checked.md) 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.