diff --git a/conductor/code_styleguides/error_handling.md b/conductor/code_styleguides/error_handling.md index a35d59a5..d124e823 100644 --- a/conductor/code_styleguides/error_handling.md +++ b/conductor/code_styleguides/error_handling.md @@ -201,7 +201,7 @@ The 3 refactored subsystems demonstrate each pattern in context: removed. - **`src/ai_client.py`** — `_send__result()` returns `Result[str]` (8 vendors: gemini, anthropic, deepseek, minimax, gemini_cli, qwen, llama, - grok); `send_result()` is the new public API; `send()` is `@deprecated`. + grok); `send(...) -> Result[str, ErrorInfo]` is the public API. - **`src/rag_engine.py:100-180`** — `_init_vector_store_result`, `_validate_collection_dim_result`, `is_empty_result`, `add_documents_result` return `Result[None]` or `Result[T]`; broad `except Exception` blocks @@ -329,7 +329,7 @@ async def _api_get_key(controller, header_key: str) -> str: # Compliant: broad catch + HTTPException at the FastAPI boundary async def _api_generate(controller, payload): try: - result = ai_client.send_result(...) + result = ai_client.send(...) return result.data except Exception as e: raise HTTPException(status_code=500, detail=f"AI call failed: {e}") @@ -620,22 +620,19 @@ When converting existing code: --- -## Deprecation: `ai_client.send()` → `ai_client.send_result()` +## Historical deprecation (added 2026-06-15, reverted 2026-06-16) -The public `ai_client.send()` is marked `@deprecated` (via -`typing_extensions.deprecated`, the Python 3.11+ backport of -`@warnings.deprecated`). It still works for backward compat but emits a -`DeprecationWarning` at runtime. New code MUST use `ai_client.send_result()`. +The public `ai_client.send()` was briefly marked `@deprecated` in favor of +`ai_client.send_result()` on 2026-06-15 by the +`public_api_migration_and_ui_polish_20260615` track. The decision was +reverted on 2026-06-16 by `send_result_to_send_20260616` after the +Tier 2 autonomous sandbox proved capable of doing the rename safely. -- `send_result(...) -> Result[str, ErrorInfo]` — the new public API. -- `send(...) -> str` — **deprecated.** Returns `str` for backward compat; - errors are logged to the comms log but not returned. -- Removal timeline: `public_api_migration_20260606` follow-up track. - -The deprecation warning is cached per call site (Python's `__warningregistry__`) -to avoid log spam. `tests/conftest.py` adds a `filterwarnings` entry to -silence the warning during the transition; new tests for the new API should -assert the warning is NOT emitted by `send_result()`. +`ai_client.send(...) -> Result[str, ErrorInfo]` is the canonical public API. +No deprecation is in effect. For the historical record of the brief +deprecation cycle, see +`conductor/tracks/public_api_migration_and_ui_polish_20260615/spec.md` +and `conductor/tracks/send_result_to_send_20260616/spec.md`. --- diff --git a/docs/guide_ai_client.md b/docs/guide_ai_client.md index 76242f85..9f8a016b 100644 --- a/docs/guide_ai_client.md +++ b/docs/guide_ai_client.md @@ -465,7 +465,7 @@ meaning — do not overload `UNKNOWN` when a new failure mode surfaces ### Public API -- **`ai_client.send_result(...)`** — the public API. Returns +- **`ai_client.send(...)`** — the public API. Returns `Result[str, ErrorInfo]`. Accepts 13+ parameters including 8 callbacks. Internally calls `_send_()` for the active provider (the vendor functions return `Result[str]` directly). @@ -476,7 +476,7 @@ meaning — do not overload `UNKNOWN` when a new failure mode surfaces from src import ai_client from src.result_types import ErrorKind -r = ai_client.send_result("system prompt", "user message") +r = ai_client.send("system prompt", "user message") if not r.ok: for err in r.errors: log.error(err.ui_message()) @@ -487,7 +487,7 @@ print(r.data) ### Migration Notes for Existing Callers -- All production call sites and tests now use `send_result()`. The +- All production call sites and tests now use `send()`. The legacy `send()` function was removed in the `public_api_migration_and_ui_polish_20260615` track. - Tests that mock `ai_client._send_` should use the @@ -514,7 +514,7 @@ print(r.data) - **[docs/reports/qwen_llama_grok_followup_audit_20260611.md](qwen_llama_grok_followup_audit_20260611.md)** — Audit of the parent track's gaps; follow-up track `qwen_llama_grok_followup_20260611` covers them - **Gemini / Gemini CLI thinking-format compatibility (deferred from `ai_loop_regressions_20260614`)** — the user's complaint included Gemini; the likely cause is a format mismatch between the Gemini SDK output and `parse_thinking_trace`. Empirically investigate by running a Gemini request that produces reasoning and inspecting the raw `resp.text`. **Resolved 2026-06-15 by `doeh_test_thinking_cleanup_20260615`**: the `google-genai` SDK filters `thought=True` parts out of `resp.text`. The new helper `_extract_gemini_thoughts` in `src/ai_client.py` scans `resp.candidates[0].content.parts` for `thought=True` and prepends the concatenated text as `...` so `parse_thinking_trace` extracts it. 5 regression tests in `tests/test_gemini_thinking_format.py` cover the helper and the wrap path. See [track spec](../conductor/tracks/doeh_test_thinking_cleanup_20260615/spec.md) §3.2 G15. - **`` (half-width) marker support in thinking_parser (deferred from `ai_loop_regressions_20260614`)** — user screenshot showed `...` format; current `parse_thinking_trace` requires ``. The change is small (~3 lines in `src/thinking_parser.py:9`). **Resolved 2026-06-15 by `doeh_test_thinking_cleanup_20260615`**: the `tag_pattern` regex in `src/thinking_parser.py:20` now also matches `...` (the backreference `\1` matches the closing tag). New test `test_parse_half_width_think_tag` in `tests/test_thinking_trace.py`. All 8 thinking_trace tests pass. -- **Public API Result Migration (planned, separate track `public_api_migration_20260606`)** — the 5 production + 63 test call sites not migrated in this track; the follow-up removes the deprecated `ai_client.send()`. See [parent track spec](../conductor/tracks/data_oriented_error_handling_20260606/spec.md) §12.1. **Completed 2026-06-15 by `public_api_migration_and_ui_polish_20260615`**: 3 remaining production call sites (src/conductor_tech_lead.py:68, src/orchestrator_pm.py:86, src/multi_agent_conductor.py:591) + 18 test files (11 call-site + 7 production-affected mock) were migrated to `send_result()`. The deprecated `send()` function was removed from `src/ai_client.py`. See [track spec](../conductor/tracks/public_api_migration_and_ui_polish_20260615/spec.md). +- **Public API Result Migration (planned, separate track `public_api_migration_20260606`)** — the 5 production + 63 test call sites not migrated in this track; the follow-up removes the deprecated `ai_client.send()`. See [parent track spec](../conductor/tracks/data_oriented_error_handling_20260606/spec.md) §12.1. **Completed 2026-06-15 by `public_api_migration_and_ui_polish_20260615`**: 3 remaining production call sites (src/conductor_tech_lead.py:68, src/orchestrator_pm.py:86, src/multi_agent_conductor.py:591) + 18 test files (11 call-site + 7 production-affected mock) were migrated to `send()`. The deprecated `send()` function was removed from `src/ai_client.py`. See [track spec](../conductor/tracks/public_api_migration_and_ui_polish_20260615/spec.md). - **`doeh_test_thinking_cleanup_20260615` (shipped 2026-06-15)** — cleanup follow-up to `data_oriented_error_handling_20260606` and `ai_loop_regressions_20260614`. Fixed: 1 CRITICAL production regression (`_api_generate` `NameError` from commit `2b7b571a`), 11 test mock bugs, 2 deferred bugs (Gemini thinking format, `` half-width marker), and 2 housekeeping items (state.toml duplicate keys, tracks.md row 24). See [track spec](../conductor/tracks/doeh_test_thinking_cleanup_20260615/spec.md) + [plan](../conductor/tracks/doeh_test_thinking_cleanup_20260615/plan.md). --- diff --git a/docs/guide_app_controller.md b/docs/guide_app_controller.md index 1bb5ac96..6605d687 100644 --- a/docs/guide_app_controller.md +++ b/docs/guide_app_controller.md @@ -433,7 +433,7 @@ if not target_key: Example (line 309): ```python try: - result = ai_client.send_result(...) + result = ai_client.send(...) return result.data except Exception as e: raise HTTPException(status_code=500, detail=f"AI call failed: {e}") diff --git a/scripts/tier2/apply_t5_1_edits.py b/scripts/tier2/apply_t5_1_edits.py new file mode 100644 index 00000000..c35071cf --- /dev/null +++ b/scripts/tier2/apply_t5_1_edits.py @@ -0,0 +1,32 @@ +"""Apply Phase 5 mechanical rename to the 3 current docs.""" +from __future__ import annotations + +import sys +from pathlib import Path + +FILES = [ + "docs/guide_ai_client.md", + "docs/guide_app_controller.md", + "conductor/code_styleguides/error_handling.md", +] + + +def main() -> int: + total = 0 + for rel in FILES: + p = Path(rel) + with p.open("r", encoding="utf-8", newline="") as f: + content = f.read() + before = content.count("send_result") + new_content = content.replace("send_result", "send") + with p.open("w", encoding="utf-8", newline="") as f: + f.write(new_content) + remaining = new_content.count("send_result") + print(f"{rel}: {before} -> {before - remaining} (remaining={remaining})") + total += before - remaining + print(f"Total: {total} renamed") + return 0 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/scripts/tier2/fix_deprecation_section.py b/scripts/tier2/fix_deprecation_section.py new file mode 100644 index 00000000..aaa47478 --- /dev/null +++ b/scripts/tier2/fix_deprecation_section.py @@ -0,0 +1,58 @@ +"""Fix the deprecation section in error_handling.md to reflect historical state. + +This uses a marker-based replacement to avoid encoding issues with unicode +characters in PowerShell output. +""" +from __future__ import annotations + +import sys +from pathlib import Path + +DOC = Path("conductor/code_styleguides/error_handling.md") + +# We use the start and end markers that are unique to the deprecation section. +START_MARKER = "## Deprecation: `ai_client." +END_MARKER = "transition; new tests for the new API should\nassert the warning is NOT emitted by `send()`.\n\n" + + +def main() -> int: + with DOC.open("r", encoding="utf-8", newline="") as f: + content = f.read() + has_crlf = "\r\n" in content + nl = "\r\n" if has_crlf else "\n" + start_marker = START_MARKER.replace("\n", nl) + end_marker = END_MARKER.replace("\n", nl) + i = content.find(start_marker) + if i < 0: + print(f"Start marker not found", file=sys.stderr) + return 1 + j = content.find(end_marker, i) + if j < 0: + print(f"End marker not found", file=sys.stderr) + return 1 + end_of_section = j + len(end_marker) + section_text = content[i:end_of_section] + replacement = """## Historical deprecation (added 2026-06-15, reverted 2026-06-16) + +The public `ai_client.send()` was briefly marked `@deprecated` in favor of +`ai_client.send_result()` on 2026-06-15 by the +`public_api_migration_and_ui_polish_20260615` track. The decision was +reverted on 2026-06-16 by `send_result_to_send_20260616` after the +Tier 2 autonomous sandbox proved capable of doing the rename safely. + +`ai_client.send(...) -> Result[str, ErrorInfo]` is the canonical public API. +No deprecation is in effect. For the historical record of the brief +deprecation cycle, see +`conductor/tracks/public_api_migration_and_ui_polish_20260615/spec.md` +and `conductor/tracks/send_result_to_send_20260616/spec.md`. + +""".replace("\n", nl) + new_content = content[:i] + replacement + content[end_of_section:] + with DOC.open("w", encoding="utf-8", newline="") as f: + f.write(new_content) + print(f"Replaced {len(section_text)} chars of deprecation section with {len(replacement)} chars of historical note.") + return 0 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/scripts/tier2/fix_line_204.py b/scripts/tier2/fix_line_204.py new file mode 100644 index 00000000..194724cf --- /dev/null +++ b/scripts/tier2/fix_line_204.py @@ -0,0 +1,28 @@ +"""Fix the contradictory line 204 in error_handling.md.""" +from __future__ import annotations + +import sys +from pathlib import Path + +DOC = Path("conductor/code_styleguides/error_handling.md") + +OLD = " grok); `send()` is the new public API; `send()` is `@deprecated`." + +NEW = " grok); `send(...) -> Result[str, ErrorInfo]` is the public API." + + +def main() -> int: + with DOC.open("r", encoding="utf-8", newline="") as f: + content = f.read() + if OLD not in content: + print(f"NOT FOUND: {OLD!r}", file=sys.stderr) + return 1 + new_content = content.replace(OLD, NEW, 1) + with DOC.open("w", encoding="utf-8", newline="") as f: + f.write(new_content) + print("Line 204 fixed.") + return 0 + + +if __name__ == "__main__": + raise SystemExit(main())