Repository navigation
docs(approvals): say how a request with no submitter leaves the returned state - #30137
Conversation
The approvals guide and the IApprovalService recall / sendBack / resubmit docblocks now state the path for a request whose run's trigger resolved no user: nobody can recall it once returned, a system-context resubmit is its way out, and the next round opens pending with no submitter, where the system or the override actor may recall it. The guide says when such a flow should declare its revise edge. Comments and prose only; no behaviour change. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017ihL2ebbZkr2QAEG1x7UC8
…-submitter-returned-docs
📓 Docs Drift CheckThis PR changes 1 package(s): 2 hand-written doc(s) NAME something this change touched and may need an implementation-accuracy re-verification:
What this run could not see
Coarse fallback — 170 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 bac9d60dc1368016061b7b59f2733c0c169f1001 && git checkout bac9d60dc1368016061b7b59f2733c0c169f1001
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 55337f4ce35dbe62434b23517547a0b5052b936c f4d534bd32cb18f6a350e67a7eb88469d78b53d2 && git checkout -B drift-repro 55337f4ce35dbe62434b23517547a0b5052b936c && git merge --no-ff f4d534bd32cb18f6a350e67a7eb88469d78b53d2
node scripts/docs-audit/affected-docs.mjs --json 55337f4ce35dbe62434b23517547a0b5052b936c
|
|
domain:devx#2 · marchtian · session_017ihL2ebbZkr2QAEG1x7UC8 Contract-review-claim: session_017ihL2ebbZkr2QAEG1x7UC8 · head 7487083 · 2026-11-04T15:34Z |
|
domain:devx#2 · marchtian · session_017ihL2ebbZkr2QAEG1x7UC8 Contract reviewServed-tier: ① Derived judgmentsRead from the tree at
② Semver level
③ Boundary flags
④ Design judgment
Attempts to break it, each answered by the tree:
Must-fix: none. Should-fix:
Verdict on the design: the three docblock additions are true at every cited point in the live tree, say nothing the ruling did not accept, and change no accept set. The gaps found are completeness and consistency of published prose, none of which misleads a consumer into a call the code refuses or omits a refusal the code makes — should-fix, not must-fix. Implemented-by: VERDICT: PASS |
Scope the "declare revise only with a server-side resubmit" rule to the triggers that never carry a user (schedule, time-relative, api), and say what a record-change flow fired by a system write faces: the sent-back round waits for that resubmit, or an operator cancel discards the run and leaves the request returned. The recall docblock's returned arm now says the run is cancelled (the revise window has no reject edge), the reissueContinuation docblock names the system context resubmit admits, and the guide says a system-context resubmit must name an actorId. Comments and prose only. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017ihL2ebbZkr2QAEG1x7UC8
|
domain:devx#2 · marchtian · session_017ihL2ebbZkr2QAEG1x7UC8 Contract reviewServed-tier: This is a DELTA record over the PASS rendered on ① Derived judgments
② Semver level
③ Boundary flags
④ Design judgment
Attempts to break the new sentences:
Must-fix: none. Should-fix: none. (Nit only, in ②: the changeset body could name the Verdict on the delta: each of the four items from the Implemented-by: VERDICT: PASS |
|
domain:devx#2 · marchtian · session_017ihL2ebbZkr2QAEG1x7UC8 席位核对 — ACCEPT ·
|
Requested by 田騏 · project thread
Fixes #29910
Clause-②: no
Metadata-protocol: none
维护者速读
IApprovalService的recall/sendBack/resubmit注释写明「没有提交人的审批单」被退回后怎么走出来:退回后谁也撤不回,唯一出路是服务端代码以系统上下文resubmit,新一轮pending仍无提交人,系统或管理员覆盖可撤回。指南还告诉作者:由无用户触发器启动的流程,只有在服务端代码会做这次重提时才声明revise边,否则不声明,让审批人改用驳回。@objectstack/specpatch changeset;非注释的 token 前后完全一致(见 Verification),行为不变。回滚即 revert。packages/spec/src/contracts/approval-service.ts的recall与sendBack注释;content/docs/automation/approvals.mdx的「A request with no submitter」段。git diff origin/main -- packages/spec/src/contracts/approval-service.ts,应只看到*开头的注释行变化。What changes
content/docs/automation/approvals.mdx, under Send-back → resubmit: a new paragraph, A request with no submitter. It says that a run whose trigger resolved no user opens its request with no submitter; that an approver can still send it back, but nobody can recall it once it isreturnedand no viewer sees Resubmit or Recall; that its one way out is a system-contextresubmitfrom server-side code, which opens the next roundpending, again with no submitter, where the system or the admin override can recall it. It also says what an author should do on such a flow: keep thereviseedge into itsapproval_revisenode only when server-side code will make that resubmit, and otherwise leave the edge off, so send-back is refused and approvers reject instead.content/docs/capabilities/approvals.mdxonly names send-back in one line and does not teach recall or resubmit, so it is unchanged.packages/spec/src/contracts/approval-service.ts, comments only:recall: a closing paragraph saying thereturnedarm has no one for a request with no submitter, and stating the way out above.sendBack: a closing paragraph saying such a request is sent back the same way, that only a system-contextresubmitmoves it on, and that a flow whose trigger resolves no user declaresreviseonly when server-side code will make that call.resubmit: "submitter-only" now reads "by the submitter or a system context (the system context alone on a request with no submitter)". The code already admits the system context, andApprovalResubmitInput.actorIdalready said so..changeset/29910-no-submitter-returned-docs.md:'@objectstack/spec': patch. The docblock text ships: after a build it is inpackages/spec/dist/contracts/index.d.tsandindex.d.mts(positive control: the existing sentence "refused there exactly as any other non-submitter" is found in the same two files). So this is a published, comment-only change, which takes a patch changeset rather thanskip-changeset.The documented path, read from code at
987ff33bpackages/plugins/plugin-approvals/src/approval-node.ts:107-111(runTriggerUser,nullwhen the trigger resolved no user) feedssubmitterIdatapproval-node.ts:199.approval-service.ts:6041(pending approver or system, no submitter test) andassertReviseEdgeatapproval-service.ts:6278-6312(thereviseedge must exist and must target anapproval_revisenode).approval-revise-node.ts:89-98: the window arms nothing, and onlyresubmitor a recall ends it.returned:approval-service.ts:5613-5618(overrideAdmitsrequiresstatus === 'pending';actsAsSubmitteratapproval-service.ts:1114-1117answers false for every actor whensubmitter_idis null).approval-service.ts:6202(if (!context.isSystem && !actsAsSubmitter(raw, actorId))), pinned atapproval-service.test.ts:6418-6423. Its resume carries noresumedBy(approval-service.ts:6241-6248), so the run context is not switched (service-automation/src/run-resume.ts:326-328). The re-entered approval node opens round N+1 throughapproval-node.ts:199again, with no submitter (also pinned for a later step bylater-step-original-submitter.integration.test.ts:322).pendinground is recalled by the system or the override actor:approval-service.ts:5613-5614withisOverrideActoratapproval-service.ts:2111-2113(context.isSystemalways passes). Pinned atapproval-service.test.ts:6403-6416.sys-approval-request.object.ts:766-778shows Resubmit only toviewer.is_submitter, and Recall onreturnedonly to the submitter (can_overrideis pending-only). The REST/resubmitroute (packages/rest/src/approvals-routes.ts:518-523) passes the caller's own resolved context.Tests
No test was added: nothing a test can pin changed. The behaviour documented here is already pinned by the
approval-service.test.tsbattery cited above.Acceptance notes
resubmitis reachable only from server-side code. The console offers no button for it, and the REST route acts as its caller. The guide says "server-side code in a system context" and does not name any other door.packages/spec/src/contracts/approval-service.tswas tokenised with the TypeScript scanner (comments skipped) at987ff33band at this branch. Both give 1420 tokens and the streams are identical. Control: changing oneactorId: stringtonumbermakes the comparison reportfalse. So no.d.tsstatement other than a comment can move.api-surface/contracts.jsonrecords only the interface names, and the spec build regenerated nothing (cleangit statusafterwards).Verification
Head
74870830(630966a2, then one merge oforigin/mainata52761fd). The diff is 3 files, +37 / -1.Local gates on 7487083: 95 derived, 95 run, all exit 0, 0 NOT MEASURED (`dispatch-gates --ran`, exit codes recorded)
pnpm install --frozen-lockfile(exit 0), thenpnpm --filter @objectstack/spec buildunder the verify lock (VERDICT command-exit 0). After that, every command fromnode scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack, each with its exit code captured before any pipe.check-plugin-teardown-shape --self-test(shallow clone),check:doc-formula-expressions,check:doc-security-posture,check:skill-examples,check:docs-transcript-drift,check:dual-build-cjs-loadsandcheck:lean-entry-closure(unbuilt workspace packages). I unshallowed the clone and ranturbo run build --concurrency=2 --filter='!@objectstack/docs'under the lock (VERDICT command-exit 0, 119/119 tasks). All 7 then exited 0.--ranwithCOMMAND :: exit Nrecords:95 derived famil(ies) accounted for — 95 run, 0 NOT-MEASURED (a DERIVED zero — all 95 recorded an exit code and none of them is 3).NODE_OPTIONS=--max-old-space-size=4096 pnpm --filter @objectstack/spec check:generated: exit 0,All 14 generated artifacts are up to date. A first run at the default heap went red only becausecheck:test-typecheck'stscran out of memory ("failed without diagnostics", heap OOM), not because an artifact was stale.pnpm --filter @objectstack/spec typecheck: exit 0.node scripts/check-dev-prereqs.mjs: exit 0.node scripts/check-commit-card-trailers.mjs --range origin/main..HEAD: exit 0.@objectstack/spec's vitest suite. Every non-comment token is unchanged (see Acceptance notes), so it is left to CI'sTest Core.git push(empty branch,630966a2,74870830); one relaypr_create; no GitHub MCP call.Generated by Claude Code
🤖 Generated with Claude Code