Skip to content

fix(buglog): allocate bug ids from the high-water mark, not the array length - #69

Open
liveoakwag wants to merge 1 commit into
cytostack:mainfrom
liveoakwag:fix/buglog-id-high-water-mark
Open

fix(buglog): allocate bug ids from the high-water mark, not the array length#69
liveoakwag wants to merge 1 commit into
cytostack:mainfrom
liveoakwag:fix/buglog-id-high-water-mark

Conversation

@liveoakwag

Copy link
Copy Markdown

bug-${bugs.length + 1} treats the array length as an id generator, and it is not one. Any entry that arrives out of band — a hand-written bug, an id claimed by another tool, a manual renumber, an entry removed from the middle — moves the numbers away from the count. From then on length + 1 re-issues an id that is already in use.

The failure is silent and it compounds: two entries share an id, related_bugs pointers stop being decidable about which of the two they meant, and dedupe-by-id starts merging unrelated bugs. Nothing raises an error at any point. In one real log seven separate ids each ended up holding two different bugs before anyone noticed, and untangling them afterwards meant guessing at intent.

The three call sites

src/buglog/bug-tracker.ts:58
src/hooks/post-write.ts:351
src/templates/opencode-plugin/post-write.ts:213

The first two now share nextBugId() in src/utils/bug-id.ts. The opencode-plugin template is copied into user projects and imports nothing outside its own folder (nothing else in it does either), so it carries a duplicate in its fs.ts — and a test pins the two implementations together so they cannot drift apart. Happy to restructure that if you would rather it were shared some other way.

Reading the ids instead of counting them is correct however the entries got there. Ids that do not match the expected shape are skipped rather than thrown on, so a hand-edited log still allocates instead of failing closed, and a separate prefix (e.g. bug-auto-) allocates in its own namespace.

Verification

  • node --test tests/bug-id.test.ts8/8
  • npm test34/34, 0 fail
  • npx tsc --noEmit — clean apart from the pre-existing src/daemon/cron-engine.ts(52,27) TS2503 Cannot find namespace 'cron', which is present on an unmodified checkout too
  • git am onto pristine main (f64e737) applies cleanly, suite still 34/34
  • package-lock.json deliberately not committed — the project builds with pnpm

The test carries its control inline rather than by reverting the fix: every case also asserts what bugs.length + 1 returns, so it demonstrates the defect rather than merely passing. On a three-entry log whose ids run to 007, the old rule returns bug-004 — already taken.

Unrelated to #66, which is still open; this branch is cut from main and does not depend on it.

🤖 Generated with Claude Code

… length

`bug-${bugs.length + 1}` treats the array length as an id generator, and it is
not one. Any entry that arrives out of band - a hand-written bug, an id claimed
by another tool, a manual renumber, an entry removed from the middle - moves the
numbers away from the count. From then on `length + 1` re-issues an id that is
already in use.

The failure is silent and it compounds. Two entries share an id, `related_bugs`
pointers stop being decidable about which of the two they meant, and dedupe-by-id
starts merging unrelated bugs. Nothing raises an error at any point. In one real
log seven separate ids each ended up holding two different bugs before anyone
noticed, and untangling them afterwards meant guessing at intent.

Three call sites had the identical expression:

  src/buglog/bug-tracker.ts
  src/hooks/post-write.ts
  src/templates/opencode-plugin/post-write.ts

The first two now share `nextBugId()` in src/utils/bug-id.ts. The opencode-plugin
template is copied into user projects and imports nothing outside its own folder,
so it gets a duplicate in its own fs.ts; a test pins the two implementations
together so they cannot drift.

Reading the ids rather than counting them is correct however the entries got
there. Ids that do not match the expected shape are skipped rather than thrown
on, so a hand-edited log still allocates instead of failing closed, and a
separate prefix (e.g. `bug-auto-`) allocates in its own namespace.

tests/bug-id.test.ts covers it, and each case also asserts what the old rule
returns, so the test demonstrates the defect rather than merely passing: on a
three-entry log whose ids run to 007 the old rule hands back bug-004, which is
already taken.

  node --test tests/bug-id.test.ts   8/8
  npm test                           34/34
  npx tsc --noEmit                   clean except the pre-existing
                                     src/daemon/cron-engine.ts TS2503, which is
                                     present on an unmodified checkout too

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant