diff --git a/sprint36_plan.md b/sprint36_plan.md new file mode 100644 index 0000000..f65de48 --- /dev/null +++ b/sprint36_plan.md @@ -0,0 +1,79 @@ +# Sprint 36 Plan: MCP Expansion — Architect Tools + Project Config + +## Context + +Sprint 36 exposes the Sprint 32 Architect Intake pipeline as MCP tools. +MarkdownSpecParser, TaskitemGeneratorV2, and TaskitemConfidenceAmbiguity are +fully implemented in C++ headers but not yet wired as MCP tools. Fix that, +add the `instructions` field to MCP initialize, and introduce per-project config. + +Primary goals: +1. Expose architect intake + taskitem generation as callable MCP tools +2. Make Claude auto-understand the editor via the initialize instructions field +3. Per-project .whetstone.json config with CWD auto-discovery + +Steps continue from Step 613 (last completed: Sprint35OperationalReadiness.h). + +--- + +## Phase 36a: Architect Intake MCP Tools (Steps 614–618) + +### Step 614: `whetstone_architect_intake` MCP Tool (12 tests) +Wire MarkdownSpecParser + RequirementNormalizationConflictDetector into a single +MCP tool call. Input: markdown spec string. Output: ParsedMarkdownSpec + conflict +signals + normalized requirements JSON. + +### Step 615: `whetstone_generate_taskitems` MCP Tool (12 tests) +Wire TaskitemGeneratorV2 + TaskitemConfidenceAmbiguity. Input: normalized plan +JSON (from Step 614 output). Output: array of AnnotatedTaskitem with confidence, +ambiguityCount, escalate, reasons. + +### Step 616: `whetstone_queue_ready` MCP Tool (12 tests) +Wire IntakeToQueueSimulationHarness. Input: array of AnnotatedTaskitem. Output: +{ready: bool, blockers: [...], readyCount, escalateCount, queueJson}. + +### Step 617: MCP initialize — add `instructions` field (12 tests) +Add an `instructions` field to the MCP `initialize` response. Content: the text +from tools/claude/system_prompt.txt. This makes Claude auto-understand the editor +without needing a CLAUDE.md file. Test: initialize response includes instructions. + +### Step 618: Phase 36a Integration (8 tests) +End-to-end: paste a markdown project spec → whetstone_architect_intake → +whetstone_generate_taskitems → whetstone_queue_ready → verified queue. + +--- + +## Phase 36b: Per-Project Config + tools.json Sync (Steps 619–623) + +### Step 619: `.whetstone.json` per-project config schema (12 tests) +Config file: `{workspace, defaultLanguage, agentRole, mcpWorkspaceAlias}`. +MCP server reads this on startup if present in --workspace dir. Lets different +projects have different language defaults without restart. + +### Step 620: Config auto-discovery (walk up from CWD) (12 tests) +If no `--workspace` flag: walk up from CWD until .whetstone.json found. This +means `cd myproject && whetstone_mcp` just works. + +### Step 621: `whetstone_set_workspace` MCP tool (12 tests) +Runtime tool: switch active workspace + language without restarting the binary. +Input: {workspace, language}. Required for HiveMind use case where one daemon +serves multiple projects. + +### Step 622: tools.json refresh — add all Sprint 32-35 tools (8 tests) +Update tools/claude/tools.json to include the new Sprint 36a tools plus any +Sprint 32-35 features that have MCP-appropriate interfaces (debug session, +workflow recorder, benchmark harness). Bump version to 2.0. + +### Step 623: Sprint 36 Integration + Summary (8 tests) +Validate: fresh Claude Code session + Whetstone MCP → Claude receives instructions +in initialize → calls whetstone_architect_intake on a real spec → generates queue. + +--- + +## Step & Test Summary + +| Phase | Steps | Tests | Theme | +|-------|-------|-------|-------| +| 36a | 614–618 | 56 | Architect intake MCP tools | +| 36b | 619–623 | 56 | Per-project config + tools.json refresh | +| **Total** | **614–623** | **~112** | 10 steps | diff --git a/sprint37_plan.md b/sprint37_plan.md new file mode 100644 index 0000000..f633d30 --- /dev/null +++ b/sprint37_plan.md @@ -0,0 +1,83 @@ +# Sprint 37 Plan: In-Editor Agent Chat Panel + +## Context + +Sprint 37 builds the "full window in the editor" agent UX — the plug-and-play +experience for non-technical users. Agent chat embedded directly in the ImGui +editor with live tool call visualization, mutation preview, and accept/reject +controls. No terminal required. + +Primary goals: +1. Embedded chat panel with message history and streaming responses +2. Live tool call visualization and AST mutation preview +3. Human-in-the-loop accept/reject for every agent mutation +4. Context auto-injection and session persistence + +--- + +## Phase 37a: Chat Window Core (Steps 624–628) + +### Step 624: Agent Chat Panel model (12 tests) +New panel: message history (scrollable), text input (multi-line), send button. +Messages: role (user/assistant/tool), content, timestamp. State lives in +AgentChatState sub-struct. Renders via ImGui but shares no state with EditorState +globals. + +### Step 625: Tool call visualization (12 tests) +When Claude calls a Whetstone tool, render it inline in the chat as a collapsible +block: `[TOOL: whetstone_mutate] ▶ setProperty fn1.name → "newName"`. Show +input/output JSON. Lets user see exactly what the agent is doing. + +### Step 626: AST mutation preview (12 tests) +Before applying any agent-requested mutation: show a side-by-side diff of the +generated code before vs after. User sees the change before it's committed. +Requires generating code from both old and new AST. + +### Step 627: Inline accept/reject controls (12 tests) +Under each mutation preview: [Accept] [Reject] [Modify]. Accept applies the +mutation. Reject discards it and posts "rejected: " back to the agent. +Modify opens the mutation in an editable JSON view. Human-in-the-loop at every +agent action. + +### Step 628: Phase 37a Integration (8 tests) +Full chat flow: user types spec → agent calls whetstone_generate_code → mutation +preview shown → user accepts → AST updated → code view refreshes. + +--- + +## Phase 37b: Context + Persistence (Steps 629–633) + +### Step 629: Project context auto-injection (12 tests) +On chat start, auto-inject a context block into the system prompt: active file +name, language, AST node count, open annotations count, workspace path. The agent +starts every conversation knowing where it is. + +### Step 630: Chat session persistence (12 tests) +Save/restore chat sessions per project file. Format: JSON alongside .whetstone.json. +Sessions indexed by timestamp. Reload on next open. User can continue a previous +conversation without losing context. + +### Step 631: Background task slots (parallel agent work) (12 tests) +Run up to N agent tasks in parallel (N from project config). Each slot has its +own chat thread. Slots shown as tabs in the chat panel. Lets user kick off +"generate the test suite" while also asking "explain this function." + +### Step 632: Agent task status overlay (12 tests) +Status bar item: `[Agent: 2 running, 1 pending]`. Click to open task panel. +Each task shows: description, elapsed time, tool calls made, current step. +Cancel button per task. + +### Step 633: Sprint 37 Integration + Summary (8 tests) +Demo scenario: open hivemind project → chat panel opens → paste BS-S1-01 task +description → agent generates drone/nexus code → user accepts mutations → +code panel shows generated Rust/C++ → chat session saved. + +--- + +## Step & Test Summary + +| Phase | Steps | Tests | Theme | +|-------|-------|-------|-------| +| 37a | 624–628 | 56 | Chat window core + mutation preview | +| 37b | 629–633 | 56 | Context injection + session persistence | +| **Total** | **624–633** | **~112** | 10 steps | diff --git a/sprint38_plan.md b/sprint38_plan.md new file mode 100644 index 0000000..1f27eb1 --- /dev/null +++ b/sprint38_plan.md @@ -0,0 +1,89 @@ +# Sprint 38 Plan: HiveMind Build Support — Drone Generators + Shared Types + +## Context + +Sprint 38 makes Whetstone the tool that builds HiveMind. Everything is C++20 +with CMake + vcpkg — the same toolchain as the editor itself. The drone binary +shares job schema types with Whetstone, and the generators produce the MQTT +client loops, SQLite schema layers, and dispatch tables that the drone needs. + +Primary goals: +1. Shared C++ type library for job schemas (editor + drone use the same headers) +2. MQTT and SQLite boilerplate generators targeting C++ / paho / sqlite3 +3. Full project skeleton generation from a description string + +--- + +## Phase 38a: Shared Type Library + Drone Skeleton (Steps 634–638) + +### Step 634: Job schema → typed C++ structs generator (12 tests) +New MCP tool: `whetstone_schema_to_cpp`. Input: JSON schema (the nexus job +payload schema). Output: C++ structs with nlohmann-json `from_json`/`to_json` +overloads, field validation, and a CMakeLists.txt INTERFACE target so both +the drone and Whetstone editor can include the same headers. + +### Step 635: Capability declaration struct generator (12 tests) +Generate the C++ types for capability graphs: NodeCapability, CapabilitySet, +EnergyContext, JobRequirements. These are shared between drone (declares +capabilities) and the orchestrator (matches jobs). Output as a header-only +library following Whetstone's existing header-only pattern. + +### Step 636: Error type synthesis for drone (12 tests) +Generate C++ error hierarchies for drone operations: MqttError, NexusError, +ExecutionError, CapabilityMismatch. Uses std::error_code / std::expected +patterns (C++23-compatible). Needed for drone's error handling across the +MQTT, SQLite, and executor layers. + +### Step 637: Cross-platform CMake target generator (12 tests) +New annotation: @Platform(target = "aarch64-apple-darwin") on platform-specific +code blocks. Generator emits CMake `if(CMAKE_SYSTEM_PROCESSOR MATCHES ...)` guards +and compile-time `#ifdef` blocks. Lets one drone CMakeLists.txt build correctly +on Mac M2, x86_64 Linux, and N100 without per-platform forks. + +### Step 638: Phase 38a Integration (8 tests) +Generate a skeleton drone binary: CMakeLists.txt, main.cpp entry, capability +declaration, shared type headers included, all targets building cleanly on the +host platform via vcpkg. + +--- + +## Phase 38b: Infrastructure Generators (Steps 639–643) + +### Step 639: `whetstone_generate_project` MCP tool (12 tests) +Generate an entire C++ project skeleton from a description string. Input: {name, +description, dependencies (vcpkg names)}. Output: CMakeLists.txt, main.cpp, +module stub headers, test scaffold following Whetstone's own architecture +conventions. The HiveMind drone bootstrap in one call. + +### Step 640: MQTT pub/sub boilerplate generator (12 tests) +Given topic names + payload schemas, generate C++ MQTT client code using paho-mqtt +(already in vcpkg). Output: typed topic handler classes with nlohmann-json +deserialization, connection/reconnect logic, QoS config. Drone subscribes to +borg/energy/context, borg/jobs/pending, borg/registry/commit — one generator call. + +### Step 641: SQLite schema → C++ data layer generator (12 tests) +Input: SQL CREATE TABLE statements (from hivemind/ARCHITECTURE.md nexus schema). +Output: C++ structs + sqlite3 helper classes with prepared statement wrappers, +CRUD methods, and transaction helpers. Generates the entire nexus DB layer +without hand-writing a single SQL string. + +### Step 642: Job dispatch table generator (12 tests) +Input: job type registry (job_type → {required_caps, payload_schema, executor}). +Output: C++ dispatch table — std::unordered_map with +type-safe payload parsing and executor function stubs. The drone's dispatch +table generated from one schema file. + +### Step 643: Sprint 38 Integration + Summary (8 tests) +End-to-end: `whetstone_generate_project` for drone → MQTT generator → SQLite +generator → dispatch table → drone binary compiling cleanly via CMake + vcpkg +on all target platforms. + +--- + +## Step & Test Summary + +| Phase | Steps | Tests | Theme | +|-------|-------|-------|-------| +| 38a | 634–638 | 56 | Shared C++ types + capability structs + platform CMake | +| 38b | 639–643 | 56 | Project skeleton + MQTT + SQLite + dispatch generators | +| **Total** | **634–643** | **~112** | 10 steps | diff --git a/sprint39_plan.md b/sprint39_plan.md new file mode 100644 index 0000000..8e816f7 --- /dev/null +++ b/sprint39_plan.md @@ -0,0 +1,82 @@ +# Sprint 39 Plan: Self-Hosting + Release Pipeline + +## Context + +Sprint 39 makes Whetstone build itself and ship as a product. Self-hosting +validates the entire constructive editing model on a real, complex C++ project. +The release pipeline (AppImage, HiveMind-push auto-update, plugin system) turns +the editor into something deployable across the drone fleet. + +Primary goals: +1. Whetstone opens and navigates its own codebase +2. CMake build system generated from project AST +3. In-editor test runner replaces external build cycle +4. AppImage packaging + HiveMind auto-update mechanism +5. Plugin system for third-party language generators + +--- + +## Phase 39a: Self-Hosting Pipeline (Steps 644–648) + +### Step 644: `.whetstone.json` for the editor project itself (12 tests) +The Whetstone project describes itself using its own config format. This validates +that the config system works for real C++ projects, not just toy examples. +Also: the editor can open itself and navigate its own AST. + +### Step 645: CMake generator from Whetstone project description (12 tests) +Given a project AST, generate CMakeLists.txt. Supports: FetchContent deps, +vcpkg integration, test targets, install rules. Lets Whetstone regenerate its own +build system from the AST — the ultimate self-hosting test. + +### Step 646: In-editor test runner (12 tests) +Run the Whetstone test suite (stepNNN_test binaries) from within the chat panel: +[Run Tests] button → streams output → shows pass/fail per step → links failures +to the relevant source file. Replaces the external build+test cycle. + +### Step 647: Self-modification safety guard (12 tests) +Detect when an agent-requested mutation targets a file that is part of the running +editor binary. Block with: "Cannot mutate live binary — use a build/restart cycle." +Prevents the editor from corrupting its own running code. + +### Step 648: Phase 39a Integration (8 tests) +Self-hosting demo: open whetstone_DSL project in the editor → ask agent to add a +new MCP tool → agent generates the header, wires it in CMake → in-editor test +runner validates → self-modification guard active. + +--- + +## Phase 39b: Distribution + Plugin System (Steps 649–653) + +### Step 649: AppImage / .deb package generator (12 tests) +Generate packaging scripts from project metadata. Output: working AppImage build +script and debian/control. Makes `whetstone` installable as a system package. +Runs as a CI step in the project. + +### Step 650: HiveMind-push auto-update mechanism (12 tests) +Drone worker type: `update_editor`. When HiveMind publishes a new editor version +to the apiary, drones on all nodes receive the update job, download the AppImage, +verify hash, replace binary, restart service. Zero-touch updates across the fleet. + +### Step 651: Language generator plugin manifest (12 tests) +Define a plugin format: a .so / shared library that exports a `ProjectionGenerator` +subclass. Third parties can add new language generators without recompiling the +editor. Plugin discovery: scan workspace for whetstone-plugin-*.so. + +### Step 652: Privacy-preserving local telemetry (12 tests) +Collect: session length, tool call counts, error rates, most-used generators. +Store locally in ~/.whetstone/telemetry.db. Aggregate weekly report. Never +transmits externally. Feeds the Active Inference engine's entropy scoring. + +### Step 653: Sprint 39 Integration + Summary (8 tests) +Full release pipeline validated: build → package → AppImage → HiveMind deploy +→ all nodes updated. Plugin system tested with a new language generator. + +--- + +## Step & Test Summary + +| Phase | Steps | Tests | Theme | +|-------|-------|-------|-------| +| 39a | 644–648 | 56 | Self-hosting + CMake generator + in-editor test runner | +| 39b | 649–653 | 56 | AppImage + HiveMind auto-update + plugin system | +| **Total** | **644–653** | **~112** | 10 steps | diff --git a/sprint40_plan.md b/sprint40_plan.md new file mode 100644 index 0000000..9c958dc --- /dev/null +++ b/sprint40_plan.md @@ -0,0 +1,105 @@ +# Sprint 40 Plan: HiveMind Integration — Whetstone + Nexus as One System + +## Context + +Sprint 40 is the convergence sprint. Whetstone and HiveMind become one integrated +system: the editor dispatches jobs to the swarm, monitors drone status, browses +the apiary, sees the energy state, and acts as the Pilot seat. Active Inference +closes the loop — the editor detects entropy and feeds it back to the swarm. + +This is the "system is complete" milestone. + +Primary goals: +1. Editor dispatches jobs directly to the HiveMind nexus +2. Live swarm status, apiary browser, and energy context panels +3. Active Inference entropy scanner in the editor +4. Pilot queue panel for human-in-the-loop swarm steering +5. Cross-session context bridge: editor ↔ HiveMind ↔ drone ↔ editor + +--- + +## Phase 40a: Nexus Integration (Steps 654–658) + +### Step 654: HiveMind job publisher from editor (12 tests) +New MCP tool: `whetstone_dispatch_to_hivemind`. Input: taskitem JSON (AnnotatedTaskitem +format). Writes job to nexus SQLite + publishes to borg/jobs/pending. Editor can +now feed the swarm directly — architect → Whetstone → HiveMind → drone. + +### Step 655: Job status subscriber panel (12 tests) +New editor panel: "Swarm Status". Subscribes to MQTT topics for job updates. +Shows: pending jobs, claimed by which node, running duration, completed/failed. +Live refresh. Editor becomes the Pilot seat for the HiveMind. + +### Step 656: Apiary browser panel (12 tests) +Browse /mnt/nas/swarm_tools/ from within the editor. Shows: tool name, version, +language, capabilities, doc summary. Click to load tool source into editor buffer. +Search by capability. Lets architect see what the swarm has already built. + +### Step 657: Energy context status bar (12 tests) +Subscribe to borg/energy/context. Show current energy state in editor status bar: +`HighSolar 450W` or `Conservation 28%`. Flashes orange in conservation mode. +Agent context injection: include energy state in system prompt so agent knows +whether to suggest GPU-heavy or CPU-light implementations. + +### Step 658: Phase 40a Integration (8 tests) +Full loop: architect opens editor → sees energy state → writes spec → dispatches +job to HiveMind → watches job status panel → drone completes → result appears in +apiary browser → architect loads result into buffer. + +--- + +## Phase 40b: Active Inference Bridge (Steps 659–663) + +### Step 659: Entropy scanner — editor-side (12 tests) +Editor scans open workspace: detect duplicate function signatures, similar module +names, unused exports. Score: entropy count. If above threshold, suggest: +"Consider extracting common logic — generate refactor job?" User can dispatch +the suggestion directly to HiveMind. + +### Step 660: `whetstone_generate_inference_job` MCP tool (12 tests) +Given an entropy observation (duplication, gap, staleness), generate a properly +formatted HiveMind Active Inference job: {type: "refactor", goal: "...", context: +{files, entropy_score}, bounty: "normal"}. Write to nexus. + +### Step 661: Pilot queue panel (12 tests) +A dedicated panel showing jobs flagged for human review (escalate=true, or +ambiguity > threshold). Jobs arrive via MQTT subscription to a pilot-specific +topic. Human can: approve (dispatch to swarm), reject (discard), modify (edit +task in editor), inject strategy (add a free-text guidance note). + +### Step 662: Cross-session context bridge (12 tests) +When the HiveMind dispatches an agent_task job with context_files, the drone +can launch whetstone_mcp --workspace and call whetstone_architect_intake on +those files. Output feeds back to the editor session that dispatched the job. +Closes the loop: editor ↔ HiveMind ↔ drone ↔ editor. + +### Step 663: Sprint 40 Integration + Final Summary (8 tests) +The complete system: Whetstone editor + HiveMind nexus + drone workers + apiary ++ active inference + pilot seat. One integrated system. Sprint 40 is the +"system is complete" milestone. + +--- + +## Step & Test Summary + +| Phase | Steps | Tests | Theme | +|-------|-------|-------|-------| +| 40a | 654–658 | 56 | Nexus dispatch + swarm status + apiary + energy | +| 40b | 659–663 | 56 | Active inference + pilot queue + context bridge | +| **Total** | **654–663** | **~112** | 10 steps | + +--- + +## Program Summary: Sprints 36–40 + +| Sprint | Steps | Theme | +|--------|-------|-------| +| 36 | 614–623 | MCP expansion + architect intake tools | +| 37 | 624–633 | In-editor agent chat panel | +| 38 | 634–643 | HiveMind build support (Rust, MQTT, SQLite generators) | +| 39 | 644–653 | Self-hosting + distribution pipeline | +| 40 | 654–663 | HiveMind full integration + Pilot seat | + +**Total new steps:** 50 +**Total tests (est.):** ~550 +**System state after Sprint 40:** Whetstone + HiveMind = one integrated agentic system diff --git a/sprint_codehealth_A.md b/sprint_codehealth_A.md new file mode 100644 index 0000000..c8840b6 --- /dev/null +++ b/sprint_codehealth_A.md @@ -0,0 +1,155 @@ +# Sprint Code-Health-A: Dispatch & Duplication Elimination + +> **Goal:** Eliminate the worst semantic-density killers — the copy-paste dispatch chains +> and duplicated generator methods that account for ~2,000+ lines of redundant code. +> +> **Prerequisite:** None. This sprint can run independently. +> **Estimated steps:** 12–15 +> **Estimated tests:** 30–40 + +--- + +## Context + +Three major duplication sites inflate the codebase: + +1. **ProjectionGenerator.h `dispatchGenerate()`** — 220-line if-else chain dispatching + ~90 annotation/node types by string comparison. Every new annotation type adds 2 lines. +2. **CompactAST.h `extractSemanticSummary()`** — 340-line if-else chain doing the same + string-match + static_cast + JSON serialization for every annotation type. +3. **Generator `emitBody()` duplication** — identical 12-line function copy-pasted into + RustGenerator, JavaGenerator, JavaScriptGenerator, and every other generator. + +--- + +## Steps + +### Step 1–3: Annotation Self-Registration + +**Goal:** Each annotation type registers itself so dispatch chains become table lookups. + +**Step 1: AnnotationRegistry infrastructure** +- Create `AnnotationRegistry.h` with: + ```cpp + using AnnotationFactory = std::function; + using AnnotationVisitor = std::function; + using AnnotationSerializer = std::function; + + class AnnotationRegistry { + static auto& visitors() { static std::unordered_map m; return m; } + static auto& serializers() { static std::unordered_map m; return m; } + public: + static void registerVisitor(const std::string& type, AnnotationVisitor v); + static void registerSerializer(const std::string& type, AnnotationSerializer s); + static std::string dispatch(const ProjectionGenerator* gen, const ASTNode* node); + static nlohmann::json serialize(const ASTNode* node); + }; + ``` +- Tests: registry lookup works, unknown type returns fallback string + +**Step 2: Migrate ProjectionGenerator dispatch (Part 1 — Subjects 1–5)** +- For each annotation in Subjects 1–5 (Memory, Type System, Concurrency, Scope, Shims): + add a static registration block in the annotation's own header +- Replace corresponding if-else branches in `dispatchGenerate()` with `AnnotationRegistry::dispatch()` +- Tests: all existing step tests for these annotations still pass, dispatch returns same results + +**Step 3: Migrate ProjectionGenerator dispatch (Part 2 — Subjects 6–9 + Core + AST nodes)** +- Complete the migration for remaining subjects (Optimization, Meta, Policy, Workflow, Semantic Core) +- Migrate non-annotation AST node dispatch (ClassDeclaration, EnumDeclaration, SQL nodes, etc.) +- Delete the entire 220-line if-else chain, replace with: + ```cpp + std::string dispatchGenerate(const ProjectionGenerator* gen, const ASTNode* node) { + return AnnotationRegistry::dispatch(gen, node); + } + ``` +- Tests: full dispatch regression (all 90+ types), empty node, unknown type + +### Step 4–5: CompactAST Serialization Refactor + +**Step 4: Add `toCompactJson()` virtual method to annotation base** +- Add virtual `nlohmann::json toCompactJson() const { return {}; }` to `ASTNode` or annotation base +- Implement for the first 20 annotation types (Subjects 1–3) +- Tests: round-trip: serialize → deserialize → compare for each type + +**Step 5: Complete CompactAST migration** +- Implement `toCompactJson()` for remaining annotation types (Subjects 4–9 + Core) +- Replace `extractSemanticSummary()` 340-line chain with: + ```cpp + json extractSemanticSummary(const ASTNode* node) { + json sem; + for (auto* a : node->getChildren("annotations")) { + json j = a->toCompactJson(); + if (!j.empty()) sem[a->shortName()] = j; + } + return sem; + } + ``` +- Tests: equivalence with old output for all annotation types, empty annotations, mixed types + +### Step 6–7: Generator Base Class Cleanup + +**Step 6: Extract shared generator methods to ProjectionGenerator base** +- Move `emitBody()`, `appendIndented()`, `quoteIdentifier()` to `ProjectionGenerator` base +- Remove duplicates from RustGenerator, JavaGenerator, JavaScriptGenerator, + PythonGenerator, CppGenerator, MySQLGenerator, CommonLispGenerator, WatGenerator +- Tests: each generator produces identical output before/after for sample ASTs + +**Step 7: Extract shared STUB patterns to base** +- The `"// STUB: empty AST body; user implementation required"` pattern appears in every generator +- Move to `ProjectionGenerator::emitStubBody()` with language-aware comment syntax: + - `//` for C-family, `#` for Python, `;;` for Lisp, `--` for SQL +- Tests: STUB output correct for each language, non-empty body unchanged + +### Step 8–9: LSPClient Response Handler Dedup + +**Step 8: Extract JSON response parsing helpers** +- LSPClient.h has repeated `result.is_array()` / `result.is_object()` / `result.contains("items")` + patterns for completions, symbols, definitions +- Create private helpers: + ```cpp + std::vector parseCompletionItems(const nlohmann::json& result); + std::vector parseDocumentSymbols(const nlohmann::json& result); + DefinitionLocation parseDefinitionLocation(const nlohmann::json& result); + ``` +- Tests: parse array form, parse object-with-items form, empty result, malformed result + +**Step 9: Simplify handleResponse dispatch** +- Replace the `if (id == lastCompletionRequestId_)` chain with a request-type map: + ```cpp + std::unordered_map> pendingHandlers_; + ``` +- Each `sendRequest()` registers its handler; `handleResponse()` becomes a lookup +- Tests: concurrent requests, handler cleanup after response, unknown id ignored + +### Step 10–11: Headless RPC Dispatch Cleanup + +**Step 10: Audit DispatchPart1–4.h for string-match duplication** +- These files dispatch RPC method strings to handler functions +- Assess: can these use a `std::unordered_map` like the LSP fix? +- If yes: refactor. If the dispatch is already small (~10 per file), leave it. +- Tests: all headless RPC methods still route correctly + +**Step 11: Consolidate dispatch infrastructure** +- If AnnotationRegistry and RPC dispatch both use string→function maps, + extract a shared `StringDispatch` template utility +- Tests: template works for both use cases + +### Step 12: Regression & Metrics + +**Step 12: Full regression + line count delta** +- Run all existing tests (615 files) +- Measure: total .h lines before vs after +- Expected savings: ~1,500–2,000 lines removed +- Document in progress.md +- Tests: no regressions, line count report + +--- + +## Success Criteria + +- [ ] No if-else chain in codebase exceeds 30 lines for type dispatch +- [ ] `emitBody()` exists in exactly one place (base class) +- [ ] CompactAST `extractSemanticSummary()` is under 20 lines +- [ ] ProjectionGenerator `dispatchGenerate()` is under 10 lines +- [ ] All 615 existing tests pass +- [ ] Net line reduction: ≥1,500 lines