fix(claude): stop treating session slug as subagent marker; recover orphaned chains by agnitum2009 · Pull Request #281 · SeemSeam/claude_codex_bridge · GitHub
Skip to content

fix(claude): stop treating session slug as subagent marker; recover orphaned chains - #281

Open
agnitum2009 wants to merge 1 commit into
SeemSeam:mainfrom
agnitum2009:fix/claude-session-slug-subagent
Open

agnitum2009 wants to merge 1 commit into
SeemSeam:mainfrom
agnitum2009:fix/claude-session-slug-subagent

Conversation

@agnitum2009

Copy link
Copy Markdown
Contributor

Problem

Claude ≥ 2.1.x writes a session-name slug on every transcript entry once a session gets named (auto or manual). comm_runtime/parsing_runtime/structured.py maps entry.slug → event subagent_name, so from that point on every main-chain event is mislabeled as subagent activity.

Observed failure cascade (live incident, Claude 2.1.220):

  1. is_top_level_user_prompt rejects the job's own anchor user prompt → anchor_seen / prompt_activated never flip in the poll state machine.
  2. _prompt_completion_is_eligible then gates off poll_exact_hook forever — the exact Stop-hook artifact (written by the provider hook with the job's own req_id) is never consumed.
  3. The job zombie-runs after its terminal reply: active-task flag never cleared, plain ask refused (forced --chain/--silence), and a --chain result continuation queued behind the zombie parent is never delivered — the child result strands on disk.

Reproduced deterministically by replaying the affected session transcript through ClaudeLogReader.try_get_entries + _process_events: anchor missed before the patch, anchor_seen=True after.

Fix

  • Parsing (root cause): drop slug from subagent markers in _event_record (it is the session name, not a subagent marker); propagate entry.isSidechain as event is_sidechain and honor it in is_top_level_user_prompt / assistant_identity so real sidechain filtering still works via the reliable field.
  • Polling (recovery): add _orphaned_exact_hook fallback — when session-log anchor tracking failed, accept the exact hook artifact only with independent proof: req_id match (already enforced by load_event), event timestamp ≥ accepted_at, 180 s grace elapsed, hook session == tracked session, and an observably idle pane. This un-zombies stuck jobs and lets terminal replies clear the active-task flag.
  • Chain delivery (no result loss): when a callback edge is already FAILED/TIMED_OUT at child completion, submit_callback_continuation used to return early and silently drop the child result. New deliver_orphaned_chain_result delivers it to the dispatching agent (edge.parent_agent) as a notice instead.

Verification

  • Transcript replay regression: anchor detected, prompt activated, reply captured after patch.
  • _orphaned_exact_hook boundary cases (7/7): busy pane, fresh event (< grace), pre-submission event, session mismatch, no pane proof, prompt-not-sent all rejected.
  • deliver_orphaned_chain_result cases (8/8): notice recorded to dispatching agent with orphan diagnostics and full body; safe on missing bureau/parent.
  • Existing suites on patched tree: test_claude_comm_parsing, test_claude_hook_results, test_claude_queued_prompt_activation, test_claude_execution_polling, test_v2_ccbd_dispatcher, test_v2_message_bureau_dispatcher_integration — 171 passed.
  • Live deployment: daemon restart finalized the zombie job via the normal hook path, delivered the stranded chain continuation to the dispatching agent, edge reached done, and all agents returned to zero open jobs.

…rphaned chains

Claude >= 2.1.x writes the session-name slug on every transcript entry of
a named session. structured.py mapped entry.slug to event subagent_name,
so is_top_level_user_prompt rejected the job's own anchor user prompt,
anchor_seen/prompt_activated never flipped, the exact Stop-hook artifact
stayed gated off by _prompt_completion_is_eligible, and the job zombie-ran
after its terminal reply. The agent's active-task flag was never cleared,
plain ask stayed refused (forced --chain/--silence), and --chain result
continuations queued behind the zombie parent were never delivered.

- parsing: drop slug from subagent markers; propagate entry.isSidechain as
  event is_sidechain and honor it in top-level-prompt and assistant
  identity checks
- polling: add _orphaned_exact_hook fallback that accepts the exact hook
  artifact when session-log anchor tracking failed, gated on req_id match,
  event timestamp >= accepted_at, a 180s grace, hook/tracked session match,
  and an observably idle pane, so terminal replies still finalize the job
  and clear the active-task flag
- callbacks/finalization: when a callback edge is already FAILED/TIMED_OUT
  at child completion, deliver the child result to the dispatching agent
  (edge.parent_agent) as a notice instead of dropping it silently
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.

1 participant