Repository navigation
fix(server): Claude prompts no longer hang on a uuid the session already holds - #16897
Conversation
…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>
ApprovabilityVerdict: Approved at 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. |
Thread transfer impact✅ Thread transfer remains within every enforced ceiling.
Baseline: Scenario and decoded snapshot size10 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.
Updated in place by a trusted workflow. PR artifacts are strictly validated and never executed. |
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configuration
📒 Files selected for processing (3)
Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 7 remain after this review. 📝 WalkthroughWalkthroughThe 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. ChangesClaude prompt flow
Priority: ➖ Normal Estimated code review effort: 3 (Moderate) | ~25 minutes Change: Bug fix Suggested reviewers: Merge Risk: ⚪ Minimal · up to The change is mergeable after normal checks; no concrete unresolved risk has been identified. 🚥 Pre-merge checks | ✅ 4✅ Passed checks (4 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
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>
## 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
## 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
Merges `pingdotgg/t3code` `0f09627a11` (44 commits since `cd41c4ada0`) into the fork. Branched from `main` at `75baf5f94`; no other merge PR is open. ## Resolution - **Counts:** 320 files landed against 320 in the upstream range, an exact match. The fork delta is still 765 files. - **Conflicts (2, both `converged`):** - `apps/web/src/components/ChatMarkdown.tsx`: the fork's Moatless Artifact chip still renders before upstream's new thread-link renderer (pingdotgg#17017). - `apps/web/src/components/chat/ThreadDetailsPanel.tsx`: took upstream's merged environment and branch row (pingdotgg#16823) and re-applied `FEATURES.openInEditor`. - `pnpm-lock.yaml` was re-derived with `install.mjs`. - `duplicate-adds.mjs` and `resolution-check.mjs` found nothing. - **Unsupported methods:** added `UnsupportedMethodError` to `mcpApps.callTool`, `toolInfo`, `readResource` and `updateModelContext`. Nothing to drop. - Formatted `docs/fork/inventory.json`, which was unformatted on `main`. ## Verification `verify.mjs` passed duplicate-adds, tripwires, resolution-check, unsupported-methods, lockfile, fmt, lint, typecheck and build. The `test` step failed: - `@t3tools/web` failed the full run and passed in isolation. - In `t3`, `OpenCodeServerLedger`, `AcpAdapterV2`, `OrchestratorReplayFixtures` and `ServerBrowserPage` fail when run alone. This is the same set the 2026-10-07 merge recorded: the sandbox does not reap process groups, `CLAUDE_CONFIG_DIR` leaks, and Playwright's headless shell is missing. Machine, not code. ## Usable as-is - Thread links reference the thread id and open in the app (pingdotgg#17017, pingdotgg#16782 client half) - Find in diffs with Cmd+F (pingdotgg#14623) - Block-level Markdown in the rich-text composer (pingdotgg#14677) - The live row shows the agent's latest thought (pingdotgg#16284), and running subagent cards stay visible (pingdotgg#16878) - Simplified workspace card rows (pingdotgg#16823), centred project monograms (pingdotgg#16841), file icons for 14 more languages (pingdotgg#16974) - Composer fixes: citation-cancel spacing (pingdotgg#16828), type-to-focus scrambling (pingdotgg#14595) - Lineage: Stop on hover (pingdotgg#16791), live names in thread-read activity (pingdotgg#13140) - Model catalogue: Claude Haiku 5.5, with Sonnet 5 and Opus 5 retired to legacy (pingdotgg#16903) - Mobile, desktop and onboarding fixes (pingdotgg#16713, pingdotgg#15856, pingdotgg#16733, pingdotgg#16886, pingdotgg#16885, pingdotgg#16939, pingdotgg#16676, pingdotgg#16887) ## Unsupported in Moatless / needs implementation - **MCP apps inline in threads** (pingdotgg#16236): `mcpApps.callTool`, `mcpApps.toolInfo`, `mcpApps.readResource`, `mcpApps.updateModelContext`, and the `McpAppFrame.tsx` UI. The frame mounts only for a work-log item that carries an MCP app snapshot. Upstream's Codex adapter projects that snapshot; Moatless does not, so nothing renders. Moatless would need to project the snapshots and dispatch the family. The new union entries are recorded in `docs/fork/gaps.md`. - **Provider update live progress** (pingdotgg#16958) and **install the `t3` command from Settings** (pingdotgg#16683): behind `providerConfiguration` and the desktop bridge respectively. Nothing new is reachable. - **Copy MCP URL over plain http** (pingdotgg#16909): still behind `FEATURES.connections`. ## Backend behavior to consider reproducing in Moatless - The orchestrator MCP thread list and detail report and filter on snooze state (`snoozed`, `snoozedUntil`; pingdotgg#16782). - Idle Codex threads are unloaded from the shared app-server (pingdotgg#16917). - A refused Claude turn keeps its session (pingdotgg#16287), and a prompt does not hang on a uuid the session already holds (pingdotgg#16897). - Claude 5-series models always run with 1M context (pingdotgg#16908). - A background Claude subagent's work shows while its parent is idle (pingdotgg#16486). - Worktree cleanup: freed for terminal thread statuses (pingdotgg#15150), removed after squash merges (pingdotgg#14847), files hidden by `showUntrackedFiles=no` are kept (pingdotgg#15834), and Windows long paths work (pingdotgg#14917). - Replaying a command or opening a long thread no longer blocks the server (pingdotgg#17041, pingdotgg#17029). - GitHub: rate limits are read from response headers, and GraphQL batches use variables (pingdotgg#16986, pingdotgg#16960). `ChangeRequest` gained an optional `headSha`. All of these are recorded under "Runtime fixes upstream made to its own server" in `docs/fork/gaps.md`. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --- Moatless task: https://moatless.soaplabstest.com/tasks/af277a83-a9de-4d81-9c77-866e383cdb99
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~/.claudetranscript 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 lonecommand_lifecyclecompleted: noqueued,started,system/initorresult. 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
Cryptoservice instead ofclaudePromptUuid(attemptId). Echo routing is unchanged: the same uuid is still stored on the turn context and matched againstuser_message_uuid. Replay already maps recorded prompt uuids to replayed ones by matched offer, so the recorder uses random uuids too.completedbefore ever reporting itstarted, 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 gotqueued→started(→completed);completedwith nostartedappears only for the dropped prompts.The uuid change ports #16254 by @saphid onto current
main. That PR now conflicts:mainmovedclaudePromptUuidonto the EffectCryptoservice since it was opened. This PR adds the backstop on top. #16254 can be closed in favor of this one.Verification
fails a prompt Claude completes without starting a turn for it: times out waiting for a terminal without the backstop, and passes with it.keeps a started prompt running until its result: aqueued→started→completedsequence followed by the echoing result still completes normally, covering a CLI that reportscompletedbefore the turn's result.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 runonClaudeAdapterV2.test.ts,ClaudeAutomaticDelivery,ClaudeReplayFixtures,OrchestratorReplayRecovery,OrchestratorReplayFixtures,OrchestratorReplayRestartBackgroundNote,ThreadMergeBack, andThreadFork: 8 files, 310 tests passed.tsc --noEmitinapps/serveris clean for these files. TheProviderSwitch.integration.test.tserrors are already present onmain.Made with Claude Opus 5.5 in Claude Code (running in T3 Code).
🤖 Generated with Claude Code