Skip to content

feat(ship): run independent decompose-and-implement sub-tasks concurrently - #651

Merged
BorisTyshkevich merged 1 commit into
mainfrom
feat/ship-parallel-decompose
Aug 8, 2026
Merged

feat(ship): run independent decompose-and-implement sub-tasks concurrently#651
BorisTyshkevich merged 1 commit into
mainfrom
feat/ship-parallel-decompose

Conversation

@BorisTyshkevich

Copy link
Copy Markdown
Collaborator

Motivation

decompose-and-implement-loop.workflow.mjs always ran a High-risk+Large unit's
sub-tasks strictly sequentially — one coding agent at a time on the same branch —
even when a sub-task's own dependsOn declared it had nothing to do with another.
On a large plan (#630 phase 7, 7 sub-tasks) that costs real wall-clock time (~107
minutes) even when several sub-tasks are genuinely independent.

What changed

  • Sub-tasks are grouped into dependency-ordered waves from their existing
    dependsOn graph (a plain topological pass, no new field). A wave of one
    sub-task runs exactly as before, directly on the unit branch. A wave of more
    than one runs those sub-tasks concurrently, each in its own
    isolation: "worktree" on its own wip/<unit>-<id> branch, since none of them
    can see another's edits until merged.
  • After a concurrent wave, one integration agent merges every branch into the
    unit branch in that wave's order (git merge --no-ff) and gates the merged
    result before the next wave starts. A merge conflict there means the sub-tasks'
    declared file scopes were not actually disjoint — treated as a real planning
    defect (error status), never forced through.
  • The decomposition prompt now tells Fable to favor adding a dependsOn edge
    whenever it isn't fully confident two sub-tasks are safe to run at the same
    time — dependsOn is the only signal driving concurrency, so a plan with
    sparse dependency information still comes out mostly or fully sequential
    (today's behavior unchanged), and only a genuinely independent plan gets real
    concurrency. This matches the skill's existing "when in doubt, serialize"
    principle for wave-planning at the unit level, applied one level down to
    sub-tasks.
  • SKILL.md step 2.3 updated to describe the new wave/integrate mechanics.

Verification

No dedicated test harness exists for .workflow.mjs scripts elsewhere in this
skill (none of the other reference scripts have one either) — verified by careful
review of the control flow, in particular:

  • phase('Implement') is re-asserted at the top of every wave iteration so a
    prior wave's phase('Integrate') label doesn't leak into the next wave's
    solo-sub-task agent call.
  • The PARALLEL_TASK_SCHEMA/INTEGRATE_SCHEMA additions are additive; the
    single-sub-task-per-wave path (today's common case) is otherwise byte-for-byte
    the original prompt/logic, so existing behavior for a fully-sequential plan is
    unchanged.

Full repository gate green (check:types/check:arch/check:schemas/
check:examples/npm test/npm run build) — this change touches only
skills/**, outside the coverage-gated src/** tree.

Co-Authored-By: Claude Sonnet 5 noreply@anthropic.com
Claude-Session: https://claude.ai/code/session_01LwFPT465eDJqYcRa8HGNLz

…ently

decompose-and-implement-loop.workflow.mjs always ran a High-risk+Large
unit's sub-tasks strictly sequentially, one coding agent at a time on the
same branch, even when a sub-task's dependsOn declared it had nothing to
do with another. On a large plan (observed: #630 phase 7, 7 sub-tasks) that
means real wall-clock time even when several sub-tasks are genuinely
independent.

Group sub-tasks into dependency-ordered waves from their existing dependsOn
graph. A wave of one sub-task runs exactly as before, directly on the unit
branch. A wave of more than one runs those sub-tasks concurrently, each in
its own isolation:"worktree" on its own wip/<unit>-<id> branch, since none
of them can see another's edits until merged. After a concurrent wave, one
integration agent merges every branch into the unit branch in that wave's
order and gates the merged result before the next wave starts; a merge
conflict there means the sub-tasks' declared file scopes were not actually
disjoint and is treated as a real planning defect (error status), never
forced through.

dependsOn is the only signal driving this — the decomposition prompt now
tells Fable to favor adding a dependsOn edge whenever it isn't fully
confident two sub-tasks are safe to run at the same time, so a plan with
sparse dependency information still comes out mostly or fully sequential,
matching today's behavior, and only a genuinely independent plan gets real
concurrency.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LwFPT465eDJqYcRa8HGNLz
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant