Repository navigation
Parked completion notifications replay one turn each; agent_read re-sends turns the caller already holds (planner s966: 13 replays / 9.9M cache-read tokens) #205
Description
Source: analysis of excore planner session s966 (claude, 2026-09-07 15:26 → 2026-09-08 04:23, daemon 0.11.0 build 0214057) and its 19 children; cross-reviewed with excore/s991 (codex). Measured from the vendor transcript (per-call usage), progress.jsonl and chat/<sid>/turns.jsonl. Complements #204 (native token accounting), which is a prerequisite for re-measuring anything below.
Defect 1 — parked completion notifications replay one turn each
docs/orchestration.md promises a completion is delivered "as its own turn, even if you were mid-turn". When the parent's turn is long, every notification that arrives is parked in deferred-input.json and, after the turn ends, replayed one turn per notification.
Observed on s966 (turn sj-18d3164fbb9ba765-7, 16:20 → 03:59, 11.6 h):
| notifications parked during the turn | 13 |
| replay turns after the boundary (s966-8 … s966-20) | 13 in 2 min 44 s |
| API calls / cache-read tokens spent on the replay | 15 calls / 9.94 M tokens |
| model output per replay turn | ~150 chars, each saying "old receipt, already handled" |
Every replayed line had already been read by the parent via agent_read while the turn was running (delegation_collected precedes delegation_notified for all 13). Nothing was lost or duplicated — the contract held — but the cost is one full-context wake-up per line.
Ask: when the parent reaches a deliverable boundary and N lines are parked, deliver the parked lines as one batch turn. Constraints (agreed with s991):
- no waiting window to accumulate a batch — batch only what is already queued at the boundary;
- each item keeps its own
request_id, answering turn, outcome andagent_read{turn:…}reference; the header line format per item is unchanged; - per-request delivery state stays independent (
delegation_notifiedper request); crash mid-batch replays and is recognisable as a repeat, one item's failure never drops the others; - a batch over the read budget is split deterministically and the batch says how many are still undelivered;
- no semantic rewriting of any line; a line that was already
collectedis not dropped (collected may come from a truncated excerpt and is not a consumption ack).
Where: claude_stream_json/mod.rs advance_deferred_queue / the Outbound::TurnResult arm (pop-all instead of pop-front), plus the parked-line mirror and orchestration.md ("nothing merged" → "batched at a boundary, never merged").
Defect 2 — agent_read re-sends turns the caller already holds
The planner read its children 61 times; 35 answers were partial:true (in-flight peek, feature G working as designed). But with n:1 on a working child the answer is last completed turn + in_flight, so the same finished turn is re-sent on every peek: s980-1 was collected 6 times (2–3 k chars each), s978-5 twice, s972-1 five times. Roughly 111 k chars of agent_read results landed in the planner context; about 40 % of it is repeats.
Ask (explicit, not implicit):
- an overall response budget for
agent_readcoveringturns+requests+in_flighttogether (todaymax_charsbounds turns only); - document and prefer
since:<cursor>for repeated reads;turn:<id>is for exact location and does not by itself avoid repeats; - history of terminated requests readable on demand rather than always attached;
- not an implicit "collected ⇒ never returned again" rule (see Defect 1 constraint).
Not asked for (decided against for now, with data)
notify:"steer"into an in-flight parent turn, oragent_read{wait}beyond 240 s: the 10.3 h / 97 full-context calls / 42.6 M cache-read tokens the planner spent insleeppolling loops were a role-discipline failure (its own role file says to end the turn and be woken by the notification). Fix is in user space; revisit only if a batch of cards run under the corrected roles still shows a quantifiable routing obstacle.- "authorised result receiver" (checker files a fix request, result routed to planner): deferred; the
task_fileforward path covers the bulk of the saving today. - cache keep-warm scheduling: deferred until measured with native accounting (Codex cumulative token accounting records only the final request (s968: 122,628 vs native 2,864,448) #204).
Acceptance
- Unit: 13 lines parked behind one turn are delivered as one batch turn at the boundary; each item's
request_id/ turn / outcome preserved;delegation_notifiedemitted per request. - Crash between "batch written" and "mirror cleared" → next life replays the batch and marks it a repeat; no item lost.
- Budget overflow splits the batch deterministically; the trailer says how many remain.
agent_read{sid, since:<cursor>}on a working child returns only unread turns +in_flight;n:1behaviour unchanged (documented as the "latest, may repeat" read).- Re-run the same planner workload after Codex cumulative token accounting records only the final request (s968: 122,628 vs native 2,864,448) #204 and report per-card context delta, calls per card, replay turns per boundary with native numbers.
Baseline numbers (s966 vs pre-optimisation planner s869, same excore track): context per hire 35.8 k vs 35.2 k tokens; calls/hour 59 vs 32; agent tool input 15.8 k vs 81.6 k chars (task_file working); notification duplicates 0 vs n/a.
Activity
fix(a2a): batch parked completion notifications at turn boundaries (#205
fix(a2a): preserve queued task routing across cold recovery (#205)
fix(mcp): bound agent reads and make incremental cursors explicit (#205)
test(a2a): align queue fixtures with the canonical turn lifecycle (#205)
fix(mcp): keep failed turns readable under shared budgets (#205)
fix(a2a): preserve unreadable queued input and use explicit error ide…
release: v0.11.1 — delegation delivery closes the loop, codex identit…
firstintent commentedon Sep 11, 2026
Resolved in v0.11.1 (tag
v0.11.1, merge commit1146cce9), landed via #197's delegation-delivery rework:62cfe4c8— parked completion notifications batch at turn boundaries instead of replaying one turn each.65cf9aca— queued task routing survives cold recovery.5b6bfa77—agent_readreads are bounded and incremental cursors are explicit.9a195ee6— queue fixtures aligned to the canonical turn lifecycle (regression coverage).22468cc1— failed turns stay readable under shared budgets.fde07e42— unreadable queued input is preserved, with an explicit error identity instead of a guess.Verified: local gate
test-baseline2393/0, fulltest3111/0, CI green on PR #207 and main.