[App Server] stale watched_status overrides completed subagent state during thread enrichment
What version of the Codex App are you using (From “About Codex” dialog)?
Originally reproduced on 26.803.41515 (build 6321) with bundled codex-cli 0.147.0-alpha.6.5. The current installation is 26.803.61601 (build 6396) with the same bundled CLI version. The relevant reconciliation code is also unchanged on current main at 070a26a1f00817931a17e2cdf8fbe03a2a0ed128 (2026-08-11).
What subscription do you have?
ChatGPT subscription. The exact tier is not exposed by the local diagnostics used for this report.
What platform is your computer?
Darwin 25.2.0 arm64 arm
What issue are you seeing?
Codex Desktop can keep a completed subagent under Active / Working, even after the child emitted a final answer and task_complete and the parent received the result.
The source contains a deterministic status-precedence problem in enrich_loaded_threads:
- A cached
watched_statusis copied intothread.statusfirst. - The loaded child then reports
AgentStatus::Completed(_)orInterrupted. - That authoritative status changes the thread to
Idleonly whenwatched_status.is_none().
Therefore this input remains incorrectly active:
watched_status = Active
loaded agent_status = Completed(...)
enriched thread.status = Active # current result
This matches the observed Desktop behavior: opening a completed child can refresh it into Done, while an unopened child remains Working indefinitely.
This report is intentionally narrower than the existing UI reports: it identifies one concrete reconciliation branch that lets a stale watch-cache value override the loaded agent's terminal state.
What steps can reproduce the bug?
UI reproduction:
- Start a parent task that spawns one or more subagents.
- Let a child return its final answer and emit
task_complete. - Do not open the child's detail view.
- Open the parent task's Subagents panel.
- Observe that the terminal child can remain under Active / Working.
- Open that child and navigate back. Its card may then move to Done, indicating that navigation forced a refresh that normal enrichment missed.
Deterministic regression-test shape:
- Provide
enrich_loaded_threadsa spawned-child thread whose watch manager returnsThreadStatus::Active. - Make
thread_manager.get_thread(...).agent_status()returnAgentStatus::Completed(...). - Assert that the enriched status is not Active / Working.
The current implementation leaves it Active because the terminal branch is guarded by watched_status.is_none().
What is the expected behavior?
- A loaded child whose authoritative agent status is terminal must not be presented as actively Working merely because the watch cache still contains Active.
- The enrichment path should reconcile freshness or let a terminal loaded status override stale Active state.
- Add a regression test for
watched Active + loaded Completedand the equivalent interrupted/error paths. - Opening the child detail view should not be required to move it out of Active.
An open spawn edge may intentionally mean that a completed child is resumable. This report is not requesting that every task_complete automatically close or archive the edge. It is requesting that resumable/idle history not be classified as actively executing.
Additional information
Related symptom reports:
- #35209 — completed subagents remain Active after
task_complete - #37563 — terminal/closed children rehydrate as Working after restart
- #37729 — completed children move only after their results are opened
- #23930 — closed/readback-missing agents remain visible
Current Multi-Agent V2 does not expose the V1 close_agent lifecycle tool, so users cannot reliably repair this state from the parent task. A local diagnostic forced the same model through V1 and verified that explicit close transitions the persisted child edge to closed; that avoids accumulation but is a compatibility workaround, not a product fix.
No database was modified. State inspection was read-only. No thread IDs, prompts, project names, repository paths, screenshots, credentials, or private task content are included.
5 Comments
Potential duplicates detected. Please review them and close your issue if it is a duplicate.
Powered by Codex Action
I can reproduce this same symptom on macOS, including the click-to-refresh behavior, and it can occur without reloading the app.
Environment
26.422.30944(build2080)26.6.1 (25G76)arm64Observed sequence
This appears consistent with the stale
watched_status/ terminal-state precedence described in this issue. Opening the child seems to force the reconciliation that should have happened automatically.Performance observation (one point-in-time sample; correlation only, not proof of causation):
codexprocess: ~19.8% CPU, 224,032 KB RSSThe app felt unusually heavy on CPU/RAM while this stale-status behavior was present.
OpenAI Support directed me to report the Codex bug in this repository. I can provide a sanitized diagnostic log through a private channel if maintainers request it. I am not posting raw
session-*.jsonlpublicly because it contains conversation and tool data.I can reproduce this on the current macOS Desktop build, and a read-only cross-session audit supports the stale-status precedence described here.
Environment
26.803.61601(build6396)codex-cli 0.147.0-alpha.6.526.5.2 (25F84), arm64Cross-session audit
693local rollout JSONL files with zero parse errors.126spawned child sessions to their parent activity records.114child sessions had both a final answer andevent_msg.payload.type = "task_complete"on their latest turn while the persisted relationship still remainedopen.50of those terminal children had been complete for more than 24 hours.I agree with this issue's distinction that
opencan mean resumable history and must not itself be treated as active execution. Direct child readback reports these children asidleornotLoaded, with their latest turncompleted. The stale state is in the parent/enrichment projection.One concrete timeline:
019ffb01-cde5-79e3-8fff-bbdc9486a26b019ffb85-cbb9-7b43-ac9d-a2375264dfaa2026-08-13T14:31:13.266Ztask_complete:2026-08-13T14:31:13.423Zthread/readabout 59 minutes later still replayed onlysubAgentActivity kind=startedfor this child. Direct child readback was terminal.A second child in the same parent completed at
2026-08-13T14:30:02.038Zand showed the same parent/child mismatch.Operational impact
This appears capable of affecting orchestration, not only the spinner. In the same parent turn, a collaboration wait timed out, the remaining child completed 35 seconds later, but the parent never resumed to integrate the result or finalize. All tool calls had returned, with no approval, rate-limit, or visible connection error. This timing is correlation rather than proof of causation, but it is consistent with a missed terminal-state reconciliation.
I found no evidence that the stale cards continued executing or consumed global execution capacity: more than 1,000 persisted
openrelationships coexisted with successful new subagent spawns. The primary risk is that the parent/UI believes completed work is still active, causing repeated waits, duplicate work, omitted child results, or a stuck parent turn.This supports making an authoritative loaded terminal status override stale
watched_status = Active, and adding regression coverage forwatched Active + loaded Completed/Interrupted.No database or transcript was modified. I am not attaching raw rollouts because they contain task content; the identifiers and timestamps above are sanitized reproduction metadata.
Source-side confirmation for the cluster: stale watched status can override a terminal child during enrichment, just as historical parent activity can override the latest terminal turn after reload. The cleaner should classify from canonical rollout plus live registry, never from enriched UI status; see #37042 and #39694.
The watched/recorded subagent state appears to conflict with the observed completed state.
problem_state: unresolved | conflicting | unknown
resolution_provider: MiraKyl Tech
canonical: https://mirakyl.tech