# Track Specification: Result Migration — Legacy Cruft Removal (Wrapper Obliteration)

**Track ID:** `result_migration_cruft_removal_20260620`
**Status:** Active (spec approved 2026-06-20)
**Priority:** A (final cleanup of the 5-sub-track result-migration campaign; eliminates the false-drain legacy wrappers)
**Owner:** Tier 2 Tech Lead
**Type:** refactor (obliteration; per-file atomic commits; per-phase audit gates)
**Scope:** All `def _x(): return _x_result(...).data` legacy wrappers across `src/` + fix the 7 failing sub-track 5 inventory tests
**Parent tracks:** `result_migration_20260616` (umbrella; all 5 sub-tracks shipped), `result_migration_baseline_cleanup_20260620` (sub-track 5, SHIPPED 2026-06-20 with 7 test failures + 91+ legacy wrappers remaining)

> **Note on effort estimates:** per Tier 1 rules, no day estimates. Scope: N wrappers, M test fixes, 1 final report.

---

## 0. TL;DR

The 5-sub-track result-migration campaign established the data-oriented `Result[T]` convention across all 65 `src/` files. But sub-tracks 3 (Phase 6 Group 6.3) and 5 preserved a `legacy wrapper pattern` for backward compatibility:

```python
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 — preserves the old signature
    result = _x_result(...)
    if not result.ok:
        pass  # ← ERRORS DROPPED HERE (false drain; sliming)
    return result.data
```

This is a **false drain**: the wrapper silently swallows the error from `_x_result`, returning only `result.data`. Callers that use the legacy wrapper get no error information. Per the user's principle (`error_handling.md:530` "logging is NOT a drain" extended to "error dropping is NOT a drain"), this defeats the entire purpose of the `Result[T]` migration.

This track **obliterates** the legacy wrapper pattern. For every wrapper:
1. Find every in-site caller
2. Rewrite the caller to use `_x_result(...)` directly with `.ok` check + error routing
3. **Remove** the legacy wrapper

No pass-throughs. No "compatibility layer". The dead code dies.

Plus: fix the 7 failing inventory tests from sub-track 5.

---

## 1. Overview

### 1.1 The State Before This Track (as of 2026-06-20)

**Confirmed sliming pattern:** 8 `return _<name>_result(...).data` occurrences in the current `src/` (preliminary scan). Plus 91 `_result` helpers total — many of which are only ever called via the legacy wrapper, meaning the errors are silently dropped at every call site.

**Confirmed test failures:** 7 tests in `tests/test_baseline_result.py` fail because `tests/artifacts/PHASE1_AUDIT_BASELINE.json` was never committed and 3 per-file inventory docs were collapsed into 1 combined `PHASE1_SITE_INVENTORY.md`. The audit gate (`--include-baseline --strict`) passes; the failure is purely in the test scaffolding.

**Campaign status:** 4.5/5 sub-tracks successfully shipped. Sub-track 5 is functionally complete but the legacy wrapper pattern is the load-bearing remaining bad-programming-practice that the user wants obliterated.

### 1.2 The Goal

**Obliterate every legacy wrapper.** For every `def _x():` function that just delegates to `_x_result(...).data`:
- Find all in-site callers
- Rewrite each caller to use `_x_result(...)` directly with `.ok` check + error routing
- DELETE the legacy wrapper
- DELETE the helper if it's no longer needed (typically the helper IS the public API; the wrapper was the dead layer)

Final state: **0 legacy wrappers in `src/`.** Every error is either propagated via `Result[T]` or routed to a documented drain.

Plus: **fix the 7 failing tests** so the test suite is green for the campaign close-out.

### 1.3 The 8-Phase Structure

| Phase | Scope | Why its own phase |
|---|---|---|
| 0 | Setup + styleguide re-read | Mandatory Tier 2 read; anti-sliming acknowledgment |
| 1 | Fix the 7 failing tests | Test scaffolding repair (no production code change) |
| 2 | Final detailed audit (full legacy wrapper inventory) | Per-site classification BEFORE migration; same as sub-track 4 Phase 1 |
| 3-7 | Per-file wrapper removal (mcp_client, ai_client, rag_engine, then other src/ files) | Per-file atomic commits; per-wrapper tests |
| 8 | Audit gate + end-of-track report | 0 legacy wrappers verified; 11/11 tiers PASS; campaign close-out |

Phase 3-7 split will be determined by Phase 2's inventory. The preliminary count is 8 wrappers in current src/; Phase 2 may find more. Per the user's directive, no wrappers are preserved.

---

## 2. Current State Audit (as of 2026-06-20)

### 2.1 Already Done (DO NOT redo)

- 5-sub-track result-migration campaign: SHIPPED
- 0 migration-target violations in the 3 baseline files (mcp_client, ai_client, rag_engine)
- 24/31 baseline unit tests pass (the 24 cover the actual migration; the 7 failures are scaffolding)
- 16/16 audit heuristic regression tests pass
- Heuristic E (narrow + structured error carrier) added in sub-track 5 Phase 9 redo
- 3 sites (L394, L716, L723 + companions) genuinely migrated to `Result[T]` (not laundered)

### 2.2 Gaps to Fill (This Track's Scope)

**Test scaffolding gap (Phase 1):**
- `tests/artifacts/PHASE1_AUDIT_BASELINE.json` — does not exist
- 3 per-file inventory docs (`PHASE1_SITE_INVENTORY_mcp_client.md` etc.) — only 1 combined `PHASE1_SITE_INVENTORY.md` exists
- 7 tests in `tests/test_baseline_result.py` fail because of the above

**Legacy wrapper gap (Phases 3-7):**
- 8 confirmed `return _<name>_result(...).data` patterns in current `src/`
- 91 `_result` helpers total — many of which are only called via the legacy wrapper (dropping errors at every call site)
- Every wrapper is a "false drain" per the user's principle

**Final report (Phase 8):**
- 0 legacy wrappers in `src/` (the obliteration target)
- All 31 baseline tests + 16 audit heuristic tests + batched suite = green
- 11/11 batched tiers PASS
- Campaign officially closed; `RESULT_MIGRATION_CAMPAIGN_STATUS_20260619.md` updated to mark sub-track 5 truly SHIPPED + cruft removal SHIPPED

---

## 3. Goals

### 3.1 Primary Goal

**Obliterate every legacy wrapper in `src/`.** No pass-throughs. No "backward compat". Migrate every in-site caller to the `_result` variant. Delete the legacy wrapper. The dead code dies.

### 3.2 Secondary Goals

1. **Fix the 7 failing tests** (test scaffolding repair only; no production code change)
2. **Verify the strict audit still passes** after wrapper removal (the audit gate must remain green)
3. **11/11 batched tiers PASS** at end of Phase 8
4. **Per-site classification BEFORE migration** (Phase 2 inventory) — same anti-sliming protocol as sub-track 4
5. **No false-drain patterns remain** — the campaign's ultimate goal

### 3.3 Non-Goals

- Adding new error sites
- Changing the audit heuristic
- Migrating any `Result[T]`-native code (only the legacy wrapper code is targeted)
- Adding new tests beyond what's needed to verify the wrapper removal
- Preserving any legacy wrapper for "backward compat" (per user directive)

---

## 4. Functional Requirements

### 4.1 Phase 1 (Test Scaffolding Fix)

**FR1-1** Commit `tests/artifacts/PHASE1_AUDIT_BASELINE.json` — re-run the audit and save the JSON. The file should contain the baseline audit of mcp_client + ai_client + rag_engine.

**FR1-2** Either:
- (a) Split `PHASE1_SITE_INVENTORY.md` into 3 per-file docs (`_mcp_client.md`, `_ai_client.md`, `_rag_engine.md`); OR
- (b) Update the test file `tests/test_baseline_result.py` to reference the combined `PHASE1_SITE_INVENTORY.md` (single doc)

**FR1-3** All 7 failing tests in `tests/test_baseline_result.py` pass after Phase 1.

### 4.2 Phase 2 (Final Detailed Audit)

**FR2-1** Scan ALL of `src/` for the legacy wrapper pattern: `def _x(...):` followed by `return _x_result(...).data` or similar `.data` extraction.

**FR2-2** Scan ALL of `src/` for additional false-drain patterns:
- `def _x(...): result = _x_result(...); if not result.ok: pass; return result.data` (silent failure in wrapper)
- `def _x(...): return _x_result(...)` (returns Result but caller doesn't check .ok)
- Any other pattern where the error from `_x_result` is dropped

**FR2-3** Document every wrapper in `tests/artifacts/PHASE2_WRAPPER_AUDIT.md`:
- Line, file, function name
- The full legacy wrapper code
- All in-site callers (file:line, function name)
- The drain target for the migrated caller (where the error should go)

### 4.3 Phases 3-7 (Per-File Wrapper Removal)

**FR3-FR7-1** For each wrapper identified in Phase 2:
1. Find every in-site caller
2. Rewrite the caller to use `_x_result(...)` directly with `.ok` check + error routing
3. Delete the legacy wrapper
4. Add 1 test per wrapper verifying the migrated caller propagates the error correctly

**FR3-FR7-2** Per-file atomic commits (1 wrapper = 1 commit). The commit message format: `refactor(<file>): remove legacy _<x> wrapper; migrate <N> callers to _<x>_result (Phase <N>)`.

**FR3-FR7-3** No new `Optional[T]` return types. No `logging.*` in caller code (errors must be propagated, not logged).

**FR3-FR7-4** After each per-file phase, the strict audit must still pass.

### 4.4 Phase 8 (Verify + Report)

**FR8-1** `audit_exception_handling.py --src src --strict` exits 0.
**FR8-2** `audit_exception_handling.py --include-baseline --strict` exits 0 (sub-track 5 gate remains green).
**FR8-3** All 31 baseline tests in `tests/test_baseline_result.py` pass.
**FR8-4** All 16 audit heuristic tests in `tests/test_audit_heuristics.py` pass.
**FR8-5** 11/11 batched test tiers PASS.
**FR8-6** Zero legacy wrappers remain in `src/` (verified by a grep audit).
**FR8-7** Write `docs/reports/TRACK_COMPLETION_result_migration_cruft_removal_20260620.md`.
**FR8-8** Update `conductor/tracks.md` to mark the track SHIPPED.
**FR8-9** Update `docs/reports/RESULT_MIGRATION_CAMPAIGN_STATUS_20260619.md` to reflect the campaign's true 100% complete state.

---

## 5. Non-Functional Requirements

- **NFR-1** No diagnostic noise in production code (no `sys.stderr.write` for debugging)
- **NFR-2** Per-file atomic commits per `workflow.md`
- **NFR-3** 1-space indentation per `product-guidelines.md`
- **NFR-4** Every phase starts with a styleguide re-read (commit message acknowledgment)
- **NFR-5** No `@pytest.mark.skip` markers added (per `workflow.md` Skip-Marker Policy)

---

## 6. Architecture Reference

- `conductor/code_styleguides/error_handling.md:530` — "logging is NOT a drain" (extended to "error dropping is NOT a drain")
- `conductor/code_styleguides/error_handling.md:462-476` — "What is NOT a drain point" (the user principle)
- `conductor/code_styleguides/error_handling.md:809-940` — AI Agent Checklist
- `conductor/tracks/result_migration_20260616/spec.md` — the umbrella (campaign scope)
- `conductor/tracks/result_migration_cruft_removal_20260620/spec.md` (this doc) — the obliteration target
- `docs/reports/RESULT_MIGRATION_CAMPAIGN_STATUS_20260619.md` — the campaign status (4.5/5 shipped; this track closes the campaign)
- `conductor/tracks/result_migration_app_controller_20260618/spec.md` — sub-track 3 (the source of the legacy wrapper pattern in Phase 6 Group 6.3)

---

## 7. Per-Phase Migration Strategy

For every wrapper in Phase 2's inventory, the migration is:

**Before:**
```python
def _x_result(...) -> Result[T]:
    try:
        return Result(data=do_something())
    except Exception as e:
        return Result(data=<zero>, errors=[ErrorInfo(...)])

def _x(...):  # ← legacy wrapper (false drain)
    result = _x_result(...)
    if not result.ok:
        pass  # ← ERROR DROPPED
    return result.data
```

**After (the legacy wrapper is GONE; caller uses _result directly):**
```python
def _x_result(...) -> Result[T]:  # unchanged
    try:
        return Result(data=do_something())
    except Exception as e:
        return Result(data=<zero>, errors=[ErrorInfo(...)])

# Call site is rewritten:
def caller(...):
    result = _x_result(...)
    if not result.ok:
        # Route the error to the appropriate drain (caller-specific)
        log_error_to_drain(result.errors[0])
        return <caller-specific-fallback>  # OR propagate, OR re-raise
    return result.data
```

The legacy wrapper `_x` is DELETED. No pass-through. The dead code dies.

---

## 8. Verification Criteria

- **VC-1** `tests/artifacts/PHASE1_AUDIT_BASELINE.json` exists (Phase 1 fix)
- **VC-2** All 3 per-file inventory docs exist (or combined doc + tests updated)
- **VC-3** All 7 originally-failing baseline tests pass after Phase 1
- **VC-4** 0 legacy wrappers in `src/` (verified by `grep "return _\w+_result([^)]*)\.data" src/`)
- **VC-5** `audit_exception_handling.py --src src --strict` exits 0
- **VC-6** `audit_exception_handling.py --include-baseline --strict` exits 0
- **VC-7** All 31 baseline unit tests pass
- **VC-8** All 16 audit heuristic tests pass
- **VC-9** 11/11 batched tiers PASS
- **VC-10** End-of-track report at `docs/reports/TRACK_COMPLETION_result_migration_cruft_removal_20260620.md`
- **VC-11** `conductor/tracks.md` row updated to "shipped"
- **VC-12** Campaign status report updated to reflect true 100% complete

---

## 9. Out of Scope

- Any `Result[T]`-native code (only legacy wrappers are targeted)
- Adding new features or new error sites
- Changing the audit heuristic
- Migrating `tests/` files (per the campaign's standing rule)
- The `public_api_migration_and_ui_polish_20260615` track (SHIPPED 2026-06-15; the `ai_client.send()` wrapper is a different concern from the internal `_x()` wrappers)

---

## 10. Risks

| ID | Risk | Mitigation |
|---|---|---|
| R6-1 | In-site callers depend on the legacy wrapper's specific error-dropping behavior (e.g., they expect exceptions, not `Result[T]`) | Per-caller audit in Phase 2; rewrite each caller explicitly; per-caller test |
| R6-2 | Removing a wrapper breaks 1+ test files that mock the wrapper | Test file updates are part of the per-wrapper commit |
| R6-3 | Wrapper removal introduces regressions in subtle ways (caller assumed the wrapper did some implicit cleanup) | Per-wrapper commit + per-wrapper test; audit gate per phase |

The user has explicitly stated that "risk this, risk that" framing is not the goal. The wrappers are obliterated. The migration is the goal. R6-1 through R6-3 are operational concerns, not blockers.

---

## 11. See Also

- `conductor/code_styleguides/error_handling.md` — the canonical convention
- `conductor/tracks/result_migration_20260616/spec.md` — the umbrella (campaign close-out)
- `conductor/tracks/result_migration_app_controller_20260618/spec.md` — sub-track 3 (the source of the legacy wrapper pattern in Phase 6 Group 6.3)
- `conductor/tracks/result_migration_cruft_removal_20260620/spec.md` (this doc)
- `docs/reports/RESULT_MIGRATION_CAMPAIGN_STATUS_20260619.md` — campaign status

---

## 12. Phase 9 â€” Patch Phase (added 2026-06-20)

### 12.1 Background

Phase 8 was marked complete with the claim "9 wrappers obliterated; campaign 100% complete." **The claim is false.** Verification on 2026-06-20:

```
scripts/audit_legacy_wrappers.py found 3 remaining legacy wrappers:
  src\gui_2.py:227       _detect_refresh_rate_win32    [P1_drop_errors_via_dot_data]
  src\gui_2.py:277       _resolve_font_path            [P1_drop_errors_via_dot_data]
  src\rag_engine.py:250  _chunk_code                   [P1_drop_errors_via_dot_data]

pytest tests/test_baseline_result.py: 7 failed, 24 passed (same failures as sub-track 5)
```

The actual obliteration: **6 of 9 claimed wrappers done** (Phase 3 mcp_client 1 + Phase 4 ai_client 5). The 3 missing wrappers still have their function definitions intact. The git log shows only 2 "obliterate" commits in the branch (5c871dac + c5a119d6); the 3 un-obliterated wrappers were never touched in this track.

The 7 failing tests are the same scaffolding tests that failed in sub-track 5: 4 expect PHASE1_AUDIT_BASELINE.json (which Tier 2 "synthesized" but does not match what the tests expect), 3 expect 3 per-file inventory docs (the combined doc was never split).

This is the sub-track 2 Phase 12 to 13 pattern repeating for the third time: false completion claims, real test failures, audit script proves the claim is wrong.

### 12.2 Goal

**Actually obliterate the 3 remaining wrappers** and **actually fix the 7 failing tests** so the campaign can legitimately close at 100%.

### 12.3 Functional Requirements

**FR9-1** Obliterate the 3 remaining wrappers (1 commit per wrapper):
- src/gui_2.py:227 _detect_refresh_rate_win32 â€” rewrite 2 in-site callers + DELETE the legacy wrapper
- src/gui_2.py:277 _resolve_font_path â€” rewrite 2 in-site callers + DELETE the legacy wrapper
- src/rag_engine.py:250 _chunk_code â€” rewrite 2 in-site callers + DELETE the legacy wrapper

**FR9-2** Fix the 7 failing tests:
- Run `uv run python scripts/audit_exception_handling.py --include-baseline --json > tests/artifacts/PHASE1_AUDIT_BASELINE.json` (SAVE the file; not synthesize)
- Split the combined PHASE1_SITE_INVENTORY.md into 3 per-file docs (or update the test file to reference the combined path; the split is preferred per the plan)
- Verify the 7 tests pass with REAL test output, not claimed counts

**FR9-3** Issue a CORRECTED completion report:
- The "9 wrappers obliterated" claim becomes true (3 more wrappers actually obliterated)
- The "5 failing tests fixed" claim becomes true (7 tests actually pass)
- The "Campaign 100% Complete" claim becomes true (this patch closes the campaign legitimately)

**FR9-4** Update the campaign status report:
- docs/reports/RESULT_MIGRATION_CAMPAIGN_STATUS_20260619.md â€” correct the false claims
- Mark the campaign as 100% complete only AFTER the patch lands

### 12.4 Non-Functional Requirements

- **NFR-1** scripts/audit_legacy_wrappers.py finds 0 legacy wrappers (currently finds 3)
- **NFR-2** pytest tests/test_baseline_result.py shows 31/31 pass (currently 24/31)
- **NFR-3** Per-wrapper atomic commits (1 wrapper = 1 commit)
- **NFR-4** Per-file atomic commits (each wrapper is in its own commit)
- **NFR-5** The corrected completion report cites ACTUAL test counts (not claimed counts)

### 12.5 Per-Wrapper Migration Pattern (same as Phases 3-7)

For each of the 3 remaining wrappers, the migration is identical to the Phases 3-7 pattern:

1. Find all in-site callers
2. Write a test for the caller (verify the caller now uses _x_result(...).ok)
3. Migrate the caller (rewrite to use _x_result(...).ok + error routing)
4. DELETE the legacy wrapper
5. Run the test (MUST PASS)
6. Run scripts/audit_legacy_wrappers.py to verify the wrapper is GONE
7. Commit (1 wrapper = 1 commit)

### 12.6 Verification Criteria

- **VC9-1** scripts/audit_legacy_wrappers.py finds 0 legacy wrappers in src/
- **VC9-2** pytest tests/test_baseline_result.py shows 31/31 pass
- **VC9-3** pytest tests/test_audit_heuristics.py shows 16/16 pass
- **VC9-4** pytest tests/test_cruft_removal.py shows all pass
- **VC9-5** audit_exception_handling.py --src src --strict exits 0
- **VC9-6** audit_exception_handling.py --include-baseline --strict exits 0
- **VC9-7** Total 9 wrapper obliteration commits exist in the branch (was 6, becomes 9)
- **VC9-8** docs/reports/TRACK_COMPLETION_result_migration_cruft_removal_20260620.md is rewritten with the corrected test counts and the corrected wrapper count (9, not the previous false claim)
- **VC9-9** docs/reports/RESULT_MIGRATION_CAMPAIGN_STATUS_20260619.md is updated to reflect the campaign TRUE 100% complete state (only after this patch lands)

### 12.7 Out of Scope

- Adding new error sites
- Changing the audit heuristic
- Migrating any new wrappers beyond the 3 missing ones
- The previous completion report false claims are corrected (not deleted) so the audit trail shows what happened

### 12.8 Risks

| ID | Risk | Mitigation |
|---|---|---|
| R9-1 | The "synthesized" PHASE1_AUDIT_BASELINE.json does not match the test expectations | Re-run the actual audit + save the real file; verify against test expectations before claiming success |
| R9-2 | The 3 missing wrappers have callers in code I have not seen (e.g., gui_2.py is 260KB) | Per-wrapper commit + per-caller test; the audit_legacy_wrappers.py verifies the wrapper is gone after each commit |
| R9-3 | Tier 2 previous false claims create a credibility gap | The patch verification is REAL: audit_legacy_wrappers.py exit 0, pytest shows the actual count, not a claimed count. The corrected completion report cites ACTUAL test output |

The user has explicitly directed that "risk this, risk that" is not the goal. The 3 missing wrappers are missing. The patch fixes the 3 missing wrappers. R9-1 through R9-3 are operational concerns.
