summaryrefslogtreecommitdiff
path: root/docs/superpowers
diff options
context:
space:
mode:
authorPeter Stone <thepeterstone@gmail.com>2026-07-08 08:20:13 +0000
committerPeter Stone <thepeterstone@gmail.com>2026-07-08 08:20:13 +0000
commite9abe208bf5d1ffbbb5e8d6b0df187d97d89b1d9 (patch)
tree7e3e80d2a1ec9c4d98e950548749e652dc6a22f6 /docs/superpowers
parent0cedb90d44b09c9eda296bcdb8cedd5b58d76d22 (diff)
docs: add design spec for recursive story decomposition
Retro from the tasks-board build (see memory claudomator-sequential-orchestration-gap): claudomator has no native way to drive a stated intent through review-gated implementation to arbitrary depth -- that role was played by a human/chatbot controller hand-dispatching and re-dispatching all session. Design converged through several rejected drafts (a separate "chain mode" pipeline, a distinct Planner role) before landing on the actual shape: one role, one recursive decompose-or-evaluate mechanism, applied at every depth, with arbitrated multi-evaluator review running at every node instead of once at a story's outer level. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VTUSAEKfsPc6WGDq45yPHD
Diffstat (limited to 'docs/superpowers')
-rw-r--r--docs/superpowers/specs/2026-07-08-recursive-story-decomposition-design.md194
1 files changed, 194 insertions, 0 deletions
diff --git a/docs/superpowers/specs/2026-07-08-recursive-story-decomposition-design.md b/docs/superpowers/specs/2026-07-08-recursive-story-decomposition-design.md
new file mode 100644
index 0000000..5810ad2
--- /dev/null
+++ b/docs/superpowers/specs/2026-07-08-recursive-story-decomposition-design.md
@@ -0,0 +1,194 @@
+# Recursive Story Decomposition — Design Spec
+
+**Date:** 2026-07-08
+**Status:** Approved
+
+---
+
+## Goal
+
+Give claudomator a native way to drive a stated user intent through review-gated
+implementation, to arbitrary depth, without a human or chatbot controller
+hand-orchestrating dispatch → review → fix → advance the way this session's
+tasks-board build required. Replace that hand-driven loop with one recursive,
+uniform mechanism inside claudomator itself.
+
+---
+
+## Context
+
+Building claudomator's own "unified Tasks board" web feature (2026-07-06/08)
+used an adapted `subagent-driven-development`: a human-facing plan document
+with 8 sequential tasks, each dispatched to claudomator as an implementer,
+each reviewed by a separately-dispatched local reviewer, fixes re-dispatched
+on failure, advanced by hand. It worked, but the retro on it surfaced a real
+architecture gap (see memory `claudomator-sequential-orchestration-gap` for
+the narrative): `internal/scheduler.StoryOrchestrator` already automates a
+Builder → 4-parallel-Evaluators → Arbitration → `REVIEW_READY` pipeline, but
+that pipeline runs exactly once, at a story's outer level, for one atomic
+deliverable. It does not decompose, and it does not apply itself recursively
+to sub-pieces of a larger story.
+
+Two early design drafts for closing this gap were rejected during
+brainstorming, for reasons worth recording so they aren't re-proposed later:
+
+- **A separate "chain mode" with a distinct sequential pipeline** (single
+ evaluator per task, `Story.Mode` field) was rejected as unnecessary
+ special-casing — two pipelines selected by a flag, instead of asking why
+ the one that already exists (arbitrated multi-evaluator review) shouldn't
+ just apply everywhere.
+- **A distinct "Planner" role that runs once, up front, and hands off to a
+ different "Implementer" role** was rejected for the same reason — it
+ special-cases "decide how to break this down" as something only one kind
+ of agent does at one point in time, rather than a judgment every task
+ makes about its own assignment, recursively.
+
+The design below is the corrected shape: one role, one recursive mechanism,
+applied at every depth.
+
+---
+
+## Design
+
+### Story is the root of a tree, and only the root
+
+A Story represents user intent — what a human (or a chatbot acting for one)
+asked for. It carries `Spec` (prose intent) and `AcceptanceCriteria`, and
+owns the single human-facing accept-gate
+(`POST /api/stories/{id}/accept`, unchanged from today). Nothing beneath the
+root is a Story. A human's attention lives at this level; an agent driving
+the work via MCP may need to inspect or adjust individual tasks at any
+depth, but that's a different altitude of view onto the same tree, not a
+different data model. `Epic` (grouping multiple Stories) is untouched by
+this design — orthogonal, already exists.
+
+### Every Task, at every depth, gets identical treatment
+
+There is one role (`builder` — already named in existing seed data, unchanged
+purpose: deliver work meeting its assignment's completion criteria). On
+dispatch, a `builder`-role task is handed its assignment (a story's
+`Spec`/`AcceptanceCriteria` if it's the root, or a parent task's own stated
+subtask instructions/`AcceptanceCriteria` otherwise) and makes one judgment:
+**is this minimal and targeted?**
+
+- **Yes:** implement directly, commit, done — this node's "work" is its own
+ diff.
+- **No:** decompose. Spawn subtasks via `spawn_subtask`, each carrying its
+ own `Instructions` and `AcceptanceCriteria` (the field already exists on
+ `Task`, mostly unused today). This node becomes a roll-up; its "work" is
+ the aggregate of its children once each has independently completed.
+
+This recurses to arbitrary depth. A subtask that itself judges its own
+assignment too large repeats the same decision. Depth is driven by how big
+the actual work is — a well-scoped leaf doesn't decompose and is evaluated
+once, same as any leaf; there's no depth ceiling imposed by the mechanism
+itself (see Non-Goals for the cost implication).
+
+This judgment has to actually be instructed, not just structurally
+possible: the `builder` role's `RoleConfig.SystemPrompt` needs to be
+written (or updated, if a draft already exists from prior seeding) to tell
+the agent explicitly to make this decompose-or-implement call against its
+own assignment, and to use `spawn_subtask`'s new `DependsOn` field when the
+pieces it's creating have a genuine order dependency rather than being
+independently parallel. Without this, the mechanism is inert plumbing — the
+plan for this design must include writing/updating that prompt as a real
+deliverable, not an assumed side effect of adding the data-model fields.
+
+### `SubtaskSpec` gains `DependsOn`
+
+Today, `agentchannel.SubtaskSpec` (`Name`, `Instructions`, `Model`,
+`MaxBudgetUSD`, `Role`) has no way to express ordering between siblings —
+every spawned subtask is structurally parallel, and `storeChannel.SpawnSubtask`
+never sets `DependsOn` on the child it creates. Add `DependsOn []string` to
+`SubtaskSpec`, wired through to `child.DependsOn` the same
+backward-compatible-optional-field way `Role` was added ("every
+pre-existing caller unchanged"). `spawn_subtask` already returns each new
+task's ID, so a decomposing agent can spawn step 1, capture its ID, spawn
+step 2 with `depends_on: [step1_id]`, and so on — or spawn three independent
+branches followed by one integration task depending on all three. One
+primitive expresses pure-sequential, pure-parallel, or mixed DAGs; nothing
+needs to pick a mode. This reuses 100% of the existing `DependsOn`
+dispatch-gating and cascade-fail-on-dependency-failure machinery already
+built for top-level tasks — no new scheduling logic.
+
+### Arbitrated review runs at every node, not once at the story's outer level
+
+The existing Builder → 4-Evaluators → Arbitration pipeline generalizes: once
+*any* node's own work is done (a leaf's direct commit, or a roll-up's
+children having all independently completed), that node goes through the
+same multi-angle evaluation against its own `AcceptanceCriteria` (the
+story's, for the root; the parent-assigned criteria, for anything beneath
+it). This is what catches integration problems that only exist at a roll-up
+level and are invisible in any single child's own diff — exactly the shape
+of the CSS cascade collision found in the tasks-board build's final
+whole-branch review (a bug between Task 3's and Task 4's changes, invisible
+in either task's own scoped review). Making arbitrated review the universal
+mechanism means every roll-up gets that same integration check, not just
+the outermost one, and not only when a human remembers to run one by hand.
+
+### The fix-and-re-evaluate loop has to become real, not stay a documented simplification
+
+Today, `StoryOrchestrator.finalizeArbitration` never actually parses the
+Arbitration task's verdict — it always routes to `REVIEW_READY` regardless,
+trusting a human to read the summary and manually set `NEEDS_FIX` if they
+disagree (see `CLAUDE.md`'s own "Documented simplification" note on this).
+That gap can't stay a simplification once arbitrated review is the
+universal per-node mechanism instead of a rare final gate a human is
+already watching for. This design requires: parse the verdict; on reject,
+spawn a fix attempt (same node, same completion criteria) and re-run
+evaluation; on approve, auto-proceed (matching today's existing
+Builder/Evaluator/Arbitration auto-accept behavior). Repeated non-convergence
+escalates through the `builder` role's `EscalationLadder` (existing
+mechanism, same one `Scheduler` already uses for FAILED-task retry/escalate
+— no new retry-cap concept to invent).
+
+### MCP surface: story-level tools, additive to what exists
+
+New: `create_story` (name, spec, acceptance_criteria, repository_url →
+story_id), `get_story`, `list_stories`, `accept_story` (wraps the existing
+`POST /api/stories/{id}/accept`). These didn't exist on chatbot MCP before —
+today it's task-only. `submit_task` and the rest of the existing task-level
+toolset are unchanged and remain the right choice for a genuinely
+single-step ask where creating a story and running it through decomposition
+judgment is unwarranted overhead.
+
+---
+
+## Non-Goals / Deferred
+
+- **No depth or cost bound in this design.** Recursion is unbounded and
+ arbitrated review (4 parallel evaluators) runs at every node, which is a
+ real cost multiplier for a large, deep story — not addressed here. The
+ intended mitigation is architectural, not a cap: a leaf task that judges
+ itself minimal/targeted should default to a cheap/local model tier
+ (`LocalRunner`/tinyllama already exists for this; the `EscalationLadder`
+ already supports tiering from cheap to expensive), reserving expensive
+ models for roll-up judgment, arbitration, and escalation. This connects
+ directly to the same session's `--model` wiring fix
+ (`internal/executor/container.go`, commit `2d9ae7e`) — model selection
+ has to actually work before tiering leaf tasks to cheap models is
+ possible at all. Left as a distinct, future piece of work.
+- **No resumable-orchestrator design here.** Retro item 4
+ (resume after session/model failures) is deliberately deferred until this
+ design's discipline — durable, DB/event-backed state per node, no
+ ledger-in-a-file — is actually built and proven. Resumability is a
+ property this design should make easier, not a feature to add on top of
+ it separately.
+- **Epic is untouched.** Grouping multiple Stories under an Epic is an
+ existing, orthogonal concept this design doesn't change.
+
+---
+
+## Testing
+
+- `internal/scheduler`: tests for the generalized per-node arbitrated-review
+ branch (fake store, assert correct spawn/evaluate/fix/advance sequencing
+ at both leaf and roll-up nodes) — extending the existing
+ `StoryOrchestrator` test style.
+- `internal/executor`: tests for `SubtaskSpec.DependsOn` wiring through to
+ the created child task (mirrors existing `Role`-field tests in the same
+ package).
+- `internal/api`: tests for the new `create_story`/`get_story`/
+ `list_stories`/`accept_story` chatbot MCP tools (mirrors existing
+ `chatbotmcp_test.go` conventions for the task-level tools).
+- No browser/UI testing needed — backend and chatbot MCP only.