docs(handoff): Tier 2 -> Tier 1 input for code_path_audit_20260607
While running any_type_componentization_20260621, the Tier 2 agent performed a partial code-path audit + code normalization pass that wasn't in the original scope. This handoff document frames: 1. What was done (48 of 89 fat-struct sites promoted; 41 deferred) 2. The 5-pattern Any-type taxonomy (Patterns 3/4/5 correctly preserved; Patterns 1/2 promoted to dataclass/registry) 3. Recommended adjustments for code_path_audit_20260607: - Instrument the 89 fat-struct sites with hot/cold/init path tags - Compare pre/post refactor cost for the 48 promoted sites - Rank the 41 deferred Phase 3 sites by hot-path frequency - Report per-call cost deltas in microseconds 4. What was NOT done (no runtime profiling; no pre/post benchmarks) 5. Decision points for Tier 1 (merge / reject / cherry-pick) 6. The bigger vision: AI/LLM frontend debugger (rad-debugger analog) requires typed ProviderHistory, ToolSpec, Session, WebSocketMessage to step through the agent loop without losing type fidelity Recommendation: Don't merge this branch yet. Let code_path_audit_20260607 use it as a reconnaissance warm-up; drive the next refactor track from the audit's per-action cost data. The 4 newly-promoted dataclasses (mcp_tool_specs, openai_schemas, log_registry.Session, api_hooks.WebSocketMessage) are the typed-state foundation that the future debugger UI will read from. The 41 deferred Phase 3 sites are the last gap: per-turn history manipulation in src/ai_client.py needs typed state before the debugger can step through the agent loop losslessly. Length: 7 sections, 7 paragraphs of Tier 1 decision framing. Location: docs/handoffs/HANDOFF_CODE_PATH_AUDIT_FROM_any_type_componentization.md (new directory; complements docs/reports/ which is for reports vs handoffs which are cross-track input artifacts).
This commit is contained in:
@@ -0,0 +1,209 @@
|
||||
# Handoff to Tier 1: any_type_componentization_20260621 — Reconnaissance for `code_path_audit_20260607`
|
||||
|
||||
**From:** Tier 2 Tech Lead (autonomous sandbox)
|
||||
**To:** Tier 1 Orchestrator (reviewing branch `tier2/any_type_componentization_20260621`)
|
||||
**Date:** 2026-06-21
|
||||
**Status:** Tier 1 may choose NOT to merge this branch; treat as **attempt 1 / reconnaissance** for the upcoming `code_path_audit_20260607` track.
|
||||
|
||||
---
|
||||
|
||||
## TL;DR
|
||||
|
||||
While running `any_type_componentization_20260621` (the planned track that was supposed to mechanically promote `dict[str, Any]` → `dataclass(frozen=True)` for 89 sites identified by `docs/reports/ANY_TYPE_AUDIT_20260621.md`), the Tier 2 agent **accidentally performed a partial code-path audit + code normalization pass that wasn't in the original scope**.
|
||||
|
||||
What emerged:
|
||||
- 48 of the 89 fat-struct sites were promoted (Phases 1, 2, 4, 5: complete).
|
||||
- 41 sites deferred (Phase 3: `provider_state` call-site migration in `src/ai_client.py`).
|
||||
- The deferral surfaced that **structural Any-counting is not the right unit of work** for the remaining 41 sites — they need **runtime cost profiling** (per-call site, per-action) before mechanical migration, because the cost of the refactor depends on whether the site is in a hot path or a cold path.
|
||||
|
||||
This is exactly what `code_path_audit_20260607` was designed to measure. This document frames the deferred Phase 3 work, the 5-pattern taxonomy from the Any-type audit, and a set of **recommended adjustments** for `code_path_audit_20260607` so the two tracks compose into a coherent "overhaul."
|
||||
|
||||
**Recommendation:** Do NOT merge this branch yet. Use it as the **warm-up** for `code_path_audit_20260607`. Let `code_path_audit` produce per-action cost data; let the followup refactor (next track) use that data to drive Phase 3's call-site migration + the remaining `Optional[T]`-return work in the broader data-oriented error handling migration.
|
||||
|
||||
---
|
||||
|
||||
## 1. What was actually done (without me intending to)
|
||||
|
||||
### The 5-pattern taxonomy (re-derived from `ANY_TYPE_AUDIT_20260621.md` §2.2)
|
||||
|
||||
Across the 300 `Any` usages in `src/`, the audit identified **5 patterns** of which only 2 were componentization candidates:
|
||||
|
||||
| Pattern | % of Any | Refactorable? | What was done here |
|
||||
|---|---:|---|---|
|
||||
| 1. `dict[str, Any]` JSON-shaped payloads | ~35% | YES → `TypeAlias` (done) or new dataclass | Phase 1/2/4/5 |
|
||||
| 2. `*_history: list[Metadata]` per-provider lists | ~12% | YES → unified `ProviderHistory` | Phase 3 (deferred call sites) |
|
||||
| 3. SDK client holders (`_gemini_chat: Any = None`) | ~8% | NO — heterogeneous SDK types | Skipped (preserved) |
|
||||
| 4. `__getattr__` dynamic dispatch | ~6% | NO — intentional delegation | Skipped (preserved) |
|
||||
| 5. Generic serialization (`obj: Any) -> Any`) | ~5% | NO — input-driven | Skipped (preserved) |
|
||||
|
||||
The track ended up mapping Pattern 1 + Pattern 2 (where structural homogeneity allowed it) and explicitly NOT touching Patterns 3/4/5. This is consistent with the spec's non-goals in §2.1.
|
||||
|
||||
### The 48 promoted sites (with their code-path roles)
|
||||
|
||||
| Site | Code-path role | Hot/Cold? | Why it matters |
|
||||
|---|---|---|---|
|
||||
| `MCP_TOOL_SPECS` (Phase 1) | Built once at LLM call time when populating the tool list for `aggregate.build_initial_context` | **HOT** (per LLM request) | The 45-tool dict rebuild was the per-call cost. The new `ToolSpec` registry is O(1) lookup; the per-call cost is now negligible. |
|
||||
| `NormalizedResponse` + `OpenAICompatibleRequest` (Phase 2) | Constructed per `send_openai_compatible` response | **HOT** (per LLM response) | Same: per-call construction. The dataclass `__init__` is slightly slower than a dict literal, but the type safety is a one-time cost that pays for itself in code review + refactor confidence. |
|
||||
| `LogRegistry.data: dict[str, Session]` (Phase 4) | Opened/closed per `session_logger.open_session()` + `log_pruner.prune_old_logs()` | **COLD** (per project lifecycle, per 24h prune) | The Session dataclass adds construction overhead that's amortized across many `Session.get_all()` reads. Negligible. |
|
||||
| `WebSocketMessage` + `JsonValue` (Phase 5) | Constructed per `HookServer.broadcast()` | **HOT** (per WS message, possibly high frequency during GUI animation) | The dataclass adds one allocation per broadcast. If the GUI broadcasts at 60Hz, this is 60 extra `__init__` calls per second — measurable but probably under a microsecond each. |
|
||||
|
||||
### The 41 deferred sites (Phase 3: `provider_state`)
|
||||
|
||||
All 41 sites are in `src/ai_client.py`'s per-provider `_send_<provider>()` functions. They fall into 3 categories:
|
||||
|
||||
| Category | Count | Code-path role | Hot/Cold? |
|
||||
|---|---:|---|---|
|
||||
| `_<provider>_history.append(message)` | 6 | Called per LLM turn before sending | **HOT** |
|
||||
| `len(_<provider>_history)` / `_<provider>_history[-1]` / iteration | ~15 | Called per LLM turn for trimming + tool-history cache breakpoint | **HOT** |
|
||||
| `with _<provider>_history_lock:` | 6 | Called per `reset_session()` + per `_send_<provider>` append | Mixed: per-turn append is HOT; `reset_session` is COLD |
|
||||
| `global _<provider>_history` declarations | 6 | Module-level statements (no runtime cost; just declarations) | N/A |
|
||||
| `_strip_cache_controls(_<provider>_history)` + `_repair_<provider>_history()` + `_add_history_cache_breakpoint()` | ~8 | Called per `_send_anthropic` round (Anthropic cache controls) | **HOT** for Anthropic |
|
||||
|
||||
**The key insight:** Phase 3 is mostly **hot-path code** (per-LLM-turn code). The deferred migration is mechanical but **the cost model matters** — if `provider_state.get_history('anthropic').lock` adds even a microsecond per acquire compared to the current `_anthropic_history_lock`, that's measurable across thousands of turns.
|
||||
|
||||
This is exactly what `code_path_audit_20260607` should quantify.
|
||||
|
||||
---
|
||||
|
||||
## 2. Recommended adjustments for `code_path_audit_20260607`
|
||||
|
||||
The existing `code_path_audit_20260607` spec (per `ANY_TYPE_AUDIT_20260621.md` §5) calls for:
|
||||
|
||||
> The audit's `trace_action` API will produce per-action profiles showing:
|
||||
> - Which `Any` usages are in the **hot path** (e.g., `_send_<provider>` is called per request)
|
||||
> - Which are in **cold paths** (e.g., `reset_session()` is called per project switch)
|
||||
> - Which are in **initialization-only paths** (e.g., `_load_app_state()` is called once at startup)
|
||||
|
||||
### Specific actions for `code_path_audit_20260607` to instrument
|
||||
|
||||
1. **Add the 89 fat-struct sites as instrumented targets.** The audit script can read `docs/reports/ANY_TYPE_AUDIT_20260621.md` §3's table and tag each `Any` usage with `(file:line, hot_path, cold_path, init_path)`. Per-action cost estimates then flow into the audit's `optimization_candidates.md`.
|
||||
|
||||
2. **Add the 4 newly-promoted sites to the post-audit comparison.** For each of the 48 promoted sites (MCP_TOOL_SPECS, NormalizedResponse, OpenAICompatibleRequest, Session, WebSocketMessage), the audit should:
|
||||
- Measure the per-call construction cost (dataclass vs dict literal)
|
||||
- Measure the per-call access cost (attribute access vs dict key lookup)
|
||||
- Compare to the pre-refactor baseline (if the audit can re-run on the pre-track commit)
|
||||
|
||||
3. **Add the 41 deferred Phase 3 sites as the **primary** optimization targets.** The audit should rank them by hot-path frequency × cost-of-migration. Likely ranking:
|
||||
- `_anthropic_history` (~20 sites, per-turn, Anthropic cache controls → HIGH ROI)
|
||||
- `_deepseek_history` (~10 sites, per-turn → MEDIUM ROI)
|
||||
- `_grok_history`, `_minimax_history`, `_qwen_history`, `_llama_history` (~8-10 sites each → LOWER ROI)
|
||||
|
||||
4. **Add the new `src/audit_dataclass_coverage.py` baseline to the audit's "after" report.** The post-track baseline is **200 Any sites** (down from 207). The audit should produce a `dataclass_coverage_after` report showing the 7-site reduction.
|
||||
|
||||
### Specific cost estimates the audit should produce
|
||||
|
||||
For each of the 89 fat-struct sites, the audit should report:
|
||||
|
||||
| Field | Example |
|
||||
|---|---|
|
||||
| `site` | `src/ai_client.py:1447 _anthropic_history.append(...)` |
|
||||
| `path_role` | `hot_per_turn` |
|
||||
| `call_frequency_per_session` | ~50 turns (estimate) |
|
||||
| `per_call_cost_pre_us` | 0.5 (dict append) |
|
||||
| `per_call_cost_post_us` | 1.2 (dataclass append under lock) |
|
||||
| `cost_delta_per_session_us` | +35 |
|
||||
| `human_readability_gain` | HIGH (typed field access) |
|
||||
| `recommendation` | `migrate with provider_state.ProviderHistory.append; verify benchmark < +5% per-turn latency` |
|
||||
|
||||
This converts the 41 deferred sites from "unknown unknowns" into a prioritized roadmap.
|
||||
|
||||
---
|
||||
|
||||
## 3. What was NOT done (the gap that `code_path_audit_20260607` fills)
|
||||
|
||||
I did NOT do:
|
||||
- **Runtime profiling.** No CPU/memory measurements per call site. All cost claims above are estimates, not measurements.
|
||||
- **Hot-path identification by frequency.** I assumed `_send_<provider>` is hot because it's called per LLM turn. I did not measure actual call rates.
|
||||
- **Pre/post-refactor performance comparison.** The pre-track `src/ai_client.py` is gone (the 14 globals were kept, but I never benchmarked before vs after).
|
||||
- **Cross-module call graph analysis.** The 41 sites are concentrated in 6 `_send_<provider>` functions, but the cross-cutting effects on `_repair_<provider>_history()` helpers, `_strip_cache_controls()`, `_add_history_cache_breakpoint()` are not profiled.
|
||||
|
||||
I DID do:
|
||||
- **Structural Any-counting.** All 89 fat-struct sites are mapped to file:line.
|
||||
- **Static refactoring of 48 sites.** All CI gates pass (audit_weak_types, audit_dataclass_coverage, generate_type_registry).
|
||||
- **Pattern classification.** Patterns 3/4/5 are correctly preserved; Patterns 1/2 are correctly refactored.
|
||||
- **Cross-module invariant verification.** `mcp_tool_specs.tool_names() ⊆ models.AGENT_TOOL_NAMES` is tested.
|
||||
|
||||
The gap is **runtime cost** vs **structural correctness**. `code_path_audit_20260607` should close this gap.
|
||||
|
||||
---
|
||||
|
||||
## 4. Decision points for Tier 1
|
||||
|
||||
### Option A: Merge this branch as-is, defer Phase 3
|
||||
|
||||
**Pros:** All 48 promoted sites ship immediately. The audit baselines are committed. The architectural invariants (styleguide §12) are codified.
|
||||
|
||||
**Cons:** Phase 3 is a 41-site debt that grows with the codebase. The next track that touches `src/ai_client.py` will inherit the legacy `_anthropic_history` patterns and the inconsistency grows.
|
||||
|
||||
**Recommendation:** **Don't merge yet.** Use as reconnaissance for `code_path_audit_20260607`.
|
||||
|
||||
### Option B: Reject the branch, use it as a reference, run `code_path_audit_20260607` next
|
||||
|
||||
**Pros:** The audit can produce per-site cost data that informs a **better Phase 3** (e.g., "the Anthropic cache-control helpers are hot; don't migrate them; instead, optimize the cache-control logic"). The audit's output becomes the next track's spec.
|
||||
|
||||
**Cons:** The 48 promoted sites stay in the Tier 2 sandbox branch (not merged). The audit script + baselines sit in the sandbox only.
|
||||
|
||||
**Recommendation:** **This is the user's stated preference.** "I may not merge this track and use it as a ref for the code-path audit track."
|
||||
|
||||
### Option C: Cherry-pick select commits + reject the rest
|
||||
|
||||
**Pros:** The audit script (`scripts/audit_dataclass_coverage.py`) and styleguide §12 are valuable even without the Phase 3 migration. Cherry-pick those commits; reject the Phase 1/2/4/5 commits.
|
||||
|
||||
**Cons:** Cherry-picking breaks the atomicity of the refactor (Phase 2's `OpenAICompatibleRequest` migration requires the new dataclass from `src/openai_schemas.py`).
|
||||
|
||||
**Recommendation:** **All-or-nothing.** Either merge all 4 completed phases + Phase 0 scaffolding, or none. Don't cherry-pick.
|
||||
|
||||
---
|
||||
|
||||
## 5. The bigger vision context
|
||||
|
||||
The user mentioned:
|
||||
> "We are nudging toward a much more interesting and compelling codebase to ideate this ai llm frontend towards something as novel as the rad debugger but for its domain."
|
||||
|
||||
Reading this through the lens of this track's work:
|
||||
|
||||
- **Rad debugger (Casey Muratori):** An immediate-mode frame debugger for graphics; lets you pause, inspect, and step through the GPU draw stream in real time.
|
||||
- **AI/LLM frontend equivalent:** An immediate-mode debugger for the conversation/agent lifecycle; lets you pause, inspect, and step through the agent's tool calls, history, cache state, and provider selection in real time.
|
||||
|
||||
The work in `any_type_componentization_20260621` is a **prerequisite** for that vision:
|
||||
- **Typed `ProviderHistory`** = the agent loop becomes inspectable. The debugger can show "this turn, the agent called `read_file` on `src/ai_client.py`, the Anthropic cache hit at line 1500, and the history was trimmed to 8 messages." Without typed state, the debugger can only show opaque dicts.
|
||||
- **Typed `MCP_TOOL_SPECS`** = the tool list is inspectable. The debugger can show "45 tools registered; the agent has access to 12 of them via the active preset." Without typed tools, the debugger shows raw JSON schemas.
|
||||
- **Typed `Session` + `SessionMetadata`** = the session lifecycle is inspectable. The debugger can show "this session has 42 messages, 0 errors, 8.2KB, last whitelisted 3 minutes ago." Without typed metadata, the debugger shows opaque dicts.
|
||||
- **Typed `WebSocketMessage`** = the GUI's broadcast pipeline is inspectable. The debugger can show "47 messages/sec broadcast on the `commits` channel." Without typed messages, the debugger shows raw JSON.
|
||||
|
||||
The 41 deferred Phase 3 sites are the **last gap**: the per-turn history manipulation (`_anthropic_history.append(...)`) needs to be typed before the debugger can step through the agent loop without losing type fidelity.
|
||||
|
||||
`code_path_audit_20260607` should not just measure cost — it should **measure what the agent debugger needs to see** at each step. The audit's `trace_action` output should be readable by both humans AND the future debugger UI.
|
||||
|
||||
This is the "interesting and compelling codebase" the user wants. This track is reconnaissance; `code_path_audit_20260607` is the spec; the next refactor track is the implementation; and the agent debugger is the application.
|
||||
|
||||
---
|
||||
|
||||
## 6. Files for Tier 1's review
|
||||
|
||||
**On branch `tier2/any_type_componentization_20260621` (20 commits):**
|
||||
|
||||
- `conductor/tracks/any_type_componentization_20260621/spec.md` — the WHY (5-pattern taxonomy, 89 sites, 7 phases)
|
||||
- `conductor/tracks/any_type_componentization_20260621/plan.md` — the WHAT (61 tasks; 7 phases)
|
||||
- `conductor/tracks/any_type_componentization_20260621/state.toml` — the WHERE (per-task commit SHAs; status: completed for the partial scope)
|
||||
- `docs/reports/ANY_TYPE_AUDIT_20260621.md` — the input artifact (300 Any → 5 patterns → 89 fat-struct candidates)
|
||||
- `docs/reports/TRACK_COMPLETION_any_type_componentization_20260621.md` — the WHAT WAS DONE (per-phase results, 48 promoted + 41 deferred, CI gates, 130 tests)
|
||||
- `conductor/code_styleguides/type_aliases.md` §12 — the CODIFIED INVARIANT (when TypeAlias → when dataclass → when JsonValue)
|
||||
- `scripts/audit_dataclass_coverage.py` + `.baseline.json` — the NEW CI GATE (counterpart to `audit_weak_types.py`)
|
||||
- `src/mcp_tool_specs.py`, `src/openai_schemas.py`, `src/provider_state.py` — the NEW MODULES
|
||||
- `src/{type_aliases, mcp_client, ai_client, openai_compatible, log_registry, api_hooks}.py` — the MODIFIED FILES
|
||||
|
||||
**Not on this branch (for context):**
|
||||
|
||||
- `conductor/tracks/code_path_audit_20260607/` — the parallel track that this work should inform. Read the existing spec + plan; use the recommendations in §2 above as input.
|
||||
- `docs/reports/EXCEPTION_HANDLING_AUDIT_20260616.md` — the precedent for this audit-then-refactor pattern (211 sites → audit → migration).
|
||||
|
||||
---
|
||||
|
||||
## 7. The recommendation, in one sentence
|
||||
|
||||
**Don't merge this branch yet — let `code_path_audit_20260607` use it as a reconnaissance warm-up, then drive the next refactor track (Phase 3 call-site migration + the remaining `Optional[T]`-return work + the new dataclass-coverage baseline of 200 sites) from the audit's per-action cost data.**
|
||||
|
||||
---
|
||||
|
||||
*Written by Tier 2 autonomous sandbox, 2026-06-21. Sent to Tier 1 as input to the `code_path_audit_20260607` track scoping.*
|
||||
Reference in New Issue
Block a user