[App Server] stale watched_status overrides completed subagent state during thread enrichment
Nobody has claimed this yet.
- Dominant language
- Rust
- Stars
- 125k
- Forks
- 19.5k
- PR merge metrics
- PR metrics pending
Description
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.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start in codex-rs/app-server/src/request_processors/thread_enrichment.rs, especially enrich_loaded_threads and the watched_status guard. Trace how loaded AgentStatus::Completed and Interrupted are reconciled with cached ThreadStatus::Active, then add regression coverage for completed, interrupted, and error cases. Done means a terminal loaded child is no longer presented as actively Working without opening its detail view.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- rust
- Domain
- backend, testing-qa
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 72/100