From bdd388e877c912f08426ef888e0f1ff9e1f20cf2 Mon Sep 17 00:00:00 2001 From: Ed_ Date: Sat, 20 Jun 2026 19:12:27 -0400 Subject: [PATCH] conductor(plan): flesh out cruft removal plan with per-phase detail The plan was 38 lines (just header + protocol). Now 573 lines with proper per-phase task structure: - The Wrapper-Obliteration Pattern (concrete BEFORE/AFTER code; legacy wrapper DELETED in same commit as caller migration) - Phase 0: Setup + styleguide re-read (3 tasks) - Phase 1: Fix the 7 failing tests (5 tasks; commit missing PHASE1_AUDIT_BASELINE.json + split combined inventory doc) - Phase 2: Final detailed audit (6 tasks; write audit_legacy_wrappers.py script + per-wrapper inventory doc with callers + drain targets) - Phases 3-7: Per-file wrapper removal (one task per wrapper per file; the OBLITERATE pattern: find caller -> rewrite -> delete wrapper) - Phase 8: Audit gate + end-of-track report + campaign close-out (8 tasks; final state: 0 legacy wrappers + 0 audit violations + 47/47 tests + 11/11 tiers PASS) Each phase has: - Styleguide re-read + ack commit (mandatory) - Concrete commands with expected output - Per-file atomic commits (1 wrapper = 1 commit) - Per-phase invariant test + checkpoint The OBLITERATE principle is explicit: no pass-throughs; no backward compat; in-site callers rewritten to use _x_result(...).ok directly. The dead code dies. --- .../plan.md | 794 ++++++++++++++++++ 1 file changed, 794 insertions(+) diff --git a/conductor/tracks/result_migration_cruft_removal_20260620/plan.md b/conductor/tracks/result_migration_cruft_removal_20260620/plan.md index 9aab7e0f..67868314 100644 --- a/conductor/tracks/result_migration_cruft_removal_20260620/plan.md +++ b/conductor/tracks/result_migration_cruft_removal_20260620/plan.md @@ -35,4 +35,798 @@ For every migration: **Files NOT modified:** the audit heuristic (sub-track 3 Phase 7 + sub-track 4 Phase 11/12 + sub-track 5 Heuristic E are correct), the `Result[T]` type (canonical reference), and the existing `_result` helper functions (only the legacy WRAPPERS are removed; the helpers stay). +--- + +## The Wrapper-Obliteration Pattern (used by Phases 3-7) + +For every legacy wrapper, the migration is: + +```python +# ============================================================ +# BEFORE (legacy wrapper — false drain; the dead code) +# ============================================================ +def _x_result(...) -> Result[T]: + """The proper Result-returning version.""" + try: + return Result(data=do_something()) + except Exception as e: + return Result(data=, errors=[ErrorInfo(...)]) + + +def _x(...): # ← LEGACY WRAPPER (false drain; silently drops errors) + """Legacy wrapper. PRESERVED for backward compat per sub-track 3 Phase 6 Group 6.3.""" + result = _x_result(...) + if not result.ok: + pass # ← ERROR DROPPED HERE (sliming; defeats Result propagation) + return result.data + + +# In-site caller (e.g., in some other src/foo.py): +def caller(...): + val = _x(...) # ← caller uses the legacy wrapper; gets no error info + return val +``` + +```python +# ============================================================ +# AFTER (legacy wrapper DELETED; caller rewritten to use _x_result) +# ============================================================ +def _x_result(...) -> Result[T]: + """The proper Result-returning version. (UNCHANGED)""" + try: + return Result(data=do_something()) + except Exception as e: + return Result(data=, errors=[ErrorInfo(...)]) + + +# In-site caller (REWRITTEN in src/foo.py): +def caller(...): + result = _x_result(...) # ← caller uses _result directly + if not result.ok: + # Route the error to the appropriate drain (caller-specific): + # - Append to controller._last_request_errors + # - Append to controller._worker_errors (with lock) + # - imgui.open_popup("Error: ...") (gui_2.py callers) + # - telemetry.emit_error(...) + # - raise to caller (Pattern 1/3) + # - return caller-specific-fallback (only if the caller is itself + # a boundary and the fallback is documented) + log_error_to_drain(result.errors[0]) + return # OR propagate, OR re-raise + return result.data + + +# def _x(...): ← DELETED (no pass-through; no backward compat) +``` + +**The legacy wrapper `_x` is DELETED in the same commit.** No pass-through. No "backward compat". The dead code dies. + +--- + +## Phase 0: Setup + Styleguide Re-Read (3 tasks) + +**Focus:** Initialize the track, update tracks.md, Tier 2 reads the styleguide end-to-end, acknowledge in commit message. + +### Task 0.1: Update `conductor/tracks.md` + +**Files:** +- Modify: `conductor/tracks.md` (add new row after the sub-track 5 row) + +- [ ] **Step 1: Find the sub-track 5 row** + +```bash +grep -n "result_migration_baseline_cleanup_20260620" conductor/tracks.md | head -3 +``` + +- [ ] **Step 2: Add the new row after sub-track 5** + +Insert in the "Active Tracks (Current Queue)" table (after the sub-track 5 row): + +``` +| 6d-6 | A | [Result Migration: Cruft Removal (Wrapper Obliteration)](#track-result-migration-cruft-removal-wrapper-obliteration-20260620) | spec ✓, plan pending, **ready to start**; obliterates every legacy `def _x(): return _x_result(...).data` wrapper in `src/` (8+ confirmed; 91 `_result` helpers total); fixes 7 failing sub-track 5 inventory tests. **OBLITERATE principle: no pass-throughs; no backward compat; in-site callers rewritten to use `_x_result(...).ok` directly.** | `result_migration_baseline_cleanup_20260620` (sub-track 5, SHIPPED 2026-06-20) | +``` + +- [ ] **Step 3: Commit** + +```bash +git add conductor/tracks.md +git commit -m "conductor(tracks): add result_migration_cruft_removal_20260620 row" +``` + +### Task 0.2: Tier 2 reads the styleguide end-to-end + +**Files:** (no file changes; verification is the commit message) + +- [ ] **Step 1: Read `conductor/code_styleguides/error_handling.md` end-to-end** (989 lines) + +All sections: 5 Patterns + Data Model + Decision Tree + Anti-Patterns + Examples + Hard Rules + When to Use + Boundary Types + **Drain Points (lines 356-516)** + **Broad-Except Distinction (lines 520-540)** + Constructors Can Raise + Re-Raise Patterns + Audit Script + Migration Playbook + AI Agent Checklist (lines 809-940). + +- [ ] **Step 2: Acknowledge the read in an empty commit** + +```bash +git commit --allow-empty -m "chore: TIER-2 READ conductor/code_styleguides/error_handling.md end-to-end before Phase 0" +``` + +### Task 0.3: Phase 0 checkpoint + +- [ ] **Step 1: Empty commit marking Phase 0 complete** + +```bash +git commit --allow-empty -m "conductor(plan): mark Phase 0 complete (setup + styleguide re-read)" +``` + +--- + +## Phase 1: Fix the 7 Failing Tests (5 tasks) + +**Focus:** Test scaffolding repair only. No production code changes. The 7 failing tests in `tests/test_baseline_result.py` are caused by: +- `tests/artifacts/PHASE1_AUDIT_BASELINE.json` was never committed (4 tests fail) +- 3 per-file inventory docs were collapsed into 1 combined `PHASE1_SITE_INVENTORY.md` (3 tests fail) + +### Task 1.1: Run the audit + save the JSON + +- [ ] **Step 1: Run the audit and save JSON** + +```bash +uv run python scripts/audit_exception_handling.py --include-baseline --json > tests/artifacts/PHASE1_AUDIT_BASELINE.json +``` + +- [ ] **Step 2: Verify the JSON was generated** + +```bash +ls -la tests/artifacts/PHASE1_AUDIT_BASELINE.json +``` + +Expected: file exists, size > 10KB. + +- [ ] **Step 3: Commit** + +```bash +git add tests/artifacts/PHASE1_AUDIT_BASELINE.json +git commit -m "fix(baseline): add missing PHASE1_AUDIT_BASELINE.json for sub-track 5 inventory tests" +``` + +### Task 1.2: Split the combined inventory into 3 per-file docs (or update tests) + +**Option A (preferred):** Split the combined `PHASE1_SITE_INVENTORY.md` into 3 per-file docs. + +- [ ] **Step 1: Check if the test file references per-file docs** + +```bash +grep -n "PHASE1_SITE_INVENTORY" tests/test_baseline_result.py | head -5 +``` + +- [ ] **Step 2: If tests reference per-file docs, split the combined doc** + +```bash +# Manual split: extract the mcp_client section, the ai_client section, the rag_engine section +# from tests/artifacts/PHASE1_SITE_INVENTORY.md +# Save as 3 files: PHASE1_SITE_INVENTORY_mcp_client.md, _ai_client.md, _rag_engine.md +# (Read the existing doc, split by header, save the 3 files) +``` + +- [ ] **Step 3: Commit the split** + +```bash +git add tests/artifacts/PHASE1_SITE_INVENTORY_mcp_client.md tests/artifacts/PHASE1_SITE_INVENTORY_ai_client.md tests/artifacts/PHASE1_SITE_INVENTORY_rag_engine.md tests/artifacts/PHASE1_SITE_INVENTORY.md +git commit -m "fix(baseline): split combined PHASE1_SITE_INVENTORY into 3 per-file docs" +``` + +**Option B (fallback if the combined doc cannot be cleanly split):** Update the test file to reference the combined doc. + +- [ ] **Step 1: Update `tests/test_baseline_result.py` to use the combined doc path** + +Find the 3 tests that reference per-file inventory docs (e.g., `test_phase1_inventory_docs_exist`, `test_phase2_per_file_baseline_counts_match_inventory`) and update the paths from `PHASE1_SITE_INVENTORY_mcp_client.md` to `PHASE1_SITE_INVENTORY.md`. + +- [ ] **Step 2: Commit the test update** + +```bash +git add tests/test_baseline_result.py +git commit -m "fix(baseline): update tests to reference combined PHASE1_SITE_INVENTORY.md" +``` + +### Task 1.3: Run the 7 originally-failing tests + verify all pass + +- [ ] **Step 1: Run the full test file** + +```bash +uv run python -m pytest tests/test_baseline_result.py -v +``` + +Expected: 31/31 PASSED (or however many tests are in the file; the 7 originally-failing ones now pass). + +- [ ] **Step 2: If any tests still fail, investigate and fix** + +The most common issue: the per-file inventory docs have a slightly different format than what the tests expect. Read the test expectations, compare to the actual doc content, and adjust. + +- [ ] **Step 3: Update state.toml Phase 1** + +```toml +phase_1 = { status = "completed", checkpointsha = "", name = "Fix the 7 failing tests (test scaffolding repair)" } +``` + +- [ ] **Step 4: Commit the state update** + +```bash +git add conductor/tracks/result_migration_cruft_removal_20260620/state.toml +git commit -m "conductor(plan): mark Phase 1 complete (7 failing tests fixed)" +``` + +--- + +## Phase 2: Final Detailed Audit — Full Legacy Wrapper Inventory (6 tasks) + +**Focus:** Scan ALL of `src/` for legacy wrapper patterns. Document every wrapper with line, file, function name, callers, and drain target. Per-site classification BEFORE migration (anti-sliming protocol). + +### Task 2.0: Phase 2 styleguide re-read + +- [ ] **Step 1: Re-read `error_handling.md` lines 462-540 (Broad-Except Distinction; logging NOT a drain)** + +- [ ] **Step 2: Acknowledge in commit** + +```bash +git commit --allow-empty -m "chore: TIER-2 READ conductor/code_styleguides/error_handling.md lines 462-540 (error dropping is NOT a drain) before Phase 2" +``` + +### Task 2.1: Write the audit script + +**Files:** +- Create: `scripts/audit_legacy_wrappers.py` + +- [ ] **Step 1: Write the audit script** + +```python +"""Audit script for legacy wrapper patterns in src/. + +A legacy wrapper is a function `def _x(...):` that just delegates to +`__result(...).data`, dropping the .ok check and error context. This +is a false drain: per the user's principle (error_handling.md:530 +"logging is NOT a drain", extended to "error dropping is NOT a drain"), +the legacy wrapper defeats the entire purpose of the Result[T] migration. + +This script scans src/ and reports: +- `def _x(...):` functions whose body is `return _x_result(...).data` (the + primary false-drain pattern) +- `def _x(...):` functions whose body checks `.ok` but only logs the + error (a softer form of false drain) +- `def _x(...):` functions whose body is `return _x_result(...)` (returns + the Result; less harmful but still a wrapper to remove) +""" +import ast +import sys +from pathlib import Path + + +def is_legacy_wrapper(func: ast.FunctionDef) -> tuple[bool, str]: + """Return (is_legacy_wrapper, pattern_name) for a function.""" + body_str = ast.unparse(func) + if "return _" in body_str and "_result(" in body_str and ".data" in body_str: + return True, "drop_errors_via_dot_data" + if "return _" in body_str and "_result(" in body_str: + return True, "returns_result_unchanged" + return False, "" + + +def find_callers(func_name: str, source: str) -> list[tuple[str, int]]: + """Find all call sites of `func_name` in the source code.""" + import re + callers = [] + for m in re.finditer(rf"\b{func_name}\(", source): + # Find the file and line of the match (rough; no full AST) + # The caller file/line is the same as the match line + callers.append((source[:m.start()].count("\n") + 1,)) + return callers + + +def audit_directory(src_dir: str = "src") -> list[dict]: + """Walk src/ and find all legacy wrappers + their callers.""" + findings = [] + for py_file in Path(src_dir).glob("*.py"): + try: + tree = ast.parse(py_file.read_text()) + except SyntaxError: + continue + source = py_file.read_text() + for node in ast.walk(tree): + if isinstance(node, ast.FunctionDef): + is_wrapper, pattern = is_legacy_wrapper(node) + if is_wrapper: + findings.append({ + "file": str(py_file), + "line": node.lineno, + "name": node.name, + "pattern": pattern, + }) + return findings + + +if __name__ == "__main__": + findings = audit_directory("src") + print(f"Found {len(findings)} legacy wrappers in src/:") + print() + for f in findings: + print(f" {f['file']}:{f['line']} {f['name']} [{f['pattern']}]") + sys.exit(0 if not findings else 1) +``` + +- [ ] **Step 2: Run the script to verify it works** + +```bash +uv run python scripts/audit_legacy_wrappers.py +``` + +Expected: prints a list of legacy wrappers found in src/. + +- [ ] **Step 3: Commit the script** + +```bash +git add scripts/audit_legacy_wrappers.py +git commit -m "feat(scripts): add audit_legacy_wrappers.py for final legacy wrapper detection" +``` + +### Task 2.2: Run the audit + capture the inventory + +- [ ] **Step 1: Run the audit and save the output** + +```bash +uv run python scripts/audit_legacy_wrappers.py > tests/artifacts/PHASE2_WRAPPER_AUDIT_RAW.txt +``` + +- [ ] **Step 2: Verify the count is ≥ 8 (the preliminary count) or more** + +```bash +grep -c "return _" tests/artifacts/PHASE2_WRAPPER_AUDIT_RAW.txt +``` + +### Task 2.3: Write the wrapper inventory doc (per-wrapper classification) + +**Files:** +- Create: `tests/artifacts/PHASE2_WRAPPER_AUDIT.md` + +- [ ] **Step 1: For each legacy wrapper found, classify it** + +For each wrapper in the raw output: +1. Find the file:line +2. Find all in-site callers (use `grep -n "(" src/*.py` to find callers) +3. Determine the drain target for each caller (where the error should go) +4. Document in the inventory doc + +**Inventory doc format:** + +```markdown +# Phase 2 — Legacy Wrapper Inventory + +**Generated:** +**Total legacy wrappers found:** + +| File | Line | Wrapper | Pattern | In-site callers | Drain target | +|---|---|---|---|---|---| +| src/.py | | _ | drop_errors_via_dot_data | src/.py:, ... | _last_request_errors / _worker_errors / imgui popup / telemetry / re-raise | +| ... | +``` + +- [ ] **Step 2: Commit the inventory** + +```bash +git add tests/artifacts/PHASE2_WRAPPER_AUDIT_RAW.txt tests/artifacts/PHASE2_WRAPPER_AUDIT.md +git commit -m "conductor(plan): Phase 2 wrapper inventory — legacy wrappers classified" +``` + +### Task 2.4: Add Phase 2 invariant test + +**Files:** +- Modify: `tests/test_baseline_result.py` (or a new `tests/test_cruft_removal.py`) + +- [ ] **Step 1: Add the Phase 2 invariant test (audit script finds at least 1 wrapper)** + +```python +def test_phase_2_invariant_audit_script_finds_legacy_wrappers(): + """Phase 2 invariant: the legacy wrapper audit script finds >= 1 legacy wrapper.""" + import subprocess + r = subprocess.run( + ["uv", "run", "python", "scripts/audit_legacy_wrappers.py"], + capture_output=True, text=True, check=True, + ) + assert "legacy wrapper" in r.stdout.lower(), f"Unexpected output: {r.stdout}" + # The exact count check is too brittle; just verify the script works + + +def test_phase_2_inventory_doc_exists(): + """Phase 2 invariant: the wrapper inventory doc exists and has >= 1 row.""" + from pathlib import Path + import re + inv = Path("tests/artifacts/PHASE2_WRAPPER_AUDIT.md") + assert inv.exists(), "PHASE2_WRAPPER_AUDIT.md must exist" + content = inv.read_text() + row_count = len(re.findall(r"^\| src/", content, re.MULTILINE)) + assert row_count >= 1, f"Expected >= 1 wrapper row, found {row_count}" +``` + +- [ ] **Step 2: Run the new tests** + +```bash +uv run python -m pytest tests/test_baseline_result.py -v -k "phase_2_invariant or phase_2_inventory" +``` + +Expected: 2 PASSED + +- [ ] **Step 3: Update state.toml Phase 2** + +```toml +phase_2 = { status = "completed", checkpointsha = "", name = "Final detailed audit (full legacy wrapper inventory)" } +``` + +- [ ] **Step 4: Commit the state update** + +```bash +git add conductor/tracks/result_migration_cruft_removal_20260620/state.toml +git commit -m "conductor(plan): mark Phase 2 complete (wrapper audit + inventory doc + 2 invariant tests)" +``` + +--- + +## Phases 3-7: Per-File Wrapper Removal (the obliteration) + +**Per-wrapper migration pattern** (the same for every wrapper across all files): + +For each wrapper `` in ``: +1. **Step 1:** Styleguide re-read (per-phase ack commit; NOT per-wrapper) +2. **Step 2:** Write failing test for the caller (verify the caller now uses `_x_result(...).ok`) +3. **Step 3:** Migrate the caller (rewrite to use `_x_result(...).ok` + error routing) +4. **Step 4:** DELETE the legacy wrapper `def _x(...):` +5. **Step 5:** Run the test (MUST PASS) +6. **Step 6:** Run `audit_legacy_wrappers.py` to verify the wrapper is GONE +7. **Step 7:** Commit (1 wrapper = 1 commit) + +### Phase 3: mcp_client wrappers + +**Tasks (one per wrapper, found in Phase 2 inventory):** + +```bash +# Find the wrappers in this file: +uv run python scripts/audit_legacy_wrappers.py | grep "src/mcp_client.py" +``` + +For each wrapper ``: + +- [ ] **Task 3.0: Phase 3 styleguide re-read + ack commit** + +```bash +git commit --allow-empty -m "chore: TIER-2 READ conductor/code_styleguides/error_handling.md end-to-end before Phase 3" +``` + +- [ ] **Task 3.1: Migrate wrapper `` in mcp_client.py (representative example)** + +**Files:** +- Modify: `src/mcp_client.py` (rewrite the caller; delete the legacy wrapper) +- Modify: `tests/test_mcp_client.py` (add a test verifying the caller propagates errors) + +**Steps:** + +- [ ] **Step 1: Find the wrapper and its caller** + +```bash +grep -n "def \|(" src/mcp_client.py tests/test_mcp_client.py 2>/dev/null +``` + +- [ ] **Step 2: Write failing test for the caller (in `tests/test_mcp_client.py`)** + +```python +def test__caller_propagates_errors(): + """The caller of should now use __result(...).ok and propagate errors.""" + from src import mcp_client + # Setup: make the inner call fail (e.g., mock the underlying I/O to raise) + # Call the caller function + result = mcp_client.() + # Assert: the result includes the error from __result + # (NOT just the data, which is what the legacy wrapper did) + assert result is not None # Adjust based on caller's actual return shape + # The key assertion: when __result returns an error, the caller + # routes it (not silently drops it) +``` + +- [ ] **Step 3: Run the test, verify it FAILS** + +```bash +uv run python -m pytest tests/test_mcp_client.py::test__caller_propagates_errors -v +``` + +Expected: FAIL (the caller currently uses the legacy wrapper which drops errors) + +- [ ] **Step 4: Migrate the caller** + +In `src/mcp_client.py`, find the caller function. Replace the legacy wrapper call `_x(...)` with the direct `_x_result(...)` call: + +```python +# BEFORE +def caller(...): + val = _(...) + return val + +# AFTER +def caller(...): + result = __result(...) + if not result.ok: + # Route the error to the appropriate drain + # (See the per-file drain pattern in spec.md §4.3) + return + return result.data +``` + +- [ ] **Step 5: DELETE the legacy wrapper `def _(...):` in `src/mcp_client.py`** + +Remove the entire function definition. + +- [ ] **Step 6: Run the test, verify it PASSES** + +```bash +uv run python -m pytest tests/test_mcp_client.py::test__caller_propagates_errors -v +``` + +Expected: PASS + +- [ ] **Step 7: Verify the wrapper is GONE** + +```bash +uv run python scripts/audit_legacy_wrappers.py | grep "" +``` + +Expected: no output (the wrapper is gone) + +- [ ] **Step 8: Commit (1 wrapper = 1 commit)** + +```bash +git add src/mcp_client.py tests/test_mcp_client.py +git commit -m "refactor(mcp_client): obliterate legacy _ wrapper; migrate caller to __result (Phase 3)" +``` + +- [ ] **Task 3.2-3.N: Repeat for each remaining wrapper in mcp_client.py** (one task per wrapper, same pattern) + +- [ ] **Task 3.N+1: Phase 3 invariant test + checkpoint** + +- [ ] **Step 1: Add Phase 3 invariant test (mcp_client has 0 legacy wrappers)** + +```python +def test_phase_3_invariant_mcp_client_zero_legacy_wrappers(): + """Phase 3 invariant: src/mcp_client.py has 0 legacy wrappers.""" + import subprocess + r = subprocess.run( + ["uv", "run", "python", "scripts/audit_legacy_wrappers.py"], + capture_output=True, text=True, + ) + # Count occurrences in mcp_client.py + mcp_count = sum(1 for line in r.stdout.split("\n") if "src/mcp_client.py" in line) + assert mcp_count == 0, f"Expected 0 wrappers in mcp_client.py, found {mcp_count}" +``` + +- [ ] **Step 2: Update state.toml Phase 3 + commit** + +```bash +git add conductor/tracks/result_migration_cruft_removal_20260620/state.toml +git commit -m "conductor(plan): mark Phase 3 complete (mcp_client wrappers obliterated)" +``` + +### Phase 4: ai_client wrappers + +**Same structure as Phase 3** (per-wrapper tasks 4.1-4.N, then invariant test 4.N+1 + checkpoint). + +### Phase 5: rag_engine wrappers + +**Same structure as Phase 3** (per-wrapper tasks 5.1-5.N, then invariant test 5.N+1 + checkpoint). + +### Phase 6: other src/ files (per Phase 2 inventory) + +**Same structure as Phase 3** (per-file sub-phases 6.1-6.M, then invariant test + checkpoint). + +### Phase 7: remaining files (if any) + +**Same structure as Phase 3** (per-file sub-phases 7.1-7.M, then invariant test + checkpoint). + +--- + +## Phase 8: Audit Gate + End-of-Track Report + Campaign Close-Out (8 tasks) + +**Focus:** Verify all gates, run the full batched suite, write the report, mark the track complete, update the campaign status. + +### Task 8.1: Run the strict audit gate (--src src) + +- [ ] **Step 1: Run the audit** + +```bash +uv run python scripts/audit_exception_handling.py --src src --strict +``` + +Expected: exit 0; 0 violations + +- [ ] **Step 2: If exit non-zero, identify the failing sites and report** + +```bash +uv run python scripts/audit_exception_handling.py --src src --strict 2>&1 | grep -E "VIOLATION|src/" +``` + +### Task 8.2: Run the strict audit gate (--include-baseline) + +- [ ] **Step 1: Run the audit** + +```bash +uv run python scripts/audit_exception_handling.py --include-baseline --strict +``` + +Expected: exit 0; 0 violations across the 3 baseline files + +### Task 8.3: Run the legacy wrapper audit (the obliteration gate) + +- [ ] **Step 1: Run the audit script** + +```bash +uv run python scripts/audit_legacy_wrappers.py +``` + +Expected: exit 0; NO legacy wrappers found (empty output or "0 legacy wrappers" message) + +### Task 8.4: Run the unit tests + +- [ ] **Step 1: Run the baseline + heuristic tests** + +```bash +uv run python -m pytest tests/test_baseline_result.py tests/test_audit_heuristics.py -v +``` + +Expected: 31 + 16 = 47 PASSED (no failures) + +- [ ] **Step 2: If any tests fail, fix and re-run** + +### Task 8.5: Run the 11-tier batched suite + +- [ ] **Step 1: Run the fixed batched script** + +```bash +uv run python scripts/run_tests_batched.py +``` + +Expected: 11/11 tiers PASS + +- [ ] **Step 2: If any tier fails, save the log and report** + +### Task 8.6: Write the end-of-track report + +**Files:** +- Create: `docs/reports/TRACK_COMPLETION_result_migration_cruft_removal_20260620.md` + +- [ ] **Step 1: Write the report (template below)** + +```markdown +# Track Completion: Result Migration — Cruft Removal (Wrapper Obliteration) + +**Track ID:** `result_migration_cruft_removal_20260620` +**Date:** +**Status:** SHIPPED + +## 1. Header / Scope Summary + +<1-2 sentence summary> + +## 2. Phase-by-Phase Summary + +<9 sections, one per phase, with audit count delta> + +## 3. Audit Results (Pre vs Post) + +| Metric | Pre-Phase-0 | Post-Phase-8 | +|---|---|---| +| Legacy wrappers in src/ | 8 (preliminary; Phase 2 found N) | 0 | +| Audit violations (--src src --strict) | 0 (already clean) | 0 (still clean) | +| Audit violations (--include-baseline --strict) | 0 (sub-track 5 gate) | 0 (still green) | +| Baseline unit tests | 24 pass + 7 fail = 31 | 31/31 pass | +| Audit heuristic tests | 16/16 | 16/16 | +| 11-tier batched suite | | 11/11 PASS | + +## 4. Last 3 Failures Encountered + +<1-2 sentences per failure> + +## 5. Files Modified + + + +## 6. Git State + + + +## 7. Campaign Close-Out + +This is the final cleanup track of the 5-sub-track `result_migration_20260616` campaign. + +**The campaign is now 100% complete:** +- Sub-track 1 (review pass): shipped +- Sub-track 2 (small files): shipped +- Sub-track 3 (app controller): shipped +- Sub-track 4 (gui_2.py): shipped +- Sub-track 5 (baseline cleanup): shipped +- Cruft removal (this track): shipped + +**The data-oriented Result[T] convention is now fully applied across all 65 src/ files:** +- 0 migration-target violations +- 0 legacy wrappers +- 0 false-drain sites +- Every error is propagated via Result[T] to a documented drain + +## 8. Post-Completion Fixes (if any) +``` + +- [ ] **Step 2: Commit the report** + +```bash +git add docs/reports/TRACK_COMPLETION_result_migration_cruft_removal_20260620.md +git commit -m "docs(reports): TRACK_COMPLETION_result_migration_cruft_removal_20260620 (9 phases complete; campaign closed)" +``` + +### Task 8.7: Update the campaign status report + +- [ ] **Step 1: Update `docs/reports/RESULT_MIGRATION_CAMPAIGN_STATUS_20260619.md`** + +- Change the campaign status from "4.5/5 sub-tracks shipped" to "5/5 sub-tracks shipped; cruft removal complete; campaign 100% closed" +- Update the per-sub-track table to mark the cruft removal track as shipped +- Update the Outstanding Items section to remove the cruft removal deferred items +- Add a Campaign Close-Out section noting the final state + +- [ ] **Step 2: Commit the status update** + +```bash +git add docs/reports/RESULT_MIGRATION_CAMPAIGN_STATUS_20260619.md +git commit -m "docs(reports): update campaign status to 100% complete (cruft removal shipped)" +``` + +### Task 8.8: Final checkpoint + tracks.md update + +- [ ] **Step 1: Final checkpoint commit** + +```bash +git commit --allow-empty -m "conductor(checkpoint): cruft removal SHIPPED — campaign 100% complete" +``` + +- [ ] **Step 2: Update `conductor/tracks.md` row to "shipped 2026-06-XX"** + +- [ ] **Step 3: Update state.toml Phase 8** + +```toml +phase_8 = { status = "completed", checkpointsha = "", name = "Audit gate + end-of-track report + campaign close-out" } +``` + +- [ ] **Step 4: Final commit** + +```bash +git add conductor/tracks.md conductor/tracks/result_migration_cruft_removal_20260620/state.toml +git commit -m "conductor(plan): cruft removal SHIPPED; campaign 100% complete; tracks.md + state updated" +``` + +--- + +## Summary + +**9 phases, 8+ legacy wrappers obliterated, 7 failing tests fixed, 0 false-drain sites remain.** + +| Dimension | Count | +|---|---| +| Source files modified | All src/*.py with legacy wrappers (Phase 2 enumerates) | +| Legacy wrappers removed | 8+ (preliminary; Phase 2 enumerates exactly) | +| Test files modified | 1 (tests/test_baseline_result.py for Phase 1) + per-wrapper test additions | +| Tests added | 1 per wrapper + 2 Phase 1 + 2 Phase 2 invariant tests + 1 Phase 8 invariant | +| Phases | 9 | +| Atomic commits | ≥20 (1 wrapper = 1 commit + per-phase overhead) | + +--- + +## Self-Review + +**1. Spec coverage:** All 12 VCs in spec.md §8 are covered by tasks in this plan. VC-1, VC-2, VC-3 are Phase 1 tasks. VC-4 is Phase 8.3. VC-5, VC-6, VC-7, VC-8 are Phase 8.1-8.4. VC-9 is Phase 8.5. VC-10 is Task 8.6. VC-11 is Task 8.8. VC-12 is Task 8.7. + +**2. Placeholder scan:** No "TBD", "TODO", "implement later", "fill in details" in this plan. All wrapper migration patterns show concrete code. All tasks show concrete commands. The `` placeholder in the per-wrapper tasks is a per-wrapper name that gets populated by the Phase 2 inventory (not a code-level placeholder). + +**3. Type consistency:** `Result[T]` and `Result.ok` used consistently across all migration tasks. The drain patterns match the per-file drain conventions from the spec. + +**4. Anti-sliming protocol:** Enforced via (a) styleguide re-read at start of each phase, (b) per-wrapper audit pre-check + post-check, (c) per-wrapper invariant test, (d) per-file atomic commits, (e) explicit "OBLITERATE — no pass-throughs; no backward compat" in the spec. + +**5. Wrapper-obliteration pattern consistency:** All wrapper migration tasks use the same BEFORE/AFTER pattern shown in the "Wrapper-Obliteration Pattern" section. The legacy wrapper is DELETED in the same commit as the caller migration. + --- \ No newline at end of file