Skip to content

fix(derive): resolve duplicate step ids so paths keep unique ids#115

Merged
benbaarber merged 1 commit into
mainfrom
ben/derive-dedup
Jul 1, 2026
Merged

fix(derive): resolve duplicate step ids so paths keep unique ids#115
benbaarber merged 1 commit into
mainfrom
ben/derive-dedup

Conversation

@benbaarber

@benbaarber benbaarber commented Jul 1, 2026

Copy link
Copy Markdown
Collaborator

What

derive_path now guarantees the derived path's step ids are unique.

Sources reuse ids across distinct records — Claude Code reuses uuid on attachment lines, so two unrelated events arrive with the same id — and carrying a duplicate through breaks any consumer that keys on the id (e.g. a store with a UNIQUE (path_id, step_id) constraint). This is blocking real imports today.

Collisions are resolved inline as each step is emitted (via push_step):

  • a byte-identical re-emission (same serialized step) is dropped — keeping it would only duplicate a step that already exists;
  • a same-id-but-different step is re-IDed to <id>#<n> so the original id stays recoverable and no data is lost.

Because resolution happens during emission and updates turn_to_step, parent references follow the rename — a later step whose parent_id matched a renamed duplicate resolves to the renamed step, not the first occurrence.

derive_path is already infallible (-> Path), so there's no signature change — this is purely additive.

Scope

  • One logic change (crates/toolpath-convo/src/derive.rs): a push_step helper wired into the turn and event loops, plus 4 regression tests (drop, rename, event-dedup, parent-reference correctness).
  • toolpath-convo 0.11.0 → 0.11.1 (patch), with the workspace / crates.json / CHANGELOG updates.
  • Full cargo test --workspace green; cargo clippy --workspace -- -D warnings clean.

Context vs #111

This is the dedup carved out of the larger cross-harness compaction PR (#108) so it can land on its own and unblock imports.

It overlaps with #111 (same drop-identical / rename-differing decision), with one caveat: #115 resolves collisions inline as steps are emitted, so parent references follow a rename — a later step pointing at a renamed duplicate resolves to <id>#<n>, not the first occurrence. #111 does it as a post-pass over the finished step list, which renames correctly but leaves parent references pointing at the first occurrence. For the immediate blocking case (duplicate uuid on attachment/event lines, which have no children) the two are equivalent; they differ only for duplicate turns with children. Whichever lands first, the other can be closed or rebased.

@github-actions

github-actions Bot commented Jul 1, 2026

Copy link
Copy Markdown

🔍 Preview deployed: https://8d90c1cd.toolpath.pages.dev

A path's step ids must be unique, but sources reuse ids across distinct
records — Claude Code reuses `uuid` on `attachment` lines, so two unrelated
events arrive with the same id — and carrying a duplicate through breaks any
consumer that keys on the id (e.g. a store with a UNIQUE (path_id, step_id)
constraint).

`derive_path` now resolves collisions inline as each step is emitted (via
`push_step`): a byte-identical re-emission is dropped, and a
same-id-but-different step is re-IDed to `<id>#<n>`. Because resolution happens
during emission and updates `turn_to_step`, parent references follow the rename
— a later step whose parent matched a renamed duplicate resolves to the renamed
step, not the first occurrence. Bumps toolpath-convo 0.11.0 -> 0.11.1.
@ben-emp ben-emp force-pushed the ben/derive-dedup branch from 1130be3 to bc7e3b8 Compare July 1, 2026 17:12

@akesling akesling left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@benbaarber benbaarber merged commit 66933c8 into main Jul 1, 2026
2 checks passed
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.

2 participants