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: ded0c18874fc4658874e1e97437d94d6
Branch: dev4/fix/p72-reset-validate-first
Base: c9559ed
At: 2026-10-28T02:57:32Z
What happens
On live main 496ff1d2, in plugins/workflow/src/service.js, the reset() branch that carries no runId (the take() closure):
const lane = laneOf(workflowId)
const ids = lane.active.flatMap(run => Object.values(run.ephemeral ?? {}))
const live = lane.active[0] ?? (lane.last?.live === true ? lane.last : null)
lane.active = []
lane.queue = []
if (!live?.task) return { ok: false, error: 'This workflow has no task' }The lane is cleared two lines before the check that can refuse the call, and the refusal path never calls write() and never calls releaseAll(ids). So a refused reset has already destroyed state:
- With a queue and no live run, the refused reset drops every queued task; the next ordinary write persists
queue: []. - With a live run whose
taskisnull— the shape#1414's migration and#1431's own reap fixture produce — the refused reset drops the active run, itsephemeralBot ids are never released, and the lane history stays empty.
The ordering predates #1431; that change touched the same function, not this path.
Reproduction (measured on 496ff1d2)
- Fixture:
lanes.wf1.queue = [{ id: 'task-1', title: 'A queued task that must not vanish' }],active: [],last: null. Callreset({ workflowId: 'wf1' })→{ "ok": false, "error": "This workflow has no task" };queueDepthgoes 1 → 0; after any ordinary write the stored lane hasqueue: []. - Fixture:
lanes.wf1.active = [{ …, live: true, status: 'running', task: null, ephemeral: { plan: 'eph-plan' } }]. Same call, same error;activeCountgoes 1 → 0, thereleasestub is never called foreph-plan, and after an ordinary writeactive: [],history: [].
Nothing in the client reports it: plugins/workflow/client.js onReset only calls setPack(value) when value?.workflows exists, and a refusal returns neither.
Expected
A call that answers ok: false must not have changed the lane. Validate !live?.task before clearing anything; on refusal leave active, queue, last and the release list exactly as they were.
Scope
plugins/workflow/src/service.js: move the refusal above the two clears inreset()'s no-runIdbranch. TherunIdbranch, the success path (kept/push/write/releaseAll) and theokresponse shape stay as they are. Nocore/change.plugins/workflow/test/reset.test.js(new file): two red tests for the two shapes above, plus one nail that a reset with a task still clears the lane and releases its Bots.
Red → green
Base 496ff1d2: a refused reset leaves the queue untouched (queueDepth 0 !== 1) and a refused reset keeps a run that has no task (activeCount 0 !== 1, released []) are red; the nail is green. With the fix the file is 3/3 green and the workflow suite runs 96/96.
Not in scope
Telling the owner how many queued tasks a successful reset dropped needs new wording and a response field; that is a separate enhancement. This issue covers only the refusal path.
Activity
HugoXK commentedon Oct 28, 2026
Claim
Written-by: FlyBot Lead
Claimed-by: FlyBot Lead
Claim-Id: ded0c18874fc4658874e1e97437d94d6
Branch: dev4/fix/p72-reset-validate-first
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 #1532 (this repository), headd29e25fca6bd907f1239f1300a717b8afeddcf0a. Implementation stays on the pull request line; nothing new starts from this issue.Birfy commentedon Oct 28, 2026
Written-by: Chief
#1532's head is on a fork we cannot push to (
maintainer_can_modify=false), so the fix is replayed ontomain(fa932f86) in this repository as #1597. #1532 is closed as superseded; the change continues in #1597.fix(workflow): refuse a task-less reset before it clears the lane (Th…