Skip to content

fix(orchestration): Preserve Claude subagent attribution after settle - #5388

Open
mwolson wants to merge 1 commit into
pingdotgg:t3code/codex-turn-mappingfrom
mwolson:fix/claude-subagent-postsettle-attribution
Open

fix(orchestration): Preserve Claude subagent attribution after settle#5388
mwolson wants to merge 1 commit into
pingdotgg:t3code/codex-turn-mappingfrom
mwolson:fix/claude-subagent-postsettle-attribution

Conversation

@mwolson

@mwolson mwolson commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Persist Claude native-task and tool-use attribution across settled root turns
    and fresh buffered continuations.
  • Keep child narration, tools, results, and distinct terminal output in child
    threads without changing ordinary root assistant text.
  • Replace raw task summaries in provider-owned root continuations with a fixed
    generic Claude prompt, preserve other providers' requested detail, and hide
    automatic provider entries from queue controls.

Problem and Fix

Problem and Why it Happened Fix
Claude child SDK frames can arrive after the root turn settles. The fresh continuation no longer has the launch turn's tool-use maps, so child text, tools, and results can leak into the root thread. Keep task identity, launch and resume aliases, bounded registration-race buffering, and resume state together in native-thread-scoped session state. Every attributed child frame resolves through that durable state.
A boolean or one-result latch cannot distinguish streamed narration, an equivalent notification fallback, and a genuinely distinct terminal Agent result across resumes. Track bounded native identities and normalized terminal equivalence per generation. Equivalent fallback text is suppressed, while distinct narration, summaries, and terminal results survive once.
task_notification.summary was used as the provider-owned Claude continuation input and could render as raw child text labelled as another agent's message. A shared override would also erase Codex background-command context. Give Claude an explicit fixed root text, Background task completed., while preserving provider-specific continuation detail for Codex. Omit provider-owned automatic entries from visible queue controls.
Unknown attributed lineage must not silently become root output. Buffer a fixed number of lineages and frames until task registration. Overflow is logged and dropped child-side, never projected into the root.
Multiple pending Agent launches cannot safely recover an omitted task_started.tool_use_id by arrival order. Infer only a single unambiguous launch. Ambiguous siblings wait for an explicit SDK alias, which atomically binds the task, preserves launch identity, and drains its child buffer.
Agent launch results and child approval requests can arrive before task_started registers their alias. A structured agentId can also appear in ordinary root tool output. Remember bounded launch identities, route known native task IDs directly, fail closed for unknown child-looking approvals, and prefer an existing root tool call before interpreting incidental agentId data.

Defensive Fixes

Problem and Why it Happened Fix
A failed continuation dispatch without a buffered terminal result left a native-thread-wide drain marker. A later sibling completion on the same Claude session could be mistaken for stale output and failed. Record the exact task IDs represented by the failed offer. Stale frames for those tasks fail closed, known sibling tasks clear the drain and continue normally, and native-process replacement clears the scoped state.
A sibling completion could append after dispatch failed but before failIfCurrent, where a live-buffer rescan pulled the sibling into the failed cohort. Freeze the failed cohort at offer time and replay later frames through normal wake buffering, so appended siblings receive their own continuation and are never projected failed.
A declined or cancelled Agent approval remained in the per-turn launch-inference queue, making a later alias-free valid launch look ambiguous. Remove only the rejected approval from pending per-turn inference while retaining its durable session launch identity.
Native query replacement, interrupt timeout, or session disposal could delete Claude's registry while durable child projections still said running. Fail-close every still-running native child with one static session-ended artifact before deleting aliases or process state. Already-terminal children remain unchanged.
An unresolved Agent result inside a multi-result SDK frame buffered the whole frame and returned, so later sibling results could be delayed or replayed more than once. Split buffered results into one-block messages and continue through the batch, preserving independent lineage even when aliases arrive in reverse order.
A split multi-result user frame could retain the original frame-level tool_use_result, then incorrectly apply that shared structured result when one buffered block replayed. Remove frame-level structured output from split messages and derive each replayed result from its own content block.
The bounded pending Agent launch queue could evict an unresolved launch while leaving implicit alias inference enabled, allowing a later alias-free start to claim the final retained sibling alias. Disable implicit launch-alias inference for the rest of the turn after overflow. Explicit SDK aliases remain authoritative and drain only their own child buffer.

Validation

  • The final MCP, Claude adapter, provider continuation, replay, and
    client-runtime set passed 189 tests with 1 skipped.
  • vp check: passed all 2,690 files.
  • vp run typecheck: passed all 15 packages.
  • A fresh isolated v2.1 Nightly AppImage built from the deliberate final union
    passed the exact packaged Grok post-settlement subagent, Claude
    post-settlement subagent, and Codex background-command wake scenarios. Claude
    projected one generic provider-owned root input while keeping raw child
    output on the child; Grok and Codex retained their provider-specific
    behavior.
  • Codex GPT-5.6 Luna identified the incidental root agentId collision. The
    regression was fixed and covered. Fresh Grok 4.5 high-reasoning source and deliberate-integration reviews
    returned SHIP after verifying teardown ordering, exactly-once terminals,
    semaphore safety, independent batched-result lineage, and fail-closed pending-launch overflow.

Note

High Risk
Changes orchestration routing for Claude native tasks, continuations, and session teardown; mis-attribution or drain bugs could leak child output to the root or drop completions.

Overview
Fixes Claude subagent frames arriving after a root turn settles being mis-attributed to the root thread when continuation turns no longer have launch-time tool-use maps.

Durable native-thread session state now holds task identity, launch/resume aliases, bounded pre-registration buffering, and resume metadata so every child frame resolves through the same lineage. Child narration, tools, results, and distinct terminal output stay on child threads; ordinary root assistant text is unchanged.

Continuation input for provider-owned Claude root wakes uses fixed text (Background task completed.) instead of raw task_notification.summary, while Codex keeps its provider-specific detail. Automatic provider entries are omitted from visible queue controls.

Adds fail-closed behavior for unknown lineage (bounded buffer until registration; overflow dropped child-side), single unambiguous launch-alias inference when task_started.tool_use_id is missing, routing for early Agent results/approvals, and defensive handling for failed continuation cohorts, sibling completions, rejected approvals in inference queues, session teardown, and split multi-result SDK frames so siblings replay independently without shared frame-level results.

Reviewed by Cursor Bugbot for commit f223029. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Preserve Claude subagent attribution after settlement in orchestration v2

  • Redesigns subagent state tracking in ClaudeAdapterV2 to be keyed per native thread, replacing a single global registry with ClaudeNativeThreadSubagentState/ClaudeSessionSubagentState structures that support alias resolution, bounded history, and generation tracking.
  • Serializes all SDK message handling and state transitions behind a Semaphore permit to eliminate race conditions in concurrent subagent/approval flows.
  • Approval requests can now originate from subagents (approvalsCanOriginateFromSubagents: true), with tool calls routed to the correct child thread via parentToolUseId/subagentTaskId.
  • Adds PROVIDER_CONTINUATION_MESSAGE_TEXT as the canonical default continuation message text, used in ProviderContinuationService and filtered from the visible queue in threadWorkflows.
  • Risk: The semaphore-guarded critical section changes the ordering of message handling; any path that previously assumed concurrent state access may behave differently.

Macroscope summarized f223029.

@coderabbitai

coderabbitai Bot commented Aug 5, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 62181832-8817-4ee0-a3ea-b77d114e9301

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@github-actions github-actions Bot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:XXL 1,000+ changed lines (additions + deletions). labels Aug 5, 2026
Comment thread apps/server/src/orchestration-v2/ProviderContinuationService.ts

@macroscopeapp macroscopeapp Bot 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.

Effect Service Conventions review: one convention issue found in the newly added test module's service imports. Everything else in the changed Effect code (subpath namespace imports, layer construction, dependency acquisition via yield* Service, error modeling) matches the conventions.

Posted via Macroscope — Effect Service Conventions

Comment thread apps/server/src/orchestration-v2/CheckpointCaptureService.test.ts Outdated
Comment thread apps/server/src/orchestration-v2/Adapters/ClaudeAdapterV2.ts
Comment thread apps/server/src/orchestration-v2/Adapters/ClaudeAdapterV2.ts Outdated
@macroscopeapp

macroscopeapp Bot commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Needs human review

Diff is too large for automated approval analysis. A human reviewer should evaluate this PR.

You can customize Macroscope's approvability policy. Learn more.

@mwolson
mwolson force-pushed the fix/claude-subagent-postsettle-attribution branch from 38aefa4 to f1d3119 Compare August 5, 2026 06:30
Comment thread apps/server/src/orchestration-v2/Adapters/ClaudeAdapterV2.ts
@mwolson
mwolson force-pushed the fix/claude-subagent-postsettle-attribution branch from f1d3119 to 7370ca6 Compare August 5, 2026 06:58
Comment thread apps/server/src/mcp/OrchestratorMcpService.ts
Comment thread apps/server/src/orchestration-v2/ProviderContinuationService.ts
Comment thread apps/server/src/orchestration-v2/Adapters/ClaudeAdapterV2.ts
Comment thread apps/server/src/orchestration-v2/Adapters/ClaudeAdapterV2.ts
@mwolson
mwolson force-pushed the fix/claude-subagent-postsettle-attribution branch from 7370ca6 to 1a18bba Compare August 5, 2026 08:04

@macroscopeapp macroscopeapp Bot 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.

Reviewed the changed Effect service code against the service conventions. One import-shape issue in the new server test; everything else (namespace imports from effect/* subpaths, Context.Service shapes, error modelling, and dependency acquisition in the touched orchestration/adapter code) looks consistent with the conventions.

Posted via Macroscope — Effect Service Conventions

Comment thread apps/server/src/mcp/OrchestratorMcpService.test.ts Outdated
@mwolson
mwolson force-pushed the fix/claude-subagent-postsettle-attribution branch from 1a18bba to f80ad36 Compare August 5, 2026 08:26
Comment thread apps/server/src/orchestration-v2/Adapters/ClaudeAdapterV2.ts
@mwolson
mwolson force-pushed the fix/claude-subagent-postsettle-attribution branch from f80ad36 to 38e7184 Compare August 5, 2026 10:24
Comment thread apps/server/src/orchestration-v2/Adapters/ClaudeAdapterV2.ts Outdated
@mwolson
mwolson force-pushed the fix/claude-subagent-postsettle-attribution branch from 38e7184 to 49162a7 Compare August 5, 2026 11:06
Comment thread apps/server/src/orchestration-v2/Adapters/ClaudeAdapterV2.ts
Comment thread apps/server/src/orchestration-v2/Adapters/ClaudeAdapterV2.ts Outdated
@mwolson
mwolson force-pushed the fix/claude-subagent-postsettle-attribution branch from 49162a7 to fe0878f Compare August 5, 2026 11:37
Comment thread apps/server/src/orchestration-v2/Adapters/ClaudeAdapterV2.ts Outdated
Comment thread apps/server/src/orchestration-v2/Adapters/ClaudeAdapterV2.ts Outdated
@mwolson
mwolson force-pushed the fix/claude-subagent-postsettle-attribution branch from fe0878f to 8e4dc09 Compare August 5, 2026 12:24
Comment thread apps/server/src/orchestration-v2/Adapters/ClaudeAdapterV2.ts
Comment thread apps/server/src/orchestration-v2/Adapters/ClaudeAdapterV2.ts Outdated
@mwolson
mwolson force-pushed the fix/claude-subagent-postsettle-attribution branch from 8e4dc09 to 905b5a1 Compare August 5, 2026 12:40
Comment thread apps/server/src/orchestration-v2/Adapters/ClaudeAdapterV2.ts Outdated
@juliusmarminge
juliusmarminge force-pushed the t3code/codex-turn-mapping branch from e24b59c to 4213ac5 Compare August 5, 2026 14:35
@mwolson
mwolson force-pushed the fix/claude-subagent-postsettle-attribution branch from 905b5a1 to 48f545d Compare August 5, 2026 14:38

@cursor cursor Bot 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.

Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 48f545d. Configure here.

Comment thread apps/server/src/orchestration-v2/Adapters/ClaudeAdapterV2.ts
Comment thread apps/mobile/src/test-fixtures.ts
Comment thread apps/mobile/src/features/threads/ThreadDetailScreen.tsx
Comment thread apps/server/scripts/acp-replay-agent.ts
Comment thread apps/server/src/orchestration-v2/CheckpointCaptureService.ts
Comment thread apps/server/scripts/record-codex-app-server-replay-fixture.ts
Comment thread apps/mobile/src/features/threads/ThreadActivityInspector.tsx
@mwolson
mwolson force-pushed the fix/claude-subagent-postsettle-attribution branch from 48f545d to f223029 Compare August 5, 2026 15:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XXL 1,000+ changed lines (additions + deletions). vouch:unvouched PR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant