From fe240db4109ffa5cf4afec8854eaf4ddebc20901 Mon Sep 17 00:00:00 2001 From: Ed_ Date: Tue, 9 Jun 2026 19:44:10 -0400 Subject: [PATCH] fix(reset): clear mma_tier_usage and RAG state in _handle_reset_session --- src/app_controller.py | 10 +++ tests/conftest.py | 5 +- .../test_reset_session_clears_mma_and_rag.py | 79 +++++++++++++++++++ 3 files changed, 92 insertions(+), 2 deletions(-) create mode 100644 tests/test_reset_session_clears_mma_and_rag.py diff --git a/src/app_controller.py b/src/app_controller.py index f955876b..ee58ccc0 100644 --- a/src/app_controller.py +++ b/src/app_controller.py @@ -3378,6 +3378,16 @@ class AppController: self.active_tickets = [] self.engines.clear() self.mma_streams.clear() + # Reset mma_tier_usage to pre-populated default (prior tests pollute it) + self.mma_tier_usage = {'Tier 1': {}, 'Tier 2': {}, 'Tier 3': {}, 'Tier 4': {}} + # Reset RAG engine state so the chroma collection from a prior test + # doesn't leak into the next session. The next _sync_rag_engine will + # rebuild the engine with the new active_project_root. + self.rag_engine = None + self.rag_config = None + self.rag_status = 'idle' + self._rag_sync_token = 0 + self._rag_sync_dirty = False self._worker_status.clear() self._current_provider = "gemini" self._current_model = "gemini-2.5-flash-lite" diff --git a/tests/conftest.py b/tests/conftest.py index 3d5091bb..458a25fa 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -663,8 +663,9 @@ def _reset_clean_baseline(request, live_gui) -> Generator[None, None, None]: if client.wait_for_server(timeout=5): client.reset_session() time.sleep(0.2) - except Exception: - pass + except Exception as e: + import sys + print(f"[CLEAN_BASELINE] reset failed: {type(e).__name__}: {e}", file=sys.stderr) yield diff --git a/tests/test_reset_session_clears_mma_and_rag.py b/tests/test_reset_session_clears_mma_and_rag.py new file mode 100644 index 00000000..ec584a71 --- /dev/null +++ b/tests/test_reset_session_clears_mma_and_rag.py @@ -0,0 +1,79 @@ +"""Regression test: _handle_reset_session must clear MMA + RAG state. + +Added in test_infrastructure_hardening_20260609 followup. Without these +resets, prior test state pollutes the next session via: +- mma_tier_usage: stale per-tier model/input/output values cause the + mma_state_update handler to merge with old data, leaving the new + push's active_tier effectively lost in the GUI render path. +- rag_engine / rag_config: the chroma collection from a prior test + doesn't get rebuilt, causing RAG queries to return nothing. +""" +import time +import pytest + +from src import api_hook_client + + +@pytest.mark.clean_baseline +def test_reset_session_clears_mma_tier_usage(live_gui) -> None: + """reset_session() must restore mma_tier_usage to the default (all empty).""" + client = api_hook_client.ApiHookClient() + assert client.wait_for_server(timeout=15) + # Pollute the mma_tier_usage via a mma_state_update push + client.push_event('mma_state_update', { + 'status': 'running', + 'active_tier': 'Tier 3 (Worker)', + 'tier_usage': {'Tier 1': {'model': 'polluted'}}, + 'tickets': [] + }) + time.sleep(0.5) + # Trigger the reset + client.reset_session() + time.sleep(0.5) + # Verify the polluted entry is gone + state = client.get_gui_state() + mma = state.get('mma_state', {}) + tier1 = mma.get('tier_usage', {}).get('Tier 1', {}) + assert tier1.get('model') != 'polluted', ( + f"reset_session() did not clear mma_tier_usage: {tier1!r}" + ) + + +@pytest.mark.clean_baseline +def test_reset_session_clears_mma_status(live_gui) -> None: + """reset_session() must set mma_status back to 'idle'.""" + client = api_hook_client.ApiHookClient() + assert client.wait_for_server(timeout=15) + client.push_event('mma_state_update', { + 'status': 'running', + 'active_tier': 'Tier 1 (Orchestrator)', + 'tier_usage': {}, + 'tickets': [] + }) + time.sleep(0.5) + client.reset_session() + time.sleep(0.5) + state = client.get_gui_state() + assert state.get('mma_status') == 'idle', ( + f"mma_status not reset: {state.get('mma_status')!r}" + ) + + +@pytest.mark.clean_baseline +def test_reset_session_clears_active_tier(live_gui) -> None: + """reset_session() must set active_tier back to None.""" + client = api_hook_client.ApiHookClient() + assert client.wait_for_server(timeout=15) + client.push_event('mma_state_update', { + 'status': 'running', + 'active_tier': 'Tier 2 (Tech Lead)', + 'tier_usage': {}, + 'tickets': [] + }) + time.sleep(0.5) + client.reset_session() + time.sleep(0.5) + state = client.get_gui_state() + assert state.get('active_tier') is None, ( + f"active_tier not reset: {state.get('active_tier')!r}" + )