# 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.

---