diff --git a/conductor/tracks/result_migration_gui_2_20260619/state.toml b/conductor/tracks/result_migration_gui_2_20260619/state.toml index 4a358ffb..24fee8ef 100644 --- a/conductor/tracks/result_migration_gui_2_20260619/state.toml +++ b/conductor/tracks/result_migration_gui_2_20260619/state.toml @@ -24,7 +24,7 @@ phase_2 = { status = "completed", checkpointsha = "5b139e6", name = "Drain plane phase_3 = { status = "completed", checkpointsha = "e622f1e", name = "INTERNAL_BROAD_CATCH Batch A — render-loop sites (<=10 sites)" } phase_4 = { status = "pending", checkpointsha = "", name = "INTERNAL_BROAD_CATCH Batch B — modal/dialog sites (<=10 sites)" } phase_5 = { status = "pending", checkpointsha = "", name = "INTERNAL_BROAD_CATCH Batch C — event handler sites (<=10 sites)" } -phase_6 = { status = "pending", checkpointsha = "", name = "Signal handler sites (<=5 sites; Pattern 3 drain)" } +phase_6 = { status = "completed", checkpointsha = "", name = "Signal handler sites (<=5 sites; Pattern 3 drain) — 0 sites in this track" } phase_7 = { status = "pending", checkpointsha = "", name = "Worker / background sites (<=5 sites; thread-safety)" } phase_8 = { status = "pending", checkpointsha = "", name = "Property setter / state sites (<=5 sites)" } phase_9 = { status = "pending", checkpointsha = "", name = "Helper / utility sites (<=5 sites)" } diff --git a/tests/test_gui_2_result.py b/tests/test_gui_2_result.py index 4423e8ee..425e9e38 100644 --- a/tests/test_gui_2_result.py +++ b/tests/test_gui_2_result.py @@ -1330,3 +1330,71 @@ def test_phase_5_invariant_all_11_migration_sites_have_tests(): f"Phase 5 invariant: missing failure test for L{line}. " f"Expected a test matching '{failure_pattern}'." ) + + +# ============================================================================= +# Phase 6 Tests - Signal handler sites +# Per PHASE1_SITE_INVENTORY.md, Phase 6 covers signal-handler category +# sites. The audit shows 0 INTERNAL_BROAD_CATCH sites in this category +# in src/gui_2.py (the inventory classifies signal-handler try/except +# under other categories — Phase 6 has no sites in this track). +# The two invariant tests below document this and pin the count. +# ============================================================================= + + +def test_phase_6_invariant_signal_handler_count_dropped(): + """ + Phase 6 invariant: the audit's INTERNAL_BROAD_CATCH count for src/gui_2.py + remains at 3 (no sites migrated in Phase 6, since the signal-handler + category has 0 INTERNAL_BROAD_CATCH sites in this track). + + Per PHASE1_SITE_INVENTORY.md, all sites that might appear in a + signal-handler category were classified into other phases (Phase 8 for + startup callbacks, Phase 7 for worker/background). Phase 6 has no + sites to migrate in this track. + + Pre-Phase 6 baseline: 3 (L591 _diag_layout_state, L897 _capture_workspace_profile, + L4321 worker). Post-Phase 6 baseline: 3 (unchanged; Phase 6 has 0 sites). + """ + result = subprocess.run( + ["uv", "run", "python", "scripts/audit_exception_handling.py", "--src", "src", "--json"], + capture_output=True, + text=True, + ) + assert result.returncode == 0, ( + f"audit_exception_handling.py exited {result.returncode}; stderr:\n" + f"{result.stderr[:2000]}" + ) + data = json.loads(result.stdout) + gui2 = [f for f in data.get("files", []) if "gui_2" in f.get("filename", "")][0] + broad_catches = [f for f in gui2.get("findings", []) if f.get("category") == "INTERNAL_BROAD_CATCH"] + # Phase 6 baseline is 3 (no migration occurred since Phase 5 ended). + # This test pins the count to 3 before Phases 7, 8, 9 each migrate sites. + assert len(broad_catches) == 3, ( + f"Phase 6 invariant: expected exactly 3 INTERNAL_BROAD_CATCH sites in " + f"src/gui_2.py (Phase 6 has 0 sites to migrate; pre-Phase-7 baseline); " + f"found {len(broad_catches)}. Lines: {[f.get('line') for f in broad_catches]}" + ) + + +def test_phase_6_invariant_zero_sites_in_phase_6(): + """ + Phase 6 invariant: documents that Phase 6 (signal-handler sites) has + 0 sites to migrate. The next test (`test_phase_7_invariant_batch_d_count_dropped`) + will pin the count after Phase 7 migrates the L4321 worker site. + + This test exists to make the "Phase 6 is empty" decision explicit and + machine-checkable: a future agent who tries to add a Phase 6 site + will see this test fail at the count assertion. + """ + import re + text = Path(__file__).read_text(encoding="utf-8") + # Expected: zero tests matching the Phase 6 site pattern + phase_6_site_tests = re.findall(r"test_phase_6_l\d+_.*_result_(success|failure)", text) + assert len(phase_6_site_tests) == 0, ( + f"Phase 6 invariant: expected 0 Phase 6 site tests (signal-handler " + f"category has 0 INTERNAL_BROAD_CATCH sites in src/gui_2.py per the " + f"PHASE1_SITE_INVENTORY); found {len(phase_6_site_tests)}. Tests: " + f"{phase_6_site_tests}. If a Phase 6 site was added, update the " + f"inventory and migrate it." + )