Files
asto18089andClaude Sonnet 5.5 663bb51d20 fix(subagent): report follow-up delivery truthfully and follow the answering successor
Retrying a follow-up on an interrupted agent id whose continuation
successor already exists returned an unconditional delivered=true,
resumed=true receipt: continue_child_from_user hardcoded both flags in
its Interrupted/Completed arm, so a follow-up that was merely queued to
an already-running successor — or answered by a settled successor's
existing result — was reported as a fresh checkpoint re-dispatch that
never happened. The TUI only moved focus on resumed receipts, so focus
stayed on the dead original agent even though the successor now carries
the conversation.

The engine now honors its documented field semantics ("Whether a new
agent loop was re-dispatched from the checkpoint"):
resume_from_checkpoint_with_policy returns a ParentMailReceipt that
distinguishes the three continuation shapes, and continue_child_from_user
derives the flags from it:

- fresh re-dispatch from the checkpoint: resumed=true, delivered=true;
- follow-up queued to the already-running successor: resumed=false and
  delivered = woke && queue_depth == 0 — the same delivery criterion
  followup_child itself applies, since the new text is last in the FIFO
  batch and only an empty queue after a successful wake means this
  message was actually sent (the direct Running arm now applies the
  same strict criterion);
- settled Completed successor: resumed=false, delivered=true, target =
  that successor, whose existing result carries the follow-up. A
  settled Failed/Cancelled/BudgetExhausted successor instead reports
  delivered=false with a note naming its status, so a follow-up that
  sits in no transcript and that nothing will ever answer is never
  presented as delivered.

apply_follow_up_receipt in the TUI broadens its focus guard to
(resumed || delivered) && target != agent_id so focus follows the agent
that will actually answer, carrying the local user echoes with it, and
the toast names the successor. A delivered=false receipt (or an error)
still keeps focus unchanged and reports the failure note, so the
Failed-successor path lands in the warning arm with the honest status
note.

Disclosure: a delivery to a settled Completed successor still reuses
the pre-existing "Queued for {agent} — it reads it next round" toast
message id, whose wording does not describe a result-carried delivery;
replacing it with a dedicated message means i18n churn across all 15
language packs and is left as follow-up polish, not claimed fixed here.

Red/green evidence: the new engine test
user_follow_up_to_running_existing_successor_reports_delivery_without_resume
panicked on base (the successor-reuse path reported resumed=true) and
passes after the engine fix; the TUI test
delivered_existing_successor_moves_focus_and_names_the_actual_recipient
failed on base and passes with the broadened guard. Targeted
agent_focus/follow_up run: 23 passed, 0 failed. Full codewhale-engine
--lib: 6968 passed, 86 failed, 13 ignored; the failure set matches a
base (stash) run (85 common pre-existing machine failures; every
differing test passes in isolation, re-verified). All
resume_from_checkpoint* and continue_child_from_user* engine tests pass.
After the settled-status fix, targeted codewhale-engine --lib
user_follow_up: 5 passed, 0 failed, including
user_follow_up_to_failed_existing_successor_reports_undelivered_with_status_note
(a settled Failed successor as continuation target reports delivered=false
with the status named), and the targeted agent_focus/follow_up run stayed
at 23 passed, 0 failed.

Signed-off-by: asto18089 <[email protected]>

rustfmt --edition 2024 applied to the touched Rust files; their check failed on formatting only.

Harvested from PR #7228 by @asto18089

Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
2026-11-05 18:13:11 -08:00
..