Files
whetstone_DSL/docs/SPRINT_2_PLAN.md
Bill 6643b7c2c7 Sprint 3 plan and docs: adopt canonical annotation system from annotations/Memory strategy.md
- Add Sprint 3 plan (37 steps, global 39-75) with canonical memory annotations,
  test quality requirements, global step numbering, and Sprint 2 overlap notes
- Refactor all docs to use canonical annotation families (@Deallocate, @Lifetime,
  @Reclaim, @Owner, @Allocate) replacing simplified @deref 4-strategy system
- Replace @perf with canonical @Hot/@Cold, @Inline, @Pure from annotations/6 optimization
- Replace @memory-footprint, @execution-mode, @deref-explicit with canonical equivalents
- Update REQUIREMENTS_OVERVIEW, SPRINT_1_REQUIREMENTS, SPRINT_2_PLAN, SPRINT_2_VISION,
  C++ Implementation Roadmap, example files, and progress report
- Remove duplicate bonus steps 41-42, consolidate Phase 3h from 7 to 4 steps

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-07 08:11:23 -07:00

289 lines
13 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Sprint 2 Plan: Whetstone Editor Stack
38 steps. Build one thing, test it, move on. If something breaks, the problem is in that step.
For detailed architecture and design rationale, see:
- `SPRINT_2_VISION.md` — Architecture diagrams, structured editing UI, agent API design
- `annotations/C++ Implementation Roadmap.md` — Full technical specs for each component (§1§7)
---
## Phase 2a: AST in C++
Port the 33 SemAnno concepts from MPS XML into C++ data structures.
### Step 1: Base node + one concept
- `ASTNode` base class with ID, concept type tag, parent pointer
- `Module` concept only — properties (name, targetLanguage), empty child vectors
- **Test:** create a Module in C++, verify fields work
### Step 2: Child links
- Add child link support to `ASTNode` (single-valued and multi-valued)
- Add `Function` and `Variable` concepts as children of Module
- **Test:** build Module → Function tree in code, walk it, verify parent/child pointers
### Step 3: Remaining concepts
- Add all Statement, Expression, Literal, and Type concepts
- Each one gets its own properties and child link definitions
- **Test:** build the Calculator example as a C++ object graph
### Step 4: Annotation concepts
- Add memory strategy annotations (`DerefStrategy` as initial implementation), `OptimizationLock`, `LangSpecific`
- Attach to Module/Function/Variable via annotations link
- **Test:** build SimpleFunctionExample with `@Reclaim(Tracing)` (initially stored as `DerefStrategy("batched")`), verify annotation reads back
### Step 5: JSON serialization (save)
- Serialize the C++ AST graph to JSON
- One function: `toJson(ASTNode*) → nlohmann::json`
- **Test:** build Calculator graph → serialize → inspect JSON output by hand
### Step 6: JSON deserialization (load)
- Parse JSON back into C++ AST graph
- One function: `fromJson(nlohmann::json) → ASTNode*`
- **Test:** save Calculator → load it back → save again → compare JSON (byte-identical)
> **CHECKPOINT:** AST round-trips through JSON. Save → load → save produces identical output. Stop here until this passes.
### Step 7: Schema validation
- `ASTSchema` class: for each concept, list legal child types per role + cardinalities
- Validation function: `isLegalChild(parentConcept, role, childConcept) → bool`
- **Test:** legal placements accepted, illegal placements rejected (e.g., Module as child of IntegerLiteral)
---
## Phase 2b: First Generator
Python generator — port of the working MPS textGen rules into C++ visitor methods.
### Step 8: Generator base + Module/Function
- `ProjectionGenerator` base with visitor dispatch
- `PythonGenerator`: generate Module header and Function signatures only
- **Test:** Calculator AST → Python output has correct `def add(x, y):` signature
### Step 9: Statements and expressions
- Add Assignment, Return, BinaryOperation, VariableReference to Python generator
- **Test:** Calculator AST → full Python output matches MPS textGen output
> **CHECKPOINT:** Python generator matches MPS. Calculator output identical to what MPS produces. Stop here until this passes.
### Step 10: Remaining Python concepts
- Literals, control flow (If/While/For), types, FunctionCall, IndexAccess, MemberAccess
- **Test:** ConditionalExample AST → correct Python with if/else
### Step 11: Annotation output
- Memory annotations → `# @Reclaim(Tracing)` / `# @Deallocate(Explicit)` / etc. comment in Python (initially emits as `# @deref(strategy)` — Sprint 3 updates to canonical names)
- OptimizationLock → `# @lock(...)` comment
- **Test:** SimpleFunctionExample with annotations → comments appear in output
---
## Phase 2c: Dear ImGui Shell
Pure presentation layer — no business logic.
### Step 12: Window + empty layout
- Dear ImGui + SDL2 scaffold: opens a window with docking enabled
- Empty panes: file tree (left), editor area (center), panel (bottom)
- **Test:** app launches, window renders, panes are resizable
### Step 13: Text viewport
- Load a hardcoded Python string into the editor pane
- Render with monospace font, line numbers in gutter
- **Test:** text displays correctly, scrolls
### Step 14: AST → text viewport
- Connect: load Calculator JSON → build AST → run Python generator → display in viewport
- **Test:** change the JSON file, restart, see different output
> **CHECKPOINT:** ImGui shows live AST. Change JSON, restart, see different output. Stop here until this passes.
### Step 15: Projection toggle
- Toolbar with [Python] [AST] buttons
- Python: show generated code. AST: show JSON tree dump
- **Test:** toggle between views, both render correctly
---
## Phase 2d: Orchestrator (Standalone Process)
The brain — separate C++ process that owns the AST and coordinates everything.
### Step 16: Orchestrator process + AST ownership
- Separate C++ process that loads AST from JSON and holds it in memory
- Exposes nothing yet — just loads, holds, saves on exit
- **Test:** start orchestrator with Calculator.json, kill it, verify JSON saved back
### Step 17: JSON-RPC server
- Orchestrator listens on a Unix socket (or named pipe on Windows)
- Responds to `ping` and `getAST` methods
- **Test:** send JSON-RPC from a Python script, get response
### Step 18: AST mutation via RPC
- Add `setProperty` method: change a node's property value via RPC
- Validate against schema before applying
- **Test:** change Calculator function name via RPC, query AST back, see new name
### Step 19: Insert and delete via RPC
- `insertNode(parentId, role, conceptType, properties)` — creates node, validates, inserts
- `deleteNode(nodeId)` — removes node and subtree
- **Test:** insert a new Parameter via RPC, delete it, verify AST integrity
### Step 20: Undo/redo
- Operation journal: each mutation recorded as a reversible op
- `undo` and `redo` RPC methods
- **Test:** insert node → undo → node gone → redo → node back
### Step 21: Connect ImGui to orchestrator
- ImGui shell connects to orchestrator via JSON-RPC instead of loading JSON directly
- Requests AST on startup, displays projection
- **Test:** launch orchestrator, launch ImGui shell, see Calculator output
> **CHECKPOINT:** ImGui talks to orchestrator. Two processes running, viewport shows AST content. Stop here until this passes.
---
## Phase 2e: Structured Editing
Build code by choosing from valid options — no typing syntax.
### Step 22: Construct chooser (read-only)
- ImGui panel queries orchestrator: `getValidConstructs(parentId, role)` → list of legal types
- Display as button grid
- **Test:** click on Function body → see [Assignment] [Return] [If] [While] [For] etc.
### Step 23: Insert from chooser
- Click a construct button → orchestrator creates node with default properties
- Viewport refreshes with new projection
- **Test:** add a Return statement to a function, see it in Python output
### Step 24: Property editing
- Click a node → property panel shows editable fields (name, type, operator, etc.)
- Edit field → `setProperty` RPC → viewport refreshes
- **Test:** rename a function, see output update
### Step 25: Scope-aware dropdowns
- Orchestrator implements `getInScopeSymbols(nodeId)` → variables, functions, types visible at that position
- VariableReference name field shows dropdown of in-scope variables
- **Test:** inside Calculator.add body, dropdown shows [x, y, result]
> **CHECKPOINT:** Structured editing works. Build a function entirely through the UI. Stop here until this passes.
---
## Phase 2f: Emacs Integration
Headless Emacs servers for file ops, search, git, completion.
### Step 26: Spawn one headless Emacs
- Orchestrator spawns `emacs --daemon=whetstone-file --load whetstone-bridge.el`
- Sends a test command via `emacsclient`, gets response
- **Test:** orchestrator starts, Emacs server responds to ping
### Step 27: File operations
- `openFile(path)` → routes to Emacs file-server → returns contents
- `saveFile(path, contents)` → writes via Emacs
- **Test:** open a file through orchestrator, verify contents match
### Step 28: Search
- `search(query)` → routes to Emacs search-server → returns file:line results
- Results displayed in ImGui panel
- **Test:** search for "calculate_sum", get result pointing to SimpleFunctionExample
### Step 29: Server pool
- Multiple Emacs daemons: file-server, search-server, git-server
- Orchestrator routes by method name
- Health monitoring: restart crashed servers
- **Test:** kill a server, verify orchestrator restarts it and retries the request
> **CHECKPOINT:** Emacs servers respond. File open, search, and git status all return results. Stop here until this passes.
---
## Phase 2g: Elisp Projection
Generate Elisp from AST, and parse Elisp into AST.
### Step 30: Elisp generator — functions and variables
- Module → `(provide 'name)`, Function → `(defun name (params) body)`, Variable → `(defvar name value)`
- **Test:** Calculator AST → valid Elisp that loads in Emacs without errors
### Step 31: Elisp generator — statements and expressions
- Assignment → `(setq target value)`, Return → value (last expression), If → `(if cond then else)`
- BinaryOperation → `(op left right)`, Literals → values
- **Test:** ConditionalExample AST → Elisp with `(if (= status_code 200) "OK" "Error")`
### Step 32: Elisp parser (tree-sitter)
- Integrate tree-sitter-elisp, parse a `.el` file into CST
- Map `defun` → Function, `defvar` → Variable, `if` → IfStatement
- **Test:** parse a small hand-written `.el` file → inspect resulting AST
### Step 33: Elisp round-trip
- Parse `.el` → AST → generate Elisp → compare with original
- Handle `@LangSpecific` for idioms that don't map cleanly
- **Test:** write a 3-function `.el` file, round-trip it, verify semantic equivalence
> **CHECKPOINT:** Elisp round-trips. Parse .el → AST → generate .el → semantically equivalent. Stop here until this passes.
---
## Phase 2h: C++ Generator + Agent API
The final projection and the external agent interface.
### Step 34: C++ generator — basic output
- Module → `#include` guards, Function → typed signatures, variables → declarations
- No memory strategy yet — just syntactically valid C++
- **Test:** Calculator AST → compilable C++ with g++
### Step 35: C++ generator — memory strategies
- `@Deallocate(Explicit)` → raw pointers, `@Reclaim(Tracing)` → shared_ptr, `@Lifetime(RAII)` / `@Owner(Single)` → unique_ptr
- **Test:** same AST with different memory annotations → different C++ output, all compile
> **CHECKPOINT:** C++ compiles from AST. Generated C++ compiles with g++ for all 3 example models. Stop here until this passes.
### Step 36: Agent API
- Orchestrator accepts JSON-RPC from external clients (same protocol as ImGui)
- `getValidConstructs`, `insertNode`, `setProperty`, `getInScopeSymbols`
- **Test:** Python script acts as agent, builds a Function node by node via RPC
### Step 37: Agent batch mode
- `insertSubtree(parentId, role, jsonSubtree)` — submit entire subtree at once
- Orchestrator validates recursively, applies atomically (all or nothing)
- **Test:** agent submits full ConditionalExample as JSON, orchestrator builds the AST
> **CHECKPOINT:** Agent builds AST remotely. Python script creates full ConditionalExample via RPC. Stop here until this passes.
### Step 38: OptimizationLock warnings
- When mutating a locked node, orchestrator returns warning (not rejection)
- ImGui shows lock icon + banner
- Shadow system: original annotation preserved, modification tracked via `@provenance`
- **Test:** lock a function, modify it, verify warning fires and original preserved
---
## Summary
| Phase | Steps | What You Have When Done |
|-------|-------|------------------------|
| 2a: AST in C++ | 17 | 33 concepts as C++ objects, JSON round-trip, schema validation |
| 2b: First Generator | 811 | Python output matching MPS for all examples |
| 2c: Dear ImGui Shell | 1215 | Window showing live AST projection with toggle |
| 2d: Orchestrator | 1621 | Separate process, RPC mutations, undo/redo, ImGui connected |
| 2e: Structured Editing | 2225 | Build code through UI, scope-aware dropdowns |
| 2f: Emacs Integration | 2629 | File ops, search, git via headless Emacs servers |
| 2g: Elisp Projection | 3033 | Generate and parse Elisp, round-trip verified |
| 2h: C++ + Agent API | 3438 | C++ generator with memory strategies, agent RPC interface |
## Dependencies
| Dependency | Version | Purpose |
|------------|---------|---------|
| Dear ImGui | 1.90+ | GUI rendering |
| SDL2 or GLFW | latest | Window/input backend for ImGui |
| Emacs | 29+ | Headless servers |
| nlohmann/json | 3.11+ | JSON serialization, JSON-RPC |
| tree-sitter | 0.22+ | Elisp/Python/C++ parsing |
| tree-sitter-elisp | latest | Elisp grammar |
| C++ compiler | C++20 | Entire C++ stack |
| GoogleTest | latest | C++ unit tests |