From 21e1400e3ca3b498182cc5b4416d8f56acf2548e Mon Sep 17 00:00:00 2001 From: ciregenz Date: Fri, 7 Aug 2026 12:27:38 -0700 Subject: [PATCH] [eric] telemetry: a silent quit carries the same envelope as a hard error, found by reading the sink --- backend/apps/agents/manager/run/empty_finish.py | 14 +++++++++++++- .../tests/test_every_error_carries_an_envelope.py | 10 ++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/backend/apps/agents/manager/run/empty_finish.py b/backend/apps/agents/manager/run/empty_finish.py index 908c2bb7..1a1d0b79 100644 --- a/backend/apps/agents/manager/run/empty_finish.py +++ b/backend/apps/agents/manager/run/empty_finish.py @@ -43,7 +43,19 @@ def maybe_nudge_empty_finish(session: AgentSession, session_id: str) -> bool: logger.warning(f"Agent {session_id}: turn finished with no answer after tool work; one hidden continue nudge") try: from backend.apps.service.client import submit_diagnostic - submit_diagnostic({"kind": "empty_finish_nudge", "session_id": session_id, "model": session.model}) + from backend.apps.agents.core import flight_recorder as p_fr + # A silent quit is the hardest class to diagnose after the fact, so it gets the same envelope + # as a hard error: without breadcrumbs you cannot see what the turn was doing when it gave up. + submit_diagnostic({ + "kind": "empty_finish_nudge", + "session_id": session_id, + "model": session.model, + "tool_calls": p_tool_calls, + "nudge": session.empty_finish_nudges, + "flight": p_fr.build_envelope( + session_id, "empty_finish_nudge", "silent_quit", session.model, "stream", session.empty_finish_nudges, + ), + }) except Exception: pass return True diff --git a/backend/tests/test_every_error_carries_an_envelope.py b/backend/tests/test_every_error_carries_an_envelope.py index 4af5e187..082a7b53 100644 --- a/backend/tests/test_every_error_carries_an_envelope.py +++ b/backend/tests/test_every_error_carries_an_envelope.py @@ -1,3 +1,4 @@ +import inspect """Clause: every surfaced error carries the full flight envelope. `cli_binary_missing` shipped without one and nobody noticed, because the only way to see it is to @@ -40,3 +41,12 @@ def test_the_cli_missing_class_specifically_is_covered(): block = [b for b in p_diagnostic_blocks(src) if '"cli_binary_missing"' in b] assert block, "the cli_binary_missing diagnostic disappeared" assert '"flight"' in block[0] + + +def test_silent_quit_diagnostic_carries_a_full_envelope(): + """A silent quit is the hardest class to diagnose later, so it must not ship envelope-less. + Found live: empty_finish_nudge was the ONE family writing only kind/model/session_id.""" + import backend.apps.agents.manager.run.empty_finish as ef + src = inspect.getsource(ef.maybe_nudge_empty_finish) if hasattr(ef, "maybe_nudge_empty_finish") else inspect.getsource(ef) + assert "build_envelope" in src, "empty_finish_nudge must attach a flight envelope" + assert '"flight"' in src, "the envelope must ride under the standard 'flight' key"