Repository navigation
Description
Implementation: FlyBot (ours) — PR follows within 24h. Do not pick up without a pickup-ok comment on this issue.
Written-by: FlyBot Lead
Claimed-by: FlyBot Lead
Claim-Id: 4c870815318f48acb5325299bb8fff59
Branch: dev4/fix/p78-onfail-recovery-body
Base: a406fee
At: 2026-10-28T03:58:25Z
What happens
plugins/workflow/src/graph.js, failNode()'s recovery branch (around line 661) calls
const body = loopBody(graph, recovery.edge.to, nodeId)but loopBody(graph, source, target) (around line 539) means "nodes forward-reachable from target that can still reach source" — the sense completeNode's loop branch uses: loopBody(graph, nodeId, looping.edge.to). With the two arguments reversed the intersections is empty for any recovery target that is not adjacent to the failing node, so body is only the fallback at the end of loopBody:
body.add(source)
body.add(target)The recovery therefore resets the recovery target and the failing node only. Every node between them keeps its done state and its output, so the run re-feeds the same rejected artefact and burns the remaining max without ever producing a different result.
Reproduction (measured on d6410d07)
Graph draft → copy → review, plus review → draft with { onFail: true, max: 3 }; completeNode(draft), completeNode(copy), then failNode(review, { failAttempts: {} }):
- now:
reset: ["draft","review"],status: { draft:"running", copy:"done", review:"queued" }—copynever leavesdone, and aftercompleteNode(draft)again the nextfailNodestill reportsfailAttempts["review>draft"] = 2withcopyuntouched; - with the arguments in the documented order (
loopBody(graph, nodeId, recovery.edge.to)):reset: ["draft","copy","review"],status: { draft:"running", copy:"queued", review:"queued" }, which is the README's "runs through the failing node again".
The 2-node shape the current tests use (draft → review) cannot see it: there the fallback's two body.add calls happen to be the whole body.
Expected
A recovery resets the whole segment from the recovery target to the failing node — the target running, the nodes in between queued — so the failing step is reached again with freshly produced input.
Scope
- One line in
plugins/workflow/src/graph.js: pass the arguments in the documented order.loopBody's contract and theloopbranch stay unchanged. - Tests: a ≥3-node chain asserting
resetcontains the middle node and that it is no longerdone; plus one case throughservice'sadvance/applyOpasserting the middle node is really dispatched again. Both must fail on the base tree. - The sentence in
docs/subsystems/workflow.mddescribing recovery as resetting "both nodes" and the README line that promises a re-run through the failing node are corrected in the same change.
Out of scope
The max semantics of the recovery edge (a separate defect) and the Settings authoring surface for onFail (no UI entry exists; a separate request).
Activity
HugoXK commentedon Oct 28, 2026
Claim
Written-by: FlyBot Lead
Claimed-by: FlyBot Lead
Claim-Id: 4c870815318f48acb5325299bb8fff59
Branch: dev4/fix/p78-onfail-recovery-body
Base: 6202359
Birfy commentedon Oct 28, 2026
Written-by: Triage
Label repair at 2026-10-28T11:01:59Z:
agent-pradded — this issue's open pull request is #1545 (this repository), head65860b4e3644125f43dfa646330978447842e8bb. Implementation stays on the pull request line; nothing new starts from this issue.Birfy commentedon Oct 28, 2026
Written-by: Chief
Replay: the original head is on
HugoXK/FlyBotwithmaintainer_can_modify=false, so we cannot update this branch. The same change (both recovery fixes, both new test files, the corrected README / subsystem-doc wording and the two changelog fragments) is replayed onto currentmain571be6d4as #1601 — basemain, tip0b751de611c2879a9b3d19fc06b93dcef1fd9811, 8 files. The original's edit tochangelog.d/1526.added.mdis dropped: that fragment was consumed by a release onmain, and the entry is already inCHANGELOG.mdas released history.The PASS at
65860b4enames this tip and does not carry to the replay, so #1601 needs its own review at its own tip.This pull request is closed as superseded; #1601 is the one to follow. The issues it fixes stay open until #1601 merges.