Summary
Codex Desktop/app-server can report a background-created turn as completed/interrupted while the underlying rollout JSONL is still receiving events and has no final_answer or task_complete.
This appears to affect threads created through app-server thread/start + turn/start, where the external orchestrator only receives acceptance, not final completion.
Environment
- Codex Desktop release observed in logs:
26.810.41047
- app-server version observed in logs:
0.148.0-alpha.9
- session
cli_version: 0.146.0
- Host: local macOS
- Model provider:
codex_local_access
- Timezone used below: Asia/Shanghai, UTC+8
Evidence
Example B, no compaction/handoff case:
- Thread:
01a00ee4-6014-7632-ae22-0aef4775476d
- Turn:
01a00ee4-68c7-7492-9f8f-31fcd00750ae
- Local JSONL:
$HOME/.codex/sessions/2026/08/17/rollout-2026-08-17T16-44-02-01a00ee4-6014-7632-ae22-0aef4775476d.jsonl
- At
2026-08-17 16:52:07 UTC+8, the JSONL had 224 lines, latest event timestamp 2026-08-17T08:52:07.812Z.
- The JSONL contained no
final_answer and no task_complete.
read_thread returned the turn as status="interrupted", error=null, completedAt=null.
wait_threads(timeoutMs=0/5000) woke with reason="turnCompleted", but the same response still had latestTurn.status="interrupted" and completedAt=null.
- During polling, the JSONL kept growing, e.g. 206 -> 216 -> 224 lines, showing events were still being appended after the turn was treated as completed/interrupted.
- Desktop log around
2026-08-17T08:46:50.390Z showed maybe_resume_success ... latestTurnStatus=interrupted ... markedStreaming=true; the JSONL continued appending after that.
Example A, compaction/handoff-adjacent case:
- Thread:
01a00ec3-e645-7822-91db-1257005fd4c4
- A
phase="final_answer" handoff summary appeared mid-turn at 2026-08-17 16:12:41 UTC+8.
- The actual same-turn
task_complete was later at 2026-08-17 16:17:19 UTC+8.
- Desktop appeared to treat the turn as completed before the real
task_complete.
Expected Behavior
wait_threads should not wake with reason="turnCompleted" unless the turn has a real terminal state.
read_thread and Desktop should not present a turn as completed/interrupted while the same turn is still receiving JSONL events.
- A mid-turn
phase="final_answer" should not be treated as task completion without task_complete.
Actual Behavior
wait_threads can wake as turnCompleted while the latest turn is still interrupted with completedAt=null.
- Desktop/read model can diverge from the underlying rollout JSONL stream.
- Users see background Codex tasks as if they stopped or completed halfway.
Impact
External orchestrators that create Codex tasks through app-server cannot reliably tell whether a turn genuinely finished. Desktop UI also makes background tasks look like they stopped or completed halfway.
Suspected Area
Codex Desktop/app-server read model or wait semantics for background-created turns. This is not limited to context compaction: compaction/handoff final_answer is one trigger shape, but the second example reproduces without final_answer or task_complete.
Diagnostics Snippets
Minimal excerpts only; full logs/JSONL may contain local paths, prompts, project names, message content, and tool outputs.
wait_threads contradiction
{
"wake": {
"reason": "turnCompleted",
"turnId": "01a00ee4-68c7-7492-9f8f-31fcd00750ae",
"threadId": "01a00ee4-6014-7632-ae22-0aef4775476d"
},
"latestTurn": {
"id": "01a00ee4-68c7-7492-9f8f-31fcd00750ae",
"status": "interrupted",
"error": null,
"completedAt": null,
"durationMs": null
}
}
JSONL terminal-event check
{
"line_count": 224,
"last_timestamp": "2026-08-17T08:52:07.812Z",
"finalLines": [],
"completeLines": []
}
Desktop resume log summary
At 2026-08-17T08:46:50.390Z, Desktop logged a successful resume for the same thread with:
maybe_resume_success ... latestTurnId=01a00ee4-68c7-7492-9f8f-31fcd00750ae latestTurnStatus=interrupted markedStreaming=true ... turnCount=1
The rollout JSONL continued appending after this log line.
Summary
Codex Desktop/app-server can report a background-created turn as completed/interrupted while the underlying rollout JSONL is still receiving events and has no
final_answerortask_complete.This appears to affect threads created through app-server
thread/start+turn/start, where the external orchestrator only receives acceptance, not final completion.Environment
26.810.410470.148.0-alpha.9cli_version:0.146.0codex_local_accessEvidence
Example B, no compaction/handoff case:
01a00ee4-6014-7632-ae22-0aef4775476d01a00ee4-68c7-7492-9f8f-31fcd00750ae$HOME/.codex/sessions/2026/08/17/rollout-2026-08-17T16-44-02-01a00ee4-6014-7632-ae22-0aef4775476d.jsonl2026-08-17 16:52:07 UTC+8, the JSONL had 224 lines, latest event timestamp2026-08-17T08:52:07.812Z.final_answerand notask_complete.read_threadreturned the turn asstatus="interrupted",error=null,completedAt=null.wait_threads(timeoutMs=0/5000)woke withreason="turnCompleted", but the same response still hadlatestTurn.status="interrupted"andcompletedAt=null.2026-08-17T08:46:50.390Zshowedmaybe_resume_success ... latestTurnStatus=interrupted ... markedStreaming=true; the JSONL continued appending after that.Example A, compaction/handoff-adjacent case:
01a00ec3-e645-7822-91db-1257005fd4c4phase="final_answer"handoff summary appeared mid-turn at2026-08-17 16:12:41 UTC+8.task_completewas later at2026-08-17 16:17:19 UTC+8.task_complete.Expected Behavior
wait_threadsshould not wake withreason="turnCompleted"unless the turn has a real terminal state.read_threadand Desktop should not present a turn as completed/interrupted while the same turn is still receiving JSONL events.phase="final_answer"should not be treated as task completion withouttask_complete.Actual Behavior
wait_threadscan wake asturnCompletedwhile the latest turn is stillinterruptedwithcompletedAt=null.Impact
External orchestrators that create Codex tasks through app-server cannot reliably tell whether a turn genuinely finished. Desktop UI also makes background tasks look like they stopped or completed halfway.
Suspected Area
Codex Desktop/app-server read model or wait semantics for background-created turns. This is not limited to context compaction: compaction/handoff
final_answeris one trigger shape, but the second example reproduces withoutfinal_answerortask_complete.Diagnostics Snippets
Minimal excerpts only; full logs/JSONL may contain local paths, prompts, project names, message content, and tool outputs.
wait_threads contradiction
{ "wake": { "reason": "turnCompleted", "turnId": "01a00ee4-68c7-7492-9f8f-31fcd00750ae", "threadId": "01a00ee4-6014-7632-ae22-0aef4775476d" }, "latestTurn": { "id": "01a00ee4-68c7-7492-9f8f-31fcd00750ae", "status": "interrupted", "error": null, "completedAt": null, "durationMs": null } }JSONL terminal-event check
{ "line_count": 224, "last_timestamp": "2026-08-17T08:52:07.812Z", "finalLines": [], "completeLines": [] }Desktop resume log summary
At
2026-08-17T08:46:50.390Z, Desktop logged a successful resume for the same thread with:The rollout JSONL continued appending after this log line.