Summary / 07. Task decomposition and planning / Document
Spec 2026-09-05
Shared copy: the operator's name and machine names are replaced by roles. Nothing else is changed.
Rendering…
# Build Spec 07 — Task Decomposition & Planning (the ≈80% fraction) > Derived from `papers/07-task-decomposition-planning.md`. This document drives the build of the > **task-decomposition-and-planning stage**: the executive function that sequences a whole user > request into an ordered, revisable, executable schedule of change and validation obligations, each > small enough to be executed and checkable in isolation. It sits after component 06 (dependency & > impact analysis, which projects forward what one edit would break) and before component 08 > (context construction, which will assemble the evidence each scheduled step needs). Where impact > analysis answers *if I change this, what else breaks?*, planning answers *in what order, against > which checkpoints, and who carries the plan?* It translates the paper's design into exact typed > artifact schemas, exact obligation-record schemas, exact dependency-resolution ordering rules, > exact per-node state machines, exact branch-scoring and checkpoint rules, exact scoped-replan > boundaries, exact caps, exact validation thresholds, exact ablation mechanics, and an exact build > sequence — no further research required. Where the paper says "≈80%", this spec pins *which* 80%. --- ## 1. Purpose & Scope Build a **reversible task-decomposition-and-planning stage** — a deterministic-first, adaptive, dependency-aware, externally-stateful planner (task canonicalization → semantic decomposition → dependency graph over obligations → plan-DAG scheduling → single-actionable-obligation execution driving → local validation gate → adaptive revision trigger → plan-state persistence & audit) with a **single weak-LLM semantic-decomposition decision**, as a drop-in *executive* stage that converts the user request plus the evidence of components 03–06 into an ordered, revisable, executable schedule of change and validation obligations before any further code is written. It is distinct from its six predecessors in kind, not merely in order: reconnaissance (03) answers what the repository *is*, retrieval (04) what context is *relevant*, localization (05) *where the fault is*, impact analysis (06) *what one edit will break* — planning (07) is the only stage that holds the *entire request* in view at once and decides how the many candidate edits interleave into a schedule that keeps the repository valid after *every* step, not merely at the end. The overall target is the paper's full 100% spec. **Round 1 lands the expected ≈80% of it**: everything deterministic (task canonicalization, the dependency graph over obligations, the plan-DAG scheduler, the execution driver, the local validation gate, the adaptive revision trigger, and plan-state persistence & audit) plus the *one* weak-LLM semantic-decomposition call — targeting the reachable fraction of the corpus where the L column holds exactly one entry and everything upstream and downstream is deterministic software on CPU. The heavy learned / multi-call / GPU pieces (SWE-Search MCTS branching with a real value model and discriminator, MetaGPT multi-agent role fan-out, Latent Programming Horizons activation-based early-failure detection) are **not** built in Round 1 and are **not excluded** — they are the content of later rounds that climb from that ~80% landing toward 100% (see §2). Round 1 is kept only if it wins a measured A/B test on the *honest* planning metrics — led by **retry-token cost** — *and* does not regress end-to-end resolve/cost/tokens (§7). --- ## 2. Round 1 vs later rounds (toward the 100% target) The goal is the paper's full **100%** spec. **~80%** is only the expected **first-round landing**; later rounds climb from there. Every element from the paper is classified below by *which round builds it*. - **BUILD-NOW = the Round 1 build** — the expected ≈80% deterministic landing this spec implements and A/B-tests (rows 1–8). - **DEFERRED = later rounds** — the learned/expensive stages (rows 9–11) that Round 1 intentionally does not build *yet*, because they need a GPU, multiple LLM calls, a value model + discriminator (fine-tuning), or rest on an unproven two-month-old preprint technique. They are **not excluded from the project** — they are the content of later rounds, the climb toward 100%, gated by the same §7 A/B protocol once the Round 1 core is in place. | # | Component (paper §) | Classification | |---|---|---| | 1 | The **L** column: semantic decomposition — the single weak-LLM call from requirement artifact + evidence (03/04/05/06) to the initial typed obligation set | **BUILD-NOW** | | 2 | (a) Task canonicalization — request → typed requirement artifact, deterministic normalization + schema validation | **BUILD-NOW** | | 3 | (b) Dependency graph over obligations — resolve each `dependencies[]` against repo structure (type-widening precedes consumer-rebinding precedes compilation; migrations precede usage; tests defined early), temporal-consistency check | **BUILD-NOW** | | 4 | (c) Plan-DAG scheduler — `{ready, blocked, alternative}` per-node state, checkpoints between steps, topological order, cycle collapse, branch scores | **BUILD-NOW** | | 5 | (d) Execution driver — expose the SINGLE currently-actionable obligation (preconditions, `permitted_actions`, `required_validation`), never the whole schedule | **BUILD-NOW** | | 6 | (e) Local validation gate — completed node → pass/fail; on fail, SCOPED replan of the affected subgraph only (failed node + its true dependents) | **BUILD-NOW** | | 7 | (f) Adaptive revision trigger — component 06 impact feedback → add/remove obligations + re-walk affected dependency edges | **BUILD-NOW** | | 8 | (g) Plan-state persistence + audit — serialized JSON plan artifact + revision history + audit trail (resumption, auditability, traceability) | **BUILD-NOW** | | 9 | SWE-Search MCTS branching — a real **value model** + **discriminator** + actual branch exploration/backtracking, not just the DAG representation | **DEFERRED** — needs a value model (fine-tuning) + multiple LLM calls per branch; Round 1 keeps the richer DAG representation (P4) but follows only the top-ranked branch | | 10 | MetaGPT multi-agent role fan-out (Product Manager → Architect → Engineer → QA agents) | **DEFERRED** — multiplies LLM calls and failure surfaces; the paper explicitly *rejects* copying the multi-agent organization (§2.2). Only its typed-artifact discipline transfers to Round 1 | | 11 | Latent Programming Horizons activation-based early-failure detection | **DEFERRED** — two-month-old preprint; specifics provisional; needs activation probing of the residual stream; no round-1 path | **Branching decision: BUILD-NOW-THE-REPRESENTATION, NOT-THE-SEARCH.** Round 1 does not build MCTS branch *search*. It builds the plan as a **DAG or tree with state from the start** — per-node `{ready, blocked, alternative}` status, checkpoint markers, branch scores, failure states, rollback, and replacement hypotheses all present — because SWE-Search's result (gains shrink as the base model improves) and the cost of full search say the *representation* is the transferable piece and the *search* is a later-round, GPU/multi-call expense (row 9). The cost of the richer representation is paid once, in the schema (§3.3); the cost of not having it is paid every time a single-trajectory plan fails and the only recovery is to restart from the top. Round 1 executes the top-ranked branch; the DAG, its checkpoint markers, and its alternative set are all present from the start (paper §2.3, §4 stage 4). --- ## 3. The Deterministic Pipeline (D) Seven stages, all **D** through the production of the persistent plan artifact. The LLM column holds exactly one thing: the semantic decomposition (§4), reached after canonicalization. The pipeline: ``` USER REQUEST + EVIDENCE (03 recon graph, 04 context, 05 localization, 06 impact DAG) → (a) task canonicalization [D] → requirement artifact → (§4) semantic decomposition [L — the ONE entry] → (b) dependency graph over obligations [D] → (c) plan-DAG scheduler [D] → (g) persistence + audit [D] → (d) execution driver [D] → (e) local validation gate [D] → (f) adaptive revision trigger [D] ── feedback loop back into (b)/(c)/(e) ``` All artifacts land in `build/07-task-decomposition-planning/`. Nothing writes into the live harness. ### 3.1 (a) Task canonicalization (D) **Input:** the raw user request (free text) + optional task text. **Output:** a **typed requirement artifact** with checkable acceptance criteria. **No language model reads or normalizes the request.** ```json { "goal": "Make the session timeout configurable", "acceptance_criteria": [ "SessionConfig accepts a timeout value", "SessionManager reads timeout from SessionConfig, not a hard-coded constant", "old-default behaviour preserved when no timeout is supplied", "a custom timeout value is honoured at runtime", "a malformed configuration is rejected" ], "constraints": [ "no breaking change to the public Session API" ] } ``` **Schema (exact):** ```json { "goal": str, "acceptance_criteria": [checkable predicate, ...], // 1..N, each a str that can be evaluated true/false "constraints": [str] } ``` **Procedure (exact, deterministic):** 1. **Text normalization:** trim, collapse whitespace, strip list-noise and boilerplate framing ("please", "thanks", "as always"). 2. **Acceptance-criterion extraction:** from the request, extract the named behaviour / test / command / observable-state predicates that would prove the task done (the paper's "a plan must terminate at a checkable predicate, never at a vibe"). If the request does **not** name one, canonicalization **derives candidate predicates** from the request's own verbs and **marks them for confirmation** (`"acceptance_criteria": [...], "needs_confirmation": true`); a plan may *start* on a derived predicate but must not *terminate* on an unconfirmed one — a checkable predicate is the only legal terminal. 3. **Schema validation:** reject (return a validation error, never a plan) any request that yields an empty `goal`, an empty `acceptance_criteria` that cannot be derived, or a non-JSON-serializable artifact. The stage is deterministic `re`-based normalization plus `json` schema validation; **no LLM is consulted** to decide what the task means. **Caps:** `goal` ≤ **500 chars**; each predicate ≤ **200 chars**; ≤ **16** acceptance criteria; ≤ **16** constraints. `acceptance_criteria` and `constraints` are arrays of `str` only — never free prose or embedded code blobs. ### 3.2 (b) Dependency graph over obligations (D) **Input:** the initial obligation set from §4 + the requirement artifact (a) + component 06's relation edges (the cause-labeled impact DAG) + component 03's recon graph. **Output:** a dependency graph over obligations, each edge an ordering constraint. **Obligation record schema (exact — the paper's P1 `PlanNode` record, verbatim shape):** ```json { "id": "O7", // unique in this plan "target_entity": "repo.auth.SessionManager.load", "obligation": "modify", // one of "modify" | "preserve" | "validate" "caused_by": "impact06: sig change → consumer re-bind", "dependencies": [ "O3" ], // obligation ids that must be discharged first "evidence": "06 DAG edge CalledBy / 03 recon call graph", "status": "ready", // one of "ready" | "blocked" | "alternative" "validation": "tests/test_session.py::test_custom_timeout" } ``` **Resolution procedure (exact, deterministic — resolves each obligation's `dependencies[]` against repo structure):** 1. **Ordering ladder (first applicable rule wins):** - a **type-widening** obligation precedes the **consumer-rebinding** obligation that precedes the **compilation** obligation (widen the type before re-binding the consumer before compiling); - a **preserve-default** obligation precedes **anything that would rely on the new default** (the old default must be preserved before the new-configuration test is trusted — paper's §2.2 example: `preserve default behavior` precedes `old-default test re-runs` precedes `custom timeout test passes`); - **shared types precede consumers**; **migrations precede usage** (a schema/migration obligation precedes any obligation that would consume the migrated shape); - **tests are defined early** to anchor success (a validation obligation that names a test depends on that test existing — `validate` obligations run against tests defined by an earlier `modify` obligation unless the test already exists in the repo). 2. **Temporal-consistency check:** after resolving every edge, check that the resulting order is **temporally consistent** — no obligation can be discharged in an order that leaves the repository invalid [CodePlan, paper §1, §4 stage 3]. A schedule whose order would leave the repo uncompilable or a dependent unresolved at any step is rejected and the offending edge(s) flagged. 3. **Reuse:** the graph reuses component 06's relation edges (its cause-labeled impact DAG gives the causal edges between obligations) and component 03's recon graph (its nodes/edges give the structural edges). No new analysis is invented; ordering is *assembled* from existing evidence. **Caps:** ≤ **64** obligations in the graph (the §4 cap, preserved through this stage — a larger decomposition was already flagged for re-scoping); each `dependencies` array ≤ **16** ids; each `evidence` string ≤ **200** chars. Nodes without an outgoing causal justification (`caused_by` empty and `dependencies` empty and `status` not `alternative`) are rejected as ungrounded obligations. ### 3.3 (c) Plan-DAG scheduler (D) **Input:** the dependency graph (b). **Output:** a **plan DAG** — the executable partial order — with three states per node and checkpoints between steps. **Per-node state (exact — three values, paper §4 stage 4):** | State | Meaning | |---|---| | **`ready`** | all `dependencies[]` discharged; this node is currently actionable (the scheduler may offer it to the driver) | | **`blocked`** | one or more `dependencies[]` not yet discharged; waiting | | **`alternative`** | a sibling branch that could substitute if a hypothesis is falsified (P4); not currently actionable, present from the start | **Procedure (exact):** 1. **Topological order:** topologically sort the dependency graph. A node is `ready` iff its dependency set is empty of not-yet-complete obligations. 2. **Cycle collapse:** if the dependency graph contains a cycle (two obligations each requiring the other — the sign of a modelling error, not a real ordering), **collapse the cycle into a single composite node** carrying all member obligations, flag it `"cycle_collapsed": true`, and record the members; the composite is validated as one unit. A true cycle that survives collapse is a rejected deliverable (it cannot be executed). 3. **Branch scores:** every `alternative` node carries a **branch score** ∈ `[0,1]`, a deterministic prior over how likely that branch is to resolve the request (e.g. lex/co-change coupling with the seed, inherited from component 06's soft-rank, plus impact confidence). Round 1 **follows the top-ranked branch**; it does not explore branches (that is DEFERRED, §2 row 9). 4. **Checkpoints:** insert a **checkpoint marker** between steps so the schedule can be resumed, rolled back, or abandoned from a known-good state. A checkpoint is a point at which the repository is temporally consistent (all prior obligations validated) and the plan state is persisted (§3.7). The scheduler emits, at every step: the set of currently-`ready` nodes, the `blocked` set waiting on dependencies, and the `alternative` branches that could substitute if a hypothesis is falsified. **Emit:** the plan DAG = `{ nodes: [PlanNode…], edges: [obligation-id pairs], ready: […], blocked: […], alternative: […], checkpoints: [step markers], branch_scores: {node_id: score} }`. **Caps:** ≤ **64** nodes; ≤ **64** branch-scores; checkpoints ≤ **32** per plan. ### 3.4 (d) Execution driver (D) **Input:** the plan DAG (c) + the downstream next-edit / context construction decision of component 08 + the tool layer of component 01. **Output:** the **single currently-actionable obligation** — nothing more. **The driver exposes ONLY the currently actionable obligation (exact — paper P7, §4 stage 5):** ```json { "node_id": "O7", "obligation": "modify", "target_entity": "repo.auth.SessionManager.load", "preconditions": { "O3": "complete", "O4": "complete" }, "permitted_actions": { "read": true, "edit": true, "test": true, "bounds": { "max_edit_files": 5, "max_test_calls": 10 } }, "required_validation": "tests/test_session.py::test_custom_timeout" } ``` **Procedure (exact):** 1. At each step the driver selects **exactly one** `ready` node (deterministic tiebreak: lowest `id`). 2. It constructs the model-facing context **only** from that node's preconditions, `permitted_actions` (read / edit / test and their bounds), and `required_validation` — **never the whole schedule**. 3. As edits land, the driver marks the node's preconditions satisfied; only then may the scheduler advance the next `ready` node. This is P7 made structural (the paper §2.5, §4 stage 5): the environment **presents** the active obligation; the model never has to **remember** the plan, and context pressure cannot evict a decision the model was never asked to hold. **Invariant 6 (§8): only the currently actionable obligation is exposed, never the whole schedule.** ### 3.5 (e) Local validation gate (D) **Input:** a completed node + its `required_validation`. **Output:** `pass` / `fail`, and on `fail` a **scoped replan** of the affected subgraph only. **Procedure (exact):** 1. On node completion, run the node's **local validation**: the prescribed test runs, the prescribed build check compiles, the acceptance predicate (a) evaluates. This is the temporal-consistency checkpoint per step. 2. **`pass`** → mark the node complete, advance the scheduler, and let the adaptive revision trigger (f) observe the outcome. 3. **`fail`** → trigger a **SCOPED replan** (paper §4 stage 6, P5): - recompute the **affected subgraph** = the failed node **plus its true dependents** (downstream nodes reachable through dependency edges — the obligations that would have run after this one and now cannot, because their dependency did not discharge); - **re-decompose and re-schedule that subgraph only** — siblings and nodes upstream remain untouched **unless the dependency graph says otherwise**; - the scoped re-decomposition is itself a scoped invocation of the semantic-decomposition entry (§4 note) over the affected subgraph only. This is P5 executed (paper §2.4, §4 stage 6, backed by Runtime-Structured's retry-token result [3]): a failure reruns the failed portion, **never the whole plan**. ### 3.6 (f) Adaptive revision trigger (D) **Input:** component 06's impact-analysis feedback + the running schedule. **Output:** added or removed obligations + re-walked dependency edges — the plan as a **living artifact**. **Procedure (exact):** 1. When an edit's observed effect contradicts the schedule's assumptions — a dependency the plan did not foresee, a change obligation it did not list — the trigger: - **adds** the missing obligation(s) (with a `caused_by` recording the evidence that demanded them) and/or - **removes** an obligation the evidence has falsified, and - **re-walks the affected dependency edges** (re-runs §3.2's resolution over the neighbourhood the new/removed obligation touches — never a full re-plan). 2. The plan is therefore revised when reality disagrees; it is never a contract frozen at emission (paper §2.1, §4 stage 7, CodePlan's adaptive plan). The revision is recorded in the audit trail (§3.7) with the causing obligation. ### 3.7 (g) Plan-state persistence + audit (D) **Input:** the plan graph + per-node status + checkpoints + branch scores + revision history. **Output:** the **serialized plan artifact** (JSON) + revision history + audit trail. **Serialized schema (exact):** ```json { "plan_id": "plan-20260905-1412", "requirement": { "goal": "…", "acceptance_criteria": ["…"], "constraints": ["…"] }, "nodes": [ { "id": "O7", "target_entity": "…", "obligation": "modify", "caused_by": "…", "dependencies": ["O3"], "evidence": "…", "status": "ready", "validation": "…", "state": "pending|complete|failed" } ], "checkpoints": [ "step markers" ], "branch_scores": { "node_id": 0.7 }, "revision_history": [ { "rev": 3, "time": "…", "change": "added O9 via impact feedback", "caused_by": "O6 evidence" } ], "audit": [ { "obligation": "O7", "accepted_edit": "…", "trace": "edit accepted because O7 discharged" } ] } ``` **Procedure (exact):** - **Persistence:** the plan — obligation graph, per-node status, checkpoints, branch scores, and revision history — is serialized to a persistent, externally visible JSON artifact at every checkpoint and every state change. Persistence buys **resumption** (a wedged run restarts from the last checkpoint, not the top), **auditability** (each accepted edit is traceable to the obligation that caused it), and **honesty** (the plan is a visible, diffable object the §6/§7 measurement can score directly — not a hidden scaffold the model improvises over). - **Audit:** each state transition writes one audit row; each accepted edit is linked to the obligation that caused it; each revision (f) records the causing obligation. The revision history makes a planner regression visible in the artifact's diff before it surfaces as a failed resolve. **Caps:** serialized artifact ≤ **32 KB**; ≤ **64** audit rows per plan; ≤ **32** revision entries. --- ## 4. The LLM Step (L, ONE entry) The **single** learned node in the entire stage: **semantic decomposition**. The weak model converts the requirement artifact (a) + the evidence from components 03/04/05/06 into the **initial typed obligation set**, emitted as schema-constrained JSON in **ONE call at temperature zero**. This is the sole entry in the L column; every upstream and downstream step is deterministic software on CPU (paper §4, P1). The model does **not** explore, does **not** call tools, does **not** re-derive the graph — it emits a bounded, schema-constrained obligation set and the harness owns the graph and its state from then on. **Prompt inputs (assembled deterministically, in this exact order):** 1. **`requirement`** — the typed requirement artifact (a): `goal`, `acceptance_criteria`, `constraints`. 2. **The evidence** — one-line summaries from component 06's impact DAG (cause-labeled edges), component 05's localization, component 04's retrieved context, and component 03's recon graph (signatures, never bodies). **Input → output schema (exact — the obligation record schema of P1, verbatim shape, emitted as a JSON array of records):** ```json { "obligations": [ { "id": "O1", "target_entity": "repo.auth.SessionConfig.schema", "obligation": "modify", "caused_by": "requirement: make timeout configurable", "dependencies": [], "evidence": "06 DAG: schema change", "status": "ready", "validation": "tests/test_config.py::test_timeout_field" }, { "id": "O2", "target_entity": "repo.auth.SessionConfig", "obligation": "preserve", "caused_by": "requirement constraint: no breaking change to public Session API", "dependencies": ["O1"], "evidence": "06 DAG: default-preservation obligation", "status": "blocked", "validation": "tests/test_config.py::test_old_default" }, { "id": "O3", "target_entity": "repo.auth.SessionManager", "obligation": "modify", "caused_by": "consumer must read timeout from config", "dependencies": ["O1"], "evidence": "06 DAG edge CalledBy", "status": "blocked", "validation": "tests/test_session.py::test_custom_timeout" } ] } ``` **Obligation record schema (exact — the model must emit nothing outside it):** ```json { "id": str, "target_entity": str, "obligation": "modify" | "preserve" | "validate", "caused_by": str, "dependencies": [str], // obligation ids that must be discharged first "evidence": str, // the component-03/06 evidence that justifies this obligation "status": "ready" | "blocked" | "alternative", "validation": str } // the checkable predicate / test that proves this node done ``` **Caps:** **ONE call**, `temperature = 0`, `max_completion_tokens = 2048`, ≤ **64** obligations (a larger decomposition — a set that exceeds 64 records — is **flagged for re-scoping**, not executed: the planner refuses to schedule an un-scoped mega-decomposition and re-canonicalizes the request into smaller scopes). `temperature = 0` makes the single call deterministic in practice so replan results are comparable. **Parse-failure fallback (exact):** any JSON parse failure, schema violation, or >64-obligation output is a **no-op**: the stage emits an **empty obligation set** `{ "obligations": [], "re_decompose": true }` and hands control back to canonicalization — **never a re-prompt, never a second call**. The L column is reached **once** per scope; a failed parse is not retried with a "please try again" call. This is the mechanical enforcement of P1/P5's "the LLM contributes one decision" and of the anti-over-prompting rule. **Re-invocation on replan (exact):** semantic decomposition is **re-invoked** when the local validation gate (e) fails or the adaptive revision trigger (f) fires, but each re-invocation is **scoped to an affected subgraph** — only the failed node + its true dependents are re-decomposed, and the model is given only that subgraph's requirement fragment and evidence. It remains the **single conceptual learned entry** — a bounded, once-per-scope decomposition decision — **never a planner that runs continuously** and never a loop that re-derives the whole plan (paper §4 stage 2 note). --- ## 5. Implementation Order Eight phases, each independently testable and reversible. Each lands in `build/07-task-decomposition-planning/` as a standalone importable module. Rollback = delete/flag-off that phase's module; nothing earlier breaks because phases only add modules and never mutate live harness code. | Phase | Delivers | Isolated test | Rollback | |---|---|---|---| | **1. Task canonicalization** | `canonicalize.py` (§3.1 normalization + acceptance-criterion extraction + schema validation) | Scripted requests: a request with a named predicate yields that predicate; one without one yields derived candidates with `needs_confirmation: true`; an empty-goal request is rejected with a validation error, never a plan; caps (16 predicates, 500-char goal) enforced. Assert **no LLM is consulted** (probe the LLM client to raise). | Delete `canonicalize.py` (pure read). | | **2. Semantic decomposition (L)** | `decompose.py` (§4 prompt assembly + ONE call + output schema + parse-failure fallback + scoped re-invoke hook) | Mock the LLM client to return a scripted obligation set: assert **one** call, `temperature=0`, `max_completion_tokens=2048`; prompt carries the requirement + evidence summaries but **no code blobs**; output schema validated (each record has exactly the 8 fields, `obligation` ∈ the 3 verbs); a malformed/over-64 response → `{"obligations":[],"re_decompose":true}` with **no second call**; the re-invoke hook is callable with a scoped subgraph only. | Delete `decompose.py` (no live-harness change). | | **3. Dependency graph over obligations** | `obliggraph.py` (§3.2 ordering ladder + temporal-consistency check, reuses component 06 relation edges + component 03 recon graph) | Fixture obligation set: a type-widening obligation precedes the consumer-rebinding that precedes compilation; a preserve-default obligation precedes the rely-on-new-default obligation; a migration precedes its usage; a `validate` naming a not-yet-existing test depends on the test-defining `modify`; an order that would leave the repo invalid at any step is rejected with the offending edge flagged; a `dependencies`-and-`caused_by`-both-empty node is rejected. | Delete `obliggraph.py`. | | **4. Plan-DAG scheduler** | `planner.py` (§3.3 topological order + `{ready,blocked,alternative}` states + cycle collapse + branch scores + checkpoints) | Fixture dependency graph: emits a topological order; a ready node appears only when its deps are complete; a two-node mutual-dependency cycle collapses into one flagged composite; alternatives carry branch scores and are present but not executed; checkpoint markers appear between steps; `ready`/`blocked`/`alternative` partition is exact and exhaustive. | Delete `planner.py`. | | **5. Execution driver** | `driver.py` (§3.4 single-actionable-obligation exposure + bounds) | Scripted plan: at each step the driver exposes **exactly one** `ready` node with preconditions / `permitted_actions` / `required_validation`; it **never emits the whole schedule** (assert the serialized context contains one node); deterministic tiebreak by lowest `id`; bounds (max 5 edit files, 10 test calls) are enforced. | Delete `driver.py`. | | **6. Local validation gate + scoped replan** | `validate.py` (§3.5 pass/fail + affected-subgraph computation + scoped re-decompose hook) | Scripted node outcomes: a pass marks the node complete and advances; a fail recomputes the affected subgraph = failed node + true dependents only — a sibling and an upstream node are **not** re-planned (assert untouched); the scoped re-decompose hook receives only the subgraph's fragment. | Delete `validate.py`. | | **7. Adaptive revision trigger** | `revise.py` (§3.6 add/remove obligations + affected-edge re-walk) | Feed a component 06 contradiction: a dependency the plan did not foresee is added with a `caused_by`; a falsified obligation is removed; only the affected neighbourhood's edges are re-walked (no full re-plan); each revision is recorded with its causing obligation. | Delete `revise.py`. | | **8. Persistence + audit + A/B harness** | `state.py` (§3.7 serialized JSON + revision history + audit), `ab.py` (feature-flag router + retry-token capture + temporal-consistency capture + ablation runner + decision) | End-to-end on 3 warm-up tasks: `state.py` persists the plan at every checkpoint and resumes a wedged run from the last checkpoint (not the top); each edit is traceable to its causing obligation; `ab.py` runs planned-vs-baseline on the §7 sample, emits retry-token cost, temporal-consistency rate, resolve/cost/tokens, the ablation report, and the §7 decision. | Feature flag `off` → live harness untouched; `ab.py` is read-only. | The A/B runner (Phase 8) is the only phase that ever *invokes* the current harness — and only to measure it, never to modify it. --- ## 6. Dependencies & Supply-Chain Per Piper's rule: nothing is installed unless >72h old AND (≥10 stars OR deep-scrutinized). This build is **zero-install for Round 1 (Python-only, stdlib + in-repo)**: | Dependency | Why | Status / age-stars | Install needed? | |---|---|---|---| | stdlib `json`, `re`, `sqlite3`, `hashlib`, `collections` | artifact schemas (§3.1/§4), normalization, storage of the plan artifact (§3.7) | CPython stdlib. | **No** | | stdlib `ast` / component 03 tree-sitter | validating that acceptance predicates and `target_entity` references are structurally grounded in the repo | Reuse component 03's `recon.db` (already built/flagged there); no new parser. | **No** | | Component 06 relation edges + impact DAG | §3.2 dependency resolution + §3.6 revision trigger | In-repo, built by spec 06. | **No** | | Component 03 recon graph (`recon.db`) | §3.2 ordering + §3.3 scheduler structural grounding | In-repo, built by spec 03. | **No** | | Component 05 localization | §3.1 acceptance-criterion grounding + §4 evidence | In-repo, built by spec 05. | **No** | | Component 04 retrieved context | §4 decomposition evidence | In-repo, built by spec 04. | **No** | | Component 01 tool layer | §3.4 execution-driver permitted actions (read/edit/test) | In-repo, already vetted. | **No** | | Component 06 soft-rank (`lex`/co-change scores) | §3.3 branch scores | In-repo, already vetted. | **No** | **Preferred path: zero-install.** Round 1 is Python-only and deterministic: the planner reuses component 06's relation edges and impact DAG, component 03's recon graph, component 05's localization, component 04's context, component 01's tool layer, and component 06's soft-rank for branch scores. The single LLM call (§4) goes to the harness's own weak model. **No new package is installed for Round 1, and nothing is flagged for a later install** — the three DEFERRED rows (§2 9–11: SWE-Search MCTS with a real value model + discriminator, MetaGPT multi-agent fan-out, Latent Programming Horizons activation probing) are code and/or fine-tuning on existing weights, not new third-party installs; any future model download or GPU dependency they imply must clear the 72h + star/scrutiny + sandbox-test gate before use, and is out of Round 1 scope entirely. --- ## 7. Acceptance Criteria — the A/B Protocol **Sample (concrete).** Reuse the **same 20 held-out SWE-bench-Verified instances as spec 01** (Python-only, single-repo, no-Docker reproduction). Held out = never seen by any tuning, prompt, or ranking pass. Seeded RNG. **Fallback:** `coding-cortex/piperbench` sampled to 20 tasks, held out identically. ### 7.1 (a) Retry-token cost — the KEY measure The key planning instrument, inherited from Runtime-Structured Task Decomposition [3]: the tokens burned **re-running failed stages**. The planned path must **STRICTLY DROP** retry-token cost versus **BOTH** a monolithic prompt AND a static (prompt-embedded) decomposition. The comparison set is explicit: monolithic, static-decomposition, and runtime-structured (this build) runs of the same requests. The template numbers to beat are Runtime-Structured's own: | Approach | Retry tokens (Kubernetes root-cause workload) | |---|---| | Static decomposition (fixed LLM chain in the prompt) | **1,632 ± 145** | | Monolithic prompt | **904 ± 17** | | Runtime-structured (harness owns execution; this build) | **436 ± 132** | **Decision:** the planned path **wins on this instrument iff** its retry-token cost is **strictly lower than both** the monolithic run and the static-decomposition run of the same requests — not merely lower than one. This instrument directly scores P5: a schedule that localizes failure to the failed subgraph (§3.5) scores low on retry tokens; one that forces re-execution from the top (static decomposition) or re-derives everything (monolithic) scores high. **This is the KEY measure — a temporal-consistency or resolve win that does not lower retry-token cost is not credited.** ### 7.2 (b) Temporal-consistency rate The fraction of **intermediate states** — after each executed node — in which the repository remains valid (buildable-and-testable). CodePlan's temporal-consistency property [1] is the criterion: a plan is good if the repository is valid after *every* step, not merely at the end. A plan that reaches a valid end-state through a broken middle has failed this instrument even if its final patch lands (paper §6). This is the plan-quality analogue of component 06's PASS_TO_PASS regression rate: temporal consistency counts the damage *during* the schedule, before final validation masks it. **The planned path must STRICTLY IMPROVE the temporal-consistency rate** versus both baselines. ### 7.3 (c) End-to-end regression guard The coarse instrument kept for parity with the program's other components — **deliberately not** the gate for planner changes, because resolve rate cannot separate planning quality from execution quality: 1. **Resolve rate** = `resolved / total` (spec 01's score). 2. **Cost** = `$ / instance` (model spend only; deterministic stages are ~free). 3. **Tokens** = `tokens / instance`. ### 7.4 Decision rule (explicit thresholds) Run candidate-vs-current on the *identical* sample with the *identical* model (the harness's own weak model, `deepseek-v4-pro`) and hardware (this box). The candidate **wins iff**: ``` Retry-token cost STRICTLY drops vs BOTH monolithic AND static-decomposition (the KEY measure) AND temporal-consistency STRICTLY improves AND resolve_candidate ≥ resolve_current (no end-to-end regression) AND cost_candidate ≤ 1.5 × cost_current AND tokens_candidate ≤ 1.5 × tokens_current ``` The retry-token cost must **strictly drop against both baselines** and temporal-consistency must **strictly improve**; resolve must not regress; cost and tokens are bounded at 1.5×. A candidate that improves resolve but leaves retry-token cost flat (or higher than static) is **not adopted**. If the candidate wins, it replaces the current path (edit-without-planning); if it loses, the build tree is kept for the record and the live harness is unchanged. ### 7.5 Ablation rule (mechanical) The instrument that enforces P6 — the paper's strongest warning, From Plan to Action [2]: a bad or over-elaborate plan can be **worse than no plan**, and extra stages that conflict with the model's internal strategy can hurt. So each planning mechanism is removed **in isolation** — the externalized plan (§3.7), the typed artifacts (§3.1/§4), the dependency ordering (§3.2), the local validation gate (§3.5), the adaptive revision trigger (§3.6) — everything else held fixed, and the delta measured on the honest metrics (retry-token cost and temporal-consistency rate, plus resolve/cost/tokens). A mechanism is **deleted** iff its removal changes none of the honest metrics beyond noise (`Δ = 0`, or `|Δ| ≤ 5%` where continuous). Applied first to the weakest a-priori case (the adaptive revision trigger), then to any other mechanism — regardless of how sensible it looks. The discipline is the title of the instrument (paper §6): **never add a planning mechanism because it sounds sensible; prove it earns its tokens.** A mechanism whose *addition* degrades the metrics is a demonstrated harm and is removed. --- ## 8. Guardrails & Reversibility **Revocability.** - The build lives entirely in `build/07-task-decomposition-planning/` (a separate tree); it never writes into the live harness's source. - A **feature flag** (env var `PLAN=plan07|current`, default `current`) routes the A/B; the flag alone switches between the new planning stage and the current "edit-without-planning" path — no code deletion required to revert. - `ab.py` is a read-only driver: it *measures* the current harness, it never modifies it. Running old-vs-new is always possible in the same session, same repo, same model. **Invariants (must hold, checked at the end of every phase).** 1. **No new `.md` files outside this folder** (`projects/self-improvement/{papers,specs,build}`). Everything else is code or DB rows. 2. **No change to the live harness** until the §7 A/B gate passes. The current tool surface stays byte-identical during the entire build. 3. **The L column holds exactly ONE entry** — semantic decomposition (§4) — reached once, never re-prompted on parse failure. Any phase that introduces a language model elsewhere in the pipeline (canonicalization, dependency resolution, scheduling, driving, validation, revision, persistence) is rejected outright. 4. **The plan is machine-readable and externally stateful** — serialized JSON (§3.7), never prose maintained in the context window. A plan that exists only as a model-held TODO list is a rejected deliverable. 5. **Runtime owns execution — a failure reruns only the affected subgraph, never the whole plan.** The local validation gate (§3.5) scopes replan to the failed node + its true dependents; the adaptive revision trigger (§3.6) re-walks only the affected edges. A whole-plan restart on a single-node failure is a rejected change. 6. **Only the currently actionable obligation is exposed to the model, never the whole schedule.** The execution driver (§3.4) presents exactly one `ready` node; the model is never handed the full DAG. Any phase that injects the whole schedule into the model-facing context is rejected outright. 7. **Temporal consistency — the repository is valid after every step.** The dependency ordering (§3.2), the topological plan-DAG (§3.3), and the per-step validation gate (§3.5) keep the repo valid after *every* executed node, not merely at the end. An unordered schedule or a step that leaves the repo invalid is a rejected deliverable. 8. **Planning mechanisms are ablated, not accumulated** — a mechanism that does not move the honest metrics (§7 retry-token cost and temporal-consistency rate) is **removed**, not kept because it sounds sensible. Every mechanism of §3/§4 must survive the §7.5 ablation or be rejected. --- *End of spec. This document is the build contract; the next document records the A/B outcome.*