Skip to content

fix(server): Claude prompts no longer hang on a uuid the session already holds - #16897

Merged
juliusmarminge merged 1 commit into
mainfrom
t3code/claude-duplicate-prompt-hang
Oct 7, 2026
Merged

juliusmarminge merged 1 commit into
mainfrom
t3code/claude-duplicate-prompt-hang

Conversation

@juliusmarminge

@juliusmarminge juliusmarminge commented Oct 7, 2026 •

Copy link
Copy Markdown
Member

Problem

A Claude thread can swallow a message: the run shows "Working" forever, nothing streams, and only Stop ends it.

Claude prompt uuids were a hash of the run attempt id, which is just the thread id and run ordinal. A dev server seeded from a copy of the database (migrate-dev-db) keeps those ids and the provider session binding, so it resumes the real ~/.claude transcript and writes prompts under the uuids the real server will use for its next runs. When the real server gets there, Claude finds the uuid already in its transcript and replies with a lone command_lifecycle completed: no queued, started, system/init or result. The adapter waits forever.

Seen on thread f9ac0fac: a dev instance had sent test prompts there as runs 17–20, and the user's real runs 17 and 19 were silently dropped (3h20m and 1h49m "Working", the second ending in a manual Stop). Each dropped prompt's uuid matched a transcript entry written four days earlier by the dev server.

Fix

  • Fresh uuid per offer. Each prompt offer now gets a random UUIDv4 from the Effect Crypto service instead of claudePromptUuid(attemptId). Echo routing is unchanged: the same uuid is still stored on the turn context and matched against user_message_uuid. Replay already maps recorded prompt uuids to replayed ones by matched offer, so the recorder uses random uuids too.
  • Backstop for a prompt Claude never runs. If Claude reports the pending prompt completed before ever reporting it started, the turn now fails with "Claude acknowledged the message but never started a turn for it." instead of hanging. The thread stays reusable, so the next message works. Across the local provider logs, every prompt that ran got queued → started (→ completed); completed with no started appears only for the dropped prompts.

The uuid change ports #16254 by @saphid onto current main. That PR now conflicts: main moved claudePromptUuid onto the Effect Crypto service since it was opened. This PR adds the backstop on top. #16254 can be closed in favor of this one.

Verification

  • New test fails a prompt Claude completes without starting a turn for it: times out waiting for a terminal without the backstop, and passes with it.
  • New test keeps a started prompt running until its result: a queued → started → completed sequence followed by the echoing result still completes normally, covering a CLI that reports completed before the turn's result.
  • fix(server): Claude prompts no longer hang when a session outlives its database #16254's gives the same run attempt a fresh prompt uuid on every offer, and its migration of the echo-routing tests to read the offered uuid.
  • vp test run on ClaudeAdapterV2.test.ts, ClaudeAutomaticDelivery, ClaudeReplayFixtures, OrchestratorReplayRecovery, OrchestratorReplayFixtures, OrchestratorReplayRestartBackgroundNote, ThreadMergeBack, and ThreadFork: 8 files, 310 tests passed.
  • tsc --noEmit in apps/server is clean for these files. The ProviderSwitch.integration.test.ts errors are already present on main.

Made with Claude Opus 5.5 in Claude Code (running in T3 Code).

🤖 Generated with Claude Code


Devin Review

…ady holds

Claude prompt uuids were a hash of the run attempt id, which is only the
thread id and run ordinal. A dev server seeded from a copy of the database
resumes the same Claude session and writes prompts under the uuids the
real server uses for its next runs. Claude finishes such a prompt with a
lone command_lifecycle "completed" and never runs a turn, so the thread
stayed "Working" forever and the message was silently lost.

Each prompt offer now gets a fresh random uuid. As a backstop, a prompt
Claude reports completed without ever starting fails its turn with an
error instead of hanging.

Ports the uuid change from #16254 by @saphid onto the Effect Crypto service.

Co-Authored-By: saphid <saphid@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@github-actions github-actions Bot added the vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. label Oct 7, 2026
@juliusmarminge juliusmarminge added the macroscope-review Opt PRs made by unvouched contributors in for Macroscope review. Vouched contributors auto-reviews label Oct 7, 2026
@github-actions github-actions Bot added the size:M 30-99 changed lines (additions + deletions). label Oct 7, 2026
@macroscopeapp

macroscopeapp Bot commented Oct 7, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Approved at 54052c8

Macroscope's review found this PR approvable — This is a focused Claude adapter bug fix that replaces a known prompt hang with a reusable failure and uses fresh per-offer UUIDs to prevent transcript collisions. Normal prompt processing remains unchanged, with targeted regression tests covering both affected and successful lifecycle paths.

You can add or adjust custom eligibility rules. Learn more.

@github-actions

github-actions Bot commented Oct 7, 2026

Copy link
Copy Markdown
Contributor

Thread transfer impact

✅ Thread transfer remains within every enforced ceiling.

ℹ️ The exact PR base did not have a successful artifact. Baseline uses the latest successful main measurement shown below.

Provider Metric Main baseline This PR Impact PR ceiling
Codex Total thread wire 4.9 KiB 5.0 KiB +23 B (+0.5%) 6.8 KiB ✅
Codex Thread snapshot wire 3.8 KiB 3.8 KiB 0 B (0.0%) 4.9 KiB ✅
Codex Live turn WebSocket wire 1.2 KiB 1.2 KiB +23 B (+1.9%) 2.0 KiB ✅
Codex Live turn WebSocket decoded 20.8 KiB 20.9 KiB +41 B (+0.2%) 29.3 KiB ✅
Codex Live turn messages 1 2 +1 (+100.0%) 8 ✅
Claude Total thread wire 5.0 KiB 5.0 KiB −17 B (−0.3%) 6.8 KiB ✅
Claude Thread snapshot wire 3.8 KiB 3.8 KiB 0 B (0.0%) 4.9 KiB ✅
Claude Live turn WebSocket wire 1.2 KiB 1.2 KiB −17 B (−1.4%) 2.0 KiB ✅
Claude Live turn WebSocket decoded 21.2 KiB 21.2 KiB 0 B (0.0%) 29.3 KiB ✅
Claude Live turn messages 2 2 0 (0.0%) 8 ✅

Baseline: 250e052 · PR result: 54052c8 · Source CI: success

Scenario and decoded snapshot size

10 historical turns, 5 command tools per turn, 878.9 KiB retained MCP result per historical turn, and a 1.05 MiB retained result in the measured turn.

  • Codex decoded thread snapshot: 108.5 KiB
  • Claude decoded thread snapshot: 108.8 KiB

Updated in place by a trusted workflow. PR artifacts are strictly validated and never executed.

@coderabbitai

coderabbitai Bot commented Oct 7, 2026

Copy link
Copy Markdown

Review in Change Stack →

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Configuration used: Path: .coderabbit.config.ts
  • Review profile: CHILL
  • Plan: Team
  • Run ID: b8846656-dd7b-444d-9a8c-8bcf562931d2
📥 Commits

Reviewing files that changed from the base of the PR and between 41985b4 and 54052c8.

📒 Files selected for processing (3)
  • apps/server/src/orchestration-v2/Adapters/ClaudeAdapterV2.test.ts
  • apps/server/src/orchestration-v2/Adapters/ClaudeAdapterV2.testkit.ts
  • apps/server/src/orchestration-v2/Adapters/ClaudeAdapterV2.ts

Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 7 remain after this review.


📝 Walkthrough

Walkthrough

The Claude adapter now generates UUIDs for non-continuation prompts and tracks their lifecycle states. Tests use the UUIDs of offered prompts and cover UUID uniqueness, lifecycle failures, and successful completion.

Changes

Claude prompt flow

Layer / File(s) Summary
Prompt UUID allocation and test framing
apps/server/src/orchestration-v2/Adapters/ClaudeAdapterV2.ts, apps/server/src/orchestration-v2/Adapters/ClaudeAdapterV2.testkit.ts, apps/server/src/orchestration-v2/Adapters/ClaudeAdapterV2.test.ts
Non-continuation prompts receive random UUIDs that the adapter validates. Replay recording generates UUIDs with Effect crypto. Wake tests stamp frames with the UUID of the offered prompt and check uniqueness across harnesses.
Prompt lifecycle handling
apps/server/src/orchestration-v2/Adapters/ClaudeAdapterV2.ts, apps/server/src/orchestration-v2/Adapters/ClaudeAdapterV2.test.ts
The adapter records matching started lifecycle frames. A matching completed frame without a prior started frame fails the turn; a started prompt can complete when its result arrives.

Priority: ➖ Normal

Estimated code review effort: 3 (Moderate) | ~25 minutes

Change: Bug fix

Suggested reviewers: esthor

Merge Risk: ⚪ Minimal · up to 54052

The change is mergeable after normal checks; no concrete unresolved risk has been identified.

🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely identifies the server fix for Claude prompts that hang when the session already contains the UUID.
Description check ✅ Passed The description provides a detailed problem statement, explains the UUID and lifecycle fixes, links the related pull request, and lists focused verification results. It uses “Fix” instead of the templ…
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR
  • Autopilot · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Comment @coderabbitai help to get the list of available commands.

@juliusmarminge
juliusmarminge merged commit f570bd2 into main Oct 7, 2026
33 of 34 checks passed
@juliusmarminge
juliusmarminge deleted the t3code/claude-duplicate-prompt-hang branch October 7, 2026 17:51
sandscooling pushed a commit to sandscooling/t3code that referenced this pull request Oct 7, 2026
Upstream sync (run on request ahead of a build): 13 commits to f570bd2,
including Claude session fixes (pingdotgg#16897, pingdotgg#16287), background subagent work
showing while the parent is idle (pingdotgg#16486), inline MCP apps (pingdotgg#16236) and
worktree cleanup changes (pingdotgg#14847, pingdotgg#15150, pingdotgg#15834, pingdotgg#14917). The one conflict,
ClaudeAdapterV2.ts, was additive: upstream's per-subagent toolCallsFor delete
is kept ahead of the fork's Claude task-tools block. The fork's Codex image
fixture gains pingdotgg#16236's MCP-app initialize extension. Attached worktrees stay
outside every new cleanup path.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
github-actions Bot added a commit to omarcresp/t3code-flake that referenced this pull request Oct 7, 2026
## What's Changed
* fix(web): replace Lineage timers with Stop on hover by @Bil0000 in pingdotgg/t3code#16791
* fix(clients): running subagent cards stay visible after their parent turn settles by @juliusmarminge in pingdotgg/t3code#16878
* feat: MCP apps render and run inline in threads by @juliusmarminge in pingdotgg/t3code#16236
* fix(server): a background Claude subagent's work shows while its parent is idle by @Vantrongs in pingdotgg/t3code#16486
* fix(mobile): hide threads from switched-off environments by @entity in pingdotgg/t3code#16886
* fix(server): a refused Claude turn no longer throws away its session by @SunkenInTime in pingdotgg/t3code#16287
* fix(web): onboarding Continue no longer locks on computers that won't connect by @juliusmarminge in pingdotgg/t3code#16887
* fix(server): worktree cleanup no longer deletes files hidden by showUntrackedFiles=no by @SunkenInTime in pingdotgg/t3code#15834
* fix(server): merged-worktree cleanup removes worktrees after squash merges by @tris203 in pingdotgg/t3code#14847
* fix(server): free worktrees for terminal thread statuses by @ANSHSINGH050404 in pingdotgg/t3code#15150
* fix(server): Windows worktrees with long paths no longer fail or strand by @That1Drifter in pingdotgg/t3code#14917
* fix(server): main typechecks again after a test used renamed helpers by @juliusmarminge in pingdotgg/t3code#16895
* fix(server): Claude prompts no longer hang on a uuid the session already holds by @juliusmarminge in pingdotgg/t3code#16897

## New Contributors
* @Vantrongs made their first contribution in pingdotgg/t3code#16486
* @entity made their first contribution in pingdotgg/t3code#16886
* @ANSHSINGH050404 made their first contribution in pingdotgg/t3code#15150
* @That1Drifter made their first contribution in pingdotgg/t3code#14917

**Full Changelog**: pingdotgg/t3code@v0.0.46-nightly.20261007.2774...v0.0.46-nightly.20261007.2787

Upstream release: https://github.com/pingdotgg/t3code/releases/tag/v0.0.46-nightly.20261007.2787
github-actions Bot added a commit to davidvanderklay/t3code-flake that referenced this pull request Oct 7, 2026
## What's Changed
* fix(web): replace Lineage timers with Stop on hover by @Bil0000 in pingdotgg/t3code#16791
* fix(clients): running subagent cards stay visible after their parent turn settles by @juliusmarminge in pingdotgg/t3code#16878
* feat: MCP apps render and run inline in threads by @juliusmarminge in pingdotgg/t3code#16236
* fix(server): a background Claude subagent's work shows while its parent is idle by @Vantrongs in pingdotgg/t3code#16486
* fix(mobile): hide threads from switched-off environments by @entity in pingdotgg/t3code#16886
* fix(server): a refused Claude turn no longer throws away its session by @SunkenInTime in pingdotgg/t3code#16287
* fix(web): onboarding Continue no longer locks on computers that won't connect by @juliusmarminge in pingdotgg/t3code#16887
* fix(server): worktree cleanup no longer deletes files hidden by showUntrackedFiles=no by @SunkenInTime in pingdotgg/t3code#15834
* fix(server): merged-worktree cleanup removes worktrees after squash merges by @tris203 in pingdotgg/t3code#14847
* fix(server): free worktrees for terminal thread statuses by @ANSHSINGH050404 in pingdotgg/t3code#15150
* fix(server): Windows worktrees with long paths no longer fail or strand by @That1Drifter in pingdotgg/t3code#14917
* fix(server): main typechecks again after a test used renamed helpers by @juliusmarminge in pingdotgg/t3code#16895
* fix(server): Claude prompts no longer hang on a uuid the session already holds by @juliusmarminge in pingdotgg/t3code#16897

## New Contributors
* @Vantrongs made their first contribution in pingdotgg/t3code#16486
* @entity made their first contribution in pingdotgg/t3code#16886
* @ANSHSINGH050404 made their first contribution in pingdotgg/t3code#15150
* @That1Drifter made their first contribution in pingdotgg/t3code#14917

**Full Changelog**: pingdotgg/t3code@v0.0.46-nightly.20261007.2774...v0.0.46-nightly.20261007.2787

Upstream release: https://github.com/pingdotgg/t3code/releases/tag/v0.0.46-nightly.20261007.2787
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

macroscope-review Opt PRs made by unvouched contributors in for Macroscope review. Vouched contributors auto-reviews size:M 30-99 changed lines (additions + deletions). vouch:trusted PR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant