conductor(followup): code_path_audit_phase_2_20260624 - the actual followup + abort SSDL campaign

VERIFIED STATE OF MASTER a18b8ad6 (just measured):
- 751 Metadata consumers in src/
- 3,454 total branches
- 4.014e+22 effective codepaths (UNCHANGED from the 4.01e+22 baseline)
- 73 nil-check funcs in Metadata consumers (real SSDL measurement)
- 14 module globals still in src/ai_client.py (_anthropic_history + lock, etc.)
- MCP_TOOL_SPECS: list[dict[str, Any]] still in src/mcp_client.py
- src/ai_client.py:908 still uses old NormalizedResponse API (usage_input_tokens=...)
- 3 orphaned modules: mcp_tool_specs, openai_schemas, provider_state (exist, nothing imports)
- 4 pre-existing INTERNAL_OPTIONAL_RETURN violations in external_editor, session_logger, project_manager (NG1)
- 7 pre-existing Optional[T] return-type violations in mcp_client.py:1285,1289 + ai_client.py:159,247,619,673,3115 (NG2)
- audit_weak_types PASS, generate_type_registry PASS, audit_main_thread_imports PASS, audit_no_models_config_io PASS, audit_code_path_audit_coverage PASS, audit_exception_handling (baseline) PASS, audit_optional_in_3_files FAIL (NG2)

SSDL CAMPAIGN ABORT (premise was wrong):
- '6 nil-check functions' was a static text string in src/code_path_audit_gen.py:108, not a runtime measurement
- SSDL detector finds 0 Metadata-typed nil-checks
- The 1 function Tier 2 migrated (_build_files_section_from_items) was a 'path is None' check, NOT a Metadata nil-check
- The 4.01e22 combinatoric explosion is from dict[str, Any] type-dispatch, not nil-checks
- Salvage: NIL_METADATA = {} in src/aggregate.py + 5 tests stay as useful primitives

THE ACTUAL FIX: re-apply any_type_componentization_20260621's 48 call-site migrations
- Phase 1: mcp_tool_specs (8 sites) - 4 in mcp_client.py + 3 in ai_client.py + 1 in mcp_client.py:2747
- Phase 2: openai_schemas (17 sites) - 12 in openai_compatible.py + 5 in 3 send_* functions in ai_client.py; REMOVE the backward-compat __init__ from fix_test_failures_20260624
- Phase 3: provider_state (14 globals + ~27 callers) - 9 send_* functions use get_history('...') instead
- Phase 4: log_registry Session (7 sites)
- Phase 5: api_hooks WebSocketMessage (16 sites)
- Phase 6: NG1 fixups (4 INTERNAL_OPTIONAL_RETURN violations)
- Phase 7: NG2 fixups (7 Optional[T] return-type violations)
- Phase 8: Re-audit (measure new effective-codepaths; target < 1e+20)
- Phase 9: Verification + end-of-track report

VERIFICATION (10 VCs):
- VC1: 3 modules actually used by src/*.py (git grep >= 5 hits in src/, not just in plan/spec text)
- VC2: 14 module globals in src/ai_client.py gone
- VC3: MCP_TOOL_SPECS dict literal gone
- VC4: usage_input_tokens= in src/ai_client.py gone
- VC5: effective codepaths drops >= 2 orders of magnitude (target: 4.014e+22 -> < 1e+20)
- VC6: NG1 fixed (0 INTERNAL_OPTIONAL_RETURN violations)
- VC7: NG2 fixed (0 Optional[T] return-type violations)
- VC8: all 6 audit gates pass --strict
- VC9: 11/11 batched test tiers PASS
- VC10: end-of-track report written

5 files aborted, 5 files created (new track), 1 post-mortem doc.
This commit is contained in:
ed
2026-06-24 16:24:53 -04:00
parent dbaf20607c
commit 7c352e1c30
11 changed files with 900 additions and 11 deletions
@@ -0,0 +1,85 @@
# SSDL Campaign Aborted: Post-Mortem
**Date:** 2026-06-24
**Campaign:** `metadata_ssdl_defusing_20260624` (umbrella) + 3 children
**Status:** ABORTED
**Author:** Tier 1 (post-mortem)
## What this campaign was
A 3-child campaign to defuse the `Metadata` aggregate's combinatoric explosion (4.01e22 effective codepaths) via Fleury's SSDL techniques:
1. `metadata_nil_sentinel_20260624` — Nil Sentinel
2. `metadata_generational_handle_20260624` — Generational Handle
3. `metadata_field_cache_20260624` — Immediate-Mode Field Cache
The 3 children were based on the parent `code_path_audit_20260607` Finding 1, which proposed "6 nil-check functions" and 3 SSDL defusing techniques.
## What actually happened
### Phase 1: Spec authoring (the original mistake)
The spec was authored based on text from the parent code path audit's AUDIT_REPORT.md, which stated:
- "6 nil-check functions" (per Finding 1)
- "3 specific techniques" (nil sentinel, generational handle, field cache)
- 4.01e22 effective codepaths
- 3466 branch points
- 123 field-access sites
The Tier 1 author (me) cited this without running the actual SSDL detector to verify. I did not read the canonical styleguides (`error_handling.md`, `data_oriented_design.md`) before authoring the spec. This violated the convention's Rule #0: "READ THIS STYLEGUIDE FIRST."
### Phase 2: Tier 2 implementation (the verification)
Tier 2 picked up child 1 (`metadata_nil_sentinel_20260624`) and:
1. **Could only find 1 function to migrate** (`_build_files_section_from_items` in `src/aggregate.py`), not 6. The function was migrated to use `NIL_METADATA = {}` defensively, but the actual nil-check it had (`if path is None:`) was a `str` check, NOT a `Metadata` check.
2. **The budget gate (≥10% drop in `compute_effective_codepaths`) failed.** Post-child-1 measurement: 4.014e+22 (within rounding error of the 4.01e+22 baseline). The 10% threshold was mathematically near-impossible due to exponential dominance in the sum.
3. **The SSDL detector found 73 nil-check functions** across the codebase — but most are on `_gemini_client`, `_anthropic_client`, `path`, `adapter`, etc., NOT on `Metadata` values. The 1 migration in `src/aggregate.py` was a `path` check refactored to `if not path:`, not a Metadata nil-check.
4. **The "6 nil-check functions" was a static text string** in `src/code_path_audit_gen.py:108`, not a runtime measurement. The text was hardcoded in the AUDIT_REPORT.md generator, not derived from the SSDL detector.
### Phase 3: Cancellation (the new followup)
The campaign was cancelled. The salvage:
- `NIL_METADATA = {}` in `src/aggregate.py` (1 line)
- `tests/test_metadata_nil_sentinel.py` (5 tests)
Both are useful primitives for future use. They stay in the codebase.
## The root cause of the 4.01e22
Per the canonical styleguide `data_oriented_design.md` (the Mike Acton + Ryan Fleury principles):
> "**Prefer Fewer Types** — A helpful lesson for me was in reframing error information... The metastasizing of types creates more required codepaths."
The 4.01e22 is **not from nil-checks**. It's from `Metadata: TypeAlias = dict[str, Any]`. Every consumer function that does `entry.get('key', default)` is a runtime type-dispatch branch. The combinatoric explosion is from the unknown type, not from missing sentinels.
The actual fix is **`any_type_componentization`**: promote `dict[str, Any]` to typed `@dataclass` instances. After promotion:
- `entry.get('key', default)` becomes `entry.field_name` (direct attribute access, 0 branches)
- The combinatoric explosion collapses at the source
The parent `any_type_componentization_20260621` track did this for 48/89 sites, but the call-site migrations were reverted at `751b94d4`. The 3 surviving modules (`src/mcp_tool_specs.py`, `src/openai_schemas.py`, `src/provider_state.py`) are orphaned on master — they exist but nothing imports them.
## The new followup
`code_path_audit_phase_2_20260624` is the actual followup. It re-applies the 48 call-site migrations + addresses the 11 pre-existing audit violations (4 NG1 + 7 NG2). After it ships, the 4.01e22 should drop by orders of magnitude.
## Lessons learned
1. **Read the canonical styleguides BEFORE writing specs.** The `data_oriented_design.md` styleguide has the "Prefer Fewer Types" principle. The `error_handling.md` styleguide has Rule #0. Neither was read before the SSDL spec was authored.
2. **Run the detectors BEFORE relying on the audit's text.** The "6 nil-check functions" was a static text string, not a measurement. Always verify with the actual detector (`src/code_path_audit_ssdl.detect_nil_check_pattern`).
3. **Verify the 4.01e22 number is from the source the fix addresses.** The combinatoric explosion was from `dict[str, Any]` type-dispatch, not from nil-checks. The fix is type promotion, not nil sentinels.
4. **Don't propose followups to fix something that wasn't measured.** The SSDL techniques (nil sentinel, generational handle, field cache) are valid Fleury techniques, but they don't apply when the cause is missing type structure, not missing sentinels.
5. **The SSDL campaign's salvageable artifact is `NIL_METADATA`.** The `NIL_*` pattern is the convention. The Metadata instance of it is now a primitive for future use, not a campaign outcome.
## See also
- `conductor/code_styleguides/error_handling.md` — the `NIL_*` sentinel convention (Rule #0: read first)
- `conductor/code_styleguides/data_oriented_design.md` — the "Prefer Fewer Types" principle (Ryan Fleury's combinatoric explosion)
- `conductor/code_styleguides/type_aliases.md` — the 10 TypeAliases (the canonical names for shapes)
- `docs/reports/SSDL_CAMPAIGN_ABORTED_20260624.md` — this post-mortem
- `conductor/tracks/code_path_audit_phase_2_20260624/spec.md` — the actual followup
- `conductor/tracks/any_type_componentization_20260621/plan.md` — the parent plan whose 48 call-site migrations are the actual fix
- `docs/reports/code_path_audit/2026-06-22/AUDIT_REPORT.md` — the source of the 4.01e22 baseline
- `src/code_path_audit_ssdl.py` — the `detect_nil_check_pattern` + `compute_effective_codepaths` measurement infrastructure