From 230653ee4251a6017d46b592ace6e824110ade7b Mon Sep 17 00:00:00 2001 From: Ed_ Date: Thu, 11 Jun 2026 23:31:52 -0400 Subject: [PATCH] docs(product-guidelines): add Data-Oriented Error Handling section --- conductor/product-guidelines.md | 45 +++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/conductor/product-guidelines.md b/conductor/product-guidelines.md index ef199034..15a05e56 100644 --- a/conductor/product-guidelines.md +++ b/conductor/product-guidelines.md @@ -47,6 +47,51 @@ - **Functions/Methods:** `[C: Caller1, Caller2]` (Primary callers). - **State Variables:** `[M: File:Line, Method]` (Mutation points) and `[U: File]` (Major use paths). +## Data-Oriented Error Handling + +The codebase follows the "errors are just cases" framework from Ryan Fleury's +[The Easiest Way To Handle Errors](https://www.dgtlgrove.com/p/the-easiest-way-to-handle-errors). +The canonical reference (with code examples) is in +[`conductor/code_styleguides/error_handling.md`](code_styleguides/error_handling.md). +Key principles: + +- **Result dataclasses** instead of `Optional[T]` or exception-based control flow. +- **Nil-sentinel dataclasses** instead of `None`. +- **Zero-initialized fields** via `@dataclass` defaults. +- **Fail early**: validation at the entry point, not deep in the call stack. +- **AND over OR**: return a struct with data + side-channel errors, not a sum type. +- **Exceptions reserved for the SDK boundary**: SDK errors are caught and converted + to `ErrorInfo` dataclasses; the rest of the application works with data, not control flow. + +This convention is established incrementally. The 2026-06-11 +`data_oriented_error_handling_20260606` track applies it to +`src/mcp_client.py`, `src/ai_client.py`, and `src/rag_engine.py`. Future +tracks will apply it to the remaining `src/` files +(`src/app_controller.py`, `src/models.py`, `src/project_manager.py`, etc. — +see `conductor/tracks/data_oriented_error_handling_20260606/spec.md` §12.2 +for the prioritized list). + +### `Optional[T]` ban (return types only) + +In the 3 refactored files (`src/mcp_client.py`, `src/ai_client.py`, +`src/rag_engine.py`), `Optional[T]` return types are forbidden. Use +`Result[T]` (with a `NIL_T` singleton if needed) instead. Argument types +that may be `None` (e.g., `rag_engine: Optional[Any] = None`) remain +allowed — they describe a caller choice, not a runtime failure of this +function. The audit script `scripts/audit_optional_in_3_files.py` enforces +this rule by failing CI on new `Optional[X]` return types in the 3 +refactored files. + +### Public API deprecation: `ai_client.send()` → `ai_client.send_result()` + +The public `ai_client.send()` is marked `@deprecated` (via +`typing_extensions.deprecated`). It still works for backward compat but +emits a `DeprecationWarning` at runtime. New code MUST use +`ai_client.send_result()`, which returns `Result[str, ErrorInfo]` instead +of `str`. Removal is planned in the follow-up +`public_api_migration_20260606` track. + + ## Testing Requirements These are the process standards the project's test infrastructure enforces. For the full implementation contract (fixture names, anti-patterns, audit scripts), see [docs/guide_testing.md §Structural Testing Contract](../docs/guide_testing.md) and the per-styleguide audit scripts in [code_styleguides/](code_styleguides/).