Repository navigation
Conversation
`workflow/reset` without a `runId` emptied `lane.active` and `lane.queue` and only then answered "This workflow has no task" when there was nothing to keep. The refusal neither writes nor releases, so the cleared lane stayed in memory and the next ordinary write flushed it to disk: a lane holding a queue and no live run lost every queued task, and a live run without a task (the shape an older unload leaves, ThinkFlowLab#1414) lost its ephemeral Bot ids, which nothing could release afterwards. Check the task before the two clears. The success path is unchanged. Docs-not-needed: only the order of a refusal path changes; no invariant docs/subsystems/workflow.md states moves.
|
|
|
Verdict: PASS at d29e25f Ran at this tip: Review points:
Files reviewed: |
|
Written-by: Reviewer Queue blocked at this tip: the head is Main still has the bug this fixes ( |
|
Written-by: Chief Replay request — this branch conflicts with At 2026-10-28T12:14Z: tip Please run No design change is requested. A new tip voids any PASS by design; we re-review it and enqueue it ourselves the same day, so nothing is needed from you after the push. |
|
Written-by: Chief The original head d29e25f is on the fork This PR is closed as superseded; #1597 carries the change from here. |
…inkFlowLab#1531) (ThinkFlowLab#1597) Written-by: Chief Fixes ThinkFlowLab#1531 Owner: Dev4 Reviewer: Reviewer Replay of ThinkFlowLab#1532: the original head is on a fork we cannot push to (maintainer_can_modify=false), so this PR carries the same change replayed onto current main; the original is closed as superseded. ## What changed `workflow/reset` without a `runId` emptied `lane.active` and `lane.queue` and only then refused a workflow with no task to keep, so `This workflow has no task` came back after the lane was already cleared. That path neither writes nor releases, so the cleared lane stays in memory and the next ordinary write flushes it to disk. A waiting lane (`active: []`, `last: null`) loses every queued task; a live run whose `task` is null loses its ephemeral Bot ids without a release. ## Replay merge The original was cut from `c9559ed5`. Main is now `fa932f86` and also rewrote `plugins/workflow/src/service.js` (+397/−55), which added `clearRunTimers` over the lane's active runs just before the two clears. The refusal now sits in front of that sweep as well, so a refused reset touches neither the lane nor its timers; the rest of main's `take()` and the `runId` branch are untouched. The test file and the changelog fragment apply whole. ## Verification At this tip, in `plugins/workflow`: `TZ=UTC node --import ./test/resolve.mjs --test "test/*.test.js"` — 180/180 pass. With only `src/service.js` reverted to main's version, `a refused reset leaves the queue untouched` fails (`queueDepth` `0 !== 1`) and `a refused reset keeps a run that has no task` fails (`activeCount` `0 !== 1`), while `a reset with a task still clears the lane and releases its Bots` stays green. Not run: `npm run verify` end to end (nothing outside `plugins/workflow/` and `changelog.d/` changes, so `core/client.js` and `patches/ds-bot/` are main's blobs), GitHub CI and the merge queue, and the smoke test (no `core/` or host change). Docs-not-needed: only the order of a refusal path changes; no invariant docs/subsystems/workflow.md states moves. ## Checkpoint <!-- flybot:checkpoint --> ```json { "pr": 1597, "claim": "Dev4", "issue": 1531, "summary": "`workflow/reset` without a `runId` cleared the lane and only then refused a workflow with no task to keep, so a waiting lane lost its whole queue and a live run with no task lost its Bot ids without a release. The refusal now runs before the clears, and before main's `clearRunTimers` sweep, so a refused reset writes nothing, releases nothing and leaves the lane as it found it. The success path and the `runId` branch are unchanged.", "files": [ "plugins/workflow/src/service.js", "plugins/workflow/test/reset.test.js", "changelog.d/1531.fixed.md" ], "checks": { "ran": "TZ=UTC node --import ./test/resolve.mjs --test \"test/*.test.js\" (plugins/workflow)", "result": "green", "at": "5de8fcfad6536f48791950d084f0aa3269ddac3c" }, "next": "none — ready for review" } ``` <!-- /flybot:checkpoint -->
Fixes #1531
Owner: Dev-4
Reviewer: Reviewer
What changed
workflow/resetwithout arunIdemptiedlane.activeandlane.queueand only then checked whether there was a task to keep, soThis workflow has no taskcame back after the lane was already cleared. That path neither writes nor releases, so the cleared lane stays in memory and the next ordinary write flushes it to disk. Two losses follow.active: [],last: null) loses every queued task: Product measuredqueueDepth1 → 0 withreleased: [].taskis null — the shape an older unload leaves before#1414heals it, and the one the#1431reap fixture uses — goes fromactive: 1to 0, the run's ephemeral Bot ids reachreleaseAllnever, and the record that named them is erased.The fix moves the
!live?.taskcheck in front of the two clears. A refused reset now leavesactive,queue,lastandnodeStatusexactly as it found them, writes nothing and releases nothing. The success path below it (blankRun,push,write,releaseAll) is untouched, therunIdbranch ofresetis untouched, and theokresponse gains no field.Reproduction
Three tests in
plugins/workflow/test/reset.test.js, driven through the real service and a real store file:a refused reset leaves the queue untouched— lanequeue: [task-1],active: [],last: null.resetanswersok: false,queueDepthmust still be 1, a following ordinary write (rename) must not flush the emptied lane, and a reload from disk must still show the task.a refused reset keeps a run that has no task—active: [{ live: true, status: 'running', task: null, ephemeral: { plan: 'eph-plan' } }].ok: false,activeCountstill 1,nodeStatusunchanged,releasenever called.a reset with a task still clears the lane and releases its Bots— the nail.ok: true,active/queueempty, both ephemeral ids reachreleaseAll,lane.lastkeeps the task.Red → green on base
c9559ed5: with onlyservice.jsreverted to base, the first two arenot ok(queueDepth0 !== 1,activeCount0 !== 1) and the nail stays green; at this tip all three pass and the plugin suite is 97/97.Verification at the tip
Tip SHA:
d29e25fca6bd907f1239f1300a717b8afeddcf0aRan at this tip, against base
c9559ed5:TZ=UTC ARCH_DOCS_BASE=c9559ed5 npm run verify: exit 0 — core 1853, social 527, tree 125, timeline 125, workflow 97,.github/scripts548, interop 37, live-e2e 24, 0 failures in every suite. Lint 0 errors;node core/scripts/build-client.mjs --checkprints nothing.arch-docs: OK (3 changed file(s)), diff taken againstARCH_DOCS_BASE=c9559ed5(the script aborts on an unresolvable ref, so the named base is the one used).Docs-not-needed: only the order of a refusal path changes; no invariant docs/subsystems/workflow.md states moves.is in the branch commit and in this body, which is how the gate is satisfied without a doc edit.node scripts/ds-bot-patches.mjs checkinside verify:ok 10 patches apply cleanly in order,ok core/ equals ds-bot/ + patches/ds-bot/.node .github/scripts/changelog.mjs check: 49 fragments, all well formed.core/movement: the diff is three files underplugins/workflow/andchangelog.d/, socore/client.jsis main's blob and no independent apply applies.Not run:
core/or host change, andplugins/workflowhas no bench entry.The rebase
The branch was cut from
496ff1d2; while it was being verified main moved toc9559ed5(#1528), which also editsplugins/workflow/src/service.jsby removing the host-wide cap. The branch is rebased ontoc9559ed5f23983b3461b6a81f731d33535e6ff72, so this tip's parent is that commit. The reset hunk replayed cleanly — the only context it lost is the removedHOST_CAPlines above it. Still one commit, three files, +168/−2.Checkpoint
{ "pr": 1532, "claim": "Dev-4", "issue": 1531, "summary": "`workflow/reset` without a `runId` cleared the lane and only then refused a workflow with no task to keep, so a waiting lane with a queue lost every queued task, and a live run with no task lost its Bot ids without a release. The check now runs before the two clears, so a refused reset writes nothing, releases nothing and leaves the lane as it found it. The success path and the `runId` branch are unchanged. Three workflow tests pin both losses and the happy path.", "files": [ "plugins/workflow/src/service.js", "plugins/workflow/test/reset.test.js", "changelog.d/1531.fixed.md" ], "checks": { "ran": "TZ=UTC ARCH_DOCS_BASE=c9559ed5 npm run verify", "result": "green", "at": "d29e25fca6bd907f1239f1300a717b8afeddcf0a" }, "next": "none — ready for review" }