Repository navigation
fix(mcp): skip parallel children, gate-respecting loops, end: steps - #131
Conversation
…loops, end: steps
- Add Workflow.ParallelChildren/NextIndex and use them in both executors.
devkit_start/devkit_advance now skip parallel children (they previously
ran one by one and then again from the dispatcher). The dispatcher
response carries each child's interpolated prompt, and devkit_advance
takes an `outputs` object with one result per child so {{child-id}}
resolves downstream.
- Loops over MCP complete only when the gate passes AND the until sentinel
appears; a failing gate is no longer overridden by DONE. Retry responses
include the gate output. On max: halt (loop_exhausted) if the gate is
still failing, otherwise continue with a LOOP EXHAUSTED warning.
advancePastLoop now honours branch rules like the CLI engine.
- New `end: true` step field: the workflow completes after that step
unless a branch matched. Set on feature.yml final-report and bugfix.yml
summary so the full paths no longer fall through into quick-fix.
- Validation rejects parallel children that are not plain prompt steps
and branch gotos that target a parallel child.
- Docs: creating-workflows schema (branch syntax, end, parallel outputs,
loop completion), CLAUDE.md rows.
… fresh loop sentinels - devkit_advance checks each parallel child's require: contract against its reported output (children are skipped in the walk, so nothing else did). - CLI engine: end: true on a parallel dispatcher now completes the workflow. - MCP loops only accept the until sentinel from output supplied in the same advance; a DONE left over from a gate-failed iteration no longer completes the loop once the gate turns green.
…n halt - Guard treats a parallel dispatcher like a prompt step (Agent/Task allowed, Write/Edit/Bash blocked under hard). MCP now parks on the dispatcher, and the old allow-all default turned the tri-* fence off. - A dispatcher without its own enforce is soft if any child is soft, so research/self-audit fan-outs keep their WebSearch/Bash. - devkit_advance without output clears the step's earlier output, so a revisited step can't branch on a stale value. - Dispatch response shows each child's require: contract. - haltWorkflow persists the halted status before clearing state. - Validation rejects branch: on a parallel dispatcher.
🛡️ Security review — Daybreak Blue
Clear — no security objection. No effect on the merge. Reviewed head SECURITY: CLEAR Run by |
🔍 REVIEW — automated merge-readinessReview only — a verdict on this PR; no code was changed. Corrections, when applied, arrive as a separate
Reviewed head No demonstrated merge-blocking defects found after reviewing the complete diff and affected code paths. Tests cover parallel outputs, gate/until behavior, stale outputs, and terminal steps. CI is GREEN as supplied. Tests were not rerun in this read-only environment. VERDICT: READY Automated pre-merge review by |
Cause
The MCP path (
devkit_start/devkit_advance, used by every skill) diverged from the CLI engine:{{review-smart}}etc. were never set from it.until, and a failing gate letuntilend it.self-testasks the agent to say DONE, so it could finish with tests still red. Running out of iterations advanced silently.advancePastLoopignoredbranch:.feature.ymlandbugfix.ymlput the TINYquick-fixstep last, with nothing ending the full path, so every full run fell through into quick-fix after its report (both executors).Fix
Workflow.ParallelChildren/Workflow.NextIndex(src/engine/workflow.go) drive the sequential walk in both executors.require:.devkit_advancetakes anoutputsobject with one string per child (required), validates each child'srequire:, and stores them under the child ids.parallelwould otherwise switch off the tri-* fence now that MCP parks on the dispatcher. A dispatcher with no ownenforceis soft if any child is soft (research/self-audit fan-outs).untilappears in output supplied in that same advance. Retry responses include gate output and exit code. Atmax: halt withloop_exhaustedif the gate is still failing, otherwise continue with aLOOP EXHAUSTEDnotice. Research loops cap at 2 rounds on purpose, so halting on every exhaustion would break them. Loop steps honourbranch:andend:.end: truestep field: complete after this step unless a branch matched. Set onfeature.ymlfinal-reportandbugfix.ymlsummary. The CLI engine honours it on prompt, loop and dispatcher steps.devkit_advancewithout output clears the step's earlier output (no branching on stale values).branch:on a dispatcher.creating-workflowsschema (realbranchsyntax,end, paralleloutputs, loop completion),CLAUDE.mdrows.Tests
src/mcp/flow_test.go: children-before-dispatcher layout, leading children, per-child outputs, childrequire:, gate+until semantics, stale sentinel, exhaustion halt/notice, loop branch,end, stale branch output.end(including on a dispatcher),NextIndex, validation rules, dispatcher enforce, shippedfeature/bugfixend before quick-fix.