Merge pull request 'Two records shared a number, twice, and every check passed' (#192) from issue/two-records-share-a-number-and-nothing-says-so into main
This commit was merged in pull request #192.
This commit is contained in:
+23
-1
@@ -14,7 +14,8 @@ What is enforced:
|
||||
its owning code (`code:`) -- no development without a design that says where.
|
||||
issues a known `status:`; once `located`, `located-in:` names the owner;
|
||||
once `resolved`, `fixed-by:` says what fixed it (prose counts --
|
||||
"nothing, the capability existed" is an answer).
|
||||
"nothing, the capability existed" is an answer). And no two records share a
|
||||
number -- the number is how a record is cited.
|
||||
research a known `status:`; a `graduated` overview says what it `became:`, and every
|
||||
target it names exists.
|
||||
decisions every accepted record is REACHABLE from the cycle: cited by a design doc's
|
||||
@@ -109,6 +110,27 @@ def main():
|
||||
"without a design that says where" % status)
|
||||
|
||||
# ---- issues ------------------------------------------------------------------------
|
||||
# Two records may not share a number. Numbers are taken as "next free after main", and work
|
||||
# sits on unmerged branches for days -- so two people reading the same main allocate the same
|
||||
# number, and nothing said so. It happened twice in one evening between two machines, and the
|
||||
# second collision landed on main with all three checks passing (issue 155). An issue number is
|
||||
# how every other record cites this one; two records answering to it means a pointer that
|
||||
# resolves to whichever the reader happened to open.
|
||||
seen = {}
|
||||
for folder in sorted(glob.glob(os.path.join(ROOT, "04-ISSUES", "*", ""))):
|
||||
name = os.path.basename(os.path.normpath(folder))
|
||||
number = name.split("-", 1)[0]
|
||||
if not number.isdigit():
|
||||
continue
|
||||
if number in seen:
|
||||
bad(os.path.join("04-ISSUES", name),
|
||||
"is numbered %s, and so is %s -- an issue number is how it is cited, and two "
|
||||
"records answering to one means a citation that resolves to whichever the reader "
|
||||
"opened. Take the next free number across main AND every open pull request"
|
||||
% (number, seen[number]))
|
||||
else:
|
||||
seen[number] = name
|
||||
|
||||
for path in sorted(glob.glob(os.path.join(ROOT, "04-ISSUES", "*", "00-report.md"))):
|
||||
front = frontmatter(path)
|
||||
if front is None:
|
||||
|
||||
+1
-1
@@ -8,7 +8,7 @@ fixed-by:
|
||||
amended-design:
|
||||
---
|
||||
|
||||
# 149 — An adopted machine's data cannot be placed where it is
|
||||
# 153 — An adopted machine's data cannot be placed where it is
|
||||
|
||||
## What was observed
|
||||
|
||||
+1
-1
@@ -8,7 +8,7 @@ fixed-by:
|
||||
amended-design:
|
||||
---
|
||||
|
||||
# 150 — A machine's own network is not a reach
|
||||
# 154 — A machine's own network is not a reach
|
||||
|
||||
## What was observed
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
---
|
||||
status: resolved
|
||||
opened: 2026-09-29
|
||||
located-in: [hq 00-META/checks/cycle.py]
|
||||
fixed-by: hq issue/two-records-share-a-number-and-nothing-says-so
|
||||
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.
|
||||
Reference in New Issue
Block a user