# Track Specification: metadata_nil_sentinel_20260624 ## Overview Child 1 of the `metadata_ssdl_defusing_20260624` campaign. Introduces `NIL_METADATA = Metadata(...)` sentinel and migrates the 6 nil-check functions identified by the parent audit. Establishes the fallback path that Child 2 (Generational Handle) returns to on generation mismatch. ## Current State Audit (master @ 7a9261c4) - `src/aggregate.py` and `src/ai_client.py` contain 6 functions with `is None` / `== None` / `!= None` patterns on `Metadata` (or aliases of `dict[str, Any]`). These are detected by `src/code_path_audit_ssdl.detect_nil_check_pattern`. - The parent audit (`docs/reports/code_path_audit/2026-06-22/AUDIT_REPORT.md` Finding 1) reports "6 nil-check functions" and "4.01e22 effective codepaths" for the `Metadata` aggregate. - No `NIL_METADATA` constant exists. ## Goals | ID | Goal | Acceptance | |---|---|---| | G1 | `NIL_METADATA = Metadata(...)` constant exists in the production source | `grep -rn "NIL_METADATA" src/` finds the constant + the 6 migration sites | | G2 | The 6 nil-check functions use the sentinel | `src.code_path_audit_ssdl.detect_nil_check_pattern` returns 0 for the 6 functions after migration | | G3 | 1 behavioral test for the sentinel | `tests/test_metadata_nil_sentinel.py` exists; all assertions pass | | G4 | Budget gate met: effective-codepaths drop ≥ 10% vs 4.01e22 baseline | `compute_effective_codepaths(Metadata_profile)` returns a number ≥ 10% smaller than 4.01e22 | ## Non-Goals - Touching the 4 other `dict[str, Any]` aliases (FileItem, CommsLogEntry, HistoryMessage, ToolDefinition, ToolCall) — they have similar patterns (parent audit Finding 2) but are out of scope for this child - Touching the list-typed aggregates (CommsLog, History, FileItems) — out of scope - Touching the 3 candidate aggregates (ToolSpec, ChatMessage, ProviderHistory) — blocked on `any_type_componentization_20260621` (NOT on master) - Refactoring the 6 functions beyond the nil-check migration (the change is surgical: replace the nil-check with sentinel-return) - Adding new audit infrastructure (the campaign USES the existing SSDL functions) ## Functional Requirements ### FR1: Define `NIL_METADATA` In a sensible location (likely `src/aggregate.py` since it's the Metadata parent module per `src/code_path_audit.py:343-368`'s `CANONICAL_MEMORY_DIM`), add: ```python NIL_METADATA: Metadata = Metadata( # safe defaults; the exact contents are up to Tier 2 ) ``` The defaults MUST be safe (no-op / no-value) such that consumers can blindly use `entry or NIL_METADATA` without triggering KeyError or AttributeError. ### FR2: Migrate the 6 nil-check functions For each of the 6 functions detected by `src/code_path_audit_ssdl.detect_nil_check_pattern`: - Replace `if entry is None: ...` / `if entry is None or entry == "": ...` / `if entry != None: ...` patterns with sentinel-return - The most common pattern: `entry = entry or NIL_METADATA` at the top of the function - Preserve the function's existing behavior for non-nil cases ### FR3: Behavioral test `tests/test_metadata_nil_sentinel.py` with at least 2 tests: - `test_nil_metadata_is_defined`: assert `NIL_METADATA` exists and is a valid `Metadata` (or `dict[str, Any]` if Metadata is a TypeAlias) - `test_migrated_function_uses_sentinel`: call one of the 6 migrated functions with `None` and assert it returns the sentinel (or behavior equivalent to using the sentinel) ## Non-Functional Requirements - NFR1: 1-space indentation - NFR2: CRLF line endings on Windows - NFR3: No comments in source code - NFR4: Per-task atomic commits with git notes - NFR5: No new pip dependencies - NFR6: The 6 migration sites use the existing convention (sentinel pattern, not new abstractions) - NFR7: No new `src/.py` files (per AGENTS.md) — `NIL_METADATA` lives in `src/aggregate.py` or another existing module ## Architecture Reference - `src/code_path_audit_ssdl.py:84-100` — `detect_nil_check_pattern` (the function that identifies the 6 sites) - `src/code_path_audit.py:343-368` — `CANONICAL_MEMORY_DIM` (where Metadata's canonical location is) - `src/aggregate.py` — the parent module for `Metadata` - `docs/reports/code_path_audit/2026-06-22/AUDIT_REPORT.md` Finding 1 — the 6 nil-check functions and the proposed fix - `conductor/code_styleguides/data_oriented_design.md` — the canonical DOD reference ## Out of Scope - All other aggregates (deferred to a follow-up campaign) - The 3 candidate aggregates (blocked on `any_type_componentization_20260621`) - Runtime profiling (Track F from the previous menu; deferred) ## Verification Criteria (Definition of Done) | # | Criterion | Verification command | |---|---|---| | VC1 | `NIL_METADATA` is defined in `src/` | `grep -rn "NIL_METADATA" src/` returns ≥ 1 hit | | VC2 | The 6 nil-check functions no longer have the 3-pattern nil-check | `src/code_path_audit_ssdl.detect_nil_check_pattern` returns False for all 6 | | VC3 | Behavioral test exists and passes | `uv run pytest tests/test_metadata_nil_sentinel.py -v` | | VC4 | Budget gate met | `compute_effective_codepaths(Metadata_profile)` returns number ≥ 10% smaller than 4.01e22 | | VC5 | Full test suite remains green | `uv run python scripts/run_tests_batched.py` → 11/11 tiers PASS | | VC6 | 4 audit gates remain clean | weak_types ≤ 112, type_registry in sync, main_thread_imports clean, no_models_config_io clean | ## Risks | # | Risk | Likelihood | Mitigation | |---|---|---|---| | R1 | The 6 nil-check functions are in unexpected locations (not aggregate.py or ai_client.py) | low | `detect_nil_check_pattern` enumerates all consumer files; the audit identified them | | R2 | The `NIL_METADATA` defaults are wrong (cause downstream bugs) | low | The defaults should be safe (empty Metadata with no required fields). Behavioral test verifies sentinel works in a real call. | | R3 | Budget gate fails (drop < 10%) | low | The 6 nil-checks are documented; their removal MUST drop. If not, the SSDL math is wrong (separate investigation). |