type: meta

slug: run-plan-dag-parallel

topic: DAG-parallel run-plan + parallelism-aware planning

exec_mode: direct

base_branch: master

status_enum: BLOCKED PENDING WORKING WRITTEN REVIEWED COMMITTED

truth_rule: this file is ground truth for INTENT; git is ground truth for DONE-NESS — reconcile statuses against git, never trust a COMMITTED line with no commit

refresh_how: native Read of THIS file — NEVER ctx_execute/ctx_search

refresh_what: meta + every goal/methodology/intent/direction record + all WORKING and BLOCKED tasks

refresh_when:
wave/phase boundary
any task status change
after a compaction system-reminder
before calling advisor

update_rule: on status change, rewrite that task's single line in place; append new tasks/session_memory as new lines

report_rule: at session end emit brief: done / blocked / deferred / canceled — NO next action


type: goal

text: Make run-plan execute its task dependency-DAG in parallel (independent tasks within a wave run concurrently, merge serially, fail-closed), and teach plan/brainstorm/fix-rot to author waves as parallelism groups.


type: methodology

text: Be critical/robust, best-practice not hacky. No stubs in deliverable code. Doc edits to agent-facing skills MUST follow agent-doc-authoring register. Tests for every fail-closed branch + negative proof (run-plan-det-extraction discipline).


type: intent

text: phase3 (t5 checkout ∥ t6 redemption, 'different files parallel OK') serializes today because run-plan.js:346 is sequential-within-wave. Unlock real parallelism without the rejected program/run-program layer (one plan, one PR).


type: direction

verbatim: none of the plans use it because none of the plans knew it could exist. i want to have the brainstorming/planning set of skills to know about the dag option and choose it where relevant


verbatim: Given you want one PR per program, which mechanism do you actually want? -> Parallel run-plan (DAG).


verbatim: we shouldn't call them even legacy vs new, it is 2 separate ways of running workflows, we may need both of them, no? according to selection of the planner agent? for different plans, different ways of execution are needed, for simple plans dag is overkill, and for complex plans the v1 is not enough


verbatim: you can just create primitives and reuse the primitives for the different versions, to not break any and avoid the drift


type: deferred

text: program-of-plans layer (run-program.js + program.jsonl schema + run-program skill)

reason: superseded by intra-plan DAG parallelism under one-PR integration; revive only if separate PRs/repos per module ever needed. Design preserved at docs/design/run-program-dag.md.


type: anchor

what: engine to refactor (wave loop lines 340-453)


what: superseded program-layer design (deferred)


type: task

desc: Extract runTaskLadder(t, leased, route, m) from run-plan.js lines 363-438 (implement→gate0→risk→finance→review→metagate), verbatim; NO lease, NO merge; inner halts return {ok:false,halt} instead of return halt(). Single-task behavior identical to current.

status: COMMITTED


desc: Add TWO co-equal strategies over the primitive + selector. runSequential = prior wave loop re-expressed (per task: lease→runTaskLadder→P.commit; integration review per wave) — behavior identical. runDagParallel = round loop: A1 serial lease over ready; A2 parallel(runTaskLadder); B serial P.commit (conflict→HALT); C gate0 on integration worktree (red→HALT,no fixer); ready=pending whose deps all done(); empty+pending→HALT(stuck). Select on meta.scheduler: 'sequential'|'dag-parallel'; absent→sequential; unknown→HALT (no silent default).


desc: Tests in workflows/lib. REGRESSION GUARD: runSequential over runTaskLadder == prior inline behavior (lease/ladder/commit order, HALT points) — in-flight safety. dag cases: (a) 2 independent→one round parallel, merged in order; (b) one task fails→wave HALT no merge; (c) intra-wave dep A→B→two rounds, B leases off A merge; (d) cyclic/unmet→stuck HALT; (e) merge conflict→HALT; (f) PHASE C integration gate0 red→HALT; (g) unknown meta.scheduler→HALT. Both branches of every fail-closed line + negative proof.


desc: plan/SKILL.md: add parallelism pass — same-wave+no-edge ⟺ independent + file-disjoint (one round); real dep→later wave with deps edge; reject serializing-for-safety. STRATEGY SELECTION rule: any wave with ≥2 independent file-disjoint tasks→stamp meta.scheduler='dag-parallel', else 'sequential'. agent-doc-authoring register.


desc: brainstorm/SKILL.md: schema block — add meta.scheduler (sequential|dag-parallel, open enum, absent⇒sequential) + OPTIONAL task field files:[...] (disjointness hint), both additive; add wave-purity note + set meta.scheduler via selection rule when section-9 tasks populated (not in skeleton), referencing plan's rule (no restate). agent-doc-authoring register.


desc: fix-rot/SKILL.md: one line on reconstruction — keep wave-purity (don't collapse parallel work into one wave, don't invent intra-wave deps), reference plan's rule. agent-doc-authoring register.


note: ~/.claude repo has NO git remote and no gh repo → run-plan's PR step cannot run here. Execution is main-thread direct, local commits only, NO PR (exec_mode=direct, not ship/run-plan). Landing on a remote is N/A. This is why brainstorm's auto-run-plan path was overridden.


note: w2.t4/t5/t6 are file-disjoint independent doc edits → a single parallel round: this plan dogfoods the feature it implements.


note: Invariant to preserve in run-plan.js: never call workflow() (keeps it a leaf Workflow). Resume path ls.resumed stays inside runTaskLadder.


note: DESIGN: sequential & dag-parallel are TWO co-equal permanent strategies (NOT legacy/v1 vs new/v2). Planner picks minimal-sufficient per plan: simple/linear→sequential, branchy→dag-parallel. Both compose ONE shared runTaskLadder primitive (no dup, no drift). meta.scheduler open enum; unknown→HALT; absent→sequential.