Repository navigation
Codex Desktop repeatedly re-enters the model during wait/status polling, consuming substantial credits #35259
Description
Summary
During intentional Ultra and multi-agent work, Codex Desktop repeatedly re-entered the model merely to wait for agents or poll terminal status. In a corrected reset-to-49%-usage window, model turns whose only tool action was wait/status polling accounted for 19.8% of raw local token volume.
Ultra and multi-agent use were intentional. The suspected defect is not normal agent fan-out; it is repeated model inference during quiet coordination and process-wait intervals, often at 30- or 60-second cadence.
Related reports exist, but this report adds current-build evidence, replay-safe accounting, a full usage-cycle window, tool-level decomposition, a representative long-running trace, and a public-rate-card estimate.
Environment
- ChatGPT Pro
- macOS on Apple silicon
- Codex Desktop 26.721.31836 (build 5828)
- Incident runtime: codex-cli 0.146.0-alpha.3.1
- Mostly GPT-5.6 Sol
What issue are you seeing?
Long-running multi-agent tasks can generate hundreds of distinct model turns that do no substantive work beyond calling one of these tools:
wait_agentlist_agentswrite_stdin- generic
wait
Each polling interval appears to re-enter the model, ingest a large cached conversation prefix, and then make another wait/status call. This can continue for hours while delegated work or a terminal process is still running.
Corrected local evidence
I analyzed local rollout telemetry from one complete weekly reset window, from the reset through the first observed 49% usage state.
The parser:
- excludes copied parent-history prefixes in child rollouts;
- starts each child at its live
task_startedboundary; - ignores unchanged cumulative token snapshots; and
- counts only genuine per-turn token deltas.
Corrected window:
- 10,586 genuine model turns
- 1,382,757,012 raw local tokens
- 43,668,351 uncached input tokens
- 1,335,723,264 cached input tokens
- 3,365,397 output tokens
- 96.83% cached-input share
- 94,241 copied-prefix token records excluded
- 404 duplicate token snapshots excluded
Tool-only wait/status turns:
| Tool group | Turns | Raw local tokens | Uncached input | Cached input | Output | Share of all raw |
|---|---|---|---|---|---|---|
wait_agent / list_agents only |
985 | 142,137,652 | 2,654,345 | 139,365,376 | 117,931 | 10.3% |
write_stdin / wait only |
983 | 131,423,068 | 1,319,437 | 130,028,544 | 75,087 | 9.5% |
| Combined | 1,968 | 273,560,720 | 3,973,782 | 269,393,920 | 193,018 | 19.8% |
Using the current public GPT-5.6 Sol rate card, the combined wait/status subset corresponds to an estimated 3,948 credits. This is a rate-card estimate from local telemetry, not a claim about the private subscription billing ledger.
Representative long-running trace
One child task ran for about 10 hours 55 minutes and contained:
- 1,417 genuine model turns
- 254
wait_agentcalls - 31
list_agentscalls - 316
write_stdincalls - 12 generic
waitcalls - 613 combined wait/status-only turns
- about 93.17 million raw local tokens attributable to those wait/status turns
The wait/status subset was about 45% of that child task's genuine raw token volume. Most agent waits requested only 30 or 60 seconds before another model-mediated poll.
Steps to reproduce
- Start an Ultra task that delegates a genuinely long-running child task.
- Let the child run for at least 30-60 minutes while the parent or another child coordinates it.
- Observe repeated
wait_agent,list_agents,write_stdin, or genericwaitcalls during otherwise quiet intervals. - Inspect per-turn local token deltas, excluding copied child-history prefixes and unchanged cumulative snapshots.
- Note that status-only polling repeatedly creates distinct model turns and reprocesses a large cached context.
Expected behavior
Waiting for an agent or terminal process should be event-driven, or handled by the harness without repeatedly invoking the model. The model should wake when:
- the child or process produces meaningful new output;
- the child completes or requires attention;
- the user sends new input; or
- a deliberately bounded, low-frequency checkpoint is required.
Actual behavior
Quiet wait intervals repeatedly invoke the model so it can issue another polling tool call. Large cached prefixes are charged through the public credit model even though the turns produce almost no substantive user-facing work.
Why this is not ordinary Ultra fan-out
Ultra and explicit multi-agent delegation were intentional, and their extra cost is expected. The anomalous subset here is narrower: nearly one-fifth of corrected raw token volume came from turns whose only action was waiting or checking status.
The same corrected window attributed 68.1% of raw volume to Ultra and 58.7% to subagents. Those figures describe the chosen workload. This issue concerns the avoidable model-mediated polling inside that workload.
Evidence boundary
- These figures come from local rollout telemetry, not OpenAI's internal billing ledger.
- Raw local token volume is not the same as subscription usage.
- The credit figure is an estimate using the published model rate card.
- Copied historical token records were explicitly excluded and are not claimed as billing events.
- I found no evidence here of a silent quota reduction.
- No private prompts, task identifiers, repository names, local paths, account details, or transcript content are included.
Related reports
- Incorrect default behavior of the parent chat when managing background agents, leading to unnecessary consumption of rate limits and tokens. #34468 — parent chat polls child agents every minute
- Codex CLI: gpt‑5.6‑sol Ultra Fast background loop drained weekly limit #33276 — wait-for-agents loop drained quota
- [Codex Desktop] Nested functions.exec wait_agent polling causes repeated parent turns and token usage #35108 — nested wait-agent polling
- Background process polling wastes tokens: each write_stdin poll triggers full API turn with complete history #13733 — terminal polling
- Make wait_agent default timeout configurable #18394 — default wait timeout
- Avoid cloning thread history for token usage replay #34361 — replay attribution work
Suggested fix direction
- Make agent and terminal waits event-driven inside the harness.
- Avoid a fresh model call when no meaningful state has changed.
- Coalesce repeated status checks and apply backoff for long-running work.
- Surface wait/polling usage separately in diagnostics.
- Add regression coverage asserting that unchanged wait state does not create repeated billable model turns.
Activity
github-actions commentedon Jul 24, 2026
Potential duplicates detected. Please review them and close your issue if it is a duplicate.
Powered by Codex Action
dimasyankauskas commentedon Jul 24, 2026
Addendum: ten-day baseline comparison (July 15–24, 2026)
I extended the replay-corrected audit to compare the July 23–24 incident period with the preceding eight-calendar-day baseline. Copied child-history prefixes and unchanged cumulative token snapshots remain excluded.
The spike is therefore primarily a much higher frequency of genuine full-context model turns, not materially larger individual turns. The increased wait/status share strengthens the narrower harness concern in this issue: quiet coordination intervals are repeatedly re-entering the model.
I also compared two consecutive weekly-meter cycles. The current cycle produced 25.50M replay-safe raw local tokens per observed meter percentage point versus 26.28M in the previous cycle, a difference of about 3%. This does not support a newly smaller Pro allowance or changed meter denominator. It is consistent with the meter depleting faster because substantially more model turns were executed per hour.
There was substantial update activity during the window: six local Desktop install-start events were observed between July 21 and July 23, and the public
openai/codexrepository published 28 releases from July 15 through July 24 UTC. However, the activity spike began before the transition to Desktop build 5828, so build 5828 cannot be identified as the sole cause. A public ChatGPT/Codex service incident also overlapped part of July 23. These timings warrant investigation but do not establish causation.Evidence boundary: these remain privacy-safe aggregates from local rollout telemetry, not OpenAI billing records. Ultra and multi-agent usage were intentional; the suspected defect remains repeated model-mediated polling during unchanged wait/status intervals.
bbingz commentedon Jul 25, 2026
Analysis (community)
Residual analysis for #35259 (Desktop re-enters the model during wait/status polling and burns credits) under docs/contributing.md — invitation-only. No unsolicited PR.
Root-cause hypothesis
wait_agentis a local timeout over an activity watch channel; on timeout the turn layer setsneeds_follow_upand issues a fresh sampling request that re-ingests the full prefix, so long delegated work becomesN ≈ ceil(W/t)billable model turns. This is client-side re-entry, not a silent server quota cut.@dimasyankauskas — this is an exceptional piece of forensic work; the 10-day baseline comparison (2.58x tokens/hr, +8.26pp wait/status share, +23.12pp subagent share) and the meter-cycle parity check are exactly the kind of evidence that isolates "more turns per hour" from "smaller allowance." Your "no evidence of a silent quota reduction" conclusion is, I think, the right read.
I want to add the missing piece you and the cluster (#32640, #35108, #34468, #32309) describe behaviorally but don't trace in code: the unified OSS root cause. At HEAD
4c43465133,wait_agent(codex-rs/core/src/tools/handlers/multi_agents_v2/wait.rs:178-196) blocks on a purely localtokio::time::timeout_atover awatch::Receiversourced fromInputQueue::subscribe_activity(input_queue.rs:49-54) — no server round-trip, no long-poll. On timeout it returnsWaitAgentResult{timed_out:true}as aFunctionCallOutput. The turn layer then unconditionally setsneeds_follow_up=true(turn.rs:2199, plusend_turn=falseon any tool call atturn.rs:2369-2370),continues the loop, and issues a freshrun_sampling_requestthat re-ingests the full prefix viasess.clone_history().for_prompt(...)(turn.rs:295-308,history.rs:143-146).prompt_cache_key/previous_response_idare billing/transport discounts only — they do not skip the model turn. SoN = ceil(W/t)polling inferences, each billing the prefix. That is your 2.58x.Two corrections to the cluster, for the record: (1) the OSS
wait_agentdefault is 30s, max 1h (config/mod.rs:209-211), not 50s — #32640's ~50s is the model's chosentimeout_mson the code_modewaittool path, a different handler; (2) out-of-rangetimeout_msis rejected, not clamped (wait.rs:54-63). Neither changes the mechanism.Ranked fix outline (all OSS): (a) re-arm
wait_for_activityonTimedOutwhile the child is still running, instead of returning to the model (wait.rs:96-117) — collapses N polling turns into ≤1; (d) coalesce unchanged-status polls with backpressure; (b) raise/documentdefault_wait_timeout_ms(defense-in-depth only; doesn't cover code_modewaitor explicit short choices); (c) suppress prefix re-billing for pure status polls (partially server-side).Fail-first tests I'd want before any merge: a 10-min delegated child produces
≤1model turn for the whole wait (today: ~20); a pure-status timeout does not issue a newrun_sampling_request(today: does); steer/mailbox wake still fires immediately (regression guard for #18968/#28341). Happy to draft the test patch if a maintainer wants it.Happy to refine measurements or a fail-first test patch if maintainers want one. No unsolicited PR from me.
dimasyankauskas commentedon Jul 25, 2026
@bbingz Thank you—this source trace is highly relevant and broadly consistent with the telemetry.
Two evidence boundaries are worth preserving:
The 2.58× figure is the total tokens/hour increase, not an attribution entirely to wait polling. From the aggregate rates, additional wait/status volume was approximately 9.83M raw tokens/hour out of a 42.66M/hour total increase—about 23%. So this mechanism plausibly explains a material, directly observed part of the spike, rather than the whole increase.
clone_history().for_prompt()establishes the logical model-visible context, while the WebSocket path may transmit an incremental delta usingprevious_response_id. OpenAI's API documentation says previous chain input remains billed as input tokens, but my ChatGPT Pro credit ledger is not directly observable. I am therefore keeping the conclusion at: repeated sampling requests are consistent with faster credit depletion, rather than proof of private subscription-billing semantics.The fail-first tests are excellent. I would also add equivalent coverage for
write_stdin/ code-mode waiting, since terminal polling accounted for another 9.5% of raw volume. Given the repository's contribution policy, waiting for maintainer direction before drafting a patch makes sense.dimasyankauskas commentedon Jul 25, 2026
Additional recurrence data: fixed 12-hour window
I ran the same replay-safe analysis on a separate fixed window (2026-07-25 05:08–17:08 UTC). The same model-mediated wait/status symptom persisted, but at lower intensity than the Jul 23–24 incident window.
Corrected aggregate totals:
wait_agent/list_agents): 202 turns, 28,298,127 raw tokenswrite_stdin/ genericwait): 127 turns, 18,048,878 raw tokensRepeated-polling evidence:
wait_agentcalls at 30 seconds, 9 at 60 seconds, and 33 generic waits at 30 secondsComparison using the same definitions:
This places the new window 3.22 percentage points above the earlier wait/status baseline, but 5.04 points below the incident. It supports recurrence of the same mechanism without suggesting that the current intensity equals the incident peak.
Method and privacy boundary:
task_startedboundarygaikman2015 commentedon Jul 30, 2026
I encountered the same issue on Codex TUI / CLI 0.145.0 on Windows with gpt-5.6-sol, Ultra, and multi-agent v2. A
parent turn ran for 16 hours 29 minutes without further user input or completion, recorded 255 wait_agent calls and 11
context compactions, and ended with another unmatched wait_agent call. The final five-minute polling cycles each re-
entered the model and processed about 213,000 tokens, overwhelmingly cached input.
phyrexia commentedon Jul 31, 2026
Independent corroboration from a different account, plus one methodological note that may help others reproduce your numbers.
I only report what I could verify. Where my own accounting is still unreliable I say so rather than post a figure.
1. The wait/status polling, in an 11-day session
Same mechanism you describe, on ChatGPT Pro with gpt-5.6-sol. One session stayed open for 11 days and produced a single 475 MB rollout.
I counted the blocking wait calls directly from their arguments:
The empty returns escalate over the life of the session:
The session recorded 8 errors in 11 days. Nothing failed and nothing retried, which is why it ran that long unnoticed. On the last day my client logged 379
usage_limit_exceedederrors.This supports @bbingz's root-cause reading: the empty return is the local timeout firing, and each one costs a fresh full-prefix turn.
2. A clean account exhausted a full weekly allowance in 407 model turns
After exhaustion I moved to a brand-new account on a different tier — no history, no prior usage. It was active for four hours (13:12–17:15 UTC) and reached 100% of its weekly cap.
Counted with your criteria (anchor on
turn_context, exclude inherited prefixes, ignore unchanged cumulative snapshots, count genuine deltas only):Four hundred turns for a week's allowance. This is the part I find hardest to explain as normal accounting, because there is no accumulated history to blame.
3. Methodological note: ~90 telemetry events per genuine turn
This is why I think several reports in these threads produce figures that cannot be reconciled with each other.
Counting
token_countevents overstates model turns by roughly two orders of magnitude. On one day I measured:turn_contextis the anchor that gives turn counts matching plausible activity. I had this wrong myself for several passes, and every derived figure was inflated until I fixed it. Your parser already handles this; it may be worth stating the anchor explicitly, since it is the single correction that reconciles the numbers.What I am not reporting
My per-window token totals for the older account are still wrong — my delta accounting mishandles the gap left when an inherited prefix is skipped, which inflates the sum. I would rather leave that out than add a number to this thread that has to be withdrawn later. The wait counts and turn counts above do not depend on that calculation.
phyrexia commentedon Jul 31, 2026
Follow-up to my comment above: the empty-return rate correlates with the CLI version, and it looks like something between 0.144.6 and 0.146.0 fixed it.
I grouped every rollout in July by the version recorded in its
session_meta, then counted blocking wait calls and how many returned with the payload field empty. These are counts of calls and of return values — they do not depend on any token accounting.Two things stand out.
0.144.6 is roughly 3x worse than any other version I ran, and it is the version that was active during the 11-day session I described above — it covered nine of those eleven days.
0.146.0 is effectively clean at 0.6%. That also resolved something that had confused me: when I measured the wait calls made by a separate, brand-new account, I got 0.6% empty and read it as "no busy-waiting happened there". It was not a different behaviour — that account simply ran on 0.146.0.
If this holds on other accounts, there is a change between 0.144.6 and 0.146.0 that addresses it, which gives a concrete range to bisect rather than a symptom description.
Caveats, stated plainly: this is one account's data; the samples are uneven (0.146.0 has only 617 wait calls against 10,828 for 0.144.6); and version attribution comes from each rollout's own
session_meta, so a session spanning an upgrade is attributed to the version it opened with. I would not read the ordering of the middle rows as meaningful — the gap between 0.144.6 and 0.146.0 is what I would test.Worth someone with 0.146.0 and heavy multi-agent use confirming whether the empty returns really did stop, or whether they are simply rarer in their workload.
phyrexia commentedon Aug 1, 2026
Follow-up on the version correlation I posted above: I think the fix is #34852, "Wake sleeping threads for queued agent mail", merged 2026-07-23.
It touches
codex-rs/core/src/tasks/mod.rs(+16/-4). From its own description:That matches the empty returns exactly. Before it, the sub-agent's message landed in the mailbox but did not wake the sleeping supervisor. The supervisor stayed asleep until its own timeout fired, woke on its own, and found the message already sitting there — and that timeout wake is the billed turn that re-ingests the full prefix. The work was already done; what was missing was the notification.
This lines up with the dates in my table. The fix merged Jul 23. I was still running 0.144.6 from Jul 19 to Jul 27 at 16.8% empty returns, i.e. several days after the fix existed. 0.146.0, which includes it, gives 0.6%.
It also matches @bbingz's reading of the source further up this thread.
Two adjacent commits in the same range suggest this was a recognised problem rather than an incidental change: #34887 "Allow disabling the multi-agent wait tool" and #34969 "Keep the sleep tool outside code mode".
Caveat: I identified this by diffing the two tags and matching commit messages against the observed behaviour — I have not built both versions to confirm the causal link. Someone on the team can verify that far faster than I can.
jkammerland commentedon Aug 2, 2026
I still experience heavy preference for polling in 1.46.0. Made a full post here:
#32309 (comment)
3 remaining items
Mateusz-Bugaj commentedon Aug 15, 2026
Environment:
Windows
Codex Desktop
Prolite
weekly window: 2026-08-13 08:13:35 → 2026-08-20 08:13:35
Observed:
6,829 genuine local model turns
554 redundant wait_agent re-entries
Waste:
73,709,145 raw input tokens
73,169,792 cached input
539,353 uncached input
19,553 output
7,973,650 input-equivalent tokens
995.314 estimated credits
Impact:
7.50% of locally observed usage
~6.00 percentage points of the entire weekly rate-limit window
Models:
551 / 554 redundant wakeups were GPT-5.6 Sol
AmeerJ97 commentedon Aug 21, 2026
Independent Linux reproduction on Codex CLI 0.149.0 with a ChatGPT Pro 20x
account. I analyzed the complete local rollout corpus from a weekly reset at 0%
used through the first observed 33% state.
Methodology:
last_token_usage, actual model,and reported quota-bucket signature.
or credentials.
Corrected ordinary-pool window:
Wait/status-only subset:
The wait/status subset is 17.4% of reconstructed ordinary credits, equivalent
to roughly 5.7 percentage points of the inferred weekly allowance. The largest
single root had 450 wait/status-only turns and about 947 estimated credits in
that subset.
Repeated patterns include identical
write_stdincalls, 25–50 second shellsleeps followed by unchanged CI/pipeline status checks, and repeated
wait_agent/list_agentscalls. Each interval re-entered the model andreprocessed a large cached prefix.
This supports the requested fix direction in this issue: waits should be
event-driven in the harness, unchanged state should not create a new model
turn, and wait/polling usage should be exposed separately.
I can provide maintainers with sanitized per-turn and per-session metadata
privately if requested. These are local rate-card estimates, not claims about
OpenAI's private server billing ledger. No chat content is included in this
report.
nos1609 commentedon Aug 22, 2026
Fresh, narrow follow-up for the direct V2 wait path on Codex CLI 0.149.0. This sample does not use the nested V1
functions.execwrapper described in #35108.Environment:
During a fixed 24-hour window, the root made 91 direct
wait_agentcalls:The 50 timeout-only returns caused 50 model re-entries with:
Completed waits caused another 5.001M processed tokens, but this comment isolates the timeout-only subset because those 50 re-entries occurred without a terminal agent event.
The analysis used each changed cumulative token snapshot once and excluded copied child-history prefixes. The sample therefore does not count fork replay as fresh model activity.
This confirms that the timer-driven re-entry mechanism remains present in 0.149.0. Increasing the timeout reduces poll frequency, but it does not fix the lifecycle: every expired wait still returns unchanged state to the model and reprocesses a large cached context.
The runtime should keep the parent suspended and re-arm waits internally. It should wake the model only for agent completion, failure, actionable output, user input, or an explicitly requested checkpoint.
No prompts, task identifiers, repository names, local paths, account data, or credentials are included.
nos1609 commentedon Aug 26, 2026
Fresh sanitized reproduction of model-mediated wait re-entry on the current 0.149.x line.
During one parent turn, the parent delegated work to an existing task and then issued at least 10 consecutive
wait_threadscalls withtimeoutMs=60000. Each timeout returned control to the model, which immediately submitted another 60-second wait. There was no intervening user message and no terminal task event that justified substantive parent work. The sequence consumed roughly 10 minutes, after which the parent also performed manual rollout-status polling.This is a task-level wait API occurrence rather than the nested V1 wrapper path. I am not attaching a token estimate for this sample; the narrow evidence is the repeated timeout -> model re-entry -> identical wait cycle within one parent turn.
Project names, prompts, local paths, hostnames, account data, and task IDs are omitted.
nos1609 commentedon Aug 26, 2026
Fresh narrow reproduction on the current 0.149.x line using Codex Desktop and a local orchestrator waiting on an existing Remote SSH task.
The target's observable task state did not change: repeated
wait_threads(timeoutMs=0)snapshots kept the same revision, reported the aggregate thread asactive, and reported the latest terminal turn ascompletedwith a final response.Despite that unchanged state, within 5 minutes 11 seconds the parent issued five completed
wait_threads(timeoutMs=60000)calls and started a sixth. Over the same interval, six model token snapshots increased the cumulative localtotal_tokenscounter by 725,168.Per re-entry:
There was no intervening user input and no target revision or terminal event. The parent was therefore repeatedly sampled to wait on a target that had no new work to report. The aggregate
activebit appears to have kept the polling loop alive even though the latest terminal turn was already completed.This is local rollout telemetry, not a claim about private billing or subscription accounting. No prompts, task IDs, project or repository names, paths, hostnames, addresses, account data, or credentials are included.
FromAriel commentedon Aug 27, 2026
Cross-linking this implementation-level consumption amplifier to #41220, the meta tracker for abnormal Codex usage/quota depletion and usage-accounting inconsistencies. Your corrected telemetry showing 19.8% of raw local token volume in wait/status-only turns is especially useful because it demonstrates one mechanism that can reduce effective usable subscription capacity even if the quota arithmetic itself is correct. The tracker explicitly distinguishes this class from entitlement/metering defects.
Oreho-git commentedon Aug 28, 2026
Addendum: Codex CLI 0.150.1 — 8m24.481s avoidable coordinator loop after an explicit no-duplicate instruction
Environment:
This is a sanitized, narrow reproduction from one rollout. No prompts, repository names, task IDs, local paths, account identifiers, or credentials are included.
Timeline
All timestamps below are UTC from the rollout JSONL:
16:54:34.327— the user explicitly warned that the coordinator was duplicating a completed validation pass.16:54:51.698— the coordinator sent a general instruction not to repeat the full suite, but left the delegated review scope broad instead of limiting it to the two recently changed boundaries.17:02:58.808— only after further user intervention did the coordinator send the exact bounded instruction: check only the two changed boundaries and stop.17:03:23.196— the worker returnedworker_done, 24.388 seconds after the exact bounded instruction.The avoidable interval from the first explicit warning to the corrective bounded instruction was exactly 504.481 seconds (8m24.481s).
Model-mediated activity in that interval
The rollout contains 34 model-issued tool calls:
write_stdinwait continuationsThus 28 of 34 calls were wait/status activity while the coordinator already had enough information to narrow the review.
Cumulative local rollout telemetry from the last snapshot before the warning (
16:54:34.268) to the first snapshot after the corrective instruction (17:02:59.577) increased by:Cached input was 99.47% of input in this interval. These are local diagnostic counters, not a claim about the private subscription billing ledger.
Why this is a useful variant of the existing issue
This was not only a quiet child wait. It combined model-mediated polling with a scope-control failure: after the user said validation was being duplicated, the coordinator acknowledged the instruction but continued monitoring a broader delegated audit for more than eight minutes. When the same coordinator finally issued the exact two-boundary stop condition, the worker completed in 24.388 seconds.
Expected behavior
tagorr commentedon Sep 8, 2026
I can reproduce the same
wait_agentpolling behavior in Codex TUI/CLI, not Desktop, with a different parent/worker model setup.I also submitted
/feedbackfrom the affected session with logs and diagnostics attached.Uploaded parent thread ID:
01a079cd-a44b-7ef2-8afb-45a3c5659a79Environment
lowxhighReproduction
The parent delegated one bounded implementation task to a Luna worker and then waited for completion.
During this single parent turn, Astra made 69 tool calls, including:
47 × wait_agent9 × exec7 × send_message2 × spawn_agent2 × interrupt_agentAll 47/47
wait_agentcalls used:and all 47/47 returned only a timeout:
So the parent repeatedly re-entered the model approximately every 30 seconds while the workers were still active.
47 × 30 seconds = 23m 30s of timeout waits during a parent task lasting about 33 minutes.
Parent polling cost
The 47 timeout-only
wait_agentturns accounted for:Average per empty poll: ~151.7k input tokens.
The full Astra parent turn used:
So timeout-only polling represented about 68% of the parent turn's raw input-token volume.
The session guidance itself included:
but the parent still used 30-second waits repeatedly.
Workers were actively doing work
This was not a case of idle or dead workers.
Worker 1 used about 14.05M input tokens and was interrupted twice. After the second interruption, the parent discovered that it had already produced a partial patch of:
A replacement Luna worker then continued the task and used about 5.46M input tokens before the overall account limit was reached.
Combined, the two Luna workers used:
The implementation did not reach its build/validation stage before exhaustion.
Server-reported usage during the same interval
Rate-limit telemetry in the parent rollout shows:
So over 33m 06s, server-reported usage changed by:
The 5h metric therefore increased by the full remaining 47 percentage points before reaching the 100% cap and terminating the run.
There was no concurrent Codex activity on the account during this interval.
Measured Luna Max baseline
I also checked a real Luna Max workload from the same Plus account earlier the same day, rather than relying only on subjective previous experience.
Over one continuous 127-minute interval, all 12/12 recorded turn contexts used
gpt-5.6-lunaatmaxreasoning.During that interval, Luna processed:
Server-reported account usage over the same interval changed from:
So this was not an idle session: Luna Max processed about 9.54M input tokens of actual work while the 5h allowance increased by only 8 percentage points.
What this implies for the two Luna workers
The two Luna X-High workers in the affected Astra run processed 19.51M input tokens combined, or about 2.05× the raw input processed by the measured Luna Max control.
Even using a deliberately generous worker-side estimate and scaling the measured Luna Max allowance consumption linearly by raw input volume:
the two Luna workers would account for roughly 16.4 of the observed +47 percentage points.
That leaves roughly 30.6 percentage points — about 65% of the observed 5h increase — unexplained by the Luna workers under this conservative scaling.
The only remaining Codex workload in this orchestration tree was the Astra parent, which processed 10.46M input tokens, including 7.13M input tokens spent solely on the 47 timeout-only
wait_agentpolls.The rollout does not expose an exact per-model breakdown of the server-side allowance charge, so this calculation is not intended as an exact billing attribution. But the measured Luna baseline makes it difficult to explain most of the +47 percentage-point increase as normal Luna worker consumption alone.
What the rollout establishes directly is that 7.13M parent input tokens were spent solely on 47 timeout-only polls that returned no new result, during a run in which the account's 5h allowance went from 53% to the 100% cap in about 33 minutes.
Expected behavior
A long-running subagent should not require the expensive parent model to re-enter inference every ~30 seconds just to discover that nothing has changed.
Ideally
wait_agentshould block/event-wait until:without repeatedly reprocessing the full parent context.
PracticalSwan commentedon Sep 9, 2026
Current-version Windows reproduction from a privacy-safe local rollout audit:
26.903.8094.0codex-cli 0.153.4The turn issued 72 model-mediated
write_stdinpolls while those operations were still running: 18 for one download, 39 for the first training process, and 15 for the second training process. Associating each poll call with its immediately following per-responsetoken_usage_recordgives:The same root turn's final cumulative local usage record was 19,580,416 tokens, so these polling responses account for about 55.2% of that turn's raw local token volume. Most polls requested a 30-second
write_stdinwait and re-entered with roughly 132k–148k input tokens, overwhelmingly cached.Immediately before the terminal error, the rollout's rate-limit snapshot showed the 300-minute primary window at
used_percent=100.0; the turn then ended withusage_limit_exceeded. This is local rollout telemetry, not a claim about the private billing ledger or an exact attribution of subscription usage to tokens. It does show the same unnecessary full-context re-entry pattern still reproduces on 0.153.4/Windows.No prompt text, project/repository name, thread ID, local path, account identifier, or credential is included here.
MatiasSF9 commentedon Sep 13, 2026
I have another concrete reproduction of this behavior, this time with GPT-6 Astra, including local rollout token telemetry and Codex rate-limit telemetry.
This was a real repository/process-engineering task using Astra High with a few independent reviewer subagents. The root Astra thread contained only 3 user turns, but produced 105 model sampling requests.
Root-thread totals:
The coordination overhead was particularly notable:
wait_agentcallswait_agentcycles alone corresponded to approximately 3.47M input tokenslist_agents/ related status coordination brings the share to roughly 24%During the run, the parent context grew beyond ~200k input tokens per sampling request. As a result, each otherwise-small coordination decision could re-enter Astra against a very large cached prefix.
The Codex rate-limit telemetry from the same rollout also shows nearly one complete 5-hour usage window being consumed, followed by a reset and nearly another complete 5-hour window during the same task.
I am not claiming that raw local tokens map 1:1 to subscription quota. The interesting observation is the mechanism: a substantial fraction of the model-visible work was spent re-entering the parent model to coordinate or wait for child agents rather than performing new semantic work.
This seems consistent with this issue's main finding, but demonstrates it on GPT-6 Astra and on a much smaller, ordinary engineering workflow rather than a 10+ hour stress case.
The current Codex source already tells the model to "prefer longer waits (minutes) to avoid busy polling." That helps with cadence, but it does not eliminate the underlying amplification: a timeout/no-change result can still cause another model sampling request over the accumulated parent context.
The stronger fix still appears to be architectural:
Related Astra quota report: #42987.
I can provide a redacted per-sampling/tool breakdown from the rollout if useful.
mlk1278 commentedon Sep 15, 2026
This is a severe issue in the harness and is destroying my limits. Genuinely can't believe they haven't fixed this yet.
tagorr commentedon Sep 15, 2026
Yeah, I agree. This is a persistent and pretty severe harness issue, and it’s surprising that it has survived across so many Codex versions.
For now, I found a temporary workaround that has been working in my testing:
This forces
wait_agentto use a 25-minute timeout instead of falling into the 30-second polling loop. It still wakes early when the worker produces activity or completes, so it does not actually delay completion by 25 minutes.It’s only a mitigation, not a real fix, but in my telemetry it eliminated the repeated 30-second parent-model re-entry pattern.
mlk1278 commentedon Sep 16, 2026
I have this applied as well. It fixed that issue but there's something else funky going on (or it didn't work). Astra is also just a seemingly insanely greedy model. I just tweeted at Tibo... My last run was a 332:1 input:output token ratio.
cintaccs commentedon Sep 17, 2026
Additional macOS Desktop evidence and a request for supported guidance: explicit project instructions already prohibited model polling and delegated build/test waiting to a non-AI release supervisor, yet we found repeated model-driven sleep/status checks and a separate 20-minute AI heartbeat still active after the supervisor had written terminal failure receipts. Quiet-on-unchanged instructions suppress messages, but do not prevent model invocations.
We are replacing the redundant heartbeat with a bounded local terminal-file observer and one
codex queue --thread ... --message ...handoff (CLI 0.155.0-alpha.2.6). What is the supported Desktop mechanism for durable, event-driven task wakeup with no model calls while waiting, including restart recovery and delivery acknowledgement? Is there a recommended way to enforce this across parent/subagent tasks rather than relying only on instructions?Related visibility issue: child tasks can be read, renamed and moved with app tools, but did not appear in the sidebar section listing; completed same-directory forks did appear. Is there a supported persistent role/agent view that exposes the actual workers without creating additional active tasks? No private logs or account data included.
renesugar commentedon Oct 2, 2026
Additional reproducible subscription-quota evidence is available in this public waiting-inference analysis, with links to every individual run report and the inspected Codex source revision.
The workload was one deterministic local sleeper lasting 3690 seconds per trial, with no substantive changes before completion. On Codex host and CLI 0.160.0:
The Codex mitigation did not downgrade the parent or use a cheaper monitor. It kept terminal re-arming inside deterministic JavaScript, avoiding a model return at each inner timeout. Separately, OMP 18.4.9 with openai-codex subscription authentication measured 2 pp/1 pp in baseline, versus 0 pp/0 pp at the reported resolution with an idle Astra/low parent and one Luna/low wait monitor (0 parent / 3 worker rounds).
These observations connect unchanged waiting, actual pre-completion model activity, and subscriber quota consumption. No API-price conversion was used. They do not attribute every quota charge to a request: headroom/context differed, Codex included an hourly host-required message, and OMP baseline finalization was delayed about 15m22s. All included targets completed once and no reset crossed an individual trial. Zero reported movement is not zero token use.
The report distinguishes the prompt-policy amplifier from terminal/Code Mode continuation boundaries and recommends completion-driven runtime waiting. Closely related terminal-path evidence belongs in #13733.