diff --git a/sprint41_plan.md b/sprint41_plan.md new file mode 100644 index 0000000..7945fd3 --- /dev/null +++ b/sprint41_plan.md @@ -0,0 +1,224 @@ +# Sprint 41 Plan: MCP Codegen Tools — Wire Missing Plumbing + +## Context + +Sprint 41 is a focused plumbing sprint. Two C++ classes have been implemented +(Steps 634, 642) but were never registered as MCP tools. Both exist in the +generator layer but are invisible to Claude Code. + +This sprint makes them callable: +- `whetstone_schema_to_cpp` — JSON schema → typed C++ struct + nlohmann serializers +- `whetstone_generate_dispatch_table` — job entry specs → C++ dispatch table header + +Use case for HiveMind: the drone binary (`hivemind/drone/src/`) currently has +hand-scaffolded structs and dispatch tables. These tools let an agent regenerate +them from the canonical schemas and capabilities.json automatically. + +--- + +## Existing C++ Implementations (Do Not Rewrite) + +| Class | File | Step | Interface | +|-------|------|------|-----------| +| `SchemaToCppGenerator` | `editor/src/SchemaToCppGenerator.h` | 634 | `::generate(json schema, string headerName, string targetName)` → `SchemaToCppOutput{success, headerCode, cmakeInterfaceTarget, errors[]}` | +| `JobDispatchTableGenerator` | `editor/src/JobDispatchTableGenerator.h` | 642 | `::generate(vector)` → `JobDispatchTableOutput{success, headerCode, errors[]}` | + +`SchemaToCppGenerator::toolName()` already returns `"whetstone_schema_to_cpp"`. + +--- + +## Wiring Pattern (copy from Sprint 36) + +The pattern is identical to `RegisterArchitectIntakeTools.h`: + +1. Create `editor/src/mcp/RegisterCodegenTools.h` + - `#include` both generator headers + - Define `registerCodegenTools()` method (same style as `registerArchitectIntakeTools()`) + - Push tool definition to `tools_` vector + - Assign lambda to `toolHandlers_[name]` + +2. Add `#include "mcp/RegisterCodegenTools.h"` to `MCPServer.h` + (after line 550, alongside other Register includes) + +3. Add `registerCodegenTools();` call in `registerWhetstoneTools()` inside + `RegisterOnboardingAndAllTools.h` (after `registerArchitectIntakeTools()`) + +4. Add two entries to `tools/claude/tools.json` + +5. Rebuild: `cmake --build editor/build-native --target whetstone_mcp` + +--- + +## Steps + +### Step 664: `RegisterCodegenTools.h` — whetstone_schema_to_cpp (12 tests) + +Create `editor/src/mcp/RegisterCodegenTools.h`. Wire `SchemaToCppGenerator`. + +Input schema for the MCP tool: +```json +{ + "schema": { "type": "object", "description": "JSON Schema object with 'title' and 'properties'." }, + "header_name": { "type": "string", "description": "Output header filename, e.g. 'EnergyContext.h'." }, + "target_name": { "type": "string", "description": "CMake INTERFACE target name, e.g. 'energy_context_types'." } +} +``` + +Output (returned as JSON): +```json +{ + "success": true, + "header_code": "...", + "cmake_interface_target": "...", + "errors": [] +} +``` + +Tests (12): valid schema produces struct + serializers, schema without title +errors cleanly, empty properties produces `raw` field fallback, integer/bool/number +types map correctly, sanitizeIdentifier strips special chars, cmakeInterfaceTarget +is non-empty on success, invalid (non-object) schema errors, multi-field struct +round-trips via from_json/to_json, MCP handler returns success=false on bad input, +handler returns success=true on minimal valid schema, headerCode contains +`#pragma once`, toolName() == "whetstone_schema_to_cpp". + +### Step 665: `RegisterCodegenTools.h` — whetstone_generate_dispatch_table (12 tests) + +Add `whetstone_generate_dispatch_table` to the same `RegisterCodegenTools.h`. + +`JobDispatchEntrySpec` fields: `jobType` (string), `requiredCaps` (array of string), +`payloadType` (string), `executor` (string — C++ function name or lambda expression). + +Input schema for the MCP tool: +```json +{ + "entries": { + "type": "array", + "description": "Array of {job_type, required_caps[], payload_type, executor} objects.", + "items": { + "type": "object", + "properties": { + "job_type": { "type": "string" }, + "required_caps": { "type": "array", "items": { "type": "string" } }, + "payload_type": { "type": "string" }, + "executor": { "type": "string", "description": "C++ callable expression, e.g. 'handleCudaTask'" } + }, + "required": ["job_type", "executor"] + } + } +} +``` + +Output: +```json +{ + "success": true, + "header_code": "...", + "errors": [] +} +``` + +Tests (12): single entry produces valid C++ header, multiple entries all appear +in output, empty entries[] errors with entries_required, missing executor errors, +headerCode contains `#pragma once` and `makeDispatchTable`, requiredCaps appear +as comments in output, MCP handler parses json array of objects correctly, +handler returns success=false on bad input, output is parseable as C++ header +(contains `{` and `}`), job_type appears as string key in table, executor appears +as value in table, roundtrip: parse output → verify jobType string present. + +### Step 666: Wire into MCPServer.h + RegisterOnboardingAndAllTools.h + tools.json (8 tests) + +**Files modified:** +- `editor/src/MCPServer.h` — add `#include "mcp/RegisterCodegenTools.h"` after line 550 +- `editor/src/mcp/RegisterOnboardingAndAllTools.h` — add `registerCodegenTools();` in `registerWhetstoneTools()` +- `tools/claude/tools.json` — add two tool entries (see format below) + +**tools.json entries to add** (match existing entry format exactly): +```json +{ + "name": "whetstone_schema_to_cpp", + "description": "Generate a typed C++ header struct with nlohmann JSON serializers from a JSON Schema object. Returns header_code (ready to write to a .h file) and a cmake_interface_target snippet.", + "input_schema": { + "type": "object", + "properties": { + "schema": { "type": "object", "description": "JSON Schema with 'title' and 'properties'." }, + "header_name": { "type": "string", "description": "Output header filename, e.g. 'EnergyContext.h'." }, + "target_name": { "type": "string", "description": "CMake INTERFACE target name." } + }, + "required": ["schema", "header_name", "target_name"] + } +}, +{ + "name": "whetstone_generate_dispatch_table", + "description": "Generate a C++ dispatch table header (makeDispatchTable()) from a list of job type specs. Each entry maps a job_type string to a C++ executor callable.", + "input_schema": { + "type": "object", + "properties": { + "entries": { + "type": "array", + "description": "Array of job dispatch entries.", + "items": { + "type": "object", + "properties": { + "job_type": { "type": "string" }, + "required_caps": { "type": "array", "items": { "type": "string" } }, + "payload_type": { "type": "string" }, + "executor": { "type": "string" } + }, + "required": ["job_type", "executor"] + } + } + }, + "required": ["entries"] + } +} +``` + +Tests (8): MCPServer initializes without error with new includes, `registerWhetstoneTools()` +calls `registerCodegenTools()`, tools.json entries are valid JSON, `whetstone_schema_to_cpp` +present in tools.json, `whetstone_generate_dispatch_table` present in tools.json, +tool count increases by 2 from previous sprint, MCPServer tools_ vector contains both +new tool names, handlers map contains both new tool names. + +### Step 667: Rebuild whetstone_mcp + smoke test (8 tests) + +Build the MCP binary and verify both new tools respond correctly over stdio. + +```bash +cmake -S editor -B editor/build-native +cmake --build editor/build-native --target whetstone_mcp +``` + +Smoke test via stdin/stdout (MCP protocol): +1. Send `tools/list` — verify both new tool names appear +2. Send `tools/call` for `whetstone_schema_to_cpp` with the `energy_context.schema.json` + from `hivemind/schemas/` — verify success=true, header_code non-empty +3. Send `tools/call` for `whetstone_generate_dispatch_table` with the 4 HiveMind job + types (agent_swarm, cuda_task, compile_job, shell_script) — verify success=true + +Tests (8): binary builds without error, binary runs without crash on `--help`, +tools/list response is valid JSON, tools/list contains whetstone_schema_to_cpp, +tools/list contains whetstone_generate_dispatch_table, schema_to_cpp smoke call +returns success=true, dispatch_table smoke call returns success=true, binary +exits cleanly on SIGTERM. + +### Step 668: Sprint 41 Integration Summary (8 tests) + +Create `editor/src/Sprint41IntegrationSummary.h`. +Record: steps completed, tools added (count before/after), files modified, +regression check result. + +Tests (8): summary struct is constructable, tool_count_before == 82, +tool_count_after == 84, steps_completed == 4, files_modified contains +RegisterCodegenTools.h, files_modified contains MCPServer.h, +files_modified contains tools.json, success == true. + +--- + +## Architecture Gate (applies to all steps) + +- All new code in `editor/src/mcp/RegisterCodegenTools.h` — header-only +- File must stay under 600 lines +- No new external dependencies +- Binary rebuild must pass without warnings +- Test count per step: as specified above (not a fixed template) diff --git a/sprint41_taskitems.json b/sprint41_taskitems.json new file mode 100644 index 0000000..50309e1 --- /dev/null +++ b/sprint41_taskitems.json @@ -0,0 +1,150 @@ +{ + "sprint": 41, + "goal": "Wire whetstone_schema_to_cpp and whetstone_generate_dispatch_table as live MCP tools", + "context": "Two C++ generator classes exist (Steps 634, 642) but are not registered in the MCP layer. This sprint is pure plumbing — no new logic. The pattern to follow is RegisterArchitectIntakeTools.h (Sprint 36).", + "architectureInvariants": [ + "Header-only C++ — all new code in .h files", + "600-line file limit — split if approaching", + "MCP-first — every capability exposed as an MCP tool", + "No new external dependencies", + "Binary must rebuild without warnings after each step" + ], + "taskitems": [ + { + "taskId": "S41-664", + "title": "Create RegisterCodegenTools.h — wire whetstone_schema_to_cpp", + "milestoneId": "Sprint41", + "dependencyTaskIds": [], + "prerequisiteOps": [ + "read editor/src/SchemaToCppGenerator.h", + "read editor/src/mcp/RegisterArchitectIntakeTools.h", + "read editor/src/mcp/RegisterASTTools.h" + ], + "queueReady": true, + "confidence": 96, + "ambiguityCount": 0, + "escalate": false, + "reasons": [ + "SchemaToCppGenerator.h is complete. Interface: SchemaToCppGenerator::generate(json schema, string headerName, string targetName) → SchemaToCppOutput{success, headerCode, cmakeInterfaceTarget, errors[]}. toolName() already returns 'whetstone_schema_to_cpp'.", + "Create editor/src/mcp/RegisterCodegenTools.h. Define registerCodegenTools() method. Push tool to tools_ with name 'whetstone_schema_to_cpp', description, and input_schema {schema (object), header_name (string), target_name (string)}. All required.", + "Lambda handler: parse args['schema'] as json, args['header_name'] and args['target_name'] as strings. Call SchemaToCppGenerator::generate(). Return {success, header_code, cmake_interface_target, errors} as json.", + "Write editor/tests/step664_test.cpp with 12 tests: valid schema produces struct, schema without title errors, empty properties produces 'raw' field, integer/bool/number types map to int/bool/double, sanitizeIdentifier strips special chars, cmakeInterfaceTarget non-empty on success, invalid schema errors cleanly, multi-field struct round-trips via from_json/to_json, MCP handler returns success=false on bad input, success=true on minimal valid, headerCode contains '#pragma once', toolName() == 'whetstone_schema_to_cpp'.", + "Add step664_test to CMakeLists.txt using the same pattern as step663_test.", + "Build and run: cmake --build editor/build-native --target step664_test && ./editor/build-native/step664_test" + ] + }, + { + "taskId": "S41-665", + "title": "Add whetstone_generate_dispatch_table to RegisterCodegenTools.h", + "milestoneId": "Sprint41", + "dependencyTaskIds": ["S41-664"], + "prerequisiteOps": [ + "read editor/src/JobDispatchTableGenerator.h", + "read editor/src/mcp/RegisterCodegenTools.h" + ], + "queueReady": true, + "confidence": 94, + "ambiguityCount": 0, + "escalate": false, + "reasons": [ + "JobDispatchTableGenerator.h is complete. Interface: JobDispatchTableGenerator::generate(vector) → JobDispatchTableOutput{success, headerCode, errors[]}. JobDispatchEntrySpec has: jobType, requiredCaps (vector), payloadType, executor (all strings).", + "Add whetstone_generate_dispatch_table to registerCodegenTools() in RegisterCodegenTools.h. Input schema: {entries: array of {job_type (string, required), required_caps (array of string, optional), payload_type (string, optional), executor (string, required)}}.", + "Lambda handler: parse args['entries'] json array. For each element, construct JobDispatchEntrySpec. Call JobDispatchTableGenerator::generate(). Return {success, header_code, errors}.", + "Write editor/tests/step665_test.cpp with 12 tests: single entry produces valid C++ header, multiple entries all appear, empty entries[] returns entries_required error, missing executor handled, headerCode contains '#pragma once' and 'makeDispatchTable', requiredCaps appear as comments, handler parses json array correctly, success=false on bad input, output contains '{' and '}', job_type appears as string key, executor appears as value, roundtrip job_type string present.", + "Add step665_test to CMakeLists.txt.", + "Build and run: cmake --build editor/build-native --target step665_test && ./editor/build-native/step665_test" + ] + }, + { + "taskId": "S41-666", + "title": "Wire RegisterCodegenTools.h into MCPServer + tools.json", + "milestoneId": "Sprint41", + "dependencyTaskIds": ["S41-665"], + "prerequisiteOps": [ + "read editor/src/MCPServer.h lines 530-560", + "read editor/src/mcp/RegisterOnboardingAndAllTools.h", + "read tools/claude/tools.json" + ], + "queueReady": true, + "confidence": 98, + "ambiguityCount": 0, + "escalate": false, + "reasons": [ + "MCPServer.h: add '#include \"mcp/RegisterCodegenTools.h\"' after the existing RegisterArchitectIntakeTools include (around line 550). This follows the identical pattern of every other Register*.h in the file.", + "RegisterOnboardingAndAllTools.h: add 'registerCodegenTools();' inside registerWhetstoneTools() after 'registerArchitectIntakeTools();'. RegisterOnboardingAndAllTools.h is the single place all registerX() calls are collected.", + "tools/claude/tools.json: add two entries matching the exact JSON structure of existing entries. Entry 1: name='whetstone_schema_to_cpp', description='Generate a typed C++ header struct with nlohmann JSON serializers from a JSON Schema object. Returns header_code and cmake_interface_target.', input_schema with schema(object), header_name(string), target_name(string) all required. Entry 2: name='whetstone_generate_dispatch_table', description='Generate a C++ dispatch table header (makeDispatchTable()) from a list of job type specs.', input_schema with entries(array of objects with job_type+executor required).", + "Write editor/tests/step666_test.cpp with 8 tests verifying: MCPServer initializes, registerWhetstoneTools calls registerCodegenTools, tools.json is valid JSON, both tool names present in tools.json, tool count is previous+2, tools_ vector contains both new names, handlers map contains both new names, no duplicate tool names.", + "Add step666_test to CMakeLists.txt.", + "Build and run: cmake --build editor/build-native --target step666_test && ./editor/build-native/step666_test" + ] + }, + { + "taskId": "S41-667", + "title": "Rebuild whetstone_mcp binary and smoke test both new tools", + "milestoneId": "Sprint41", + "dependencyTaskIds": ["S41-666"], + "prerequisiteOps": [ + "read hivemind/schemas/energy_context.schema.json", + "read editor/src/mcp_main.cpp" + ], + "queueReady": true, + "confidence": 90, + "ambiguityCount": 1, + "escalate": false, + "reasons": [ + "Build: cmake -S editor -B editor/build-native && cmake --build editor/build-native --target whetstone_mcp. Must complete without errors or warnings.", + "Smoke test via MCP stdio protocol (send JSON-RPC to stdin, read from stdout). Use the MCPBridge stdio format: {jsonrpc:'2.0', id:1, method:'tools/list', params:{}}. Verify both new tool names appear in the response.", + "Smoke test whetstone_schema_to_cpp: send tools/call with the energy_context.schema.json content as 'schema', header_name='EnergyContext.h', target_name='energy_context_types'. Verify success=true and header_code contains 'struct'.", + "Smoke test whetstone_generate_dispatch_table: send tools/call with entries for the 4 HiveMind job types [{job_type:'agent_swarm',executor:'handleAgentSwarm'},{job_type:'cuda_task',executor:'handleCudaTask'},{job_type:'compile_job',executor:'handleCompileJob'},{job_type:'shell_script',executor:'handleShellScript'}]. Verify success=true and header_code contains 'makeDispatchTable'.", + "Ambiguity: the exact JSON-RPC framing for the whetstone_mcp stdio protocol — read mcp_main.cpp to confirm MCPBridge input format before crafting test input.", + "Write editor/tests/step667_test.cpp with 8 tests: binary exists + executable, runs without crash on --help, tools/list is valid JSON, schema_to_cpp in tools/list, dispatch_table in tools/list, schema_to_cpp call returns success=true, dispatch_table call returns success=true, binary exits on SIGTERM.", + "Add step667_test to CMakeLists.txt." + ] + }, + { + "taskId": "S41-668", + "title": "Sprint 41 integration summary", + "milestoneId": "Sprint41", + "dependencyTaskIds": ["S41-667"], + "prerequisiteOps": [ + "read editor/src/Sprint40IntegrationSummary.h" + ], + "queueReady": true, + "confidence": 99, + "ambiguityCount": 0, + "escalate": false, + "reasons": [ + "Create editor/src/Sprint41IntegrationSummary.h. Model it exactly on Sprint40IntegrationSummary.h.", + "Capture: tool_count_before=82, tool_count_after=84, steps_completed=5 (664-668), files_added=['RegisterCodegenTools.h'], files_modified=['MCPServer.h','RegisterOnboardingAndAllTools.h','tools/claude/tools.json'], success=true.", + "Write editor/tests/step668_test.cpp with 8 tests: struct constructable, tool_count_before==82, tool_count_after==84, steps_completed==5, files_added contains RegisterCodegenTools.h, files_modified contains MCPServer.h, files_modified contains tools.json, success==true.", + "Add step668_test to CMakeLists.txt.", + "Run full sprint regression: cmake --build editor/build-native --target step664_test step665_test step666_test step667_test step668_test. All must pass.", + "Update progress.md with Sprint 41 entries (one block per step, matching format of Sprint 40 blocks).", + "Commit: 'Sprint 41: wire whetstone_schema_to_cpp + whetstone_generate_dispatch_table as MCP tools (Steps 664-668)'" + ] + } + ], + "agentOrientation": { + "readFirst": ["ARCHITECT.md", "sprint41_plan.md"], + "keyFiles": { + "implementationTarget": "editor/src/mcp/RegisterCodegenTools.h", + "wiringPoints": [ + "editor/src/MCPServer.h (add #include)", + "editor/src/mcp/RegisterOnboardingAndAllTools.h (add registerCodegenTools() call)" + ], + "catalogUpdate": "tools/claude/tools.json", + "existingImpls": [ + "editor/src/SchemaToCppGenerator.h", + "editor/src/JobDispatchTableGenerator.h" + ], + "patternToFollow": "editor/src/mcp/RegisterArchitectIntakeTools.h" + }, + "doNotModify": [ + "editor/src/SchemaToCppGenerator.h — implementation complete, do not change", + "editor/src/JobDispatchTableGenerator.h — implementation complete, do not change", + "editor/src/mcp_main.cpp — entry point, no changes needed" + ], + "buildCommand": "cmake -S editor -B editor/build-native && cmake --build editor/build-native --target whetstone_mcp", + "testPattern": "cmake --build editor/build-native --target step{N}_test && ./editor/build-native/step{N}_test" + } +}