From 39d8da2697428501b2157a327ea752fa96325fe5 Mon Sep 17 00:00:00 2001 From: ciregenz Date: Wed, 19 Aug 2026 11:41:02 -0700 Subject: [PATCH] [eric] agents: a vanishing quit (nothing persisted) on a session that already silent-quit is claimed and compacted; the poke-storm hole the one-for-one repro exposed (ENG-354) --- backend/apps/agents/manager/run/empty_finish.py | 6 +++++- backend/tests/test_empty_finish.py | 13 +++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/backend/apps/agents/manager/run/empty_finish.py b/backend/apps/agents/manager/run/empty_finish.py index fc79cbf6..521fb672 100644 --- a/backend/apps/agents/manager/run/empty_finish.py +++ b/backend/apps/agents/manager/run/empty_finish.py @@ -157,7 +157,11 @@ def turn_finished_empty(session: AgentSession) -> bool: p_last_call_name = p_tool_name_of(m) return not any(marker in p_last_call_name for marker in P_ANSWER_TOOL_MARKERS) if role in ("user", "system"): - return False + # A user-message tail normally means a bare prompt (never claimed). But when the model + # QUIT so hard it persisted nothing at all, and this session has already silent-quit + # before, that vanishing act IS the quit repeating (Haik's poke storms: "continue" -> + # instant thinking-only end_turn -> nothing persisted -> detector shrugged). + return role == "user" and getattr(session, "empty_finish_total", 0) >= 1 return False diff --git a/backend/tests/test_empty_finish.py b/backend/tests/test_empty_finish.py index 4339ddcd..aa90bf9d 100644 --- a/backend/tests/test_empty_finish.py +++ b/backend/tests/test_empty_finish.py @@ -202,3 +202,16 @@ def test_drill_seam_disables_compaction(monkeypatch): s.tokens["input"] = 190_000 assert maybe_nudge_empty_finish(s, "sid-seam") is True assert s.compacted_through_msg_id is None + + +def test_vanishing_quit_on_repeat_session_is_claimed(): + """Haik's poke storm: 'continue' -> instant thinking-only quit -> NOTHING persisted. A session + that already silent-quit must claim that vanishing act; a truly bare first prompt stays unclaimed.""" + from backend.apps.agents.manager.run.empty_finish import turn_finished_empty + s = p_session(("user", "task"), + ("tool_call", {"tool": "Read", "input": {}}), + ("tool_result", {"text": "x"}), + ("user", "you stopped. continue.")) + assert turn_finished_empty(s) is False, "first-time session: user tail stays unclaimed" + s.empty_finish_total = 1 + assert turn_finished_empty(s) is True, "repeat session: the vanishing quit is claimed"