# Plan: Public API Migration + UI Polish Test Cleanup

**Track:** `public_api_migration_and_ui_polish_20260615`
**Spec:** `spec.md`
**Status:** Active (plan approved 2026-06-15)

## TDD Protocol (MANDATORY)

For each phase, the order is:
1. **Red**: verify the test/failure is present (TDD red phase)
2. **Green**: implement the fix; run the test; confirm it passes
3. **Verify green**: run the targeted test batch to confirm no regression
4. **Commit**: one atomic commit per task with a clear message
5. **Git note**: attach a 3-5 sentence summary to the commit

Per the project rule (see `AGENTS.md` "Critical Anti-Patterns"), per-task atomic commits. The 1-space indentation rule is in effect (see `conductor/product-guidelines.md` "AI-Optimized Compact Style").

**Style enforcement:** Every task delegation to a Tier 3 worker MUST include the reminder "Use exactly 1-space indentation for Python code" to prevent style drift.

---

## Phase 1: Production call site migration (1 day)

**Focus:** Migrate 3 production call sites from `ai_client.send()` to `ai_client.send_result()`. This is the highest-risk phase (MMA worker has 5 callbacks; production behavior must be preserved).

### Task 1.1: Migrate `src/conductor_tech_lead.py:68` (easiest; 2-arg call)

- [ ] **Task 1.1a**: Verify the call is currently using `ai_client.send()` (no test change needed; this is a refactor, not a bug fix)
  - **Command:** `uv run rg "ai_client\.send\(" src/conductor_tech_lead.py`
  - **EXPECTED:** 1 hit at line 68
  - **COMMIT:** No new commit; this is a verification step.

- [ ] **Task 1.1b**: Migrate to `send_result()` with Result handling
  - **WHERE:** `src/conductor_tech_lead.py:60-90` (the `try/except` block containing the call)
  - **WHAT:** Replace the `ai_client.send(md_content="", user_message=user_message)` call with the Result pattern. On error, log to comms as `WARN/tech_lead_send_failed` and `return None` (the function returns a list of ticket definitions or None on failure).
  - **HOW:** Use `manual-slop_edit_file` with `old_string` (the `response = ai_client.send(...)` line + the comment block) and `new_string` (the new `result = ai_client.send_result(...)` block with `if not result.ok: ...` handling).
  - **SAFETY:** The `set_custom_system_prompt` and `set_current_tier` calls before the `send()` MUST be preserved. The `try/except` outer block at line 64 MUST be preserved.
  - **REFERENCES:** `docs/guide_ai_client.md` "Result API" section; `doeh_test_thinking_cleanup_20260615/spec.md` §3.1 (G1 fix pattern).
  - **VERIFY:** `uv run rg "ai_client\.send\(" src/conductor_tech_lead.py` returns 0 hits
  - **COMMIT:** `refactor(conductor_tech_lead): migrate to send_result() (G1, public_api_migration_and_ui_polish_20260615 Phase 1.1)`

- [ ] **Task 1.1c**: Verify the Tier 2 dispatch tests still pass
  - **Command:** `uv run pytest tests/test_conductor_tech_lead.py tests/test_orchestrator_pm.py -v 2>&1 | tee tests/artifacts/public_api_phase1_1.log` (if tests exist) OR `uv run pytest tests/ -k "conductor or tech_lead or orchestrator_pm" -v 2>&1 | tee tests/artifacts/public_api_phase1_1.log`
  - **EXPECTED:** No regression
  - **COMMIT:** No new commit; this is a verification step.

### Task 1.2: Migrate `src/orchestrator_pm.py:86` (3-arg call)

- [ ] **Task 1.2a**: Verify the call is currently using `ai_client.send()`
  - **Command:** `uv run rg "ai_client\.send\(" src/orchestrator_pm.py`
  - **EXPECTED:** 1 hit at line 86
  - **COMMIT:** No new commit.

- [ ] **Task 1.2b**: Migrate to `send_result()` with Result handling
  - **WHERE:** `src/orchestrator_pm.py:80-100` (the `try/except` block containing the call)
  - **WHAT:** Replace the `ai_client.send(md_content="", user_message=user_message, enable_tools=False)` call with the Result pattern. On error, log to comms as `WARN/orchestrator_send_failed` and `return None`.
  - **HOW:** Same pattern as Task 1.1b.
  - **SAFETY:** The `set_provider` call before the `send()` MUST be preserved.
  - **VERIFY:** `uv run rg "ai_client\.send\(" src/orchestrator_pm.py` returns 0 hits
  - **COMMIT:** `refactor(orchestrator_pm): migrate to send_result() (G2, public_api_migration_and_ui_polish_20260615 Phase 1.2)`

- [ ] **Task 1.2c**: Verify the orchestrator tests pass
  - **Command:** `uv run pytest tests/ -k "orchestrator_pm or orchestrator or tier1" -v 2>&1 | tee tests/artifacts/public_api_phase1_2.log`
  - **EXPECTED:** No regression
  - **COMMIT:** No new commit.

### Task 1.3: Migrate `src/multi_agent_conductor.py:591` (HARDEST; 8-arg call with 5 callbacks)

- [ ] **Task 1.3a**: Verify the call is currently using `ai_client.send()` and the 5 callbacks are passed
  - **Command:** `uv run rg "ai_client\.send\(" src/multi_agent_conductor.py`
  - **EXPECTED:** 1 hit at line 591; the call has `md_content=`, `user_message=`, `base_dir="."`, `pre_tool_callback=`, `qa_callback=`, `patch_callback=`, `stream_callback=`
  - **COMMIT:** No new commit.

- [ ] **Task 1.3b**: TDD red - verify a known MMA test fails with the current code (or at least the test catches the call path)
  - **Command:** `uv run pytest tests/test_mma_concurrent_tracks_sim.py tests/test_mma_step_mode_sim.py -v 2>&1 | tee tests/artifacts/public_api_phase1_3_red.log`
  - **EXPECTED:** Tests pass currently (no regression in baseline); this is a baseline check
  - **NOTE:** If tests are slow or hit live_gui, use a smaller subset: `uv run pytest tests/test_undo_redo_sim.py -v 2>&1 | tee tests/artifacts/public_api_phase1_3_red.log` (or any single MMA-adjacent test)
  - **COMMIT:** No new commit.

- [ ] **Task 1.3c**: Migrate to `send_result()` with per-ticket Result handling
  - **WHERE:** `src/multi_agent_conductor.py:580-605` (the `try/except` block containing the call)
  - **WHAT:** Replace the `ai_client.send(...)` call with `ai_client.send_result(...)`. On `!result.ok`:
    1. Log to comms via the existing `worker_comms_callback` (already set at line 587) with `WARN/worker_send_failed` and `err.ui_message()` as the status entry content
    2. Return early from `run_worker_lifecycle` with a sentinel value (e.g., `None` or `("error", err.ui_message())`); the worker exits with non-zero status
  - **HOW:** Use `manual-slop_edit_file`. The change is ~10-15 lines.
  - **SAFETY:** The `set_comms_log_callback`, `set_current_tier`, and `comms_baseline` calls before the `send_result()` MUST be preserved. The `try/except` outer block MUST be preserved.
  - **REFERENCES:** `docs/guide_mma.md` "Worker Lifecycle" section; the `doeh_test_thinking_cleanup_20260615/spec.md` G1 fix at `src/app_controller.py:265-295` is the canonical Result pattern (adapted for MMA's comms log instead of HTTPException).
  - **VERIFY:** `uv run rg "ai_client\.send\(" src/multi_agent_conductor.py` returns 0 hits
  - **COMMIT:** `refactor(multi_agent_conductor): migrate worker dispatch to send_result() (G3, public_api_migration_and_ui_polish_20260615 Phase 1.3)`

- [ ] **Task 1.3d**: Verify the MMA tests pass
  - **Command:** `uv run pytest tests/test_mma_concurrent_tracks_sim.py tests/test_mma_step_mode_sim.py tests/test_undo_redo_sim.py -v 2>&1 | tee tests/artifacts/public_api_phase1_3_green.log`
  - **EXPECTED:** No regression
  - **COMMIT:** No new commit.

### Task 1.4: Phase 1 verification

- [ ] **Task 1.4**: Full Phase 1 verification
  - **Command:** `uv run rg "ai_client\.send\(" src/` (should return 0 hits)
  - **EXPECTED:** 0 hits
  - **COMMIT:** `conductor(checkpoint): Phase 1 complete - 3 production call sites migrated to send_result()`

---

## Phase 2: Test file migration (1 day)

**Focus:** Migrate 12 test files using `ai_client.send()` to use `send_result()`. Mechanical pattern (per `doeh_test_thinking_cleanup_20260615` Phase 2).

**The canonical migration pattern:**
```python
# Before:
result = ai_client.send(md_content, user_message, base_dir)
assert result == "expected text"

# After:
result = ai_client.send_result(md_content, user_message, base_dir)
assert result.ok, f"send_result failed: {result.errors[0].ui_message() if result.errors else 'no error info'}"
assert result.data == "expected text"
```

**OR (when the test does NOT need to assert on success):**
```python
# Before:
response = ai_client.send(...)
assert response == "x"

# After:
result = ai_client.send_result(...)
assert result.ok and result.data == "x"
```

### 2A: Simple files (1 call site each, 6 files)

- [ ] **Task 2.1**: Migrate `tests/test_ai_client_cli.py:22`
  - **WHERE:** `tests/test_ai_client_cli.py:22` (`response = ai_client.send(...)`)
  - **WHAT:** Change to `result = ai_client.send_result(...)` + `assert result.ok` + use `result.data`
  - **VERIFY:** `uv run pytest tests/test_ai_client_cli.py -v` passes
  - **COMMIT:** `test(ai_client_cli): migrate to send_result() (Phase 2.1)`

- [ ] **Task 2.2**: Migrate `tests/test_ai_cache_tracking.py:47`
  - **WHERE:** `tests/test_ai_cache_tracking.py:47`
  - **VERIFY:** `uv run pytest tests/test_ai_cache_tracking.py -v` passes
  - **COMMIT:** `test(ai_cache_tracking): migrate to send_result() (Phase 2.2)`

- [ ] **Task 2.3**: Migrate `tests/test_gemini_cli_edge_cases.py:38`
  - **VERIFY:** `uv run pytest tests/test_gemini_cli_edge_cases.py -v` passes
  - **COMMIT:** `test(gemini_cli_edge): migrate to send_result() (Phase 2.3)`

- [ ] **Task 2.4**: Migrate `tests/test_gemini_cli_parity_regression.py:12`
  - **VERIFY:** `uv run pytest tests/test_gemini_cli_parity_regression.py -v` passes
  - **COMMIT:** `test(gemini_cli_parity): migrate to send_result() (Phase 2.4)`

- [ ] **Task 2.5**: Migrate `tests/test_gui2_mcp.py:47`
  - **VERIFY:** `uv run pytest tests/test_gui2_mcp.py -v` passes
  - **COMMIT:** `test(gui2_mcp): migrate to send_result() (Phase 2.5)`

- [ ] **Task 2.6**: Migrate `tests/test_token_usage.py:34`
  - **VERIFY:** `uv run pytest tests/test_token_usage.py -v` passes
  - **COMMIT:** `test(token_usage): migrate to send_result() (Phase 2.6)`

### 2B: `test_ai_client_result.py` (3 sites; includes the deprecation test)

- [ ] **Task 2.7**: Migrate `tests/test_ai_client_result.py` (3 sites) and DELETE the `test_send_deprecated_emits_warning` test (it will be obsolete in Phase 6)
  - **WHERE:** `tests/test_ai_client_result.py:10-25` (the 3 tests using `send()`)
  - **WHAT:** 
    - DELETE `test_send_deprecated_emits_warning` (line 16) - obsolete after Phase 6
    - MIGRATE the other 2 `send()` tests to `send_result()`
    - KEEP `test_send_result_does_not_emit_deprecation` (line 18) as a regression test
  - **VERIFY:** `uv run pytest tests/test_ai_client_result.py -v` passes (3 tests, not 4)
  - **COMMIT:** `test(ai_client_result): migrate to send_result(); drop test_send_deprecated (Phase 2.7)`

### 2C: `test_api_events.py` (2 sites)

- [ ] **Task 2.8**: Migrate `tests/test_api_events.py:63,106`
  - **VERIFY:** `uv run pytest tests/test_api_events.py -v` passes
  - **COMMIT:** `test(api_events): migrate 2 sites to send_result() (Phase 2.8)`

### 2D: `test_deepseek_provider.py` (6 sites)

- [ ] **Task 2.9**: Migrate `tests/test_deepseek_provider.py:31,54,96,122,142,171` (6 sites in 1 file)
  - **VERIFY:** `uv run pytest tests/test_deepseek_provider.py -v` passes (6+ tests)
  - **COMMIT:** `test(deepseek): migrate 6 sites to send_result() (Phase 2.9)`

### 2E: `test_gemini_cli_integration.py` (2 sites)

- [ ] **Task 2.10**: Migrate `tests/test_gemini_cli_integration.py:15,29`
  - **VERIFY:** `uv run pytest tests/test_gemini_cli_integration.py -v` passes
  - **COMMIT:** `test(gemini_cli_integration): migrate 2 sites to send_result() (Phase 2.10)`

### 2F: `test_tier4_interceptor.py` (1 site; complex setup)

- [ ] **Task 2.11**: Migrate `tests/test_tier4_interceptor.py:83`
  - **NOTE:** This test has complex callback setup (`qa_callback=qa_callback`); the Result handling may need `with patch('src.ai_client.send_result', return_value=Result(data="response"))` for the `qa_callback` to work
  - **VERIFY:** `uv run pytest tests/test_tier4_interceptor.py -v` passes
  - **COMMIT:** `test(tier4_interceptor): migrate to send_result() (Phase 2.11)`

### 2G: Test mock migrations for production-affected tests (added 2026-06-15 during Phase 1)

**CRITICAL DISCOVERY during Phase 1.1:** The original Phase 2 list of 12 test files covered files that *call* `ai_client.send(...)`. However, several test files use `patch('src.ai_client.send')` to *mock* the deprecated function for tests of the production code paths. When the production code is migrated to `send_result()` (Phases 1.1-1.3), the mocks receive 0 calls and the tests fail with `'send' was called 0 times`.

**Affected test files (8 discovered; the plan/spec missed them):**
- `tests/test_conductor_tech_lead.py` (3 mocks; breaks after Phase 1.1) - was the regression I hit
- `tests/test_orchestration_logic.py` (1 mock; breaks after Phase 1.1) - was the regression I hit
- `tests/test_orchestrator_pm.py` (3 mocks; breaks after Phase 1.2)
- `tests/test_orchestrator_pm_history.py` (1 mock; breaks after Phase 1.2)
- `tests/test_phase6_engine.py` (1 mock; breaks after Phase 1.3 if migration touches worker_comms_callback path)
- `tests/test_run_worker_lifecycle_abort.py` (1 mock; breaks after Phase 1.3)
- `tests/test_spawn_interception_v2.py` (1 mock; breaks after Phase 1.3)
- `tests/test_rag_integration.py` (1 mock; already pre-existing failure; deferred to RAG track per spec §7.1 OOS1)

**Migration pattern for mocks:**
```python
# Before:
with patch('src.ai_client.send') as mock_send:
    mock_send.return_value = '[{"id": "T1"}]'
    ...

# After:
with patch('src.ai_client.send_result') as mock_send_result:
    mock_send_result.return_value = Result(data='[{"id": "T1"}]')
    ...
```

Must also add `from src.result_types import Result` to imports if not already present.

- [ ] **Task 2.12**: Migrate test_conductor_tech_lead.py (3 mocks)
  - **VERIFY:** `uv run pytest tests/test_conductor_tech_lead.py -v` passes
  - **COMMIT:** `test(conductor_tech_lead): mock send_result not send (Phase 2.12, fixes Phase 1.1 regression)`

- [ ] **Task 2.13**: Migrate test_orchestration_logic.py (1 mock)
  - **VERIFY:** `uv run pytest tests/test_orchestration_logic.py -v` passes
  - **COMMIT:** `test(orchestration_logic): mock send_result not send (Phase 2.13, fixes Phase 1.1 regression)`

- [ ] **Task 2.14**: Migrate test_orchestrator_pm.py (3 mocks; pre-empt Phase 1.2 regression)
  - **VERIFY:** `uv run pytest tests/test_orchestrator_pm.py -v` passes
  - **COMMIT:** `test(orchestrator_pm): mock send_result not send (Phase 2.14, pre-empts Phase 1.2 regression)`

- [ ] **Task 2.15**: Migrate test_orchestrator_pm_history.py (1 mock; pre-empt Phase 1.2 regression)
  - **VERIFY:** `uv run pytest tests/test_orchestrator_pm_history.py -v` passes
  - **COMMIT:** `test(orchestrator_pm_history): mock send_result not send (Phase 2.15, pre-empts Phase 1.2 regression)`

- [ ] **Task 2.16**: Migrate test_phase6_engine.py (1 mock; pre-empt Phase 1.3 regression)
  - **VERIFY:** `uv run pytest tests/test_phase6_engine.py -v` passes
  - **COMMIT:** `test(phase6_engine): mock send_result not send (Phase 2.16, pre-empts Phase 1.3 regression)`

- [ ] **Task 2.17**: Migrate test_run_worker_lifecycle_abort.py (1 mock; pre-empt Phase 1.3 regression)
  - **VERIFY:** `uv run pytest tests/test_run_worker_lifecycle_abort.py -v` passes
  - **COMMIT:** `test(run_worker_lifecycle_abort): mock send_result not send (Phase 2.17, pre-empts Phase 1.3 regression)`

- [ ] **Task 2.18**: Migrate test_spawn_interception_v2.py (1 mock; pre-empt Phase 1.3 regression)
  - **VERIFY:** `uv run pytest tests/test_spawn_interception_v2.py -v` passes
  - **COMMIT:** `test(spawn_interception_v2): mock send_result not send (Phase 2.18, pre-empts Phase 1.3 regression)`

### Task 2.19: Phase 2 verification

- [ ] **Task 2.19**: Full Phase 2 verification
  - **Command:** `uv run rg "ai_client\.send\(" tests/ | grep -v test_ai_client_result.py` (should be 0 hits after Phase 2)
  - **EXPECTED:** 0 hits outside `test_ai_client_result.py` (which is handled in Task 2.7)
  - **COMMIT:** `conductor(checkpoint): Phase 2 complete - 18 test files migrated to send_result()` (11 call-site + 7 mock)

---

## Phase 3: `test_qwen_provider.py` fix (1 hour)

**Focus:** Fix the 2 pre-existing test failures in `test_qwen_provider.py` by using the `Result` API assertion pattern (mirrors what `doeh_test_thinking_cleanup_20260615` did for grok/llama).

- [ ] **Task 3.1**: TDD red - verify the 2 Qwen tests fail
  - **Command:** `uv run pytest tests/test_qwen_provider.py::test_send_qwen_routes_to_dashscope tests/test_qwen_provider.py::test_qwen_vision_vl_model_accepts_image -v 2>&1 | tee tests/artifacts/public_api_phase3_red.log`
  - **EXPECTED:** 2 failures with `AssertionError: assert 'hi from qwen' == Result(data='hi from qwen', ...)` (or similar)
  - **COMMIT:** No new commit.

- [ ] **Task 3.2**: Fix both tests
  - **WHERE:** `tests/test_qwen_provider.py:13-20` (`test_send_qwen_routes_to_dashscope`) and `:22-31` (`test_qwen_vision_vl_model_accepts_image`)
  - **WHAT:** 
    - For `test_send_qwen_routes_to_dashscope`: Change `assert result == "hi from qwen"` to `assert result.ok and result.data == "hi from qwen"`
    - For `test_qwen_vision_vl_model_accepts_image`: Change `assert "cat" in result.lower()` to `assert result.ok and "cat" in result.data.lower()`
  - **HOW:** Use `manual-slop_edit_file` with the exact old/new strings.
  - **REFERENCES:** `doeh_test_thinking_cleanup_20260615/plan.md` Task 2.4 (test_llama_ollama_native pattern is the closest reference).
  - **VERIFY:** `uv run pytest tests/test_qwen_provider.py -v` passes (5/5)
  - **COMMIT:** `test(qwen): adapt 2 tests to Result API (Phase 3, fixes 2 pre-existing failures)`

- [ ] **Task 3.3**: Verify no regression
  - **Command:** `uv run pytest tests/test_qwen_provider.py tests/test_minimax_provider.py tests/test_grok_provider.py tests/test_llama_provider.py tests/test_llama_ollama_native.py -v 2>&1 | tee tests/artifacts/public_api_phase3_green.log`
  - **EXPECTED:** All vendor tests pass
  - **COMMIT:** No new commit.

---

## Phase 4: `test_symbol_parsing.py` fix (30 min)

**Focus:** Fix the 2 pre-existing test failures by mocking `send_result` not `send`.

- [ ] **Task 4.1**: TDD red - verify the 2 symbol_parsing tests fail
  - **Command:** `uv run pytest tests/test_symbol_parsing.py -v 2>&1 | tee tests/artifacts/public_api_phase4_red.log`
  - **EXPECTED:** 2 failures with `Expected 'send' to have been called once. Called 0 times.`
  - **COMMIT:** No new commit.

- [ ] **Task 4.2**: Fix both tests
  - **WHERE:** `tests/test_symbol_parsing.py:45,74`
  - **WHAT:** 
    - For `test_handle_request_event_appends_definitions` (line 45): Change `patch('src.ai_client.send') as mock_send` to `patch('src.ai_client.send_result') as mock_send_result` AND add `mock_send_result.return_value = Result(data="mocked response")` to the with block
    - For `test_handle_request_event_no_symbols` (line 74): Same pattern
  - **HOW:** Use `manual-slop_edit_file`. Add `from src.result_types import Result` to imports if not already present.
  - **REFERENCES:** `doeh_test_thinking_cleanup_20260615/plan.md` Task 2.7 (the headless_service `test_generate_endpoint` mock migration is the canonical reference).
  - **VERIFY:** `uv run pytest tests/test_symbol_parsing.py -v` passes (2/2)
  - **COMMIT:** `test(symbol_parsing): mock send_result not send (Phase 4, fixes 2 pre-existing failures)`

- [ ] **Task 4.3**: Verify no regression
  - **Command:** `uv run pytest tests/test_symbol_parsing.py tests/test_api_events.py -v 2>&1 | tee tests/artifacts/public_api_phase4_green.log`
  - **EXPECTED:** No regression
  - **COMMIT:** No new commit.

---

## Phase 5: UI Polish test fixes (30 min)

**Focus:** Fix the 2 pre-existing test failures in `test_discussion_truncate_layout.py` and `test_log_management_refresh.py`. The production code is already correct (user commits `d0b06575` and `df7bda6e`); the test `find()` logic locates the comment block instead of the actual code.

- [ ] **Task 5.1**: TDD red - verify the 2 UI Polish tests fail
  - **Command:** `uv run pytest tests/test_discussion_truncate_layout.py tests/test_log_management_refresh.py -v 2>&1 | tee tests/artifacts/public_api_phase5_red.log`
  - **EXPECTED:** 2 failures with `AssertionError: ... 'set_next_item_width(140)' in ...` (truncated snippet) and similar for the second test
  - **COMMIT:** No new commit.

- [ ] **Task 5.2**: Fix `test_discussion_truncate_layout.py`
  - **WHERE:** `tests/test_discussion_truncate_layout.py:7` (`idx = src.find(marker)`)
  - **WHAT:** Change `src.find(marker)` to `src.rfind(marker)`. The `find()` locates the comment block at line 5113; `rfind()` locates the actual code at line 5130.
  - **HOW:** Use `manual-slop_edit_file` with `old_string` = `idx = src.find(marker)` and `new_string` = `idx = src.rfind(marker)`.
  - **VERIFY:** `uv run pytest tests/test_discussion_truncate_layout.py -v` passes (1/1)
  - **COMMIT:** `test(discussion_truncate): use rfind() to locate code (Phase 5.1, fixes 1 pre-existing failure)`

- [ ] **Task 5.3**: Fix `test_log_management_refresh.py`
  - **WHERE:** `tests/test_log_management_refresh.py:6` (`idx = src.find(marker)`)
  - **WHAT:** Change `src.find(marker)` to `src.rfind(marker)`. The `find()` locates the comment block at line 2090; `rfind()` locates the actual code at line 2111.
  - **HOW:** Same as Task 5.2.
  - **VERIFY:** `uv run pytest tests/test_log_management_refresh.py -v` passes (1/1)
  - **COMMIT:** `test(log_management_refresh): use rfind() to locate code (Phase 5.2, fixes 1 pre-existing failure)`

- [ ] **Task 5.4**: Verify no regression
  - **Command:** `uv run pytest tests/test_discussion_truncate_layout.py tests/test_log_management_refresh.py -v 2>&1 | tee tests/artifacts/public_api_phase5_green.log`
  - **EXPECTED:** 2/2 pass
  - **COMMIT:** No new commit.

---

## Phase 6: Deprecation removal (30 min)

**Focus:** Remove the legacy `send()` function + the `filterwarnings` entry + the obsolete test file. **MUST be after Phases 1 + 2 + 3 + 4 + 5** (so no caller is left using `send()`).

- [ ] **Task 6.1**: TDD red - verify no caller of `send()` remains in `src/` or `tests/`
  - **Command:** `uv run rg "ai_client\.send\(" src/ tests/ | wc -l` (should return 0)
  - **EXPECTED:** 0 hits
  - **COMMIT:** No new commit.

- [ ] **Task 6.2**: Remove the `@deprecated` decorator and the legacy `send()` function in `src/ai_client.py`
  - **WHERE:** `src/ai_client.py:2939-3040` (the `def send(...)` function with the `@deprecated` decorator at line 2939)
  - **WHAT:** Delete the decorator and the entire function body. The `send_result()` function (at line 3002) is the permanent replacement.
  - **HOW:** Use `manual-slop_edit_file` or `set_file_slice` to delete the range. Verify the line range first with `get_file_slice`.
  - **SAFETY:** The function is the ONLY public `send()`; all production and test callers have been migrated in Phases 1-5. Verify `rg "ai_client\.send\(" src/ tests/` returns 0 BEFORE the deletion.
  - **REFERENCES:** `conductor/tracks/data_oriented_error_handling_20260606/spec.md` §3.5 (deprecation strategy).
  - **VERIFY:** `uv run rg "def send\(" src/ai_client.py` returns 0 hits (only `def send_result(` should remain)
  - **COMMIT:** `refactor(ai_client): remove deprecated send() function (Phase 6.1)`

- [ ] **Task 6.3**: Delete `tests/test_deprecation_warnings.py`
  - **WHERE:** `tests/test_deprecation_warnings.py` (entire file, 25 lines)
  - **WHAT:** Delete the file. Both tests in it are obsolete:
    - `test_send_deprecated_warning_emitted_once_per_site` — cannot run after `send()` is removed
    - `test_send_result_does_not_emit_deprecation` — trivially true after `send()` is removed
  - **HOW:** `rm tests/test_deprecation_warnings.py` (or use the file removal MCP tool if available)
  - **VERIFY:** `uv run pytest tests/test_deprecation_warnings.py -v 2>&1` should fail with "file not found"
  - **COMMIT:** `test(ai_client): delete obsolete test_deprecation_warnings.py (Phase 6.2)`

- [ ] **Task 6.4**: Remove the `filterwarnings` entry in `pyproject.toml`
  - **WHERE:** `pyproject.toml:46-47` (the `filterwarnings = [...]` block)
  - **WHAT:** Delete the `"ignore:Use ai_client.send_result.*:DeprecationWarning"` line. If the `filterwarnings` block becomes empty after the deletion, delete the block entirely.
  - **HOW:** Use `manual-slop_edit_file` with `old_string` and `new_string`.
  - **VERIFY:** `uv run rg "ignore:Use ai_client.send_result" pyproject.toml` returns 0 hits
  - **COMMIT:** `chore(pyproject): remove send_result deprecation filterwarnings (Phase 6.3)`

- [ ] **Task 6.5**: Phase 6 verification
  - **Command:** `uv run rg "ai_client\.send\(" src/ tests/ pyproject.toml` (should return 0)
  - **EXPECTED:** 0 hits
  - **COMMIT:** `conductor(checkpoint): Phase 6 complete - deprecation removed`

---

## Phase 7: Docs + housekeep (1 hour)

**Focus:** Update docs, run the full test suite, update metadata + tracks.md, attach final report.

- [ ] **Task 7.1**: Update `docs/guide_ai_client.md` to remove deprecation references
  - **WHERE:** `docs/guide_ai_client.md` (search for "deprecat" case-insensitive)
  - **WHAT:** Remove or update any mention of "deprecat" + "send()" together. The Result API section should no longer note "send() is deprecated".
  - **HOW:** Use `manual-slop_edit_file` per occurrence.
  - **VERIFY:** `uv run rg -i "deprecat" docs/guide_ai_client.md | grep -i send` returns 0 hits
  - **COMMIT:** `docs(ai_client): remove send() deprecation references (Phase 7.1)`

- [ ] **Task 7.2**: Update `conductor/product-guidelines.md` to remove deprecation language
  - **WHERE:** `conductor/product-guidelines.md` (search for "deprecat" case-insensitive)
  - **WHAT:** Mark the "Public API deprecation" section as RESOLVED. Remove or update "send() is deprecated; use send_result()" mentions.
  - **HOW:** Use `manual-slop_edit_file` per occurrence.
  - **VERIFY:** `uv run rg -i "send.*deprecat|deprecat.*send" conductor/product-guidelines.md` returns 0 hits
  - **COMMIT:** `docs(product): mark public API deprecation as resolved (Phase 7.2)`

- [ ] **Task 7.3**: Run the full test suite
  - **Command:** `uv run pytest tests/ 2>&1 | tee tests/artifacts/public_api_phase7_full.log`
  - **EXPECTED:** 4 fewer failures than pre-track baseline (10 - 6 = 4 RAG failures remain)
  - **ACTION:** If NEW failures appear (not in the 4 RAG pre-existing list), STOP and report to the user.
  - **COMMIT:** No new commit; this is a verification step.

- [ ] **Task 7.4**: Update `metadata.json` to mark the track complete
  - **WHERE:** `conductor/tracks/public_api_migration_and_ui_polish_20260615/metadata.json`
  - **WHAT:** Change `"status": "active"` to `"status": "completed"`. Update `verification_criteria` to reflect what was actually verified.
  - **HOW:** Direct file edit.
  - **COMMIT:** `conductor(track): mark public_api_migration_and_ui_polish_20260615 as completed`

- [ ] **Task 7.5**: Conductor - User Manual Verification (Protocol in workflow.md)
  - **ACTION:** Announce the track is complete. Provide the user with a summary of the 18 fixes (3 production + 12 test + 4 pre-existing-failure + 1 deprecation removal + 2 doc updates) and the test delta (1280 + 6 = 1286 pass; 4 RAG failures deferred).

---

## Summary

- **Total tasks:** ~28 (across 7 phases)
- **Total atomic commits:** ~28 (1 per task) + 6 phase checkpoints = ~28
- **Total estimated effort:** 2-3 days Tier 2 work (16-24 hours)
- **Dependencies:** None (independent track; no `blocked_by`)
- **Out of scope (deferred to separate tracks, documented in spec §7):**
  - 4 RAG test fixes (separate RAG subsystem track)
  - The `_send_<vendor>()` → `_send_<vendor>_result()` rename (not needed; tests work with current names)
  - 23 lower-impact weak-type files (next major track: `data_structure_strengthening_20260606`)
  - `live_gui_mock_injection_20260615` infrastructure (separate infrastructure track)

## Test count math

- **Pre-track baseline:** 1280 pass + 4 skip + 10 fail (verified 2026-06-15)
- **After this track:** 1286 pass + 4 skip + 4 fail (6 newly-passing: 2 Qwen + 2 symbol_parsing + 1 truncate + 1 refresh)
- **The 4 remaining failures are all RAG subsystem; deferred to the next track**
