Numeric document IDs are a global counter with no locking, and the resulting collisions have now put two production main branches red, three days apart. This is the highest-cost operational defect we have hit with 2119.
Evidence
panopticon, 2026-08-07: three concurrent branches each allocated REQ-050. Each branch's lint was green — the collision does not exist until the merge. Main's gate went red with 8 violations (2 duplicate-ID + 6 stale, 5 of them collision-caused). The project log records six collision waves in three days, the largest hitting five branches at once, with three prior repair commits (#177, 22ea6ef9, #209).
phoneopticon, red right now and undiagnosed for days:
check: FAIL — 34 violation(s), 0 uncovered, 0 failing review(s), 28 stale review(s)
REQ-009 openai-compatible-chat-adapter x notifier-rotation-and-launch
REQ-010 structured-action-approval x task-notification-dwell
REQ-011 coordinator-install-and-phone-config x notification-preferences
Both halves of each pair are on main, merged via separate PRs that were individually green.
Two distinct problems
1. The advisory "prefer file-scoped IDs" rule does not hold
File-scoped kebab-case namespaces exist precisely to end this class — a filename cannot be double-allocated silently. But REQ-052 and REQ-053 on panopticon, and REQ-009/010/011 on phoneopticon, were all allocated numerically after file-scoped IDs shipped, by agents that had read the guidance. A rule that documents a preference and enforces nothing gets ignored under concurrency, which is exactly when it matters.
Proposed: a config option (e.g. new_specs: file-scoped in .2119.yml) that makes a newly added numeric-grammar spec a lint error while grandfathering every existing file. Turn the README's advice into a gate. Repos mid-migration keep working; new drift stops.
2. The diagnostics point at the expensive wrong repair
When REQ-001.1.7 fires, the output is dominated by derived staleness — 28 "stale review(s)" on phoneopticon. That reads as "go re-review 28 requirements," which is hours of judgment review that cannot possibly work: each colliding ID resolves to two documents, so it has two evidence hashes and no verdict satisfies both. Recording one re-stales the other, permanently. The gate is mathematically unfixable by reviewing, and nothing in the output says so.
Proposed: when a duplicate document ID is detected, suppress the derived per-requirement staleness noise for the affected IDs and emit one actionable message — which files collide, that the staleness is an inherent flip-flop, and that the repair is renumber → prune → re-review only what genuinely changed.
3. Optional: catch it before the merge
lint --merge-base <ref> — evaluate the branch's document IDs against the merge base as well as the working tree, so a branch that will collide fails on the branch rather than after the merge. This is where the cost actually is: every collision so far was invisible until it was already on main.
Priority
Quality (gate integrity — a permanently red gate trains people to ignore it) and speed (removes repeated multi-hour repairs). No trade against either.
Numeric document IDs are a global counter with no locking, and the resulting collisions have now put two production main branches red, three days apart. This is the highest-cost operational defect we have hit with 2119.
Evidence
panopticon, 2026-08-07: three concurrent branches each allocated
REQ-050. Each branch'slintwas green — the collision does not exist until the merge. Main's gate went red with 8 violations (2 duplicate-ID + 6 stale, 5 of them collision-caused). The project log records six collision waves in three days, the largest hitting five branches at once, with three prior repair commits (#177,22ea6ef9, #209).phoneopticon, red right now and undiagnosed for days:
Both halves of each pair are on main, merged via separate PRs that were individually green.
Two distinct problems
1. The advisory "prefer file-scoped IDs" rule does not hold
File-scoped kebab-case namespaces exist precisely to end this class — a filename cannot be double-allocated silently. But
REQ-052andREQ-053on panopticon, andREQ-009/010/011on phoneopticon, were all allocated numerically after file-scoped IDs shipped, by agents that had read the guidance. A rule that documents a preference and enforces nothing gets ignored under concurrency, which is exactly when it matters.Proposed: a config option (e.g.
new_specs: file-scopedin.2119.yml) that makes a newly added numeric-grammar spec a lint error while grandfathering every existing file. Turn the README's advice into a gate. Repos mid-migration keep working; new drift stops.2. The diagnostics point at the expensive wrong repair
When
REQ-001.1.7fires, the output is dominated by derived staleness — 28 "stale review(s)" on phoneopticon. That reads as "go re-review 28 requirements," which is hours of judgment review that cannot possibly work: each colliding ID resolves to two documents, so it has two evidence hashes and no verdict satisfies both. Recording one re-stales the other, permanently. The gate is mathematically unfixable by reviewing, and nothing in the output says so.Proposed: when a duplicate document ID is detected, suppress the derived per-requirement staleness noise for the affected IDs and emit one actionable message — which files collide, that the staleness is an inherent flip-flop, and that the repair is renumber → prune → re-review only what genuinely changed.
3. Optional: catch it before the merge
lint --merge-base <ref>— evaluate the branch's document IDs against the merge base as well as the working tree, so a branch that will collide fails on the branch rather than after the merge. This is where the cost actually is: every collision so far was invisible until it was already on main.Priority
Quality (gate integrity — a permanently red gate trains people to ignore it) and speed (removes repeated multi-hour repairs). No trade against either.