Private
Public Access
0
0

fix(rag): stop live_gui tests from polluting session-scoped subprocess

Per Tier 1 investigation
(docs/reports/INVESTIGATION_rag_phase4_final_verify_20260627.md),
two live_gui tests were leaking temp/relative paths into the shared
subprocess's ui_files_base_dir, which survived across @clean_baseline
tests and caused RAGEngine.index_file to silently no-op on a dead
base_dir.

Three fixes:

1. tests/test_rag_visual_sim.py: stop using tempfile.mkdtemp() (which
   defaults to C:\Users\Ed\AppData\Local\Temp\tmpXXXX) and instead use
   tempfile.mkdtemp(dir="tests/artifacts", ...). Also restore
   files_base_dir and rag_enabled in finally so the next live_gui test
   in the session doesn't inherit the dead path.

2. tests/test_visual_sim_mma_v2.py: stop changing files_base_dir to
   'tests/artifacts/temp_workspace' and stop clicking btn_project_save
   (which persisted the path to manual_slop.toml). The MMA lifecycle
   does not depend on a specific files_base_dir.

3. src/app_controller.py _handle_reset_session: defensive fix that
   resets ui_files_base_dir from the default project's base_dir. This
   makes reset_session() robust to any future polluter (not just the
   two known ones). Without this, a test that sets files_base_dir via
   set_value leaves a dead path in the session-scoped subprocess even
   after reset_session().

Verified: tests/test_rag_visual_sim.py passes 2/2 after the fix.
This commit is contained in:
2026-06-27 22:39:19 -04:00
parent 08264e550a
commit ab16f2f278
3 changed files with 53 additions and 20 deletions
+8
View File
@@ -3893,6 +3893,14 @@ class AppController:
self.ui_ai_input = ""
self.ui_manual_approve = False
self.ui_auto_add_history = False
# Reset ui_files_base_dir to a sane default so a prior live_gui test
# that set a temp/relative path via set_value('files_base_dir', ...)
# does not pollute the session-scoped subprocess with a dead path.
# See tests/test_rag_visual_sim.py and tests/test_visual_sim_mma_v2.py
# for the original polluters. Per Tier 1 investigation:
# docs/reports/INVESTIGATION_rag_phase4_final_verify_20260627.md
self.ui_files_base_dir = self.project.get("files", {}).get("base_dir", ".")
self.ui_shots_base_dir = self.project.get("screenshots", {}).get("base_dir", ".")
self.active_track = None
self.active_tier = None
self.mma_status = 'idle'
+37 -17
View File
@@ -15,26 +15,33 @@ from src import api_hook_client
def test_rag_full_lifecycle_sim(live_gui):
client = api_hook_client.ApiHookClient()
assert client.wait_for_server(timeout=15), "Hook server did not start"
# 1. Setup mock project data
test_dir = tempfile.mkdtemp()
# Per Tier 1 investigation (docs/reports/INVESTIGATION_rag_phase4_final_verify_20260627.md):
# Use a temp dir under tests/artifacts/ (NOT tempfile.mkdtemp() which defaults
# to C:\Users\Ed\AppData\Local\Temp\tmpXXXX and pollutes the session-scoped
# subprocess's ui_files_base_dir with a dead path that persists across
# live_gui tests). Also restore files_base_dir and rag_enabled in finally
# to prevent state leakage into subsequent live_gui tests.
test_dir = tempfile.mkdtemp(dir="tests/artifacts", prefix="rag_visual_sim_")
previous_files_base_dir = client.get_value('files_base_dir')
try:
(Path(test_dir) / "test_file.txt").write_text("This is a test file about RAG integration. It should be indexed.")
(Path(test_dir) / "other_file.py").write_text("# This is another file\ndef hello():\n print('world')")
# 2. Configure project through Hook API
client.set_value('files_base_dir', test_dir)
client.set_value('files_base_dir', str(Path(test_dir).resolve()))
client.set_value('rag_enabled', True)
client.set_value('rag_source', 'mock') # Use mock to avoid sentence-transformers dependency in CI
# 3. Verify initial status
status = client.get_value('rag_status')
assert status in ['idle', 'ready', 'initializing...'], f"Unexpected initial status: {status}"
# 4. Trigger Rebuild Index
print("[SIM] Triggering index rebuild...")
client.click('btn_rebuild_rag_index')
# 5. Wait for status transition
# Wait for 'indexing...'
found_indexing = False
@@ -44,9 +51,9 @@ def test_rag_full_lifecycle_sim(live_gui):
found_indexing = True
break
time.sleep(0.1)
print(f"[SIM] Found indexing: {found_indexing}")
# Wait for 'ready'
success = False
for _ in range(50):
@@ -57,35 +64,48 @@ def test_rag_full_lifecycle_sim(live_gui):
if "error" in status.lower():
pytest.fail(f"RAG indexing failed: {status}")
time.sleep(0.2)
assert success, f"RAG indexing timed out. Final status: {status}"
print("[SIM] RAG indexing SUCCESS.")
# 6. Verify retrieval visualization
# We simulate a response that has RAG context prepended
# Since we are testing GUI visualization, we'll manually inject a message into the discussion
# that contains the RAG marker, then verify the GUI state if possible.
# However, verifying ImGui internal render state via Hook API is limited to exposed fields.
# We've already verified the wiring of settings and status.
# One final check: toggle RAG off and verify
client.set_value('rag_enabled', False)
assert client.get_value('rag_enabled') is False
finally:
shutil.rmtree(test_dir)
# Restore state to prevent pollution of session-scoped subprocess.
# ui_files_base_dir and rag_enabled are sticky; without restoration,
# the next live_gui test (e.g. test_rag_phase4_final_verify) inherits
# the dead temp path and its RAG search silently no-ops on missing files.
try:
client.set_value('rag_enabled', False)
except Exception:
pass
if previous_files_base_dir is not None:
try:
client.set_value('files_base_dir', previous_files_base_dir)
except Exception:
pass
shutil.rmtree(test_dir, ignore_errors=True)
@pytest.mark.integration
def test_rag_settings_persistence_sim(live_gui):
client = api_hook_client.ApiHookClient()
assert client.wait_for_server(timeout=15)
# Change settings
client.set_value('rag_chunk_size', 1234)
client.set_value('rag_chunk_overlap', 56)
# Verify they were set in the controller
assert client.get_value('rag_chunk_size') == 1234
assert client.get_value('rag_chunk_overlap') == 56
print("[SIM] RAG settings persistence simulation PASSED.")
+8 -3
View File
@@ -71,10 +71,15 @@ def test_mma_complete_lifecycle(live_gui) -> None:
time.sleep(0.3)
client.set_value('gcli_path', f'"{sys.executable}" "{os.path.abspath("tests/mock_gemini_cli.py")}"')
time.sleep(0.3)
client.set_value('files_base_dir', 'tests/artifacts/temp_workspace')
# Per Tier 1 investigation: do NOT change files_base_dir here and do NOT
# click btn_project_save. The previous version set files_base_dir to
# 'tests/artifacts/temp_workspace' and persisted it via btn_project_save,
# which polluted the session-scoped subprocess's ui_files_base_dir (and
# the workspace's manual_slop.toml) with a test-only path that persisted
# into subsequent live_gui tests (e.g. test_rag_phase4_final_verify).
# The MMA lifecycle does not depend on a specific files_base_dir — the
# mock_gemini_cli returns canned responses regardless.
time.sleep(0.3)
client.click('btn_project_save')
time.sleep(1.0) # one full second — let GUI process all set_value tasks
# ------------------------------------------------------------------
# Stage 2: Start epic planning