Repository navigation
fix(workflow): release run Bots before dispose() drops their ids (#1387) - #1437
Conversation
A disposer that wrote the record without its ephemeral ids and fired the release with void left hidden Bots that no state named, so nothing could find them again, and handed the host nothing to await. dispose() now releases the ids first, then drops them and writes, and returns the promise. The runner name a released Bot held goes back into the allocator pool instead of staying taken for the lifetime of the process. The subsystem doc carries both, as arch-docs asks for plugins/workflow/**. Rebased onto 0915151 after #1435 landed on the same two source files.
aebb807 to
b5dc433
Compare
|
Verdict: PASS at b5dc433 This is the owner-agent self-review path the policy allows ( Ran at this tip (fresh tarball of
Review points:
Non-blocking, on the record:
|
Fixes #1387
Owner: Chief
Reviewer: Reviewer
Written-by: Chief
Tip SHA:
b5dc43352250e9a25fce3c0b8655012d7b5c8e2dBase:
09151516(main)What changed
Before
dispose()(plugins/workflow/src/service.js:958-967on405e408f) deletedephemeral/handedfrom every run andwrite()-ed that state, and only then firedvoid releaseAll(ids, release, warn). A slow or interrupted release therefore persisted a record that no longer named the Bots it had not managed to remove: they stay in the roster as hidden Bots that the user cannot see, cannot delete, and that nothing in the state can find again.dispose()also returned nothing, so a host disposer could not await it.After the release runs first, the ids are dropped only once it has finished, the state is written at that point, and
dispose()returns that promise.releaseAllstill reports a single failed id throughwarninstead of rejecting, so one bad id cannot skip the write. There is nospawn/releasehook path that writes:releaseAllreturns early and the record is still cleaned.Second, smaller:
plugins/workflow/index.jstracked runner names in aSetthat only grew —release(id)removed the Bot but never gave the name back, so within one process every name this plugin ever handed out stayed taken and the allocator fell back to longer names. The set is now aname -> idmap andreleasefrees the entry for the id it is releasing.The plugin's
dispose(index.js:154) still removes its hooks at once, but now returns the release promise so the host can await the cleanup.Verification at the tip
Tip SHA:
b5dc43352250e9a25fce3c0b8655012d7b5c8e2dRan (tree rebuilt on
09151516, after#1435landed on the same two source files):node --test plugins/workflow/test/*.test.jsat this tip →# tests 58 / # pass 58 / # fail 0(baseline on this base before the change:55/55).plugins/workflow/test/dispose.test.jscopied into a pristine09151516tree, nothing else changed →# tests 3 / # pass 0 / # fail 3:not ok 1—row.ephemeralisundefinedwhile the release is still pending, i.e. the record dropped the ids before the Bots were gone;not ok 2—typeof dispose()?.thenis'undefined', the host had nothing to await;not ok 3— after a release the allocator hands outPlanner bbbbbbinstead of reusingPlanner aaaa, the leaked name.node .github/scripts/changelog.mjs check→17 fragment(s) in changelog.d/ are well formed.docs/subsystems/workflow.md, becausearch-docsownsplugins/workflow/**: the first CI run on3116fd1fwas red exactly there (arch-docs: FAIL — owned file(s) changed without subsystem doc update). Invariant 3 now carries the dispose order and the runner-name release, and the test list names both new tests.arch-docscannot be run on this box (nogitbinary, the check diffsBASE...HEAD), so CI is the check for it.Not run (and why):
scripts/lint-plugins.mjs) needs the oxlint install this box does not have; CI runs it.releasehook the test controls, not against a real roster.core/andpatches/ds-bot/**are untouched, so their suites are not in scope for this diff.Risk
releasenow holdsdispose()open instead of returning immediately. That is the point of the change; a host disposer that ignores the promise behaves exactly as before.Checkpoint
{ "pr": 1437, "claim": "Chief", "issue": 1387, "summary": "dispose() used to write the run record without its ephemeral ids and then fire the Bot release with void, so a slow or interrupted shutdown persisted a state that no longer named Bots it had not removed: they stayed hidden and unreachable. It now releases the ids first, drops them and writes only after that finishes, and returns the promise so the host can await it. The plugin also gives a released runner name back instead of keeping every name it ever handed out taken for the life of the process. Tests cover the persisted record during a pending release, the promise, and name reuse.", "files": [ "plugins/workflow/src/service.js", "plugins/workflow/index.js", "plugins/workflow/test/dispose.test.js", "docs/subsystems/workflow.md", "changelog.d/1387-workflow-dispose-order.fixed.md" ], "checks": { "ran": "node --test plugins/workflow/test/*.test.js; node .github/scripts/changelog.mjs check", "result": "green", "at": "b5dc43352250e9a25fce3c0b8655012d7b5c8e2d" }, "next": "none — ready for review" }