Skip to content

fix(claude-queue): a committed notification retires the twin it carries - #1234

Merged
Juliusolsson05 merged 2 commits into
mainfrom
fix/claude-queue-notification-identity
Sep 25, 2026
Merged

Juliusolsson05 merged 2 commits into
mainfrom
fix/claude-queue-notification-identity

Conversation

@Juliusolsson05

@Juliusolsson05 Juliusolsson05 commented Sep 25, 2026 •

Copy link
Copy Markdown
Owner

Fixes #678

What was wrong

entryClaims matched a queued task-notification on its task id alone. The id is present on every recorded notification, but it is not unique: upstream reuses it when reconciling a background shell from a previous session. In the recording, the pairs at events 111/112 and 359/360 are "…was stopped" followed by "No completion record was found…", each under one id. find returned the first twin, so it was retired as delivered-observed with the second twin's uuid as evidence, and the item that actually departed stayed pending.

Fix

resolveEntryTarget (in reconcile.ts) mirrors resolveRemoveCarrierTarget:

  1. Prefer the claimant whose whole normalized body is contained in the committed entry. Containment, not equality, because entries wrap notifications.
  2. Otherwise fall back to the id, but only when a single pending item carries it. Twins with no body match mean no delivery can be proven, so none is claimed.

Batched deliveries, where one entry carries several different ids, are unaffected.

Corrected expectations (evidence, not convenience)

Two corpus tests had blessed the misattribution. #678 predicted this.

  • "uses the recorded remove content in a mixed queue": it retained event 112, the twin that departed at 114. It now retains 111.
  • "does not strand background commands": it passed only because the first twins were retired with their siblings' evidence. In the recording, each pair has one dequeue and one committed entry, and that entry carries the second body; nothing shows the first leaving. They now stay pending and become unconfirmed on the idle sweep (the strip's existing honest state), and the test asserts exactly that.

Tests

  • New, from recorded events 111–114: the right twin is retired with its own evidence, and the other stays pending (failed first on main).
  • New: a reworded entry naming only the shared id retires neither twin.
  • Mutations killed: restoring the old find (4 red), returning the first twin when ambiguous (1 red), and dropping the exact pass (2 red).
  • Suites: renderer 3,035 of 3,035 pass (Node 24); tsc -b is clean.

🤖 Generated with Claude Code

Review disposition (A Codex, B Pi)

Finding Disposition
A MAJOR: ambiguous twins still settle by cohort inference (the first twin can be retired delivered-inferred) Declined as an accepted residual and documented in resolveEntryTarget. A's round-2 targeted count: 203 notification entries after same-id twins in 2,413 transcripts; all 203 carry one exact body and zero are reworded. A confirmed the decline
A minor: containment untested (startsWith survived) Fixed: a wrapped-twin test from the recorded events
B: surviving mutations on unreachable shapes Accepted: 0 corpus rows with ≥2 complete bodies in one entry
B: phantom "unconfirmed" row for the never-delivered twin Accepted by design; strictly better than main's false decisions log

Round 2: A MERGE-READY (decline confirmed); B MERGE-READY.

The identity pass matched a queued task notification on its task id
alone, but the id is not unique: upstream reuses it when it reconciles a
background shell from a previous session, so two different bodies can be
queued under one id (divergence-stranded-background-commands.json
events 111/112 and 359/360). The first was retired as delivered-observed
with the second's uuid as evidence, and the one that left stayed pending.

resolveEntryTarget now prefers the claimant whose whole normalized body
is inside the entry, and falls back to the id only when a single pending
item carries it. Batched deliveries (several different ids in one entry)
keep their order.

Two corpus tests had blessed the misattribution and are corrected
against the recording: 111 is the twin that stays, and the two
first-twins the recording never shows departing end as `unconfirmed` on
idle rather than being silently retired.

Fixes #678

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Juliusolsson05 added a commit that referenced this pull request Sep 25, 2026
#1234 opened

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…iguity residual

Review of #1234: a prefix check passed every test; a wrapped-twin case
from the recorded events now fails it. The ambiguous-twin settlement
residual (cohort inference after a decline) is documented as accepted:
no reworded twin entry exists in 2,410 local transcripts.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Juliusolsson05 added a commit that referenced this pull request Sep 25, 2026
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@Juliusolsson05
Juliusolsson05 merged commit 6a00232 into main Sep 25, 2026
2 checks passed
@Juliusolsson05
Juliusolsson05 deleted the fix/claude-queue-notification-identity branch September 25, 2026 09:47
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.

bug(claude-queue): committed-entry identity matches notifications by task id alone

1 participant