Context
Nessie #604: an 8.6-second plan collapsed 6 enumerated findings into ONE workstream with ONE path; the developer sprawled to 11 files, looped 17 failed builds, burned 10.5M tokens, and died. The #582-586 oversized-diff incidents show decomposition is also the convergence fix. The pre-driver PM flow defaulted to parallel (up to 10 slots); inlinePlanPrompt (work-driver.ts:4413-4441) carries no decomposition doctrine, and runPlan accepts any parseWorkstreams result (:805) unchecked. Issue #280's addendum proposed counting enumerated findings but only warning — this issue absorbs and supersedes that addendum (one corrective re-dispatch instead of a warning).
Two-level accounting: K≤2 groups × M workstreams; develop peak = K×M children, lens peak = K×6 = 12 — all bounded by the spawn semaphore (PI_ENSEMBLE_SPAWN_CAP=8 FIFO); async-jobs MAX_JOBS=50 and dispatch MAX_PARALLEL=10 unchanged.
This work must ship as its own separate PR, independent of any other open issue.
What to build
A. inlinePlanPrompt overhaul (:4413-4441) — replace the doctrine block with: (1) ENUMERATE the issue's discrete findings/deliverables first (numbered/checkbox items are the default enumeration); (2) map EACH finding to its own workstream unless two genuinely require edits to the same files — independence criterion = disjoint file sets, nothing else; (3) every workstream MUST declare non-empty paths: and out-of-scope: fences; (4) bias TOWARD more workstreams (cite #604); unmapped findings go under an explicit Deferred: line; (5) floor: one workstream per genuinely separable file-set — a single-file 2-line fix is ONE workstream; target per-workstream diff ≤ ~150 lines.
B. Deterministic plan-quality check in runPlan after parseWorkstreams (:805): pure countEnumeratedFindings(body) counting top-level ^\s*(\d+[.)]|- \[[ x]\]) items against the issue body cached by explore (writeDispatchArtifact, :598). If findings ≥ 3 && workstreams === 1 → re-dispatch the plan ONCE with corrective steer ("the issue enumerates N findings; map each to its own workstream or list it under Deferred"). Independently, any workstream with paths.length === 0 → same single corrective re-dispatch ("declare paths per workstream" — paths drive the scope-fanout gate #285 and worktree independence). One combined retry max; second result is final; empty paths after retry are kept but recorded.
Schema (additive): pipelineState.planQuality?: { findingsCount: number; redispatched: boolean; reason?: "under-decomposed" | "empty-paths" }.
Knob: PI_ENSEMBLE_PLAN_QUALITY=0 disables the check (prompt doctrine stays).
Acceptance criteria
Out of scope
Parallel groups/mutex; worktree mechanics; #280's main body (repeat-finding seam escalation, dead step-back); scope-fanout gate implementation (#285); grouping rules.
Test plan
Offline: fixtures above via dispatchFn injection. Live on nessie: /work on a multi-finding issue; verify plan yields ≥2 workstreams with non-empty paths, or a recorded corrective re-dispatch; compare per-workstream diff sizes against the ≤150-line target.
Context
Nessie #604: an 8.6-second plan collapsed 6 enumerated findings into ONE workstream with ONE path; the developer sprawled to 11 files, looped 17 failed builds, burned 10.5M tokens, and died. The #582-586 oversized-diff incidents show decomposition is also the convergence fix. The pre-driver PM flow defaulted to parallel (up to 10 slots);
inlinePlanPrompt(work-driver.ts:4413-4441) carries no decomposition doctrine, andrunPlanaccepts anyparseWorkstreamsresult (:805) unchecked. Issue #280's addendum proposed counting enumerated findings but only warning — this issue absorbs and supersedes that addendum (one corrective re-dispatch instead of a warning).Two-level accounting: K≤2 groups × M workstreams; develop peak = K×M children, lens peak = K×6 = 12 — all bounded by the spawn semaphore (
PI_ENSEMBLE_SPAWN_CAP=8FIFO); async-jobsMAX_JOBS=50and dispatchMAX_PARALLEL=10unchanged.This work must ship as its own separate PR, independent of any other open issue.
What to build
A.
inlinePlanPromptoverhaul (:4413-4441) — replace the doctrine block with: (1) ENUMERATE the issue's discrete findings/deliverables first (numbered/checkbox items are the default enumeration); (2) map EACH finding to its own workstream unless two genuinely require edits to the same files — independence criterion = disjoint file sets, nothing else; (3) every workstream MUST declare non-emptypaths:andout-of-scope:fences; (4) bias TOWARD more workstreams (cite #604); unmapped findings go under an explicitDeferred:line; (5) floor: one workstream per genuinely separable file-set — a single-file 2-line fix is ONE workstream; target per-workstream diff ≤ ~150 lines.B. Deterministic plan-quality check in
runPlanafterparseWorkstreams(:805): purecountEnumeratedFindings(body)counting top-level^\s*(\d+[.)]|- \[[ x]\])items against the issue body cached by explore (writeDispatchArtifact, :598). Iffindings ≥ 3 && workstreams === 1→ re-dispatch the plan ONCE with corrective steer ("the issue enumerates N findings; map each to its own workstream or list it under Deferred"). Independently, any workstream withpaths.length === 0→ same single corrective re-dispatch ("declare paths per workstream" — paths drive the scope-fanout gate #285 and worktree independence). One combined retry max; second result is final; empty paths after retry are kept but recorded.Schema (additive):
pipelineState.planQuality?: { findingsCount: number; redispatched: boolean; reason?: "under-decomposed" | "empty-paths" }.Knob:
PI_ENSEMBLE_PLAN_QUALITY=0disables the check (prompt doctrine stays).Acceptance criteria
runWorkDrivertest: 6-numbered-finding body +dispatchFnreturning 1 workstream then 4 → exactly 2 plan dispatches;planQuality.redispatched === true, reasonunder-decomposed.empty-paths; combined violation → still exactly one retry.countEnumeratedFindingsunit tests (numbered, checkbox, nested-indent exclusion).PI_ENSEMBLE_PLAN_QUALITY=0→ zero re-dispatches.Out of scope
Parallel groups/mutex; worktree mechanics; #280's main body (repeat-finding seam escalation, dead step-back); scope-fanout gate implementation (#285); grouping rules.
Test plan
Offline: fixtures above via
dispatchFninjection. Live on nessie:/workon a multi-finding issue; verify plan yields ≥2 workstreams with non-empty paths, or a recorded corrective re-dispatch; compare per-workstream diff sizes against the ≤150-line target.