Skip to content

fix(server,mobile): deduplicate keyed thread launches - #21611

Open
juliusmarminge wants to merge 3584 commits into
composer-chat-17/restart-recoveryfrom
composer-chat-17/launch-retries
Open

juliusmarminge wants to merge 3584 commits into
composer-chat-17/restart-recoveryfrom
composer-chat-17/launch-retries

Conversation

@juliusmarminge

@juliusmarminge juliusmarminge commented Oct 19, 2026 •

Copy link
Copy Markdown
Member

An agent retrying t3_thread_launch after credential rotation can create another thread. A stable clientRequestId now names one launch for the calling thread and provider instance. The same key and arguments recover the accepted thread; omitted keys stay fresh.

The existing thread-claim receipt binds the original request with a SHA-256 fingerprint in the claim transaction. This closes the crash window before initial-message admission and prevents a no-message launch acquiring later retry work. Preparation reads the accepted run's saved workspace intent. A fresh launch reusing an empty thread replaces a stale checkout binding with the requested workspace and atomically rejects a concurrent checkout change; an unprepared draft keeps its branch choice if preparation fails. A conflicting or historically unverifiable launch intent returns actionable MCP invalid_request guidance. Pending attachment copies are released on rejection. Mobile derives a queued worktree branch from its persisted command UUID so a lost-response retry retains the same launch arguments. Migration 65 adds one nullable receipt column; the full request is not added to client projections.

Rebuilt from @maria-rcks's #17589. This layer contains launch retry handling; the preceding layer preserves restart steering.

Verification:

  • Launch suite: 79 baseline cases → 86, all passing. Four additions cover credential replacement/key isolation, accepted preparation replay, the create/message crash boundary, and a no-message key retried with new work. Two more cases prove root and new-worktree preparation replace a stale checkout, including the actual setup destination and checkpoint directory. One concurrency case proves a second client cannot change that checkout between validation and claim; rejection leaves its binding intact and admits no run. All five boundary/workspace regressions failed before their fixes.
  • All 112 current launch/toolkit/registry/instruction/migration cases pass. Existing migration-ledger expectations include migration 65. A mobile regression drives the actual outbox drain through transport failure and remount, comparing the complete RPC payload: 15 existing cases → 16, all passing; 138 related cases and the scoped mobile typecheck pass. The scoped server typecheck passes on the current head, including the concurrency test; contracts typecheck passed earlier. Targeted lint/format pass. Six focused Claude background-steering cases and three isolated Chromium workflow-opening cases also pass; those diagnose intermittent CI failures and do not replace full CI. The lower layer's final Codex/recovery suites pass separately.
  • Live isolated server through the authenticated Browser WebSocket: first launch succeeds, identical retry resumes the same thread, changed-title retry fails validate-intent; a projection read confirms the original title and zero messages/runs. No external provider started. Migration 65 applied successfully on startup.
  • Sanitized before/after evidence and commands.

Keys bind the complete original launch arguments, including inherited defaults. Changed arguments need a fresh key after inspecting existing work. Historical claims without a fingerprint require an already accepted initial-message receipt; missing workspace intent is refused. No-message workspace preparation has no new durable rescheduling workflow. A fresh reused launch that fails worktree preparation leaves its accepted workspace unbound instead of restoring the old checkout. A claim rejected for a concurrent checkout change needs a fresh key after inspecting the current thread. Workspace preflight can still fail if a base ref or existing checkout disappears after acceptance; inspect the accepted thread before choosing another key. Key scope also becomes stable across credential replacement for other keyed MCP operations. An edited queued mobile creation can visibly fail if the original launch was accepted before its thread appears in the live shell; inspect that thread before retrying with new arguments.

No live provider, actual HTTP MCP credential rotation, physical OS restart, macOS, Windows, iOS, Android, or Electron desktop verification. Those platform and account checks remain for a human. Fresh reuse workspace verification uses real service/orchestrator/SQLite code with faked Git and setup services; no real checkout or shell setup was driven. The mobile change is payload construction only; it introduces no native capability, asset, persisted format, or visual control.

Implementation: GPT-6.1-Sol; tests: GPT-6-Astra; independent full-diff reviews: Claude Opus 5.5 and GPT-6-Sol, through T3 Code's Codex and Claude harnesses.

Fixes #16184

Loading
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:L 100-499 changed lines (additions + deletions). vouch:trusted Author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Retrying an MCP mutation with the same clientRequestId creates duplicate work after a server restart