docs(approvals): reassign TSDoc holds slot addresses; ADR-0042 §2 superseded in part by ADR-0118 D1; SLA checklist expects no actor - #21556
Conversation
…erseded line; SLA checklist expects no actor - spec ApprovalActionRow: reassign_from / reassign_to hold the slot address in its stored spelling (a user id, an email, or a position address); the *_name companions resolve only for a user id or an email an account carries. - ADR-0042: status line records §2's reserved actor `system:sla` as superseded in part by ADR-0118 D1 (machine actions record actor_id null; the escalate row is the attribution). - platform checklist approvals.sla-escalation (revision 2): the escalate row carries no actor. Co-authored-by: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YDt3PzwfrkuFzUBF89WPmM
…proval-actor-texts
📓 Docs Drift Check1 anchor(s) derived from 1 changed package(s); no hand-written page names any of them, so this run has nothing to list — not a clean bill of health. This check sees only pages that NAME a derived anchor: one that documents this change in prose, or enumerates it in an authoring dialect, names none and stays invisible to it on every run. What this run could not see
Coarse fallback — 138 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 22deb8f42377a842a3b6ca4b5f56248741178458 && git checkout 22deb8f42377a842a3b6ca4b5f56248741178458
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 6cf1154a65ffcae3fdfe607a5d221572157ee353 bfc5e472c2717552b7d1226dd7fb78af6cebc348 && git checkout -B drift-repro 6cf1154a65ffcae3fdfe607a5d221572157ee353 && git merge --no-ff bfc5e472c2717552b7d1226dd7fb78af6cebc348
node scripts/docs-audit/affected-docs.mjs --json 6cf1154a65ffcae3fdfe607a5d221572157ee353 |
Contract reviewServed-tier: Inputs read, and nothing else: card #21517 (body; comments ① Derived judgmentsThe diff is 4 files, +34/−11: one new changeset, one ADR status line, one checklist item revised, one TSDoc block. No schema, export, type, runtime or test line changes, so the diff implies no accept-set change and one public-surface text change: the TSDoc that ships in
Check-runs on the head, read at 2026-10-03T06:52Z: 24 success, 3 skipped ( ② Semver level
③ Boundary flagsDev flags, from report
Implemented-by: VERDICT: PASS Generated by Claude Code |
ACCEPT — PR #21556 @
|
维护者速读(终稿)— PR #21556
改了什么:三处与审批「谁做的」有关的过时文字,一张卡、一个 PR(分诊裁定,
为什么改:PR #21514(#21455)按 ADR-0118 D1 把审批里的「系统操作人」改成了空值、把转办字段改成了槽位地址;这三处文字还停在旧说法上。 风险与代价(含回滚):
席位意见:建议批准。改动最小,三处都已对照运行时代码核实。ADR 只加状态行、不改历史决策,符合 ADR 的记录方式。若你希望在 §2 正文旁再加一条注记,可以在批准时说明。 你要做的:在 PR #21556 上点 APPROVE(批准后由本坐席清标签并落地)。 Generated by Claude Code |
Approval received on PR #21556: this seat lands it
Generated by Claude Code |
Fixes #21517
Clause-②: no
Three texts still described the approval actor as a sentinel or as a user after the actor-column change landed (
88fb5e85a0). This PR corrects all three, as triage ruled on the card (comment5964851617): one card, one PR, three text positions. Text only: no schema, export, type or runtime change.What changes
ApprovalActionRowreassign TSDoc (packages/spec/src/contracts/approval-service.ts).reassign_from/reassign_towere "the user whose pending-approver slot was moved, and the user who received it", and each*_namewas "sys_user.name, when resolvable".position:NAME; any othertype:valueliteral a slate kept is stored the same way). Likeacted_as, neither is asys_userreference, and neither makes a claim about who made the move: that person isactor_id. A*_nameresolves only when the address names an account: a user id, or an email an account carries. A position address never resolves, so an absent name means "render the address".string) does not change. The rewritten block cites no tracker number; the old block's tracker citation went with the rewrite.ADR-0042 status line (
docs/adr/0042-approval-sla-escalation.md). One continuation line under Status, in the form ADR-0046 uses for a decision superseded in part:ADR-0118 is linked in the file. The decision text is not rewritten: the record keeps what was decided on 2026-06-12, and the status line points to what supersedes it (Prime Directive 13). "Wherever this record names it" covers the TL;DR, Mechanics and Consequences mentions as well as §2 itself.
Platform checklist
approvals.sla-escalation(docs/qa/platform-checklist/areas/approvals.json), revision 1 to 2 with a history entry.escalaterow's actor to beSLA_ACTOR_ID.actor_idis absent on theGET /:id/actionsread and stored null, because a machine action records no actor and theescalaterow is the attribution (ADR-0118 D1). A QA run that followed the old text would report a false failure.Changeset:
@objectstack/specpatch, because the TSDoc ships in the published.d.ts.The texts were checked against the runtime (read at
24dc7c1134)reassign()inpackages/plugins/plugin-approvals/src/approval-service.tsrecordsreassign_from: from, reassign_to: to, the two slot addresses as the slate spells them.sys-approval-action.object.tsdeclares both asField.text, described as "in the slot's stored spelling: a user id, an email, or a position address".listActions()sends only addresses without a:toresolveUserNames. That function looks each one up bysys_user.id, then looks up the ones still unresolved that contain an@bysys_user.email.escalateRequest()insertsactor_id: null.rowFromActionmaps null to undefined, and the REST route answersres.json({ data: rows }), so the key is absent on the read.pnpm --filter @objectstack/spec build, the new sentence is inpackages/spec/dist/contracts/index.d.tsandindex.d.mts, and the old "pending-approver slot was moved" sentence is in nodistfile.Gates
The union was re-run on HEAD
bfc5e472c2, the final commit. That commit is a merge oforigin/mainfd5a1cd597, which touched onlydriver-tursoand a changeset, nothing on this PR's paths.pnpm --filter @objectstack/spec build: exit 0.check-dts-emitted: @objectstack/spec - 38/38 declared declaration file(s) present.pnpm --filter @objectstack/spec check:generated: exit 0.✓ All 15 generated artifacts are up to datepnpm --filter @objectstack/spec typecheck: exit 0.check:test-typecheck: OKpnpm --filter @objectstack/spec exec vitest run --project local --maxWorkers=2: exit 0.Test Files 604 passed (604),Tests 17861 passed | 1 todonode scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commandsderived 86 commands. All 86 were run onbfc5e472c2with their exit codes recorded, then reconciled:✓ dispatch-gates --ran: 86 derived famil(ies) accounted for — 85 run, 1 NOT-MEASURED (1 DERIVED from a recorded exit 3).Among them:pnpm check:doc-authoring:✓ doc authoring guard: 17314 customer-facing string(s) across 1249 spec sources clean — no internal issue-id referencespnpm check:platform-checklist:check-platform-checklist: OK — 15 areas, 269 items (265 active, 2 planned)pnpm check:nul-bytes:check-nul-bytes: OK (scanned 9898 text file(s) ... no raw ASCII control bytes).check-empty-changeset:✓ No empty-frontmatter changeset introduced by this diff (1 declaring changeset(s) added).check-adr-0087-registration:✓ ... this PR adds no declared-breaking changeset (1 non-breaking changeset(s) seen).check-changeset-no-major:✓ This diff introduces no `major` bump.The level axis was also run offline with this body as the--eventpayload (see the report on the card).pnpm check:dual-build-cjs-loads. Reason:PREREQUISITE NOT MET. The gate reads the built output of all 83 workspace packages, which takes a fullpnpm build. This PR edits one comment block inpackages/spec, and CI's Build Core runs the gate.check-changeset-fixed,check:authz-resolver,check:error-code-casing,check:filter-alias-parity.check:meta-url-spellingandcheck:spec-changesran insidecheck:generated.node scripts/pm/check-governed-merges.mjs --branch claude/issue-21517-approval-actor-texts:⛔ GOVERNED, Tier H, bydocs/adr/0042-approval-sla-escalation.md. Size is 45 changed lines.Acceptance notes
reassign(),fromisinput.from ?? slot ?? actorId. On the admin-rescue branch (the caller holds no slot, andfromis not on the slate), the whole slate is replaced with the one addressto. The audit row then recordsreassign_fromas the caller-namedfromor the admin's own user id, not a slot that was handed over. The new TSDoc states the contract ("the pending-approver slot that was handed over"), which matches the object's field description. This branch was not driven through a public door, so it is noted here and not filed.patchchangeset (Clause-②: no). The TSDoc ships in the published.d.ts, and every changeset gate run passed.维护者速读(草稿)
改了什么:三处文字,全部是说明性文本,不改任何类型、接口或运行时行为。① 审批动作记录的 TSDoc 现在写明:「转办来源 / 转办目标」两个字段存的是审批槽位的地址(用户 id、邮箱或岗位地址),不一定是某个人,显示名只在地址对应到一个账号时才解析得出。② ADR-0042 在状态行加一句:第 2 节「SLA 机器决策记为保留身份
system:sla」已被 ADR-0118 D1 部分取代,机器动作的行为人记为空,由escalate那一行本身说明是 SLA 触发的。③ QA 测试清单里的 SLA 升级用例改为期望escalate行没有行为人。为什么改:运行时早已按 ADR-0118 实现(转办字段存槽位地址,SLA 扫描记空行为人),但这三处文字还是旧说法。AI 或开发者按旧文字写代码、跑 QA,会把岗位地址当成用户去关联,或把正确行为误报成失败。ADR 被推翻却没有状态行,也违反「已接受的 ADR 在被新 ADR 取代前一直有效」的原则。
风险与代价(含回滚):风险很低:只改文字,发布的
.d.ts只有注释变化,附 patch 级 changeset。因为碰了docs/adr/**,本 PR 属于受管面(Tier H),需要您批准才能合入。回滚就是 revert 这个提交,没有数据或迁移影响。席位意见:
你要做的:看一眼 ADR-0042 新加的那一行状态说明,措辞没问题就批准;如果还希望在第 2 节标题下也加一条指向说明,请在 PR 上说一声。
Generated by Claude Code