Skip to content
1 change: 1 addition & 0 deletions docs/BACKLOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,7 @@ are closed (status: closed in frontmatter)._
- [ ] **[B-0448](backlog/P1/B-0448-cloud-routines-integration-4th-catch-43-defence-layer-2026-05-13.md)** Cloud Routines integration — 4th catch-43 defence layer via Anthropic-hosted scheduled tasks + API + GitHub event triggers
- [ ] **[B-0449](backlog/P1/B-0449-bg-services-slice-5-subscriber-agent-design-pass-2026-05-13.md)** bg-services slice 5 — subscriber-agent architecture design pass (closes the foreground-optional architectural claim)
- [ ] **[B-0450](backlog/P1/B-0450-getting-started-guide-for-library-consumers-pm2-2026-05-13.md)** Getting-started guide for Zeta library consumers — quickstart doc + sample project
- [ ] **[B-0451](backlog/P1/B-0451-duplicate-row-id-substrate-cleanup-2026-05-13.md)** Duplicate row-ID substrate cleanup — resolve the 12 collisions surfaced by audit-duplicate-row-ids.ts

## P2 — research-grade

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
---
id: B-0451
priority: P1
status: open
title: "Duplicate row-ID substrate cleanup — resolve the 12 collisions surfaced by audit-duplicate-row-ids.ts"
tier: factory-infrastructure
effort: M
created: 2026-05-13
last_updated: 2026-05-13
depends_on: []
composes_with: []
tags: [substrate-hygiene, backlog, ID-collision, audit-finding, multi-Otto-coordination]
type: friction-reducer
---

# B-0451 — Duplicate row-ID substrate cleanup

## Origin

Filed 2026-05-13 after the same-tick discovery: while resolving the
B-0444 ID collision (PR #3053), an inline audit (`find docs/backlog
| awk` over each row's `id:` field) revealed **12 additional
duplicate-ID groups** across the backlog directory. The audit tool
`tools/bg/audit-duplicate-row-ids.ts` was shipped alongside this
row (same PR) to mechanize the check going forward.

## What the audit reports

```
$ bun tools/bg/audit-duplicate-row-ids.ts
audit-duplicate-row-ids: 12 duplicate-ID group(s) found across 559 rows:
B-0068.1: forge-cli-ollama-research-slice (P2) vs -xs-riven (P2)
B-0090.1: lost-substrate-3-bucket-classification-taxonomy vs ts-worktree-survey-atomic-riven
B-0090.2: ts-orphan-branch-survey-atomic-riven vs worktree-branch-delta-audit
B-0090.3: closed-not-merged-pr-scan vs ts-closed-pr-survey-atomic-riven
B-0090.4: cadence-and-hygiene-history-hook vs ts-draft-pr-aged-survey-atomic-riven
B-0370: durable-computation-checkpoint-interface (P1) vs contributor-compliance-core (P2)
B-0371: pages-seo-metadata-jsonld (P1) vs contributor-compliance-cross-reference (P2)
B-0372: pages-sitemap-robots (P1) vs t1-t2-self-audit-trajectories (P2)
B-0373: alignment-proof-primitive-ladder (P1) vs t4-t5-onboarding-drift-trajectories (P2)
B-0409: wallet-immune-system-vaccine (P1) vs amara-persona-bootstrap (P2) vs peer-call-ts-audit (P2) [3-way]
B-0410: amara-ts-core-openai-api (P2) vs peer-call-persona-loader (P2)
B-0411: amara-ts-readme-update-courier (P2) vs grok-ts-persona-flag (P2)
```

## Collision-class taxonomy

Two distinct collision patterns visible:

1. **Cross-priority namespace bleed** (`B-0370..B-0373`): Otto-on-CLI
filed P1 rows in the 0370 range (durable / SEO / sitemap /
alignment) while a parallel agent filed P2 rows in the same
range (contributor-compliance, trajectory-audit). The same
pattern produced the B-0444 P1+P2 collision resolved by PR #3053.

2. **Within-priority concurrent decomposition** (`B-0068.1`,
`B-0090.1-4`, `B-0409-0411`): Two agents (likely Riven + Otto)
decomposed adjacent atomic sub-row series simultaneously and
landed on overlapping sub-row numbers. Most are 2026-05-10/11
timeframe — pre-claim-acquire-rule (PR #3032 landed 2026-05-13).

## Resolution per collision

For each colliding group, apply the substrate-honest rule (per
PR #3053's resolution):

1. **If one of the colliding rows has external references** (PR
commits, sibling-row composes_with, etc.) → KEEP that one with
its original ID.
2. **If both are unreferenced** → keep the one that was filed
first (per git log on the directory).
3. **Renumber the other** to the next-free ID with
`renumbered_from: B-NNNN` + reason in the frontmatter.
4. **Update all cross-references** to the renumbered row.

This is bounded mechanical work: 12 groups × ~5 minutes each =
~60 minutes total. Can be done atomically (one PR per group) or
bundled (one PR for the full sweep).

## Acceptance criteria

- [ ] Each of the 12 colliding groups resolved (one row keeps the
ID; others renumbered with provenance recorded).
- [ ] `bun tools/bg/audit-duplicate-row-ids.ts` exits 0 on main.
- [ ] All cross-references updated (B-0445 composes_with, B-0271
gap-table, etc.).
- [ ] `docs/BACKLOG.md` regenerated.
- [ ] Wire `audit-duplicate-row-ids.ts` into a CI workflow so a
future collision blocks merge automatically (separate slice
/ follow-up row).

## Why P1

Silently-overwriting substrate state is high-severity hygiene risk.
A consumer of `id: B-0409` gets one of THREE files depending on
load order; the implicit "primary key" guarantee that every other
substrate consumer relies on is broken. The audit tool surfaces
the symptoms; this row tracks the cleanup.

## Composes with

- PR #3053 (the B-0444 resolution that surfaced the broader pattern)
- PR shipping `tools/bg/audit-duplicate-row-ids.ts` (same as this
row's filing PR)
- `.claude/rules/claim-acquire-before-worktree-work.md` — coordination
discipline that would have prevented most of these had it been
in force during the 05-10/11 timeframe

## Future work

- CI wiring (separate slice): `tools/bg/audit-duplicate-row-ids.ts`
added as a required-check job so future collisions block merge.
- Mechanize "next-free-ID" lookup in row-creation tooling so manual
ID selection doesn't drift.
120 changes: 120 additions & 0 deletions docs/hygiene-history/ticks/2026/05/13/2317Z.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
---
tick: 2026-05-13T23:17Z
agent: otto-cli
session: cron-resumption
pr: 3056
---

# Tick 2317Z — Duplicate-ID audit tool + 12 collisions surfaced + competing PR closed

## Refresh

- CronList: live (`9ac08520`, `* * * * *`, sentinel `<<autonomous-loop>>`).
- PR #3053 (B-0444 ID collision fix) MERGED → `25729eb`.
- PR #3051 (Codex loop headless provenance) MERGED → `e2c306e`.
- Competing PR #3052 (parallel Otto-Desktop, targeted taken B-0449)
closed with substrate-honest comment pointing to #3053.

## Speculative work picked

Per the previous tick's insight ("`tools/bg/audit-duplicate-row-ids.ts`
is the next hygiene tool that wants to exist"), an inline audit run
against `origin/main` discovered **12 more ID collisions** beyond the
B-0444 one that #3053 resolved. The substrate-honest move: ship the
audit tool + file the cleanup row in one PR.

## Landed concretely

| Artifact | Where | What |
|---|---|---|
| `tools/bg/audit-duplicate-row-ids.ts` | PR #3056 | New audit tool: walks `docs/backlog/` via `git ls-files`, extracts frontmatter `id:`, reports any ID in >1 file; exit 0/1 |
| `tools/bg/audit-duplicate-row-ids.test.ts` | PR #3056 | 14 tests covering extraction + sorting + real-world patterns (pair, triple, missing-id skip, sub-row IDs, unreadable-file resilience) |
| `docs/backlog/P1/B-0451-...md` | PR #3056 | Tracks the 12-collision cleanup work + taxonomy + per-collision resolution rule |
| `docs/BACKLOG.md` | PR #3056 | Regenerated |
| PR #3052 close | gh CLI | Closed with comment explaining B-0449 conflict + pointing to #3053 |

## Discovered substrate state

`bun tools/bg/audit-duplicate-row-ids.ts` on `origin/main`:

```
12 duplicate-ID group(s) found across 559 rows:
B-0068.1 ×2
B-0090.1 ×2
B-0090.2 ×2
B-0090.3 ×2
B-0090.4 ×2
B-0370 ×2 (P1/P2)
B-0371 ×2 (P1/P2)
B-0372 ×2 (P1/P2)
B-0373 ×2 (P1/P2)
B-0409 ×3 (P1/P2/P2) ← three-way!
B-0410 ×2
B-0411 ×2
```

## Collision-class taxonomy

Two distinct patterns:

1. **Cross-priority namespace bleed** (`B-0370..B-0373`, the B-0444
pattern): Otto-CLI files P1 rows in some range; parallel agent
files P2 rows in the same range; both pick the same number.
2. **Within-priority concurrent decomposition** (`B-0068.1`,
`B-0090.1-4`, `B-0409-0411`): two agents decompose adjacent
atomic sub-row series simultaneously. Most are 2026-05-10/11 —
**pre-claim-acquire-rule** (`.claude/rules/claim-acquire-...`
landed 2026-05-13 via PR #3032).

## Multi-Otto coordination evidence

PR #3052 (Otto-Desktop's parallel fix attempt) discovered the same
B-0444 collision independently AND tried to renumber to B-0449 —
which Otto-Desktop's own PR #3046 had just taken. Same Otto, two
surfaces, both noticed the collision, both attempted a fix, neither
checked next-free-ID against the just-merged sibling work.

My PR #3053 won by picking the actually-free B-0450. PR #3052 closed
with substrate-honest comment preserving the coordination context
in the discussion thread.

This is the EXACT failure class the new audit tool prevents going
forward.

## Holding-discipline check

PR #3056 named-dependency: required CI in flight, auto-merge armed,
threads clear, `wait-ci`. Real-dependency-wait — not Holding.

## Verify

- 14/14 pass on `tools/bg/audit-duplicate-row-ids.test.ts`
- Tool against real substrate: 12 groups found, exits 1 (will exit 0
once B-0451's per-collision cleanup ships)
- Backlog index regenerated cleanly (B-0451 added, no other changes)

## CronList

- Live (`9ac08520`, `* * * * *`).

## Visibility signal

Session arc (now 10 PRs):

| PR | What | Status |
|---|---|---|
| #3041, #3042 | Otto-Desktop's substrate work | MERGED |
| #3043, #3044, #3045 | B-0444 + recovery + notifier fix | MERGED |
| #3046 | Otto-Desktop's B-0449 | MERGED |
| #3047 | Slice rows B-0054.1 + B-0055.1 | MERGED |
| #3048 | Rule 0 staleness | MERGED |
| #3050 | otto-channels card staleness | MERGED |
| #3051 | Codex loop headless provenance | MERGED |
| #3053 | B-0444 ID collision renumber | MERGED |
| #3052 | Competing collision fix (B-0449 conflict) | CLOSED |
| #3056 | Duplicate-ID audit tool + B-0451 row | wait-ci, auto-merge armed |

9 PRs merged this session; 1 in flight; 1 closed-with-provenance.
Substrate-hygiene cascade revealed: dangling-dep → ID-collision →
audit-tool-mechanization. Each finding surfaced the next failure
class. Loop continues.
86 changes: 86 additions & 0 deletions docs/hygiene-history/ticks/2026/05/13/2339Z.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
---
tick: 2026-05-13T23:39Z
agent: otto-cli
session: cron-resumption
pr: 3056
---

# Tick 2339Z — Copilot round-1 on PR #3056 addressed; #3054 + #3055 landed

## Refresh

- CronList: live (`9ac08520`, `* * * * *`, sentinel `<<autonomous-loop>>`).
- PRs merged since previous tick:
- #3054 (Otto-Desktop shadow lesson log for B-0449 collision drift)
→ `f48c94e`
- #3055 (Otto-Desktop archive of PR discussions 3046-3051) → `21de62f`
- Open PRs: #3056 (mine, audit tool, surfaced 3 review threads),
#3057 (mine, B-0068.1 cleanup, wait-ci).

## Named-dependency check

PR #3056 surfaced 3 unresolved Copilot threads at tick start —
addressed this tick (real-dependency-action, not Holding). PR #3057
remains `wait-ci`.

## Speculative work picked

PR #3056 hit `nextAction: resolve-threads` — Copilot ran a review
pass on the audit tool. Three findings, all valid:

1. **Missing eslint-disable** on `spawnSync("git", ...)`. Every other
tools/**.ts spawnSync invocation in the repo carries the
`// eslint-disable-next-line sonarjs/no-os-command-from-path -- ...`
comment. Mine didn't → added the suffixed-rationale form.
2. **`rowsScanned` misleadingly named** — it counted only rows with
an extractable `id:` field, not total files inspected. The tests
already asserted the smaller count; the CLI's "X rows scanned"
message therefore under-reported. → Renamed to `rowsWithId`;
updated docstring + CLI message: "X rows with id field, no
duplicate IDs".
3. **Dead `idToFiles.size > 0` ternary** — `reduce` on an empty
iterable already returns 0. → Simplified to plain spread+reduce.

## Landed concretely

| Artifact | Where | What |
|---|---|---|
| `tools/bg/audit-duplicate-row-ids.ts` | PR #3056 `7444a05` | All 3 Copilot findings fixed |
| `tools/bg/audit-duplicate-row-ids.test.ts` | PR #3056 `7444a05` | 3 assertions migrated from `rowsScanned` → `rowsWithId` |
| 3 review threads | PR #3056 GraphQL | Resolved via `resolveReviewThread` mutation |

## Verify

- 14/14 pass on `tools/bg/audit-duplicate-row-ids.test.ts`
- `bun tools/bg/audit-duplicate-row-ids.ts`: 12 duplicate-ID
group(s) found across 560 rows with id field (560 — up by 1
from earlier 559 because one new row landed on main since)
- PR #3056 unresolved threads: 3 → 0
- Both PRs back to `wait-ci`, auto-merge armed

## Reviewer-thread metabolism

Copilot's first finding was a *consistency* call (matches existing
sibling tools). Second was a *semantic* call (the field name
implied a wrong promise). Third was a *minimalism* call (dead code).
Three different concern classes in one review pass — the same
"better fix the second time" pattern as PR #3043's Codex round-2
re-review. Round-1 ships fast; round-2 ships *correctly*.

## CronList

- Live (`9ac08520`, `* * * * *`).

## Visibility signal

Session arc (now 12 PRs):

| PR | What | Status |
|---|---|---|
| #3041..#3048, #3050, #3051, #3053, #3054, #3055, #3049 | Substrate-hygiene rounds 1-5 + sibling PRs | MERGED (13 total) |
| #3056 | Duplicate-ID audit tool + B-0451 + Copilot round-1 | wait-ci, threads clear |
| #3057 | First B-0451 cleanup (B-0068.1 → B-0068.4) | wait-ci, threads clear |
| #3052 | Competing collision fix | CLOSED with provenance |

13 PRs merged this session; 2 in flight (both mine, both threads-
clear); 1 closed. Loop continues.
Loading
Loading