Files
whetstone_DSL/sprint116_plan.md
Bill 84bdad8e9e Add Sprints 111-117: closed-loop iteration epoch
Sprint 111: IterationSession context primitive
Sprint 112: EnvironmentSnapshot and diff
Sprint 113: Build output feedback loop
Sprint 114: Test failure feedback loop
Sprint 115: Requirements derivation from AST
Sprint 116: FeedbackLoopOrchestrator (wires 111-115)
Sprint 117: HiveMind integration (iteration steps as distributed jobs)

These sprints begin Epoch 3 — closed-loop determinism.
Sprints 1-110 made code generation open-loop deterministic.
Sprints 111+ make the full dev workflow (sense→act→observe→repeat)
structurally deterministic, with HiveMind as the execution layer.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-21 13:27:32 -07:00

206 lines
8.6 KiB
Markdown

# Sprint 116 Plan: Feedback Loop Orchestrator
## Context
Sprints 111-115 built the primitives: iteration sessions, environment snapshots,
build feedback, test feedback, and requirements derivation. Each works
independently. Sprint 116 wires them into a single orchestrated loop.
The `FeedbackLoopOrchestrator` is a state machine that drives an
`IterationSession` from start to convergence (or escalation). It decides the
next action based on the current session state: if the environment is not
verified, run `verify_requirements` first; if the build is failing, run
`run_build_iteration`; if tests are failing, run `run_test_iteration`. After
each action it selects the highest-confidence fix candidate, applies it, and
loops. When max_attempts is reached without convergence, it escalates to human
with a structured summary of what was tried and what the current gap is.
This is the "inner loop" of deterministic development: goal → sense → act →
observe → repeat.
---
## Goals
1. Define the orchestrator's decision policy (what to do given current state)
2. Implement automatic candidate selection and application
3. Handle escalation with a structured "what was tried" summary
4. Expose the orchestrator as a single MCP entry point
5. Ensure the loop is inspectable at every step (full audit trail)
---
## Steps
### Step 1389: `OrchestratorPolicy` decision model (12 tests)
Create `editor/src/OrchestratorPolicy.h`.
The policy maps (session_status, gap_model, last_attempt_outcome) →
next action type:
- If environment not verified: probe environment
- If requirements gap present: generate setup script → escalate (can't
auto-install; human must run the script)
- If build failing: run build iteration, apply top candidate
- If tests failing: run test iteration, apply top candidate
- If gap = 0: mark converged
- If max_attempts reached: escalate
- If last attempt made gap worse (worsening trend, 2+ consecutive): escalate
Each decision includes: `action_type`, `rationale` string, `confidence` float.
Tests (12): environment probe first when no snapshot, requirements gap → escalate,
build failure → build iteration, test failure → test iteration, zero gap →
converge, max_attempts → escalate, worsening trend → escalate, consecutive
no-progress → escalate, decision includes rationale, confidence in range,
JSON round-trip of decision, deterministic decision for same inputs.
### Step 1390: Candidate auto-selector (10 tests)
Create `editor/src/CandidateAutoSelector.h`.
Given a list of `FixCandidate`s and a policy, selects the candidate to apply.
Rules:
- Select highest confidence candidate
- Never re-apply a candidate that was already attempted in this session
(tracked by candidate description hash)
- If all non-manual candidates were already tried: escalate
- If top candidate is manual (mutation_type=manual): escalate immediately
(cannot apply manually)
Tests (10): highest confidence selected, already-tried skipped, all tried →
escalate decision, manual type → escalate, empty list → escalate, confidence
tie broken deterministically, attempt history consulted, selection logged
to session, JSON round-trip of selection record, deterministic output.
### Step 1391: Escalation report composer (10 tests)
Create `editor/src/EscalationReport.h`.
Produces a human-readable + machine-readable summary when the loop escalates:
- `session_id`, `goal`, `goal_type`
- `attempts_made` (count)
- `final_gap` (GapModel)
- `attempts_summary[]`: each attempt's action, outcome, gap_before, gap_after
- `top_remaining_candidates[]`: the best manual candidates not yet tried
- `escalation_reason` (enum: max_attempts, worsening_trend, all_auto_tried,
manual_required, infra_gap)
- `recommended_next_step` (human-readable string)
Tests (10): report constructable, session_id present, attempts_summary accurate,
top candidates included, escalation_reason populated, recommended_next_step
human-readable, JSON round-trip, empty attempts handled, gap accurate,
deterministic output.
### Step 1392: `FeedbackLoopOrchestrator` core loop (10 tests)
Create `editor/src/FeedbackLoopOrchestrator.h`.
The orchestrator drives one step of the loop at a time (not a blocking loop —
caller steps it). Interface:
- `step(session_id)``OrchestratorStepResult` (action taken, new session
status, gap after, escalation_report if escalated)
Internally:
1. Load session from SessionStore
2. Run OrchestratorPolicy to get next action decision
3. Execute the action (build iteration / test iteration / env probe)
4. Run CandidateAutoSelector on result
5. Apply selected mutation to AST (if non-manual)
6. Record attempt, update session, persist
7. Return result
Tests (10): step runs without crashing, action matches policy, mutation applied
to AST, attempt recorded in session, session converges when gap=0, session
escalates at max_attempts, worsening trend triggers escalation, escalation
report present when escalated, step result includes gap, deterministic output.
### Step 1393: Full loop driver (end-to-end stepping) (10 tests)
Add `FeedbackLoopOrchestrator::run_to_completion(session_id, max_wall_s)`.
Calls `step()` in a loop until session reaches a terminal state or wall time
expires. Each step result appended to an audit log. Returns the final session
state + full audit log.
Tests (10): run_to_completion returns on convergence, returns on escalation,
respects wall time limit, audit log has one entry per step, step count ≤
max_attempts, gap trend visible in audit log, escalation report in last entry
if escalated, deterministic for deterministic inputs, session persisted at end,
no infinite loop possible.
### Step 1394: Audit trail and inspection (8 tests)
Create `editor/src/LoopAuditLog.h`.
A serializable list of `AuditEntry` records: one per orchestrator step.
Fields: `step_index`, `action_type`, `action_description`, `candidate_applied`
(optional), `gap_before`, `gap_after`, `session_status_after`, `duration_ms`.
Persist to `.whetstone/audits/<session_id>.jsonl` (newline-delimited JSON,
one entry per line, appendable).
Tests (8): audit entry constructable, appended per step, persisted to JSONL,
JSONL format valid, gap_before/after present, candidate_applied present when
applied, duration_ms populated, deterministic output.
### Step 1395: `whetstone_start_feedback_loop` MCP tool (8 tests)
Input: `{ "goal": string, "goal_type": string, "build_command": string?,
"test_command": string?, "workspace": string, "max_attempts": int? }`
Output: `{ "session_id": string, "status": "pending" }`
Creates the session and registers build/test commands for the orchestrator.
Does not start the loop — caller steps it.
Tests (8): tool registered, session_id returned, status is pending, session
persisted, build_command stored, test_command stored, missing workspace error,
deterministic output.
### Step 1396: `whetstone_step_feedback_loop` MCP tool (8 tests)
Input: `{ "session_id": string }`
Output: `{ "action_taken": string, "session_status": string, "gap": GapModel,
"candidates": FixCandidate[]?, "escalation": EscalationReport? }`
Calls orchestrator.step() once and returns the result.
Tests (8): tool registered, action_taken populated, session_status updated,
gap present, candidates present on failure, escalation present when escalated,
terminal session returns error, deterministic output.
### Step 1397: `whetstone_run_feedback_loop` MCP tool (8 tests)
Input: `{ "session_id": string, "max_wall_seconds": int? }`
Output: `{ "final_status": string, "steps_taken": int, "final_gap": GapModel,
"audit_log": AuditEntry[]?, "escalation": EscalationReport? }`
Calls run_to_completion and returns the full result.
Tests (8): tool registered, final_status correct, steps_taken accurate,
final_gap present, audit_log included when requested, escalation present when
escalated, wall time respected, deterministic output shape.
### Step 1398: Sprint 116 integration summary + regression (8 tests)
Create `editor/src/Sprint116IntegrationSummary.h`.
End-to-end: start_feedback_loop → run_feedback_loop on a project with a
known fixable error → verify converged within max_attempts.
Tests (8): headers constructable, tools registered, end-to-end convergence
demonstrated, audit log produced, no header exceeds 600 lines,
deterministic snapshots, escalation path tested, full prior regression passes.
---
## Architecture Gate
- Orchestrator steps are non-blocking (one step per call) — no background
threads, no blocking I/O in the orchestrator itself
- The loop is always inspectable: every step is logged to the audit trail
before returning
- Manual candidates never auto-applied — escalation is the only path for
mutation_type=manual
- Max 600 lines per header