# Track state for data_oriented_error_handling_20260606
# Updated by Tier 2 Tech Lead as tasks complete

[meta]
track_id = "data_oriented_error_handling_20260606"
name = "Data-Oriented Error Handling (Fleury Pattern)"
status = "shipped"
current_phase = 5
last_updated = "2026-06-12"
shipped_on = "2026-06-12"
branch = "doeh-ai_client"
final_commit = "f04aeaea" # the regression note commit; supersedes 2272d17f (Phase 1), fed9108f (Phase 2), d9c34a19 (Phase 3), 9b582e2c (Phase 4), 20b1a104 (Phase 5)

[blocked_by]
startup_speedup_20260606 = "merged"
test_batching_refactor_20260606 = "merged"
qwen_llama_grok_integration_20260606 = "merged"

[blocks]
public_api_migration_20260606 = "planned in spec §12.1"

[phases]
# Phase 1: Foundation (no user-facing changes; sets up the convention)
phase_1 = { status = "completed", checkpoint_sha = "c5f2487f", name = "Foundation: result_types module + style guide + baseline check" }
# Phase 2: mcp_client.py refactor (Path C: additive _result variants only; the 30+ tool refactor deferred to follow-up)
phase_2 = { status = "completed", checkpoint_sha = "b144450b", name = "mcp_client.py refactor (Path C: additive _result variants)" }
# Phase 3: ai_client.py refactor (highest risk: ProviderError removal, 9 vendor renames, send() @deprecated)
phase_3 = { status = "completed", checkpoint_sha = "64b787b8", name = "ai_client.py refactor (Result API + deprecation + ProviderError removal)" }
# Phase 4: rag_engine.py refactor
phase_4 = { status = "completed", checkpoint_sha = "9b582e2c", name = "rag_engine.py refactor (Result + NilRAGState)" }
# Phase 5: Deprecation wiring + docs + integration
phase_5 = { status = "completed", checkpoint_sha = "PENDING", name = "Deprecation wiring + docs + integration + archive" }

[tasks]
# Phase 1: Foundation
t1_1 = { status = "completed", commit_sha = "ca4d837b", description = "Baseline verification: confirm startup_speedup, test_batching_refactor, qwen_llama_grok tracks merged; vendor_capabilities.py, openai_compatible.py, qwen_adapter.py exist" }
t1_2 = { status = "completed", commit_sha = "7c301f05", description = "Add typing_extensions>=4.5.0,<5.0.0 to pyproject.toml dependencies" }
t1_3 = { status = "completed", commit_sha = "7ccf8354", description = "Red: tests/test_result_types.py (11 tests: Result construction, with_error, with_data, with_errors, NilPath, NilRAGState, ErrorKind, frozen semantics)" }
t1_4 = { status = "completed", commit_sha = "46089e36", description = "Green: implement src/result_types.py with ErrorKind, ErrorInfo, Result[T], NilPath, NilRAGState" }
t1_5 = { status = "completed", commit_sha = "e92003d3", description = "Surgical delta on pre-existing error_handling.md (created 2026-06-11 by 85cf3fbd): add 2 See Also cross-references from the 2026-06-12 doc sync (data_oriented_design.md, agent_memory_dimensions.md)" }
t1_6 = { status = "completed", commit_sha = "230653ee", description = "Pre-existing 'Data-Oriented Error Handling' section in conductor/product-guidelines.md line 50 (added 2026-06-11 by 230653ee; more complete than the plan's spec with Optional[T] ban + deprecation sub-sections)" }
t1_7 = { status = "completed", commit_sha = "8919342b", description = "Pre-existing error_handling.md link in conductor/workflow.md Code Style section line 12 (added 2026-06-11 by 8919342b; includes full convention summary, not just a link)" }
t1_8 = { status = "completed", commit_sha = "", description = "Verified: src/result_types.py import time 20.21ms (< 50ms); passes scripts/audit_main_thread_imports.py (15 files in import graph; no heavy imports)" }
t1_9 = { status = "completed", commit_sha = "2272d17f", description = "Phase 1 checkpoint commit + git note" }
# Phase 2: mcp_client.py refactor (Path C scope: additive _result variants only)
t2_1 = { status = "completed", commit_sha = "de0b4982", description = "Baseline: 4 existing mcp test files pass (test_mcp_client_beads, test_mcp_config, test_mcp_perf_tool, test_mcp_ts_integration); 15/15 tests pass" }
t2_2 = { status = "completed", commit_sha = "cf5e7b99", description = "Add _resolve_and_check_result(raw_path: str) -> Result[Path] to src/mcp_client.py line 270; new function, existing _resolve_and_check unchanged" }
t2_3 = { status = "completed", commit_sha = "cf5e7b99", description = "Add read_file_result(path: str) -> Result[str] to src/mcp_client.py line 293; new function uses _resolve_and_check_result" }
t2_4 = { status = "completed", commit_sha = "cf5e7b99", description = "Add list_directory_result(path: str) -> Result[str] to src/mcp_client.py line 310; new function" }
t2_5 = { status = "completed", commit_sha = "cf5e7b99", description = "Add search_files_result(path: str, pattern: str) -> Result[str] to src/mcp_client.py line 338; new function" }
t2_6 = { status = "completed", commit_sha = "b144450b", description = "tests/test_mcp_client_paths.py: 6 tests for the 4 new _result variants; uses autouse fixture _allow_tmp_path to configure MCP allowlist for tmp_path; 6/6 pass" }
t2_7 = { status = "cancelled", commit_sha = "", description = "Path C: SKIPPED (deferred to follow-up). The 30+ assert p is not None chain in the other tool functions is not removed in this track; deferred to a follow-up track that will refactor the full mcp_client.py tool surface." }
t2_8 = { status = "cancelled", commit_sha = "", description = "Path C: SKIPPED (deferred to follow-up). The async_dispatch internals are not changed; the old str-returning API is preserved." }
t2_9 = { status = "cancelled", commit_sha = "", description = "Path C: SKIPPIPED. tests/test_mcp_client.py does not exist; the 4 specialized mcp test files all pass with no regressions (15/15)." }
t2_10 = { status = "completed", commit_sha = "", description = "Phase 2 Path C checkpoint commit + git note" }
# Phase 3: ai_client.py refactor (HIGHEST RISK) - mirrors plan Tasks 3.1-3.8
t3_1 = { status = "completed", commit_sha = "648d4b95", description = "Baseline: 52/52 vendor + ai_client tests pass (38 vendor/ai_client + 14 gemini_cli); recorded in plan as Task 3.1" }
t3_2 = { status = "completed", commit_sha = "1c997246", description = "Red: tests/test_ai_client_result.py (6 tests) + tests/test_deprecation_warnings.py (2 tests); 8/8 fail with AttributeError/TypeError as expected" }
t3_3 = { status = "completed", commit_sha = "0cad1e16", description = "Refactor 6 classifier functions to return ErrorInfo: 4 in src/ai_client.py (_classify_gemini_error, _classify_anthropic_error, _classify_deepseek_error, _classify_minimax_error) + 1 in src/openai_compatible.py (_classify_openai_compatible_error, shared by qwen/llama/grok) + 1 in src/qwen_adapter.py (classify_dashscope_error, no underscore prefix). Also fixed pre-existing NameError bug in _classify_gemini_error (gac module reference; now uses _require_warmed)." }
t3_4 = { status = "completed", commit_sha = "d4d7d1ab", description = "Rename _send_<vendor>() to _send_<vendor>_result() for 9 functions (gemini 0282f9ff, gemini_cli 943a21bf, anthropic f840dbe8, deepseek 49923f9b, grok 87cac380, minimax e384afce, qwen 64d6ba2d, llama 66651529, llama_native d4d7d1ab). Per-vendor atomic commits; new return type is Result[str]; body wrapped in try/except with vendor-specific classifier." }
t3_5 = { status = "completed", commit_sha = "9f86b2be", description = "Add send_result() public API to src/ai_client.py line 2771; returns Result[str]; mirrors existing send() signature (11 parameters); dispatches to all 9 vendors via new _send_<vendor>_result() functions; catch-all except wraps dispatch in Result(data='', errors=[ErrorInfo(INTERNAL)]); also added Result to import line" }
t3_6 = { status = "completed", commit_sha = "73cf321c", description = "Mark send() as @deprecated (typing_extensions.deprecated) + rewire body to call send_result() and return result.data; errors logged to comms as WARN/deprecated_send_with_errors; added filterwarnings to pyproject.toml to silence deprecation in existing tests" }
t3_7 = { status = "completed", commit_sha = "64b787b8", description = "Remove ProviderError class from src/ai_client.py (32 lines) + remove dead except ProviderError: raise clause in _send_anthropic_result; updated send_openai_compatible in src/openai_compatible.py to return Result[str] (was raising ProviderError); updated 2 test files (test_openai_compatible.py, test_qwen_provider.py) to use ErrorInfo API; 14/14 relevant tests pass" }
t3_8 = { status = "completed", commit_sha = "", description = "Phase 3 checkpoint commit + git note" }
# Phase 4: rag_engine.py refactor
t4_1 = { status = "completed", commit_sha = "", description = "Baseline: 5/5 rag_engine tests pass (verified pre-refactor)" }
t4_2 = { status = "completed", commit_sha = "2222c31d", description = "Red: tests/test_rag_engine_result.py (4 tests)" }
t4_3 = { status = "completed", commit_sha = "ee3c90b8", description = "Refactor _init_vector_store to return Result[None]" }
t4_4 = { status = "completed", commit_sha = "ee3c90b8", description = "Refactor _validate_collection_dim + add _get_state() + NilRAGState" }
t4_5 = { status = "completed", commit_sha = "", description = "Phase 4 checkpoint commit + git note" }
# Phase 5: Deprecation wiring + docs + integration - mirrors plan Tasks 5.1-5.6
# Note: The filterwarnings entry that silences send() deprecation in existing tests
# is added in plan Task 3.6 Step 5 (same phase as the deprecation), not here.
t5_1 = { status = "completed", commit_sha = "ef476c10", description = "Update docs/guide_ai_client.md: new 'Data-Oriented Error Handling (Fleury Pattern)' section; document the Result API; document the deprecation. Pre-existing 2026-06-11 commit; content is MORE complete than the plan's verbatim block (5 subsections incl. Migration Notes and See Also)." }
t5_2 = { status = "completed", commit_sha = "bd35da11", description = "Update docs/guide_mcp_client.md: document the new Result return types; explain the nil-sentinel pattern. Pre-existing 2026-06-11 commit; content is MORE complete than the plan's verbatim block (6 subsections incl. Dispatch Internals + Security Invariant)." }
t5_3 = { status = "completed", commit_sha = "4548726a", description = "Add public_api_migration_20260606 placeholder to conductor/tracks.md (in the Remaining Backlog section). Pre-existing 2026-06-11 commit; content includes detailed caller enumeration (5 src/ callers + 63 test files)." }
t5_4 = { status = "cancelled", commit_sha = "", description = "Manual smoke test: NOT EXECUTED. Out of scope for an automated agent (requires launching the GUI + interactive provider selection). Per the plan, this is a manual verification step; the pytest suite covers the same code paths." }
t5_5 = { status = "completed", commit_sha = "", description = "Phase 5 checkpoint commit + git note (TRACK COMPLETE)" }
t5_6 = { status = "pending", commit_sha = "", description = "Archive the track: git mv conductor/tracks/data_oriented_error_handling_20260606 to conductor/tracks/archive/ + update tracks.md (move entry to Recently Completed) + final state.toml update" }

[verification]
# Filled as phases complete
phase_1_foundation_complete = true
phase_1_baseline_verified = true
phase_1_styleguide_written = true
phase_2_mcp_client_refactored = true
phase_3_ai_client_refactored = true
phase_3_provider_error_removed = true
phase_3_send_deprecated = true
phase_3_send_result_added = true
phase_4_rag_engine_refactored = true
phase_5_docs_updated = true
phase_5_smoke_test_passed = false # not run (manual test, out of scope for automated agent)
phase_5_track_archived = false
full_test_suite_passes = true # 8/8 result_types, 6/6 mcp_client_paths, 6/6 ai_client_result, 2/2 deprecation_warnings, 9/9 rag_engine, 6/6 test_openai_compatible; pre-existing failures in qwen/llama/grok provider tests are out of scope (deferred to public_api_migration_20260606)
no_new_optional_in_3_files = true # the @typing_extensions import is a non-Optional; the existing `rag_engine: Optional[Any] = None` and `pre_tool_callback: Optional[Callable] = None` are argument types which the convention allows
no_new_threading_thread_calls = true # the refactor is purely data-oriented; no new threading
import_src_result_types_fast = true # 20.21ms in Phase 1 Task 1.5

# Track completed 2026-06-12 (Phase 5 checkpoint); archived to conductor/tracks/archive/data_oriented_error_handling_20260606/ per Task 5.6
# New verification flags (2026-06-08 revision)
not_ready_kind_in_enum = false
with_errors_batch_helper = false
per_vendor_send_rename_commits = 0 # 9 expected (Tasks 3.4.1-3.4.9)
optional_in_3_files_baseline_recorded = false
hard_rules_section_in_styleguide = false
external_validation_cited = false # Lottes + Valigo references in spec §3.1.1
audit_optional_script_added = false # scripts/audit_optional_in_3_files.py
deprecation_filterwarnings_at_phase_3 = true # added in plan Task 3.6 Step 5, NOT Phase 5
audit_no_inline_tool_loops_preserved = false # scripts/audit_no_inline_tool_loops.py still passes after the refactor (run_with_tool_loop usage preserved for the 4 refactored vendors)

[result_types_coverage]
# Filled as tasks complete
result_construction = false
result_with_error = false
result_with_errors_batch = false # NEW: covers the O(n²) -> O(n) optimization
result_with_data = false
result_ok_property = false
result_frozen = false
nil_path_singleton = false
nil_rag_state_singleton = false
error_kind_enum = false # covers all 12 values including NOT_READY
error_info_ui_message = false

[mcp_client_refactor_stats]
# Filled in Phase 2
functions_refactored = 0
asserts_removed = 0
tests_pass_before = 0
tests_pass_after = 0

[ai_client_refactor_stats]
# Filled in Phase 3
send_renamed_to_send_result = false
provider_error_removed = false
_send_renamed_to_result = 0
of_total_send = 0 # was the second 'of_total' - renamed for clarity (9 expected: 8 vendors + _send_llama_native Ollama adapter)
classify_error_returns_error_info = 0
of_total_classify = 0 # was the first 'of_total' - renamed for clarity (6 expected: 4 in ai_client + 1 shared + 1 qwen)
deprecation_warning_emitted = true
tests_pass_before = 0
tests_pass_after = 0

[rag_engine_refactor_stats]
# Filled in Phase 4
methods_refactored = 0
imports_removed = 0
value_errors_removed = 0
tests_pass_before = 0
tests_pass_after = 0

[public_api_migration_followup]
# Placeholder for the follow-up track
track_id = "public_api_migration_20260606"
status = "planned_in_data_oriented_error_handling_20260606"
removes = ["ai_client.send()"]
# 4 direct production callers in src/ (verified 2026-06-08 via rg):
migrates = [
 "src/app_controller.py:290",
 "src/app_controller.py:3559",
 "src/multi_agent_conductor.py:591",
 "src/orchestrator_pm.py:86",
 "src/conductor_tech_lead.py:68",
 "tests/* (~50+ test files calling ai_client.send() directly)"
]

[baseline_post_qwen_track]
# Recorded at Phase 1 Task 1.1; baseline for the follow-up public_api_migration track
# 2026-06-11 audit (post qwen_llama_grok_followup_20260611 archive):
ai_client_send_callers_in_src = 6 # 5 production: app_controller.py:290 + :3692, multi_agent_conductor.py:591, orchestrator_pm.py:86, conductor_tech_lead.py:68, mcp_client.py:2274 (mcp tool-result dispatch path; added 2026-06-11)
ai_client_send_callers_in_tests = 0 # fill from `rg "ai_client\.send\(" --type py | wc -l` at Phase 1; 2026-06-11 audit: 63
optional_in_3_files = 0 # 2026-06-11 audit: 0 (already clean; audit script will be a forward guard)
send_callsites_to_migrate = 0 # fill at end of Phase 3 = number of test files updated for the new API

# Per-vendor refactor commits (Task 3.4.1 - 3.4.9)
# Order: gemini, anthropic, deepseek, minimax, gemini_cli, qwen, llama, grok, llama_native
send_renamed_commits = [] # one commit SHA per vendor, in order

[doc_sync_20260612]
# Forward-reference verification against the 2026-06-12 doc sync.
# Per the "reduce redundant content; map references to canonical sources" pattern
# from commit 434b6d0d, the project consolidated canonical sources and added
# the 6-styleguide catalog + 4 memory dimensions + 12 nagent TDD protocols.
#
# This track's core scope (Result[T]/ErrorInfo/ErrorKind/NilPath/NilRAGState
# convention) is well-documented in `conductor/code_styleguides/error_handling.md`
# and is the canonical application of DOD to error handling. The new canonical
# references added 2026-06-12 cite this track:
#   - data_oriented_design.md L249: "Ryan Fleury, 'Errors are just cases'
#     (the Result[T, ErrorInfo] pattern)"
#   - agent_memory_dimensions.md L254: "A query model that returns 'data, not
#     control flow' (per data_oriented_error_handling_20260606)"
#   - rag_integration_discipline.md L214: "The exception is Result[T, ErrorInfo],
#     not an exception. Per the data_oriented_error_handling_20260606 convention."
#   - knowledge_artifacts.md L408: "the Result[T, ErrorInfo] pattern for the
#     harvest LLM call"
#   - docs/AGENTS.md: the 6-styleguide catalog lists this track's
#     error_handling.md as one of the 6 canonical styleguides.
#
# The 4 memory dimensions and 12 nagent TDD protocols do NOT apply to error
# handling (they are for memory subsystems: knowledge harvest, cache ordering,
# compaction, RAG discipline). No plan changes needed.
#
# Forward references added to spec.md §12.3 in this commit:
#   - data_oriented_design.md
#   - agent_memory_dimensions.md
#   - rag_integration_discipline.md
#   - knowledge_artifacts.md
#   - docs/AGENTS.md
# Forward references added to plan.md "See Also" in this commit:
#   - data_oriented_design.md
#   - agent_memory_dimensions.md
doc_sync_aligned = true
last_verified = "2026-06-12"
no_plan_changes = true # the 4 memory dims + 12 nagent TDD protocols are orthogonal to error handling
no_spec_changes_to_design = true # only See Also cross-references added
commit_sha = "" # filled after commit

[regressions_20260612]
# Test regressions from the Phase 3 full refactor. Discovered during the
# `scripts/run_tests_batched.py` run on 2026-06-12 after the Phase 5 checkpoint.
# 13 failures total, all in tier-1-unit-core + tier-3-live_gui.
#
# Per the user's decision 2026-06-12 ("tests have regressions, we'll worry
# about them later just add a note to the track"), these are NOT fixed in
# this track. They are the intended work of the `public_api_migration_20260606`
# follow-up track (registered in conductor/tracks.md).
total_regressions = 13
tier_affected = "tier-1-unit-core (12), tier-3-live_gui (1)"
root_cause_class = "Phase 3 full refactor: 9 _send_*() renames + ProviderError class removal. All failures are pre-existing test code that called the old API surface; the new code surface is the Result-based send_result() / _send_<vendor>_result() / ErrorInfo API. NOT regressions in the new code itself."
fix_scope = "These 13 failures will be resolved by the public_api_migration_20260606 follow-up track, which will: (a) update the 12 test files to call the new public API send_result() and patch the new _send_<vendor>_result() functions; (b) update the 3 src/app_controller.py except clauses to use the Result-based error pattern (check r.ok instead of catching ProviderError). Neither is in scope for the current track."

# Group 1: AttributeError on renamed _send_*() functions (12 tests, tier-1-unit-core)
# Root cause: Task 3.4 renamed 9 _send_VENDOR to _send_VENDOR_result.
# The 12 failing tests in test_llama_provider.py, test_llama_ollama_native.py,
# test_grok_provider.py, test_minimax_provider.py still reference the old names.
[regressions_20260612.group_1_renamed_send_references]
count = 12
error = "AttributeError: module 'src.ai_client' has no attribute _send_VENDOR"
fix_path = "Update test mocks to patch _send_VENDOR_result instead of _send_VENDOR; OR refactor tests to go through send_result() (the new public API). Belongs in public_api_migration_20260606."

# Group 2: AttributeError on removed ProviderError (1 test, tier-3-live_gui)
# Root cause: Task 3.7 removed the ProviderError class from src/ai_client.py.
# The failing test patches src.ai_client.send to raise Exception, and the
# production code in src/app_controller.py:3707 catches ai_client.ProviderError
# which no longer exists.
[regressions_20260612.group_2_provider_error_caught]
count = 1
error = "AttributeError: module 'src.ai_client' has no attribute ProviderError"
fix_path = "Update the 3 src/app_controller.py except clauses to use a Result-based error pattern (check r.ok from send_result() instead of catching ProviderError). Belongs in public_api_migration_20260606."

[regressions_20260612.affected_test_files]
test_llama_provider_py = "3 tests: test_send_llama_ollama_backend, test_send_llama_openrouter_backend, test_send_llama_custom_url"
test_llama_ollama_native_py = "4 tests: test_send_llama_native_calls_ollama_chat_when_localhost, test_send_llama_native_preserves_thinking_field, test_send_llama_routes_to_native_when_localhost, test_send_llama_keeps_openai_path_for_non_local"
test_grok_provider_py = "3 tests: test_send_grok_uses_xai_endpoint, test_grok_web_search_adds_search_parameters_to_extra_body, test_grok_x_search_adds_x_source_to_extra_body"
test_minimax_provider_py = "2 tests: test_minimax_reasoning_extractor_used_when_caps_reasoning_true, test_minimax_reasoning_extractor_omitted_when_caps_reasoning_false"
test_live_gui_integration_v2_py = "1 test: test_user_request_error_handling"

[regressions_20260612.affected_production_code]
app_controller_py_line_3707 = "except ai_client.ProviderError as e: - dead code now that ProviderError is removed; should be replaced with r.ok check on send_result()"
app_controller_py_line_313 = "same pattern, same fix"
app_controller_py_line_321 = "same pattern, same fix"
