Skip to content

fix(flows): route flows run through the DAG-honoring swarm code preset#94

Merged
RNT56 merged 1 commit into
mainfrom
feat/flows-dag
Jul 2, 2026
Merged

fix(flows): route flows run through the DAG-honoring swarm code preset#94
RNT56 merged 1 commit into
mainfrom
feat/flows-dag

Conversation

@RNT56

@RNT56 RNT56 commented Jul 1, 2026

Copy link
Copy Markdown
Owner

The bug

nilcore flows run consumed a portable agentic-flows workflow by composing every agent_task node into a single newline-joined goal string and handing it to the decompose preset. decompose runs its children independently off HEAD and merges them in declaration order.

That silently collapsed the flow's DAG. The adapter correctly decodes each producesrequires dataflow edge into a real spawn.Subtask.DependsOn — but flattening the subtasks into a goal list threw those edges away. A dependent agent_task was then coded against the original tree instead of its dependency's output, which is exactly the structure a flow exists to express.

The fix

Route flows run through the verified swarm path with the code preset instead:

  • Lift the agent_task subtasks into a planner.Treeid / goal / DependsOn carried verbatim, plus the flow title + id@version provenance on the run goal.
  • Dispatch through swarm's code preset (Shape=DAG, FanIn=merge, Role=implementer, packs software+code). Swarm honors the tree's DependsOn: a dependent shard runs in a later pass on the integrated tip of its dependencies, not HEAD — so the flow's structure survives.
  • Completion stays verifier-owned (I2): each shard is pack-verified and the merged tip re-verified; no self-report ships.

Mechanics

  • swarm.TreeSharder (+ a shared treeToShards) maps a pre-built planner.Tree onto run-namespaced shards, re-namespacing DependsOn (plan-task ids) onto Shard.Deps (shard ids) — the same mapping PlanSharder uses, minus the model call.
  • swarmMain's tail is refactored into a reusable swarmRun(swarmDeps); swarmDeps gains an optional tree *planner.Tree seam consumed by buildInitialShards (falls back to the flag/preset sharder when nil — unchanged).
  • flowsRun builds default swarm flags, forces preset=code + the flow's dir, and calls swarmRun with the injected tree. No new dispatch loop.

Invariants

Pure additive seam. I1 backend contract untouched; I2 preserved (verifier still owns "done"); no I3/I4/I5/I6/I7 surface changed. flows/swarm/agenticflows/docs file sets are disjoint from the currently-open #93.

Tests

  • TestTreeSharderReNamespacesDeps — a 2-dep diamond (wire depends on scaffold+impl) maps onto swarm-<run>-{0,1,2} with Deps re-namespaced, routing carried, state queued.
  • TestFlowRunPreservesDAGThroughSwarm — the full flow→flowTreeTreeSharder path keeps implement-depends-on-plan as a real Shard.Dep, and stamps title + id@version provenance on the run goal.

Gate

make verify (119 pkgs) · go vet · golangci-lint (0 issues) — all green locally.

🤖 Generated with Claude Code

`nilcore flows run` flattened a flow's agent_task DAG into a newline-joined
goal string handed to the `decompose` preset, which runs children
independently off HEAD and merges in order. That discarded the flow's
produces→requires edges (decoded into spawn.Subtask.DependsOn): a dependent
agent_task was coded against the original tree, not its dependency's output
— collapsing exactly the structure a flow exists to express.

Lift the agent_task subtasks into a planner.Tree (id/goal/DependsOn verbatim
+ title & id@version provenance on the run goal) and dispatch through the
verified swarm path with the `code` preset (Shape=DAG, FanIn=merge,
Role=implementer, packs software+code). Swarm honors DependsOn: a dependent
shard runs in a later pass on the integrated tip of its dependencies, not
HEAD. Completion stays verifier-owned (I2): each shard is pack-verified and
the merged tip re-verified.

- swarm.TreeSharder + shared treeToShards: map a pre-built planner.Tree onto
  run-namespaced shards, re-namespacing DependsOn onto Shard.Deps (the same
  mapping PlanSharder uses, minus the model call).
- swarmMain tail refactored into reusable swarmRun(swarmDeps); swarmDeps
  gains an optional `tree *planner.Tree` seam consumed by buildInitialShards.
- flowsRun builds default swarm flags, forces preset=code + the flow's dir,
  and calls swarmRun with the injected tree. No new dispatch loop.

Tests: TreeSharder re-namespaces a 2-dep diamond + carries routing; the
flow→tree→shards path preserves the implement-depends-on-plan edge as a real
Shard.Dep and stamps title+provenance. Docs updated off the stale
"decompose preset" wording. make verify + golangci-lint green.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@RNT56 RNT56 force-pushed the feat/flows-dag branch from eeb37ad to 21034b6 Compare July 1, 2026 18:43
@RNT56 RNT56 merged commit f2dbbf5 into main Jul 2, 2026
6 checks passed
@RNT56 RNT56 deleted the feat/flows-dag branch July 2, 2026 05:39
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