Files
whetstone_DSL/sprint12_plan.md

890 lines
42 KiB
Markdown
Raw Normal View History

# Sprint 12 Plan: Workflow Model + C++ Depth
## Context
Sprint 11 completed the annotation foundation: Semanno format for all 67+ types,
validation rules across all 8 subjects, parser deepening with 9 new AST node types,
Kotlin + C# as languages 9 and 10, and the workflow annotation foundation (Subject 9
routing annotations, skeleton AST, annotation inference, inference-to-routing bridge).
Sprint 12 builds the **execution layer** on top of that foundation. The skeleton AST
from Sprint 11e describes *what* needs to be done; Sprint 12 adds *how* it gets done.
WorkItems track execution state, the routing engine reads annotations and dispatches
to the right worker type, and review gates ensure humans stay in the loop where they
should be.
In parallel, Sprint 12 deepens C++ AST coverage with 5 construct families from
`feature-requests.md`, progressing toward the self-hosting milestone where Whetstone
can parse its own headers.
**What Sprint 11 delivered that Sprint 12 builds on:**
- `SkeletonAST.h` — skeleton modules, task list generation, SkeletonTask struct
- `AnnotationInference.h` — multi-subject inference + routing bridge + suggestWorkerType()
- Subject 9 annotations: @ContextWidth, @Review, @Ambiguity, @Automatability, @Priority, @ImplementationStatus
- `ResponseBudget.h` — budget truncation + continuation tokens (Sprint 9c)
- `AgentPermissionPolicy.h` — 3-role system (Linter, Refactor, Generator)
- `Pipeline.h` — 8-stage parse→infer→validate→optimize→generate flow
- 42+ MCP tools, 10 language parsers/generators, 73+ annotation types
**Sprint 12 Deliverables:**
- **WorkItem execution model** with lifecycle state tracking
- **Task queue** with dependency resolution and priority scheduling
- **Routing engine** that maps annotations → worker dispatch decisions
- **Worker abstractions** (deterministic, agent, human) with context estimation
- **Review gates** with auto-approve rules and human review queue
- **7 new C++ AST node types**: enhanced ClassDeclaration (multiple inheritance),
TemplateClass, IncludeDirective, PragmaDirective, MacroDefinition, EnumDeclaration,
NamespaceDeclaration
- **C++ parser deepened** with inheritance, preprocessor, enum, namespace support
- **50+ MCP tools** (42 current + 8 workflow/routing tools)
---
## Phase 12a: WorkItem Model + Task Queue (Steps 320-325)
*The execution model that turns skeleton tasks into trackable, assignable work.*
### Step 320: WorkItem.h — Core Execution Model (12 tests)
**Goal:** Define the WorkItem lifecycle — the unit of work that flows through the
routing engine, gets assigned to a worker, produces results, and optionally goes
through human review.
**New file: `editor/src/WorkItem.h`** (~350 lines)
**WorkItem struct** (extends SkeletonTask concept):
```
WorkItem:
// Identity (from SkeletonTask)
id: string // unique work item ID (wi-001, wi-002, ...)
nodeId: string // AST node this work item targets
nodeName: string // human-readable name
nodeType: string // "function" | "class" | "method" | ...
bufferId: string // which buffer this belongs to
// Routing (from annotations, set by routing engine)
contextWidth: string // "local" | "file" | "project" | "cross-project"
workerType: string // "deterministic" | "template" | "slm" | "llm" | "human"
reviewRequired: bool // whether output needs review before acceptance
priority: string // "critical" | "high" | "medium" | "low"
dependencies: vector<string> // work item IDs that must complete first
// Lifecycle
status: string // "pending" | "ready" | "assigned" | "in-progress" |
// "review" | "complete" | "rejected"
assignee: string // worker ID or "human:<name>"
createdAt: string // ISO timestamp
assignedAt: string
completedAt: string
// Result (populated after execution)
result: WorkItemResult
```
**WorkItemResult struct:**
```
WorkItemResult:
generatedCode: string // the code produced by the worker
astJson: json // the AST subtree produced
diagnostics: vector<json> // any diagnostics from validation
confidence: float // worker's confidence in the result (0.0-1.0)
tokensBudget: int // context tokens consumed
tokensGenerated: int // output tokens produced
reasoning: string // worker's explanation of decisions made
```
**Status transition rules:**
- `pending``ready` (when all dependencies complete)
- `ready``assigned` (when routing engine dispatches)
- `assigned``in-progress` (when worker begins)
- `in-progress``review` (if reviewRequired) or `complete` (if auto-approved)
- `review``complete` (human approves) or `rejected` (human rejects)
- `rejected``ready` (re-enters queue for re-routing with feedback)
**Helper functions:**
- `createWorkItem(skeletonTask, bufferId) -> WorkItem` — from SkeletonTask
- `isTerminal(status) -> bool` — complete or rejected-and-abandoned
- `canTransition(from, to) -> bool` — validates state machine
- `transitionWorkItem(item, newStatus) -> bool` — applies transition with timestamp
- `workItemToJson(item) -> json` / `workItemFromJson(json) -> WorkItem`
**Tests:** construction from SkeletonTask, status transitions (valid and invalid),
JSON roundtrip, timestamp population, result attachment, dependency tracking,
terminal state detection, ID generation.
### Step 321: TaskQueue.h — Priority Queue with Dependencies (12 tests)
**Goal:** Ordered queue that respects both priority levels and dependency chains.
Items whose dependencies are unsatisfied stay blocked; ready items are ordered
by priority then creation time.
**New file: `editor/src/TaskQueue.h`** (~300 lines)
**TaskQueue class:**
- `enqueue(WorkItem) -> void` — adds item, sets status to pending or ready
- `getReady() -> vector<WorkItem>` — returns items whose dependencies are all
complete, ordered by priority (critical first) then creation time
- `peek() -> optional<WorkItem>` — next ready item without removing
- `dequeue() -> optional<WorkItem>` — removes and returns next ready item,
transitions to assigned
- `complete(itemId) -> bool` — marks complete, triggers dependency re-evaluation
(blocked items may become ready)
- `reject(itemId, feedback) -> bool` — marks rejected, re-enqueues as ready
with feedback attached
- `getBlocked() -> vector<WorkItem>` — items waiting on dependencies
- `getByStatus(status) -> vector<WorkItem>` — filter by lifecycle status
- `size() -> int` / `readyCount() -> int` / `blockedCount() -> int`
- `getItem(itemId) -> optional<WorkItem>` — lookup by ID
- `updateItem(itemId, WorkItem) -> bool` — replace item (for status updates)
**Dependency resolution:**
- When `complete(itemId)` is called, scan all blocked items
- For each blocked item, check if all dependencies are now complete
- If so, transition from pending → ready
- O(n) scan is fine for project-scale queues (hundreds, not millions)
**Priority ordering:**
- critical=0, high=1, medium=2, low=3 (lower number = higher priority)
- Ties broken by createdAt (earlier first)
**Tests:** enqueue/dequeue ordering, priority ordering (critical before low),
dependency blocking (B blocked by A, A completes → B becomes ready), reject and
re-enqueue, getReady returns only unblocked items, empty queue behavior,
getByStatus filtering, size tracking, completion cascading (A→B→C chain),
mixed priorities with dependencies.
### Step 322: WorkflowState.h — Project-Level Workflow Tracking (12 tests)
**Goal:** Top-level state that manages the full workflow lifecycle for a project:
from skeleton creation through routing, execution, review, and completion.
**New file: `editor/src/WorkflowState.h`** (~300 lines)
**WorkflowPhase enum:**
- `Modeling` — architect is creating/annotating skeletons
- `Routing` — routing engine is assigning worker types
- `Executing` — workers are producing results
- `Reviewing` — human review in progress
- `Complete` — all work items complete
**WorkflowState class:**
- `queue: TaskQueue` — the project's task queue
- `phase: WorkflowPhase` — current workflow phase
- `projectName: string`
- `createdAt: string`
**Methods:**
- `populateFromSkeleton(module) -> int` — walks skeleton AST, creates WorkItems
from SkeletonTask list, enqueues all, returns count
- `routeAll(RoutingEngine&) -> int` — routes all ready items (Sprint 12b),
returns count routed
- `getStats() -> WorkflowStats` — counts by status, by worker type, by priority
- `getPhase() -> WorkflowPhase` — auto-computed from item statuses
- `getHistory(itemId) -> vector<StatusChange>` — audit trail for an item
- `toJson() / fromJson()` — full state serialization
**WorkflowStats struct:**
```
WorkflowStats:
total: int
pending: int, ready: int, assigned: int, inProgress: int
review: int, complete: int, rejected: int
byWorkerType: map<string, int> // deterministic: 5, llm: 3, human: 2
byPriority: map<string, int> // critical: 1, high: 4, medium: 5
completionPercent: float
```
**StatusChange struct** (audit trail):
```
StatusChange:
itemId: string
fromStatus: string
toStatus: string
timestamp: string
actor: string // "routing-engine" | "worker:det-001" | "human:bill"
note: string // rejection reason, routing rationale, etc.
```
**Tests:** populateFromSkeleton creates correct item count, phase auto-detection
(all pending → Modeling, some assigned → Executing, some in review → Reviewing,
all complete → Complete), stats accuracy, history tracking, JSON roundtrip,
empty workflow behavior, phase transitions.
### Step 323: Workflow Sidecar Persistence (12 tests)
**Goal:** Save and load workflow state to `.whetstone/<project>.workflow.json`
so workflows survive across sessions.
**New file: `editor/src/WorkflowPersistence.h`** (~200 lines)
- `workflowSidecarPath(workspaceRoot, projectName) -> string`
— returns `.whetstone/<projectName>.workflow.json`
- `saveWorkflow(workspaceRoot, state) -> SaveResult`
— serializes WorkflowState to JSON, writes to sidecar path
- `loadWorkflow(workspaceRoot, projectName) -> optional<WorkflowState>`
— reads sidecar, deserializes, returns nullopt if not found
- `deleteWorkflow(workspaceRoot, projectName) -> bool`
— removes sidecar file
**SaveResult struct:**
```
SaveResult:
success: bool
path: string
bytesWritten: int
itemCount: int
```
**Tests:** save/load roundtrip, all work item fields preserved, status history
preserved, missing file returns nullopt, save creates parent directories,
delete removes file, multiple workflows in same workspace, workflow with
results attached, empty workflow save/load.
### Step 324: Workflow RPC + MCP Tools (12 tests)
**Goal:** Expose workflow management through RPC methods and MCP tools so agents
can create, inspect, and advance workflows.
**Modifies: `editor/src/HeadlessEditorState.h`**
- Add `WorkflowState` member (optional, null until created)
- Include WorkflowState.h, WorkflowPersistence.h
**Modifies: `editor/src/HeadlessAgentRPCHandler.h`** — 8 new RPC methods:
- `createWorkflow` — create WorkflowState, populate from active buffer's skeleton
- params: projectName
- returns: { itemCount, phase, stats }
- `getWorkflowState` — return current workflow stats + phase
- returns: { phase, stats, readyCount, blockedCount }
- `getReadyTasks` — return work items ready for assignment
- returns: { items: [...], count }
- `getWorkItem` — return a single work item's full details
- params: itemId
- returns: { workItem with result if present }
- `assignTask` — move a ready task to assigned status
- params: itemId, assignee
- returns: { success, item }
- `completeTask` — mark a task complete with result
- params: itemId, result (generatedCode, confidence, reasoning)
- returns: { success, newlyReady: [...] }
- `rejectTask` — reject a task back to the queue
- params: itemId, reason
- returns: { success }
- `saveWorkflow` — persist workflow to sidecar
- returns: { success, path, bytesWritten }
**Modifies: `editor/src/AgentPermissionPolicy.h`**
- `getWorkflowState` / `getReadyTasks` / `getWorkItem` — read-only (all roles)
- `createWorkflow` / `assignTask` / `completeTask` / `rejectTask` / `saveWorkflow`
— mutation (Refactor/Generator only)
**Modifies: `editor/src/MCPServer.h`** — registerWorkflowExecutionTools()
- `whetstone_create_workflow` — create and populate workflow
- `whetstone_get_workflow_state` — inspect current workflow
- `whetstone_get_ready_tasks` — get assignable items
- `whetstone_get_work_item` — inspect single item
- `whetstone_assign_task` — assign a ready task
- `whetstone_complete_task` — mark task complete with result
- `whetstone_reject_task` — reject task with feedback
- `whetstone_save_workflow` — persist to sidecar
**Tool count:** 50+ (42 from Sprint 11 + 8 workflow execution tools)
**Tests:** createWorkflow from skeleton module, getReadyTasks ordering, assignTask
transitions, completeTask triggers dependency cascade, rejectTask re-enqueues,
getWorkItem returns full details, Linter role can read but not mutate, MCP tool
registration (8 new tools, 50+ total), saveWorkflow round-trip.
### Step 325: Phase 12a Integration Tests (8 tests)
**Goal:** End-to-end workflow lifecycle from skeleton to completion.
**Tests:**
1. Create skeleton module → createWorkflow → verify item count matches skeleton
2. Priority ordering: critical task appears before low in getReadyTasks
3. Dependency chain: A blocks B blocks C → complete A → B ready → complete B → C ready
4. Full lifecycle: create → assign → in-progress → complete with result → verify
5. Rejection flow: assign → reject with feedback → re-appears in ready queue
6. WorkflowState persistence: save → reload → verify all items and history preserved
7. Stats accuracy: mixed statuses → getWorkflowState returns correct counts
8. Combined: skeleton with 5 functions, mixed priorities and dependencies,
complete in correct order, verify final phase = Complete
---
## Phase 12b: Routing Engine + Workers (Steps 326-331)
*The brain that reads annotations and decides who handles what.*
### Step 326: RoutingEngine.h — Annotation-to-Dispatch Logic (12 tests)
**Goal:** Given a WorkItem with routing annotations, produce a RoutingDecision
that says what kind of worker should handle it and how much context to provide.
**New file: `editor/src/RoutingEngine.h`** (~350 lines)
**RoutingDecision struct:**
```
RoutingDecision:
workerType: string // "deterministic" | "template" | "slm" | "llm" | "human"
contextWidth: string // "local" | "file" | "project" | "cross-project"
contextBudgetTokens: int // estimated tokens for context window
reviewRequired: bool // whether result needs human review
confidence: float // engine's confidence in this routing (0.0-1.0)
reasoning: string // human-readable explanation of the decision
agentRole: string // "linter" | "refactor" | "generator"
```
**RoutingEngine class:**
- `route(WorkItem) -> RoutingDecision` — main entry point
- `routeBatch(vector<WorkItem>) -> vector<RoutingDecision>` — batch routing
**Routing rules (priority order):**
1. **Explicit annotation override** — if @Automatability is set on the node,
use it directly (human architect has spoken)
2. **Ambiguity gate**@Ambiguity(high) → human, regardless of other signals
3. **Review gate**@Review(required, human) → sets reviewRequired=true
4. **Complexity routing:**
- @Complexity(cognitive<=2) + @ContextWidth(local) → deterministic
- @Complexity(cognitive<=4) + @ContextWidth(local|file) → slm
- @Complexity(cognitive<=7) → llm
- @Complexity(cognitive>7) → llm + reviewRequired
5. **Context width escalation:**
- cross-project → llm (needs large context window)
- project → llm or slm depending on complexity
- file → slm unless complex
- local → deterministic or template unless complex
6. **Pattern defaults** (if no annotations):
- Skeleton with no body → template if simple signature, slm otherwise
- Function with existing body (modification) → llm
- Getter/setter/accessor patterns → deterministic
**Context budget estimation:**
- local: ~500 tokens (node + immediate siblings)
- file: ~2000 tokens (buffer content, budget-truncated)
- project: ~8000 tokens (all buffers, compact AST summaries)
- cross-project: ~16000 tokens (project + external references)
- Uses `estimateContextTokens()` from Sprint 11e AnnotationInference
**Tests:** explicit @Automatability overrides inferred routing, high ambiguity →
human, low complexity + local → deterministic, high complexity → llm, cross-project
→ llm, review annotation sets reviewRequired, batch routing, no-annotation defaults,
getter pattern → deterministic, confidence reflects annotation coverage, context
budget reasonable for each width.
### Step 327: WorkerRegistry.h — Worker Abstractions (12 tests)
**Goal:** Define the worker interface and provide concrete implementations for
deterministic and pass-through workers. LLM/SLM workers are stubs that prepare
context — actual model invocation happens externally via MCP.
**New file: `editor/src/WorkerRegistry.h`** (~400 lines)
**WorkerInterface (abstract):**
```
class WorkerInterface:
type() -> string // "deterministic" | "template" | "slm" | "llm" | "human"
canHandle(WorkItem) -> bool // whether this worker accepts the item
execute(WorkItem, context) -> WorkItemResult // produce result
```
**WorkerContext struct:**
```
WorkerContext:
nodeAst: json // the target node's AST (always present)
bufferContent: string // current buffer text (file+ context)
projectSummary: json // compact AST summaries of all buffers (project+ context)
annotations: vector<json> // all annotations on the target node
diagnostics: vector<json> // relevant diagnostics
skeletonIntent: string // @Intent annotation value if present
feedbackFromRejection: string // if this is a re-routed rejected item
```
**DeterministicWorker** — uses Pipeline for code generation:
- Handles: simple skeleton functions with clear signatures and @Intent
- Execute: parses intent into AST manipulations, runs Pipeline.generate()
- Confidence: 0.9+ for pattern-matched templates, 0.5 for heuristic fills
**TemplateWorker** — uses language-specific templates:
- Handles: getters, setters, constructors, simple CRUD patterns
- Execute: pattern-matches skeleton signature → fills template
- Confidence: 0.95 for exact pattern match
**AgentWorker** — prepares context for external LLM/SLM invocation:
- Handles: anything too complex for deterministic/template
- Execute: assembles WorkerContext at appropriate context width,
returns a "prepared" result with context bundle (the actual model
invocation happens externally through MCP)
- Subclasses: `SLMAgentWorker` (narrow context), `LLMAgentWorker` (wide context)
- Confidence: 0.0 (deferred to external model)
**HumanWorker** — marks item for human review:
- Handles: items routed to human
- Execute: returns result with status="needs-human", includes context bundle
and reasoning for why this was routed to human
- Confidence: 0.0 (deferred to human)
**WorkerRegistry class:**
- `registerWorker(WorkerInterface*) -> void`
- `getWorker(workerType) -> WorkerInterface*`
- `getDefaultRegistry() -> WorkerRegistry` — pre-populated with all 5 worker types
**Tests:** deterministic worker produces code for simple skeleton, template worker
fills getter pattern, agent worker prepares context bundle, human worker marks for
review, registry lookup, canHandle filtering, worker type strings, context assembly
at local/file/project widths, rejection feedback included in context, pipeline
integration for deterministic worker.
### Step 328: Context Assembly + Budget (12 tests)
**Goal:** Build the context window for each work item based on its @ContextWidth,
respecting token budgets and using the ResponseBudget system for truncation.
**New file: `editor/src/ContextAssembler.h`** (~250 lines)
**ContextAssembler class:**
- `assembleContext(workItem, bufferStates, contextWidth, budget) -> WorkerContext`
— main entry point; builds context at the specified width within budget
**Assembly strategies by width:**
- **local:** target node AST + immediate sibling nodes + parent annotations
- **file:** target node + full buffer content (editBuf), truncated if over budget
- **project:** target node + compact AST summaries of all open buffers +
import graph for the target file + cross-file symbols
- **cross-project:** project context + external dependency annotations
(from sidecar files in workspace)
**Budget enforcement:**
- Estimate each context component's token cost (json.size() / 4)
- If total exceeds budget, prioritize: target node > annotations > diagnostics >
siblings > buffer content > project summaries
- Use ResponseBudget::applyBudget() for array truncation
- Return actual tokens used in WorkerContext
**Integration with existing systems:**
- Uses `CompactAST::toJsonCompact()` for project-wide summaries
- Uses `ProjectState::ImportGraph` for cross-file references
- Uses `ResponseBudget::applyBudget()` for truncation
- Uses `AnnotationInference::estimateContextTokens()` for estimates
**Tests:** local context contains only target node, file context includes buffer
content, project context includes other buffer summaries, budget truncation
activates when over limit, priority ordering preserved under truncation, import
graph included in project context, cross-file symbols included, empty project
returns minimal context, token estimate within 20% of actual, budget=0 means
unlimited.
### Step 329: Routing RPC + MCP Tools (12 tests)
**Goal:** Expose routing and worker dispatch through RPC and MCP tools.
**Modifies: `editor/src/HeadlessEditorState.h`**
- Add `RoutingEngine` and `WorkerRegistry` members
- Initialize default routing rules and worker registry
**Modifies: `editor/src/HeadlessAgentRPCHandler.h`** — 4 new RPC methods:
- `routeTask` — route a single work item, return RoutingDecision
- params: itemId
- returns: { decision: { workerType, contextWidth, budget, reasoning } }
- `routeAllReady` — route all ready items in the workflow
- returns: { routed: int, decisions: [...] }
- `executeTask` — assign worker and execute (deterministic/template only;
agent/human items are prepared but not executed)
- params: itemId
- returns: { result, workerType, autoApproved }
- `getRoutingExplanation` — explain why a specific item was routed a certain way
- params: itemId
- returns: { reasoning, annotationsUsed, rulesApplied }
**Modifies: `editor/src/AgentPermissionPolicy.h`**
- `getRoutingExplanation` — read-only
- `routeTask` / `routeAllReady` / `executeTask` — mutation (Refactor/Generator)
**Modifies: `editor/src/MCPServer.h`** — registerRoutingTools()
- `whetstone_route_task` — route single item
- `whetstone_route_all_ready` — batch route
- `whetstone_execute_task` — execute deterministic/template tasks
- `whetstone_get_routing_explanation` — explain routing decision
**Tool count:** 54+ (50 + 4 routing tools)
**Tests:** routeTask returns valid decision, routeAllReady batch processes queue,
executeTask runs deterministic worker and produces code, agent items marked as
prepared not executed, human items marked for review, routing explanation includes
annotation references, Linter role can read explanation but not route, MCP tool
registration (4 new tools).
### Step 330: Review Gates (12 tests)
**Goal:** Configurable rules for auto-approving low-risk results and surfacing
high-risk results for human review.
**New file: `editor/src/ReviewGate.h`** (~200 lines)
**ReviewPolicy struct:**
```
ReviewPolicy:
autoApproveRules: vector<AutoApproveRule>
defaultAction: string // "require-review" | "auto-approve"
```
**AutoApproveRule struct:**
```
AutoApproveRule:
workerType: string // match worker type ("deterministic", "*")
maxComplexity: int // max cognitive complexity to auto-approve
minConfidence: float // minimum worker confidence to auto-approve
riskLevel: string // max risk level ("none", "low")
```
**ReviewGate class:**
- `shouldAutoApprove(workItem, result, policy) -> ReviewDecision`
- `ReviewDecision`: approved (bool), reasoning (string), rule matched or why not
- Default policy: auto-approve deterministic + confidence>=0.9 + risk<=low;
everything else requires review
**Modifies: `editor/src/HeadlessAgentRPCHandler.h`**
- `setReviewPolicy` — configure auto-approve rules
- `getReviewPolicy` — inspect current review policy
**Modifies: `editor/src/MCPServer.h`**
- `whetstone_set_review_policy` + `whetstone_get_review_policy`
**Tool count:** 56+ (54 + 2 review tools)
**Tests:** deterministic + high confidence → auto-approve, llm result → require
review, low confidence → require review even if deterministic, high risk overrides
auto-approve, custom policy respected, default policy behavior, explicit
@Review(required) overrides auto-approve, rejection with feedback, policy
serialization roundtrip, empty policy uses defaults, MCP tool registration.
### Step 331: Phase 12b Integration Tests (8 tests)
**Goal:** Full routing pipeline from skeleton through execution and review.
**Tests:**
1. Create skeleton → populate workflow → route all → verify worker type assignments
2. Simple getter skeleton → route → deterministic → execute → auto-approve → complete
3. Complex function skeleton → route → llm → prepare context → verify context width
4. High ambiguity skeleton → route → human → verify marked for review
5. Dependency chain with mixed routing: A(deterministic)→B(llm)→C(human) in order
6. Rejection flow: execute → reject → re-route with feedback in context
7. Review policy: set strict policy → nothing auto-approved → set permissive → deterministic auto-approved
8. Full lifecycle: 5-function skeleton with mixed complexity → workflow → route → execute deterministic ones → verify stats
---
## Phase 12c: C++ AST Depth — Inheritance + CRTP (Steps 332-336)
*Multiple inheritance, virtual inheritance, and CRTP — Whetstone's own patterns.*
### Step 332: Multiple Inheritance in ClassDeclaration (12 tests)
**Goal:** Upgrade ClassDeclaration from single `superClass` string to a vector
of base classes with access specifiers and virtual flags.
**Modifies: `editor/src/ast/ClassDeclaration.h`**
- New struct `BaseClass { name, accessSpecifier, isVirtual }`
- accessSpecifier: "public" | "protected" | "private" (default: "private" for C++)
- isVirtual: bool (default: false)
- `ClassDeclaration` gains: `vector<BaseClass> baseClasses`
- Backward compat: existing `superClass` string still works (converted to
single BaseClass with public access), deprecated but supported
- Helper: `addBase(name, access, isVirtual)`, `getBases() -> vector<BaseClass>`
- Helper: `hasDiamondInheritance(classMap) -> bool` (detects shared bases)
**Modifies: `editor/src/ast/Serialization.h`**
- `propertiesToJson` — serialize baseClasses array
- `setPropertiesFromJson` — deserialize baseClasses, handle legacy superClass
- `createNode` — no change (ClassDeclaration factory exists from Sprint 11c)
**Tests:** single base (backward compat), multiple bases, access specifiers,
virtual inheritance flag, BaseClass JSON roundtrip, mixed virtual and non-virtual,
diamond detection (A→B, A→C, D→B+C), empty bases list, legacy superClass
migration, addBase helper.
### Step 333: Template Class Declarations (12 tests)
**Goal:** Represent `template<typename T> class Foo : public Bar<T> { ... }`
template parameters on classes (not just functions), including CRTP patterns.
**Modifies: `editor/src/ast/GenericType.h`**
- `GenericType` gains: `isClassTemplate: bool` (vs function template)
- When attached to a ClassDeclaration, represents `template<...> class`
- TypeParameter gains: `isVariadic: bool` (for `typename... Args`)
**New recognition helpers in `editor/src/ast/GenericType.h`:**
- `isCRTP(classDecl) -> bool` — detects when a class inherits from a base
parameterized by itself: `class Foo : public Base<Foo>`
- `getTemplateParameters(classDecl) -> vector<TypeParameter>` — extracts
template params from attached GenericType children
**Modifies: `editor/src/ast/Serialization.h`**
- GenericType: serialize `isClassTemplate`
- TypeParameter: serialize `isVariadic`
**Modifies: `editor/src/CompactAST.h`**
- `getNodeName` for GenericType includes template indicator
**Tests:** class template construction, CRTP detection (class Foo : Base<Foo>),
non-CRTP base parameterized by other type, variadic type parameter, JSON roundtrip
for isClassTemplate, template class with multiple type params, GenericType
attached to ClassDeclaration, compact AST name, isCRTP with diamond inheritance,
template + multiple inheritance combined.
### Step 334: C++ Parser — Inheritance + Templates (12 tests)
**Goal:** Deepen CppParser to handle multiple inheritance, virtual inheritance,
access specifiers, template class declarations, and CRTP patterns.
**Modifies: `editor/src/ast/CppParser.h`**
- Parse `class Foo : public Bar, private virtual Baz { ... }`
→ ClassDeclaration with baseClasses vector
- Parse `template<typename T> class Foo { ... }`
→ ClassDeclaration with GenericType child (isClassTemplate=true)
- Parse `template<typename T, typename... Args>`
→ TypeParameters including variadic
- Parse `class Foo : public Base<Foo>` → CRTP detection
- Parse `struct` same as `class` but default public access
**Backward compatibility:** existing class parsing (single base) continues
to work, now populates baseClasses[0] instead of superClass.
**Tests:** single inheritance (backward compat), multiple inheritance parsed,
access specifiers detected, virtual inheritance flag, template class parsed,
CRTP pattern detected, struct vs class default access, nested class (inner class),
template with variadic, combined template + multiple inheritance, existing
function-level tests still pass, real Whetstone-style class signature.
### Step 335: C++ Generator — Inheritance + Templates (12 tests)
**Goal:** CppGenerator outputs correct C++ syntax for multiple inheritance,
virtual inheritance, access specifiers, and template classes.
**Modifies: `editor/src/ast/CppGenerator.h`**
- Generate `class Foo : public Bar, private virtual Baz { ... }`
- Generate `template<typename T> class Foo { ... }`
- Generate `template<typename T, typename... Args>` for variadic
- Access sections: `public:`, `protected:`, `private:` grouping for methods
**Cross-language considerations:**
- Other generators handle multiple inheritance differently:
- Java/Kotlin/C# → single extends + multiple implements (interfaces)
- Python → multiple inheritance directly
- Rust → no inheritance, use traits
- Go → embedding
- Add `adaptInheritance(classDecl, targetLanguage) -> ClassDeclaration` helper
in CrossLanguageProjector that converts multiple inheritance to
target-appropriate pattern
**Modifies: `editor/src/CrossLanguageProjector.h`**
- `adaptInheritance()` — converts C++ multiple inheritance to target patterns
**Tests:** C++ multiple inheritance output, access specifier output, virtual
keyword present, template class output, CRTP output, cross-language: C++ → Java
(multiple bases → extends + implements), C++ → Python (direct), C++ → Rust
(traits), cross-language: Java → C++ (implements → base classes), roundtrip:
parse C++ → generate C++, combined template + inheritance output.
### Step 336: Phase 12c Integration Tests (8 tests)
**Goal:** Full C++ inheritance + template roundtrip and cross-language projection.
**Tests:**
1. Parse Whetstone-style class: `class KotlinGenerator : public ProjectionGenerator, public virtual AnnotationVisitorExtended, public SemannoAnnotationImpl<KotlinGenerator>` → verify AST structure
2. CRTP detection: `SemannoAnnotationImpl<KotlinGenerator>` recognized as CRTP
3. Round-trip: parse complex C++ class → generate → parse again → AST equivalent
4. Cross-language: C++ class with multiple inheritance → Java output (extends + implements)
5. Cross-language: C++ class with multiple inheritance → Python output (multiple bases)
6. Template class with 3 type params → parse → generate → verify
7. Diamond inheritance detection: parse class hierarchy → hasDiamondInheritance returns true
8. Mixed: class with templates, multiple inheritance, virtual methods, annotations → full pipeline
---
## Phase 12d: C++ AST Depth — Preprocessor, Enums, Namespaces (Steps 337-341)
*The remaining C++ constructs needed for self-hosting progress.*
### Step 337: Preprocessor AST Nodes (12 tests)
**Goal:** Represent `#include`, `#pragma`, and `#define` as first-class AST nodes.
**New file: `editor/src/ast/PreprocessorNodes.h`** (~150 lines)
**IncludeDirective** (Statement-level):
- `path: string` — the include path ("ast/ASTNode.h" or <string>)
- `isSystem: bool` — angle brackets (true) vs quotes (false)
**PragmaDirective** (Statement-level):
- `directive: string` — the pragma content ("once", "pack(push, 1)", etc.)
**MacroDefinition** (Statement-level):
- `name: string` — macro name
- `parameters: vector<string>` — macro params (empty for object-like macros)
- `body: string` — macro body text (unparsed — macros are fundamentally textual)
- `isFunctionLike: bool` — has parameter list
**Design note:** Preprocessor directives are statement-level nodes added to Module's
children. They are *not* deeply parsed into sub-AST (macro bodies stay as text).
This matches the reality that preprocessor operates on text, not AST. For annotation
purposes, `@Synthetic(macro-expanded)` can mark nodes that result from macro expansion.
**Modifies: `editor/src/ast/Serialization.h`**
- propertiesToJson/createNode/setPropertiesFromJson for all 3 types
**Modifies: `editor/src/CompactAST.h`**
- getNodeName for IncludeDirective, PragmaDirective, MacroDefinition
**Tests:** IncludeDirective construction + roundtrip, system vs local flag,
PragmaDirective construction + roundtrip, MacroDefinition with params,
function-like vs object-like distinction, compact AST names, module with
mixed preprocessor + function nodes, empty macro body, Serialization createNode
dispatch.
### Step 338: EnumDeclaration + NamespaceDeclaration (12 tests)
**Goal:** Scoped enums and namespaces as first-class AST nodes.
**New file: `editor/src/ast/EnumNamespaceNodes.h`** (~150 lines)
**EnumDeclaration** (Statement-level, has children):
- `name: string`
- `isScoped: bool``enum class` (true) vs plain `enum` (false)
- `underlyingType: string` — optional (e.g., "int", "uint8_t")
- Children role "members": vector of EnumMember nodes
**EnumMember** (leaf node):
- `name: string`
- `value: string` — optional explicit value ("1", "0xFF")
**NamespaceDeclaration** (Statement-level, has children):
- `name: string` — namespace name (empty for anonymous)
- Children role "body": vector of statements/declarations inside the namespace
**TypeAlias** (Statement-level):
- `aliasName: string` — the new name
- `targetType: string` — what it aliases
- `isUsing: bool``using` (true) vs `typedef` (false)
**Modifies: `editor/src/ast/Serialization.h`**
- propertiesToJson/createNode/setPropertiesFromJson for all 4 types
**Modifies: `editor/src/CompactAST.h`**
- getNodeName for EnumDeclaration, EnumMember, NamespaceDeclaration, TypeAlias
**Tests:** EnumDeclaration construction, scoped vs unscoped, EnumMember with explicit
value, enum with 4 members as children, NamespaceDeclaration with body children,
TypeAlias using vs typedef, JSON roundtrip for all 4 types, compact AST names,
nested namespace (namespace inside namespace), enum inside namespace.
### Step 339: C++ Parser — Preprocessor, Enum, Namespace (12 tests)
**Goal:** Parse these constructs from C++ source code.
**Modifies: `editor/src/ast/CppParser.h`**
- Parse `#include "path"` and `#include <path>` → IncludeDirective
- Parse `#pragma once` and `#pragma ...` → PragmaDirective
- Parse `#define NAME(args) body` → MacroDefinition
- Parse `enum class Name : Type { A = 1, B = 2 }` → EnumDeclaration + EnumMembers
- Parse `enum Name { ... }` → EnumDeclaration (isScoped=false)
- Parse `namespace Name { ... }` → NamespaceDeclaration with body
- Parse `using Name = Type;` → TypeAlias (isUsing=true)
- Parse `typedef Type Name;` → TypeAlias (isUsing=false)
**Tests:** #include system/local parsed, #pragma once, #define object-like,
#define function-like, enum class with values, plain enum, namespace with
contents, using alias, typedef, mixed file with preprocessor + namespace +
enum + functions, backward compat (existing C++ tests pass), real Whetstone
header snippet.
### Step 340: C++ Generator — Preprocessor, Enum, Namespace (12 tests)
**Goal:** CppGenerator produces correct output for all new node types.
**Modifies: `editor/src/ast/CppGenerator.h`**
- Generate `#include "path"` / `#include <path>` with correct brackets
- Generate `#pragma once`
- Generate `#define NAME(args) body`
- Generate `enum class Name : Type { A = 1, B };`
- Generate `namespace Name { ... }`
- Generate `using Name = Type;`
**Cross-language considerations:**
- Python: no preprocessor, no enums (use class), no namespaces (use modules)
- Java: import instead of include, enum keyword, package instead of namespace
- Rust: use instead of include, enum, mod instead of namespace
- Add basic adaptation in generators for enum/namespace equivalents
**Tests:** #include output, #pragma output, #define output, enum class output,
namespace output, using alias output, round-trip parse → generate → verify,
cross-language: C++ enum → Java enum, C++ namespace → Java package (comment),
C++ enum → Python class, C++ enum → Rust enum, mixed file generation.
### Step 341: Phase 12d Integration + Sprint 12 Summary (8 tests)
**Goal:** Full C++ depth validation and sprint verification.
**Tests:**
1. Parse realistic C++ header: includes + pragma + namespace + enum + class + functions → full AST
2. Round-trip: complex C++ header → AST → generate → parse again → equivalent
3. Enum inside namespace: parse → verify scoping in AST
4. Cross-language: C++ header → Java output with imports + package + enums adapted
5. Combined workflow + C++: create skeleton with C++ class patterns → workflow → route
6. All new AST nodes serialize/deserialize correctly (batch verification)
7. Sprint 12 totals: 56+ MCP tools, all new C++ constructs, workflow engine operational
8. C++ self-hosting progress: parse simplified Whetstone header fragment → verify structure
---
## Step & Test Summary
| Phase | Steps | Tests | Theme |
|-------|-------|-------|-------|
| 12a | 320-325 | 68 | WorkItem model, task queue, workflow state, persistence, RPC/MCP |
| 12b | 326-331 | 68 | Routing engine, workers, context assembly, review gates, RPC/MCP |
| 12c | 332-336 | 56 | C++ multiple inheritance, CRTP, template classes, cross-language |
| 12d | 337-341 | 56 | C++ preprocessor, enum, namespace, type alias, generators |
| **Total** | **320-341** | **~248** | 22 steps |
**MCP tool count projection:** 56+ tools (42 from Sprint 11 + 8 workflow + 4 routing + 2 review)
---
## Key Files to Modify
| File | Changes |
|------|---------|
| `editor/src/HeadlessEditorState.h` | Add WorkflowState, RoutingEngine, WorkerRegistry members |
| `editor/src/HeadlessAgentRPCHandler.h` | 12 new RPC methods (8 workflow + 4 routing) |
| `editor/src/AgentPermissionPolicy.h` | Permission mapping for 12 new methods |
| `editor/src/MCPServer.h` | registerWorkflowExecutionTools() + registerRoutingTools() + registerReviewTools() |
| `editor/src/ast/ClassDeclaration.h` | BaseClass struct, baseClasses vector, diamond detection |
| `editor/src/ast/GenericType.h` | isClassTemplate, isVariadic, isCRTP detection |
| `editor/src/ast/CppParser.h` | Inheritance, templates, preprocessor, enum, namespace parsing |
| `editor/src/ast/CppGenerator.h` | Multiple inheritance, templates, preprocessor, enum, namespace output |
| `editor/src/ast/Serialization.h` | 7+ new node types in all 3 dispatch points |
| `editor/src/CompactAST.h` | getNodeName for all new node types |
| `editor/src/CrossLanguageProjector.h` | adaptInheritance() for cross-language inheritance mapping |
| `editor/CMakeLists.txt` | Test targets for steps 320-341 |
**New files:**
- `editor/src/WorkItem.h` — WorkItem struct, WorkItemResult, lifecycle state machine
- `editor/src/TaskQueue.h` — Priority queue with dependency resolution
- `editor/src/WorkflowState.h` — Project-level workflow tracking, phase detection, stats
- `editor/src/WorkflowPersistence.h` — Workflow sidecar save/load
- `editor/src/RoutingEngine.h` — Annotation-to-dispatch routing logic
- `editor/src/WorkerRegistry.h` — Worker abstractions (deterministic, template, agent, human)
- `editor/src/ContextAssembler.h` — Context window assembly with budget enforcement
- `editor/src/ReviewGate.h` — Auto-approve rules and review policy
- `editor/src/ast/PreprocessorNodes.h` — IncludeDirective, PragmaDirective, MacroDefinition
- `editor/src/ast/EnumNamespaceNodes.h` — EnumDeclaration, EnumMember, NamespaceDeclaration, TypeAlias
- `editor/tests/step320_test.cpp` through `editor/tests/step341_test.cpp`
---
## Verification
After each phase:
1. Build all new test targets: `cmake --build . --target stepNNN_test`
2. Run each test: `./stepNNN_test` — expect "Results: 12/12" (or 8/8 for integration)
3. Phase integration test validates no regressions on earlier steps
Full sprint verification:
- All ~248 tests pass across steps 320-341
- Run full test suite (steps 245-341) to verify no regressions
- MCP `tools/list` returns 56+ tools
- Create skeleton → workflow → route → execute deterministic tasks → verify results
- Routing engine produces sensible decisions for varied annotation patterns
- C++ parser handles: multiple inheritance, CRTP, preprocessor, enum class, namespace
- Parse simplified Whetstone header → verify AST structure (self-hosting progress)
- Cross-language: C++ → Java/Python/Rust inheritance adaptation works
- All 10 languages parse and generate correctly (no regressions)
---
## Dependencies on Sprint 11
Sprint 12 assumes all Sprint 11 phases are complete:
- **11a** (done): Semanno format, annotation codegen
- **11b**: Validation rules (E0600-E1299) — used by routing engine to assess risk
- **11c**: 9 new AST nodes including ClassDeclaration — Sprint 12c extends it
- **11d**: Kotlin + C# — 10 languages total
- **11e**: SkeletonAST, routing annotations, inference engine — Sprint 12a/12b build directly on these