Repository navigation
fix(plugin-approvals): a revise-window recall on a batch item resumes the batch - #28228
Conversation
… the batch A revise-window recall cancels the item's run with cancelRun, which never touches the parent, so a batch sign-off (a map over approval items) stayed parked on the recalled item with nothing to wake it. The recall now finds the run parked at the built-in map node on that item's run and resumes it; the engine records the item's slot as the cancelled marker, outside count, and the map goes on. A run parked on such a link at any other node is left alone. A refused or stranded batch resume is told on resumeError and, for the engine's stranded exit, resumeFailure, as the recall's own resume is. Co-authored-by: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016WV4d13k5TVyAhqhiKKgN3
…hrough the dispatch asserts The double's update/delete now open with assertEngineUpdateDispatch / assertEngineDeleteDispatch and its find holds the caller's numeric offset/limit, as check:engine-double-contract and check:objectql-double-limit require; the pinned ledger learns the two new rows (check-engine-double-contract --write). Co-authored-by: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016WV4d13k5TVyAhqhiKKgN3
📓 Docs Drift CheckThis PR changes 1 package(s): 1 hand-written doc(s) NAME something this change touched and may need an implementation-accuracy re-verification:
⛔ 2 release-owned page(s) also name something this change touched. These are read-only:
What this run could not see
Coarse fallback — 6 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): Which tree this was computed onThis run read A worktree cut from an older # while this PR is open — GitHub drops the merge commit once it closes
git fetch origin ee4a23998c8b9b2640e76d83ac056a3e3c94eeb9 && git checkout ee4a23998c8b9b2640e76d83ac056a3e3c94eeb9
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 7c3cc889f7c64d465486bb94ded8c8ea558d6945 4007cab0a1d634b87db5a3db7a91b2b81a9a70ca && git checkout -B drift-repro 7c3cc889f7c64d465486bb94ded8c8ea558d6945 && git merge --no-ff 4007cab0a1d634b87db5a3db7a91b2b81a9a70ca
node scripts/docs-audit/affected-docs.mjs --json 7c3cc889f7c64d465486bb94ded8c8ea558d6945
|
Co-authored-by: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016WV4d13k5TVyAhqhiKKgN3
|
domain:server#4 · os-elon-musk · session_016WV4d1Np3hU7RQnA13YZcL 维护者速读
席位意见:ACCEPT。 席位核对Head-sha:
|
Requested by Elon · project thread
domain:server#4 · os-elon-musk · session_016WV4d13k5TVyAhqhiKKgN3
Fixes #28183
Clause-②: no (a batch run that nothing could wake after the recall now continues, in the shape the cancelled-item ruling already set; no schema, accept set, error code or result field changes)
Metadata-protocol: none
维护者速读
{ $status: 'cancelled', $itemRunId },count不算它,然后开下一项或走完。cancelRun,批次 run 一直停在map:<该项 run>,第 2 项的审批永远不开,除非运维手动用批次 run id 恢复。按分诊与裁决 A(6523833308)的形状修,不新增标记或错误码。cancelRun确实取消了、且有 run 停在内置map节点上等这一项”时多做一次恢复;pending 撤回、无批次的撤回、全部决定完的批次不变(对照钉子)。回滚即 revert 本 PR。packages/plugins/plugin-approvals/src/approval-service.ts的recall修改窗口分支与新私有方法resumeBatchOfRecalledItem。pnpm --filter @objectstack/plugin-approvals exec vitest run src/batch-item-recall-resumes-batch.test.ts,预期 5 passed。What changes
packages/plugins/plugin-approvals/src/approval-service.ts. Inrecall's revise-window branch, whencancelRunanswerstrue(it really cancelled the item's run), the new privateresumeBatchOfRecalledItem(itemRunId, requestId)looks for the run parked onmap:<itemRunId>(listSuspendedRunsDurable, a member the surface already declares), checks throughgetFlowthat the node it is parked at is the built-inmap, and resumes that run withserviceResume(batchRunId, {}). The engine's existing parent-id resume (PR fix(service-automation)!: a map whose item run was cancelled records the item as cancelled on a parent-id resume #28176) does the rest: it reads the item'scancelledhistory, records the marker in the item's slot, leaves it out ofcount, and the map opens its next item or runs on. Noservice-automationchange.409 RESUME_CHILD_PENDINGwhen the item's history cannot be read) or a lookup that throws fillsresumeErrorand logs aterror; the engine's stranded exit, and a strand bubbled to a subflow parent above the batch, also fillresumeFailurewithRESUME_FAILED, the one code this package's ledger row admits.resumedstill describes the recalled request's own run, which was cancelled, so it staysfalse.listSuspendedRunsDurableorgetFlowon the attached engine, no run parked on that item, or a parked node that is not the built-inmap: the recall answers exactly as before. A home-grown node that parks on amap:link is never re-run, because the engine records the cancelled item only for the built-inmap, and re-running another node would advance it past the item with nothing recorded.packages/plugins/plugin-approvals/src/batch-item-recall-resumes-batch.test.ts(new). The realAutomationEnginewith the built-in nodes and the approval node, arelease_signoffbatch (mapovertask_signoff, an approval with a revise window), the showcase'sshowcase_release_signoff→showcase_one_task_signoffshape.scripts/engine-double-contract.pinned.json. Two generated rows (delete,update) for the new test's engine double, written bycheck-engine-double-contract.mjs --write..changeset/28183-batch-item-recall-resumes-batch.md.@objectstack/plugin-approvalspatch.Why
Before (measured at
origin/main3a2f4c00)Two tasks; item 1 sent back by the approver, then recalled by the submitter from the revise window:
cancelledcancelledsignoffs, correlationmap:<item 1's run>, historypausedsignoffs, correlationmap:<item 2's run>pendingresumed: false, noresumeErrorresumed: false, noresumeErrorcompleted;signoffResults=[{ $status: 'cancelled', $itemRunId }, { decision: 'approved' }],count1Why this path
Triage 6527285884 routed the card to ruling A (6523833308): a cancelled item records
cancelledand the map moves on, and the recall follows the same shape by resuming the parent with the cancelled marker. PR #28176 already built that resume behind the batch run's own id; the only thing missing was a caller. So the fix stays in the recall path and reuses that resume as is: no new marker shape, no new code, nopackages/specedit.Tests
batch-item-recall-resumes-batch.test.ts, 5 cells:count1, item 2's request opens, and the batch completes after item 2 is approved (red onmain);pendingresumes the item downreject, and the map records{ decision: 'rejected' };count2;map:link at a node other than the built-inmapis not woken.Ablations through
scripts/ablation-replace.mjs, each restored to the HEAD blob withgit diff HEADempty:cancelRunmap:parent, not this item'spendingrecall takes the cancel pathapprovemapnode check(A3, the batch resume also issued on the
pendingpath, stayed green: by then the item has completed and the map has moved to item 2, so no run is parked on item 1 and the lookup finds nothing. Harmless, so not a guard.)Verification
Head
acae6743, after a whole-treeturbo run buildand fetching the teardown self-test's pinned commit.pnpm --filter @objectstack/plugin-approvals exec vitest run: 106 files, 1357 passed.pnpm --filter @objectstack/plugin-approvals run typecheck: exit 0, test layer held at its ledger.dispatch-gates --commands(re-derived after the second commit): 71 families, all exit 0.--ran: 71 derived, 71 run, 0 NOT-MEASURED, 0 UNRUN. The first sweep caught the test double (check:engine-double-contract,check:objectql-double-limit); the second commit routes it through the dispatch asserts and adds its two generated ledger rows.pnpm lint: exit 0.check-commit-card-trailers --range origin/main..HEAD: exit 0.Out of scope
listSuspendedRunsDurablereads a durable store's deployment-wide page (ObjectStoreSuspendedRunStore.list(), 1000 rows). Past 1000 parked runs the batch run may not be on that page, and the recall then answers as it did before this PR (the batch stays parked, nothing is told). A precise lookup needs an engine member (the item run's$parentRunId), which is outside this card's surface.content/docs/automation/flows.mdx's cancelled-item paragraph andapprovals.mdx's revise-window paragraph do not yet say that a recall wakes the batch. Docs were outside the claimed surface.🤖 Generated with Claude Code
https://claude.ai/code/session_016WV4d13k5TVyAhqhiKKgN3