The decisive eventIf no later
todo/write exists, turn/end intentionally preserves the last list—including in_progress.Four facts. Four owners.
assistant/messageWhat was saidProse is not task state.todo/writeWhat was recordedWhole-list replacement.turn/endWhy the loop stoppedProtocol outcome, not proof.todos projectionWhat the dock rendersLatest snapshot, last wins.Trace the actual lifetime.
todo_writeLast item remains active.todo/writeFull snapshot appended.turn/start clears it.Route the mismatch.
snapshot activemodel omitted reconciliationImprove discipline or add one bounded stop reminder.snapshot completedock still activeInspect projection asOfSeq and event delivery.call failedno snapshot eventFix the tool error; arguments are not committed state.old row activedock is completeThe row describes a historical call, not current state.Reconcile truth, not color.
Start a new turn, verify real outputs, then write a fresh complete list.
No in_progress only after every item has evidence.
Use agent/turn-stopping plus logged steering, bounded to one continuation.
Regression gates.
- Completed final writeSurvives turn end.
- Missing final writeRemains visible.
- Next turnClears prior projection.
- Failed callWrites no snapshot.
- Stop guardAt most one retry.
- ReplaySame list and sequence.
Primary evidence.
- Todo tool and projection implementation
- Projection lifetime regression test
- Agent stop lifecycle
- Upstream report #3424
Keep the complete event router.
The canonical guide covers both Web surfaces, safe recovery, a bounded stop-guard design, all turn-ending reasons, and ten regression gates.
Read the full runbook