From 4bce6abc7ccdb1beb7682ebcffc4a5fd23b51fdd Mon Sep 17 00:00:00 2001 From: Patrick Buckley Date: Thu, 11 Jun 2026 01:05:39 -0700 Subject: [PATCH] test(console): pin system-turn dedupe wiring on both read paths The live-SSE/history system-turn dedupe (renderedSystemEventIds / _renderedSystemEventIds) was already in place on both panes and merged to main (21af6c4 aligned the persisted row event_id with its SSE event; 09e41d1 added the belt-and-braces Set on the coordinator). The existing pin tests only assert the Set's .has()/.add()/.clear() symbols appear somewhere in the file, so a refactor that keeps the Set but short-circuits the live-handler consultation (guard -> false) re-opens the double-render while the pins stay green. Scope the new assertions to their blocks: the live system_turn case must CONSULT and RECORD against the Set, and the history render path (replayHistory / refetchHistory's system-role branch) must record each replayed row's event_id. Bounded at the next switch case rather than the first break; the dedup-skip path itself breaks before the .add(), so a break-bounded slice would drop the record half. Verified the new slice checks fail on a dedupe-neutered factory (a headless-Chrome harness driving the real createCoordinatorPane confirms that neutering produces two rendered nodes for one event id; intact code renders one, and the no-event-id legacy path still renders both). --- tests/test_app_js.py | 27 +++++++++++++++++++++++++++ tests/test_coordinator_page.py | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 59 insertions(+) diff --git a/tests/test_app_js.py b/tests/test_app_js.py index 3de90b82..8eeb54fc 100644 --- a/tests/test_app_js.py +++ b/tests/test_app_js.py @@ -285,6 +285,33 @@ def test_system_turn_dedups_against_history_by_event_id() -> None: "replayHistory (and the live handler) must record system-turn ids for the dedup set." ) + # Pin the wiring on BOTH read paths, scoped to its method — a refactor that + # keeps the Set but drops the live-handler consultation (or the + # replayHistory-side record) silently re-opens the double-render while the + # file-global checks above still pass. + live_start = body.index('case "system_turn":') + # End at the NEXT switch case, not the first ``break;`` — the dedup-skip + # path breaks before the ``.add(``, so a ``break;``-bounded slice would + # drop the record half and false-fail the ``.add(`` assertion below. + live_end = body.index('\n case "', live_start + 1) + live_block = body[live_start:live_end] + assert re.search(r"_renderedSystemEventIds[\s\S]*?\.\s*has\(", live_block), ( + "the live system_turn handler must CONSULT the dedup set (skip an id " + "already painted from /history), not merely reference the Set elsewhere." + ) + assert re.search(r"_renderedSystemEventIds[\s\S]*?\.\s*add\(", live_block), ( + "the live system_turn handler must RECORD the id it renders so a later " + "/history re-render (clear_ui) doesn't repaint it." + ) + + replay_start = _pane_method_offset(body, "replayHistory") + replay_end = _pane_method_offset(body, "_attachRetryToLastAssistant") + replay_block = body[replay_start:replay_end] + assert re.search(r"_renderedSystemEventIds[\s\S]*?\.\s*add\(", replay_block), ( + "replayHistory must record each replayed system row's event_id so the " + "live system_turn handler can dedup against it." + ) + def test_retry_walk_skips_operator_context_cards() -> None: """Interactive twin of the coord retry-skip guard. diff --git a/tests/test_coordinator_page.py b/tests/test_coordinator_page.py index 74511b20..9a8729bd 100644 --- a/tests/test_coordinator_page.py +++ b/tests/test_coordinator_page.py @@ -401,6 +401,38 @@ def test_coord_dedups_system_turn_against_history_by_event_id(): "false-skip after clear_ui / replay_truncated." ) + # The seam must be wired on BOTH read paths, not merely present somewhere + # in the file — a refactor that keeps the Set but drops the live-handler + # consultation (or the history-side record) silently re-opens the + # double-render. Scope each assertion to its block so the wiring, not the + # bare symbol, is pinned. (A dedupe-neutered factory — guard short-circuited + # to ``false`` — still contains ``renderedSystemEventIds.has(`` and so + # passes the file-global checks above; these slice checks catch it.) + sys_case = body.index('case "system_turn":') + # End at the NEXT switch case, not the first ``break;`` — the dedup-skip + # ``...has(sysEid)) break;`` is itself a break that precedes the ``.add(``, + # so a ``break;``-bounded slice would drop the record half. + sys_case_end = body.index('\n case "', sys_case + 1) + live_block = body[sys_case:sys_case_end] + assert "renderedSystemEventIds.has(" in live_block, ( + "the live system_turn handler must CONSULT the dedup set (skip an id " + "already painted from /history) — not just reference the Set elsewhere." + ) + assert "renderedSystemEventIds.add(" in live_block, ( + "the live system_turn handler must RECORD the id it renders so a later " + "/history re-render (clear_ui) doesn't repaint it." + ) + + # The history render path must seed the set from each replayed system row's + # event_id, so a subsequent live replay of the same id is skipped. + assert 'role === "system"' in body + sys_replay = body.index('role === "system"', body.index("refetchHistory")) + replay_window = body[sys_replay : sys_replay + 600] + assert "renderedSystemEventIds.add(" in replay_window, ( + "the history render's system-role branch must record each replayed " + "turn's event_id so the live system_turn handler can dedup against it." + ) + def test_coord_retry_walk_skips_operator_context_cards(): """Retry must NOT regenerate a stale assistant turn when the last DOM row is