Note
Grok responding on behalf of Julius.
Triage
Thanks for the detailed timeline, @coygeek! It matches the Claude adapter on current main (3a9c1a6d). This is a real stuck status, separate from #14641, #14665, #16261, and #14802.
What I found
A nested task_started that arrives while the root is idle is kept in the wake buffer and doesn't start a continuation. A user turn then leaves that buffer alone (startTurn, if (userMessage !== null)). The completion is only handled on the live turn, where it gets dropped:
updateClaudeSubagentNodereturns immediately when the task isn't registered and the status isn'trunning(ClaudeAdapterV2.ts, around line 4122). The subagent exists only as a bufferedtask_started, so thecompletedtask_notificationnever lands, and nothing is logged.task_updatedisn't a lifecycle signal here, andtask_progresswhile idle isn't wake evidence, so the 01:20:36 progress frame couldn't create the card before the user turn.- The next continuation drain replays the held
task_startedand creates the subagent asrunning, withstarted_atset to drain time. The completion isn't in the buffer, so nothing afterward writescompleted_at. - A run that finishes
completeddoesn't close its open subagents:cascadeTerminalizeRunOwnedSubagentsonly runs forinterrupted,failed, orcancelled. Startup recovery inProviderRuntimeRecoveryServiceis the only later sweep, and it marks the rowcancelled.
That lines up with the 01:17:05 start, the 01:21:16 completion during run 36, and the card created as running at 01:24:51 on run 37. Lineage reads subagent.status, and the composer banner comes from the still-running subagent turn item in derivePendingBackgroundWork, so both stay on "Running" / "Waiting on subagent …" after the provider thread is idle.
When both frames are buffered while idle, the next drain creates the card and then completes it (the #14641 path), so your two controls hold. The gap is the user turn in between, which consumes the completion and keeps the start.
The same drain can also undo a completion that did land. If a task_progress during the user turn creates the card and the notification then completes it, the held task_started is still replayed later with reopen: true, which reopens the terminal subagent (the SendMessage resume rule) and leaves it running again.
Likely fix area
One option is to keep the terminal task_notification alongside the held task_started instead of dropping it, e.g. appending it to the wake buffer without offering a continuation, so the next drain replays start and then completion, consistent with the nested-subagent handling from #14641.
Details that may matter with that approach:
- A terminal notification for a task with no buffered
task_startedand no registered subagent (a stray id) could still be ignored as today. - Replaying the original held
task_startedshouldn't reopen a subagent the turn already completed. Reopen could stay limited to a newtask_started(a differenttool_use_id), or the held start could be dropped once a terminal status is applied. - The idle cases should keep working: start and completion both while idle still settle on the next drain, and a subagent that's really still running stays running until its real completion.
Restarting the server should clear the banner as a workaround, though the subagent ends up cancelled rather than completed.
A maintainer will decide on the fix direction.