Some checks failed
Release & Docker / release (push) Has been cancelled
## Release v0.51.261 — Release IC (stage-r11) Live Todos panel via an explicit `todo_state` SSE contract. ### Fixed | Issue/PR | Author | Fix | |----------|--------|-----| | #3373 follow-up (#3454) | @v2psv | The Todos side panel now tracks `todo` tool state **live during an active run** instead of staying stale until settle / rolling back on a mid-stream reload. A dedicated `todo_state` SSE event sends a full, redacted, idempotent snapshot on todo-tool completion (no more truncated `tool_complete.preview`); the same `api.todo_state` parser feeds live + cold-load; live snapshots persist into INFLIGHT so reload/reattach restores the panel; cold-load vs INFLIGHT reconciled by timestamp (incl. the `coldTs===0` compressed-session edge); legacy reverse-scan kept as fallback for old servers. | ### Gate - Full pytest suite: **7692 passed, 0 failed** - ESLint: CLEAN · ruff: CLEAN · browser-smoke: CLEAN - Codex (regression): **SAFE TO SHIP** — verified the new `todo_state` SSE handler composes with existing dispatch (no double-subscribe), INFLIGHT persistence is cleared on terminal/cancel (composes with discard_session + turn-journal), timestamp reconciliation can't let a stale local snapshot win, redaction holds, the legacy reverse-scan fallback still works with no double-render, and the `models.py` change is todo-scoped (no CLI-classification interaction). Co-authored-by: v2psv <v2psv@users.noreply.github.com>
37 lines
1.5 KiB
Python
37 lines
1.5 KiB
Python
from pathlib import Path
|
|
|
|
|
|
REPO_ROOT = Path(__file__).parent.parent
|
|
|
|
|
|
def test_ensure_messages_loaded_hydrates_session_todo_state_sidecar():
|
|
src = (REPO_ROOT / "static" / "sessions.js").read_text(encoding="utf-8")
|
|
|
|
assert "if(data.session.todo_state !== undefined)" in src
|
|
assert "S.session.todo_state = data.session.todo_state" in src
|
|
assert "delete S.session.todo_state" in src
|
|
assert "_hydrateTodosFromSession(S.session)" in src
|
|
assert "scheduleTodosRefresh()" in src
|
|
|
|
|
|
def test_load_todos_renders_single_source_of_truth_before_legacy_scan():
|
|
src = (REPO_ROOT / "static" / "panels.js").read_text(encoding="utf-8")
|
|
start = src.find("function loadTodos()")
|
|
end = src.find("function _legacyTodosFromMessages()")
|
|
|
|
assert start != -1
|
|
assert end != -1
|
|
load_todos = src[start:end]
|
|
|
|
assert "if (S.todoStateMeta)" in load_todos
|
|
assert "todos = Array.isArray(S.todos) ? S.todos : [];" in load_todos
|
|
assert "todos = _legacyTodosFromMessages();" in load_todos
|
|
assert load_todos.find("todos = Array.isArray(S.todos) ? S.todos : [];") < load_todos.find("todos = _legacyTodosFromMessages();")
|
|
|
|
|
|
def test_legacy_todos_fallback_still_uses_raw_session_messages():
|
|
src = (REPO_ROOT / "static" / "panels.js").read_text(encoding="utf-8")
|
|
|
|
assert "function _legacyTodosFromMessages()" in src
|
|
assert "const sourceMessages = (S.session && Array.isArray(S.session.messages) && S.session.messages.length) ? S.session.messages : S.messages;" in src
|