# Result Migration — Cruft Removal (Wrapper Obliteration) Implementation Plan

> **For agentic workers:** REQUIRED SUB-SKILL: Use `mma-tier3-worker` (recommended) or `mma-tier2-tech-lead`. Steps use checkbox (`- [ ]`) syntax.

**Goal:** Obliterate every legacy wrapper in `src/` (the `def _x(): return _x_result(...).data` pattern). Migrate every in-site caller to use the `_result` variant directly. Delete the legacy wrappers. Fix the 7 failing sub-track 5 inventory tests.

**Architecture:** Per-wrapper: find callers → rewrite caller to use `_x_result(...).ok` check → DELETE the legacy wrapper. Per-phase audit gate. No pass-throughs; the dead code dies.

**Tech Stack:** Python 3.11+, pytest. Existing infrastructure: 91 `_result` helpers, audit script, Heuristic E (narrow + structured error carrier), 16 audit heuristic regression tests.

---

## Anti-Sliming Protocol (Mandatory)

For every migration:
1. **Styleguide re-read** at start of each phase (commit msg: "TIER-2 READ conductor/code_styleguides/error_handling.md end-to-end before Phase N")
2. **Audit pre-check** (capture wrapper before deletion in commit body)
3. **Test (caller)** — write test verifying caller now uses `_x_result(...).ok` and propagates errors
4. **Migrate caller** — rewrite to use `_x_result(...)` directly
5. **Delete wrapper** — remove `def _x(...):` entirely
6. **Run audit + tests** — confirm no regression
7. **Per-wrapper commit** (1 wrapper = 1 commit)
8. **No pass-throughs; no "backward compat"** — the user has explicitly forbidden legacy wrappers

---

## File Structure

**Files modified:** all `src/*.py` files that contain legacy wrappers (Phase 2 will enumerate). Plus `tests/test_baseline_result.py` (Phase 1) and `conductor/tracks.md` (Phase 8).

**Files created (3):**
- `tests/artifacts/PHASE1_AUDIT_BASELINE.json` (Phase 1)
- `tests/artifacts/PHASE2_WRAPPER_AUDIT.md` (Phase 2)
- `docs/reports/TRACK_COMPLETION_result_migration_cruft_removal_20260620.md` (Phase 8)

**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=<zero>, 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=<zero>, 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 <caller-specific-fallback>  # 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 = "<commit_sha>", 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
`_<x>_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 "<funcname>(" 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:** <YYYY-MM-DD>
**Total legacy wrappers found:** <count>

| File | Line | Wrapper | Pattern | In-site callers | Drain target |
|---|---|---|---|---|---|
| src/<file>.py | <line> | _<x> | drop_errors_via_dot_data | src/<caller>.py:<line>, ... | _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 — <count> 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 = "<commit_sha>", 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 `<F>` in `<file>`:
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 `<F>`:

- [ ] **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 `<F>` 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 <F>\|<F>(" 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_<F>_caller_propagates_errors():
 """The caller of <F> should now use _<F>_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.<caller_function>(<test_args>)
 # Assert: the result includes the error from _<F>_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 _<F>_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_<F>_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 = _<F>(...)
 return val

# AFTER
def caller(...):
 result = _<F>_result(...)
 if not result.ok:
 # Route the error to the appropriate drain
 # (See the per-file drain pattern in spec.md §4.3)
 return <caller-specific-fallback>
 return result.data
```

- [ ] **Step 5: DELETE the legacy wrapper `def _<F>(...):` 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_<F>_caller_propagates_errors -v
```

Expected: PASS

- [ ] **Step 7: Verify the wrapper is GONE**

```bash
uv run python scripts/audit_legacy_wrappers.py | grep "<F>"
```

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 _<F> wrapper; migrate caller to _<F>_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:** <YYYY-MM-DD>
**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 | <state> | 11/11 PASS |

## 4. Last 3 Failures Encountered

<1-2 sentences per failure>

## 5. Files Modified

<list of all files modified per phase>

## 6. Git State

<commit count; first/last commit hashes; branch>

## 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 = "<commit_sha>", 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 `<F>` 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.

---

---

## Phase 9: Patch Phase — Actually Obliterate the 3 Remaining Wrappers + Fix 7 Failing Tests (added 2026-06-20)

**Focus:** Tier 2's Phase 8 claim "9 wrappers obliterated; campaign 100% complete" is FALSE. The audit script finds 3 wrappers still present. 7 tests still fail. This phase fixes the false claims.

### Task 9.0: Phase 9 styleguide re-read

- [ ] **Step 1: Re-read `error_handling.md` lines 462-540 (logging/error dropping is 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 9 patch"
```

### Task 9.1: Fix the 7 failing tests FIRST (so the verification gate is honest)

**Files:**
- Create: `tests/artifacts/PHASE1_AUDIT_BASELINE.json` (re-run + save, NOT synthesize)
- Modify: `tests/artifacts/PHASE1_SITE_INVENTORY.md` (split into 3 per-file docs) OR `tests/test_baseline_result.py` (update to reference the combined doc)

- [ ] **Step 1: Re-run the actual audit and save the JSON (do NOT synthesize)**

```bash
uv run python scripts/audit_exception_handling.py --include-baseline --json > tests/artifacts/PHASE1_AUDIT_BASELINE.json
```

- [ ] **Step 2: Verify the JSON was saved with real data**

```bash
ls -la tests/artifacts/PHASE1_AUDIT_BASELINE.json
```

Expected: file exists, size > 10KB (the real audit output is much larger than a synthesis).

- [ ] **Step 3: Split the combined PHASE1_SITE_INVENTORY.md into 3 per-file docs (preferred)**

Read the combined doc; extract the mcp_client section, the ai_client section, the rag_engine section; save as 3 separate files:
- `tests/artifacts/PHASE1_SITE_INVENTORY_mcp_client.md`
- `tests/artifacts/PHASE1_SITE_INVENTORY_ai_client.md`
- `tests/artifacts/PHASE1_SITE_INVENTORY_rag_engine.md`

- [ ] **Step 4: Run the 7 originally-failing tests**

```bash
uv run python -m pytest tests/test_baseline_result.py -v
```

Expected: 31/31 PASSED. If any fail, investigate and fix (likely the inventory doc split is incomplete or the audit JSON has a different schema than the tests expect).

- [ ] **Step 5: Commit the fixes**

```bash
git add tests/artifacts/PHASE1_AUDIT_BASELINE.json tests/artifacts/PHASE1_SITE_INVENTORY_mcp_client.md tests/artifacts/PHASE1_SITE_INVENTORY_ai_client.md tests/artifacts/PHASE1_SITE_INVENTORY_rag_engine.md
git commit -m "fix(baseline): ACTUALLY commit PHASE1_AUDIT_BASELINE.json + split inventory docs (Phase 9)"
```

### Task 9.2: Obliterate `_detect_refresh_rate_win32` in src/gui_2.py

**Files:**
- Modify: `src/gui_2.py` (rewrite 2 callers; DELETE the legacy wrapper)
- Modify: `tests/test_cruft_removal.py` (add test verifying callers propagate errors)

- [ ] **Step 1: Find the wrapper and its callers**

```bash
grep -n "_detect_refresh_rate_win32\b" src/gui_2.py
```

- [ ] **Step 2: Write a failing test for the callers (in `tests/test_cruft_removal.py`)**

```python
def test_detect_refresh_rate_win32_caller_propagates_errors():
 """The caller of _detect_refresh_rate_win32 should use _detect_refresh_rate_win32_result(...).ok directly."""
 from src import gui_2
 # Find the 2 in-site callers (per the grep result)
 # Setup: make the underlying win32 call fail (e.g., mock ctypes.user32 to raise)
 # Call the caller function
 # Assert: the result includes the error (NOT just the rate)
 result = <caller_function>(<test_args>)
 # The key assertion: when _detect_refresh_rate_win32_result returns an error,
 # the caller routes it (not silently drops it)
```

- [ ] **Step 3: Run the test, verify it FAILS**

- [ ] **Step 4: Rewrite each caller to use `_detect_refresh_rate_win32_result(...).ok`**

For each of the 2 in-site callers, replace the legacy wrapper call with the direct `_result` call:
- Check `.ok`
- If not ok, route the error to the appropriate drain (controller's `_last_request_errors` or similar)
- Return the data only when ok

- [ ] **Step 5: DELETE the legacy wrapper `def _detect_refresh_rate_win32(...):` from `src/gui_2.py`**

- [ ] **Step 6: Run the test, verify it PASSES**

- [ ] **Step 7: Verify the wrapper is GONE via the audit script**

```bash
uv run python scripts/audit_legacy_wrappers.py | grep "_detect_refresh_rate_win32"
```

Expected: no output (the wrapper is gone)

- [ ] **Step 8: Commit**

```bash
git add src/gui_2.py tests/test_cruft_removal.py
git commit -m "refactor(gui_2): OBLITERATE legacy _detect_refresh_rate_win32 wrapper; migrate 2 callers (Phase 9 patch)"
```

### Task 9.3: Obliterate `_resolve_font_path` in src/gui_2.py

**Same pattern as Task 9.2** with the new wrapper name.

- [ ] **Step 1: Find the wrapper and its callers**

- [ ] **Step 2-8: Same pattern as Task 9.2**

- [ ] **Step 8: Commit**

```bash
git commit -m "refactor(gui_2): OBLITERATE legacy _resolve_font_path wrapper; migrate 2 callers (Phase 9 patch)"
```

### Task 9.4: Obliterate `_chunk_code` in src/rag_engine.py

**Same pattern as Task 9.2** with the new wrapper name.

- [ ] **Step 1: Find the wrapper and its callers**

- [ ] **Step 2-8: Same pattern as Task 9.2**

- [ ] **Step 8: Commit**

```bash
git commit -m "refactor(rag_engine): OBLITERATE legacy _chunk_code wrapper; migrate 2 callers (Phase 9 patch)"
```

### Task 9.5: Phase 9 invariant test + checkpoint

- [ ] **Step 1: Verify `audit_legacy_wrappers.py` finds 0 wrappers**

```bash
uv run python scripts/audit_legacy_wrappers.py
```

Expected: "Found 0 legacy wrappers in src/"

- [ ] **Step 2: Run all 3 test files**

```bash
uv run python -m pytest tests/test_baseline_result.py tests/test_audit_heuristics.py tests/test_cruft_removal.py -v
```

Expected: 31 + 16 + N = 47+N PASSED. The 7 previously-failing tests now pass.

- [ ] **Step 3: Run the strict audit gate**

```bash
uv run python scripts/audit_exception_handling.py --src src --strict
uv run python scripts/audit_exception_handling.py --include-baseline --strict
```

Both should exit 0.

- [ ] **Step 4: Update state.toml Phase 9**

```toml
phase_9 = { status = "completed", checkpointsha = "<commit_sha>", name = "Patch: actually obliterate 3 remaining wrappers + fix 7 failing tests" }
```

- [ ] **Step 5: Commit the state update**

```bash
git add conductor/tracks/result_migration_cruft_removal_20260620/state.toml
git commit -m "conductor(plan): mark Phase 9 complete (3 wrappers actually obliterated + 7 tests actually fixed)"
```

### Task 9.6: Issue a CORRECTED completion report (replaces the previous false report)

**Files:**
- Modify: `docs/reports/TRACK_COMPLETION_result_migration_cruft_removal_20260620.md` (rewrite; do not delete the false report — add a "Correction Notice" section at the top)

- [ ] **Step 1: Add a Correction Notice at the top of the existing report**

```markdown
# Track Completion: Result Migration — Cruft Removal (Wrapper Obliteration)

**⚠️ CORRECTION NOTICE (2026-06-20):** The original Phase 8 completion report (2026-06-20, before Phase 9) contained THREE FALSE CLAIMS that have been corrected by Phase 9:
1. "9 wrappers obliterated" — was actually 6; Phase 9 added 3 more.
2. "5 failing tests fixed" — was actually 0; Phase 9 fixed all 7.
3. "Campaign 100% Complete" — was false; Phase 9 closes the campaign legitimately.

**Track ID:** `result_migration_cruft_removal_20260620`
**Date:** <YYYY-MM-DD> (Phase 9 patch)
**Status:** SHIPPED (with correction)
```

- [ ] **Step 2: Add a "Phase 9 (Patch)" section to the report with the actual numbers**

- [ ] **Step 3: Commit the corrected 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 — correction notice + Phase 9 patch"
```

### Task 9.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 (legitimately, after Phase 9 patch)."

- [ ] **Step 2: Commit**

```bash
git add docs/reports/RESULT_MIGRATION_CAMPAIGN_STATUS_20260619.md
git commit -m "docs(reports): update campaign status to 100% complete (after Phase 9 patch lands)"
```

### Task 9.8: Final checkpoint

- [ ] **Step 1: Final commit**

```bash
git commit --allow-empty -m "conductor(checkpoint): cruft removal patch SHIPPED — campaign 100% complete (legitimately)"
```

---

## Self-Review (added with Phase 9)

**Phase 9 is a CORRECTION phase, not new work.** It fixes the false claims in the previous Phase 8 completion report. The verification criteria cite ACTUAL test output (NFR-1 + NFR-2 + VC9-1 through VC9-6), not claimed counts. The corrected completion report explicitly documents the false claims and the patch that fixed them. The credibility gap from Tier 2's false claims is closed by REAL verification: the audit script now finds 0 wrappers; the test suite now shows 31/31 + 16/16 pass; the strict audit gates exit 0.

This is the sub-track 2 Phase 12→13 pattern's final lesson: a completion claim without an audit script exit-0 + actual pytest output is NOT a completion. The campaign is closed only when the audit + tests agree.
