Skip to content

docs(adr-0043,skill-automation): open-time notification is approval.requested; one-tap links stay remind()-only (#22631, Tier H half) - #22652

Merged
os-zhuang merged 1 commit into
mainfrom
claude/issue-22631-approval-requested-texts
Oct 10, 2026
Merged

os-zhuang merged 1 commit into
mainfrom
claude/issue-22631-approval-requested-texts

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Part of #22631
Clause-②: no

Two governed texts said the opposite of what openNodeRequest does since PR #22625 (e8c6666870): opening an approval request publishes approval.requested to each concrete approver on the slate the request opens on, through the single notify() ingress, and one-tap links are still minted by remind() only. This PR carries items 1 and 2 of #22631 (Tier H: docs/adr/**, skills/**). Item 3 and the token-door item ride the sibling PR on claude/issue-22631-qa-checklist-approval-requested. #22631 remains open until both PRs land.

Dispatched by the domain:skills seat PM, session session_01RdnZdPZH9ByduzPRWuH9tN. Claim 6095805515, triage 6095381775.

Measured first

  • All premises held at origin/main 3d0eeefa (86da194919 plus five later commits; git diff --stat 86da194919 3d0eeefa over the three card paths is empty, so none of them moved).
    • ADR-0043 :40–:42 read "(Open-time notification remains the flow author's notify node; templates there can adopt the same links later.)": 1 hit with a wrap-tolerant grep; positive control sys_approval_token: 2 hits.
    • The skill's item 5 read "rather than expecting the node to send mail itself": 1 hit; control approve: 48 hits.
  • packages/plugins/plugin-approvals/src/approval-service.ts: the literal is 'approval.requested' (:3349, inside openNodeRequest, declared at :2999). The fan-out loops over openedOn, the slate after OOO delegation and after an onEmptyApprovers: 'fallback' replacement, minus type:value literals and OOO delegates, one this.notify() per approver. issueActionTokens has exactly one caller, :4815 inside remind() (declared at :4763), so one-tap links are minted by remind() only. feat(plugin-approvals): ApprovalService.handleActionPage serves the ADR-0043 action page from a Request (segment 4 of #22438) #22641 (3d0eeefa) shifted these lines by 15 and changed none of it.
  • The skill's eval set (skills/objectstack-automation/evals/**) asserts nothing about the dropped half: grep send mail itself|node does not send|node to send|downstream nodes|notify node gives 0 hits in both files; control approval gives 4 and 13 hits. Nothing moves there.

What changed

docs/adr/0043-actionable-approval-links.md (two one-line touches)

  • The **Status** line takes the corpus form of a dated status amendment, · **Amended** (2026-10-10, #22631 — …), as ADR-0029, ADR-0030 and ADR-0044 carry theirs: open-time notification is the approvals service's own approval.requested topic, not a flow-authored notify node; one-tap links stay remind()-only; the token table and every decision below are unchanged.
  • The Issue bullet's parenthesis, the sentence the card quotes, becomes the dated correction: the topic as the code spells it, published by openNodeRequest to each concrete approver on the slate the request opens on (PR feat(plugin-approvals): opening an approval step tells each resolved approver (approval.requested) #22625), carrying no links, with one-tap links remaining remind()-only.
  • ⛔ No new ADR number. The token table and the decisions are untouched.

skills/objectstack-automation/references/state-machines-and-approvals.md

  • Item 5 keeps the decision half (notify the submitter of the outcome from the approve / reject edges), drops "rather than expecting the node to send mail itself", and names the trap: the opening already tells each resolved approver (approval.requested), so no notify node for the opening, or they are told twice.
  • Ratchet currency: the file sat exactly at its token ceiling (5569 of 5569), and check-skills-token-ratchet accepts only deletion in the same file as payment. The deleted text is the two-line code comment at :183–:184 ("No config and no waitEventConfig: the window ends on the submitter's explicit resubmit, not on a signal or a timer."), which restated the prose at :167 ("The node takes no config — there is no signal to wait on."). No fact leaves the file.

Readings (skills/**, per the line budget)

reading before (3d0eeefa) after (af35cd5be) delta
references/state-machines-and-approvals.md, lines 383 383 0
references/state-machines-and-approvals.md, tokens (ceil(bytes/4), the ratchet's unit) 5569 (ceiling 5569) 5562 −7
package lines (the five ratcheted files under skills/objectstack-automation/) 1048 1048 0
package tokens 14581 14574 −7

node scripts/check-skills-token-ratchet.mjs prints "state-machines-and-approvals.md is 5562 tokens (ceiling 5569; headroom 7)". No ceiling moved.

Verification (all at af35cd5be)

  • node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack (no paths; the change set is taken from the merge base) derived 30 commands. All 30 ran in the foreground, each exit captured before any pipe; --ran reconciliation: "30 derived, 30 run, 0 NOT-MEASURED, 0 UNRUN". check:doc-formula-expressions first answered exit 3 (PREREQUISITE NOT MET: no dist/ for @objectstack/formula and @objectstack/lint); after that build through the verify lock (4 of 4 tasks cached) it measured exit 0 ("22 record-scoped formula example(s) across 471 files / 1387 TS blocks judged clean").
  • Among the 30: check-adr-links, check-adr-symbol-anchors, check:adr-anchors, check-skills-token-ratchet (each with its --self-test), check:skill-refs, check:skill-compatibility, check:skill-frame-sync, check:skill-identifier-liveness, check:role-word, check:corpus-claim-drift, check:pm-prior-rulings, check:pm-governed-merges, check:doc-authoring, check:nul-bytes: all exit 0.
  • Not run locally: the repo-wide pnpm lint (CI's; this diff touches no lintable source) and package test suites (no package is touched).

Changeset

Docs-only, nothing published: docs/adr/** and skills/** ship in no package's files[]. skip-changeset is applied through label-write.

Landing

Tier H (docs/adr/**, skills/**): draft until an authorized APPROVED review. No seat merges, queues or arms auto-merge on it.

维护者速读(草稿)

改了什么: 两处文字。ADR-0043 的 Status 行加一条 2026-10-10 的修订记号;机制段里那句「开单通知仍由流程作者的 notify 节点负责」改为:开单通知现在是审批服务自己的 approval.requested 主题,发给这次开单落到的每个具体审批人(PR #22625);一键链接仍只在催办(remind())时签发。自动化技能的最佳实践第 5 条保留「结果由 approve/reject 边上的下游节点通知提交人」,删掉「节点自己不发邮件」,并写明:开单已经通知了每个审批人,⛔ 不要再为开单加 notify 节点,否则重复通知。

为什么改: 自 PR #22625 起这两句是假的;技能那句正把 AI 作者引向变更集要求删掉的那个 notify 节点(重复通知陷阱)。

风险与代价(含回滚): 纯文档,无代码、无发布面;ADR-0043 的令牌表与各项决策不动,不新开 ADR。技能文件处在 token 上限,新增文字用同一文件里一段重复的代码注释抵付(该事实上一行散文已经写了),行数净增 0。回滚即 revert 本 PR。

席位意见:

你要做的: 批准本 PR(Tier H,需你的 APPROVED review);落地由席位执行。


Generated by Claude Code

…equested; one-tap links stay remind()-only

ADR-0043's Issue bullet said open-time notification remained the flow
author's notify node. Since openNodeRequest publishes approval.requested
to each concrete approver on the slate the request opens on, that
sentence is false. The Status line carries the dated amendment marker and
the parenthesis carries the correction; the token table and every
decision are unchanged.

The automation skill's best practice 5 keeps the decision half (notify
the submitter of the outcome from the approve/reject edges), drops "the
node does not send", and names the double-notify trap: the opening
already tells each resolved approver, so no notify node for the opening.
The reference file sits at its token ceiling; the duplicated
approval_revise comment (it restated the "no config, no signal" sentence
above it) pays for the new text.

Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RdnZdPZH9ByduzPRWuH9tN
@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

Contract review

Served-tier: CONTRACT_REVIEW_TIER
Head-sha: af35cd5be5f26ff8239fe2192c97582742fe8888
Local-runs: none

Skills seat 1 (seat post #7623), session_01RdnZdPZH9ByduzPRWuH9tN, read at 2026-10-10T09:43Z. Inputs: the PR diff and file list at this head; card #22631 (triage 6095381775, the token-door note 6095140961, claim 6095805515, dev report 6096101681); PR #22625's merge e8c6666870 and packages/plugins/plugin-approvals/src/approval-service.ts on origin/main (approval.requested published inside openNodeRequest, one notify() per concrete approver on the slate; issueActionTokens called only from remind(), as the dev measured and this seat re-read); origin/main at 5fb174661; the head's check-runs.

① Derived judgments

  1. Accept set and public surface: none — two governed text files (docs/adr/**, skills/**); no package, no schema, no code. Right.
  2. ADR-0043, governed text: the Status line gains the corpus-form amendment marker (dated, with the card number and a one-sentence summary), and the Issue bullet's parenthesis becomes the dated correction: open-time notification is the service's own approval.requested topic, published by openNodeRequest to each concrete approver on the slate the request opens on (PR feat(plugin-approvals): opening an approval step tells each resolved approver (approval.requested) #22625), carrying no links; one-tap links remain remind()-only. The token table and every decision are untouched; no new ADR number. Two single-line touches in one file, both faithful to the triage direction (one-line status amendment; ⛔ token decision unchanged). Right.
  3. The published skill (skills/objectstack-automation/references/state-machines-and-approvals.md), governed Tier H text that ships verbatim to third parties: best practice 5 keeps the decision half (notify the submitter from the approve/reject edges), drops "rather than expecting the node to send mail itself", and names the double-notify trap (opening already tells each resolved approver; ⛔ no notify node for the opening). Read from the customer agent's seat: an author who follows the old line adds the very notify node the changeset tells authors to remove; the new line closes that trap in two sentences. The token ratchet had 0 headroom (5569/5569), so the text is paid by deleting the duplicated approval_revise code comment at the old :183–:184, whose content ("the node takes no config — there is no signal to wait on") stands at :167–:168 of the same file; net lines 0 (budget ≤ +2), tokens 5569 → 5562. The evals assert nothing about the dropped half (git grep over skills/objectstack-automation/evals for "send mail", "expecting the node", "notify node": 0 hits on origin/main). Right; the deletion is content-preserving, not a re-wrap.
  4. Byte-identity of what the skill teaches elsewhere: no other line of the skill package moved (two hunks in one reference file). Right.

② Semver level

Nothing publishes from a package (docs/adr/** and skills/** are not in any package's files[]); skip-changeset right; Clause-②: no right. Consistent.

③ Boundary flags

Implemented-by: claude/issue-22631-approval-requested-texts
Reviewed-by: session_01RdnZdPZH9ByduzPRWuH9tN

VERDICT: PASS


Generated by Claude Code

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

维护者速读(终稿)

skills 席 1(#7623)· session_01RdnZdPZH9ByduzPRWuH9tN · 2026-10-10T09:44Z · 席位对照自己读的 diff(head af35cd5be)与 origin/main 上的审批服务代码校正了草稿;维护者只读这一条。

改了什么:两份治理文本各改一处,共 +10/−8。ADR-0043 的 Status 行加「Amended(2026-10-10)」标记,机制段里那句「开请求时的通知仍靠流程作者自己放 notify 节点」改为:开请求时审批服务自己发 approval.requested 给名单上每个具体审批人(PR #22625 起),不带链接;一键审批链接仍只由 remind() 发;token 表与各项决定一字未动。automation 技能的最佳实践第 5 条:保留「结果通知由 approve/reject 边上的下游节点发给提交人」,删掉「而不是指望节点自己发邮件」,并点名双重通知陷阱(开请求已经通知了审批人,⛔ 不要再为开请求放 notify 节点)。技能文件 token 上限已满,靠删掉一段与 :167 重复的代码注释付账,净行数 0。

为什么改:PR #22625 落地后这两段话与代码相反;技能是 AI 作者读的,照旧文会把 changeset 让作者删掉的那个 notify 节点加回来。

风险与代价(含回滚):纯文档,不碰运行时;回滚 revert 本 PR。非受管的 QA 清单半边在姊妹 PR #22656,走队列,不需要你批。

席位意见:建议批准。席位核了主题名、通知名单、链接只在 remind 发三点;两处改动与分诊方向一致,token 决定未动;删除的注释内容在同文件 :167 仍在。契约复审 PASS 已记在本 PR。

你要做的:在本 PR 上 Approve(Tier H 治理面)。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation size/s skip-changeset PR has no user-facing published change; bypasses the changeset gate

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants