From a6bc86e331399f938cfce971d7105b07a94b2ff3 Mon Sep 17 00:00:00 2001 From: Michael <52305679+michaelxer@users.noreply.github.com> Date: Fri, 14 Aug 2026 16:22:27 +0700 Subject: [PATCH] fix(scheduler): treat /api/email/unread-state as passive UI poll (#6009) Background scheduled agent runs were aborted as "Stopped by user" when the web UI was merely open, because the idle /api/email/unread-state poll was counted as foreground activity while its sibling /api/email/urgency-state was already excluded. Fixes #5981 Co-authored-by: michaelxer --- src/interactive_gate.py | 2 ++ tests/test_interactive_gate_passive_paths.py | 19 +++++++++++++++++++ 2 files changed, 21 insertions(+) create mode 100644 tests/test_interactive_gate_passive_paths.py diff --git a/src/interactive_gate.py b/src/interactive_gate.py index c0f5907fc..38c684fa2 100644 --- a/src/interactive_gate.py +++ b/src/interactive_gate.py @@ -65,6 +65,8 @@ _PASSIVE_EXACT_PATHS = { "/api/tasks/notifications", "/api/research/active", "/api/email/urgency-state", + # UI idle poll sibling of urgency-state; must not pre-empt background tasks. + "/api/email/unread-state", } _PASSIVE_PREFIXES = ( diff --git a/tests/test_interactive_gate_passive_paths.py b/tests/test_interactive_gate_passive_paths.py new file mode 100644 index 000000000..e811c839b --- /dev/null +++ b/tests/test_interactive_gate_passive_paths.py @@ -0,0 +1,19 @@ +"""Regression for idle UI polls that must not count as foreground activity.""" + +from src.interactive_gate import should_track_interactive_request + + +def test_email_unread_state_is_passive_like_urgency_state(): + assert should_track_interactive_request("/api/email/urgency-state") is False + assert should_track_interactive_request("/api/email/unread-state") is False + + +def test_real_interactive_paths_still_tracked(): + assert should_track_interactive_request("/api/chat_stream") is True + assert should_track_interactive_request("/api/email/messages") is True + assert should_track_interactive_request("/api/tasks", method="POST") is True + + +def test_options_never_tracked(): + assert should_track_interactive_request("/api/email/unread-state", method="OPTIONS") is False + assert should_track_interactive_request("/api/chat_stream", method="OPTIONS") is False