Repository navigation
docs(skills): a system flow is refused identity-assignment writes in objectstack-automation - #26566
Conversation
…objectstack-automation The runAs 'system' guidance called system context the trusted-writer channel and never said that a system flow's governed writes to sys_user_position, sys_user_permission_set, sys_invitation and sys_member are refused PERMISSION_DENIED. Add one paragraph beside "Elevate the write, not the flow" stating the refusal and the remedy the refusal prescribes, linking system-context row 1b, and eval 11 as the counter-case to eval 1. Raise the two touched token-ratchet rows by the measured remainder under the maintainer's ruling A. Claude-Session: https://claude.ai/code/session_01JQwxba5RipjC9aRL8Cjjux Co-authored-by: Claude <noreply@anthropic.com>
…ation identity-assignment paragraph skills/** ships in @objectstack/skills (sync-catalog copies it into the package's dist), so the teaching change publishes and carries a patch changeset with both declaration lines. Claude-Session: https://claude.ai/code/session_01JQwxba5RipjC9aRL8Cjjux Co-authored-by: Claude <noreply@anthropic.com>
Contract reviewServed-tier: Director seat (summon #52, ledger objectstack#12708), after the fact by the maintainer's word 「#26566、#26568、#26570、#26585 也要追加复审,虽然我已经点了合并」: the PR was approved by ① Derived judgments
② Semver level
③ Boundary flags
④ Design judgment
Implemented-by: VERDICT: PASS Generated by Claude Code |
|
Retracted: this comment was a duplicate post of the director seat's contract-review record on this PR; the record of record is comment 6439727886 above (same head, same verdict). Nothing else changes. Generated by Claude Code |
Requested by Warren · project thread
Fixes #26502
Clause-②: no
Metadata-protocol: none
维护者速读
runAs: 'system'流程写四张身份分配表会被PERMISSION_DENIED拒绝,并给出拒绝文案自带的补救;新增 eval 11 作为 eval 1 的反例;两行 token 天花板按裁决 A 抬到实测值。runAs: 'system'叫作 trusted-writer channel,AI 照着写系统流程去授予权限集,运行时被拒,技能却从未提过,作者拿不到补救路径。@objectstack/skillspatch changeset;无运行时代码。回滚 = revert 本 PR。skills/objectstack-automation/SKILL.md新段落(措辞是否与运行时拒绝一致);evals/flows-triggers-approvals.json的 eval 11;scripts/check-skills-token-ratchet.mjs两行上限及注释。node scripts/check-skills-token-ratchet.mjs,预期末行✓ check-skills-token-ratchet: 81 authored bundle file(s) within their ceilings。skills/**)。What changes
skills/objectstack-automation/SKILL.md: one paragraph placed right after 「Elevate the write, not the flow」, inside the same quote block:The remedy is the refusal's own prescription, not a third wording. The flow source of
plugin-security/src/flow-system-identity-write-refusal.tsprescribes "Set the flow's runAs to 'user': the delegated-administration gate then judges the user the run acts for, and records that user as the grant's granted_by." The membership half isMEMBERSHIP_PRESCRIPTIONinpackages/spec/src/identity/identity-assignment-body-writes.ts. The sentence about the subflow closes the gap with the paragraph right above it, which tells the author to move an elevated write into a dedicated system subflow. The paragraph names the refusal and the door that judges the write; it describes no way around it. It mirrors the wording PR #26501 uses inhooks.mdxandactions.mdxand does not touchcontent/docs/**.skills/objectstack-automation/evals/flows-triggers-approvals.json: eval 11, the counter-case to eval 1's readonly sweep. Inserted as text, so ids 1 to 10 are byte-identical.contractorrecord is markedonboarded, grant its linked user (contractor.user_id) thecontractor_portalpermission set. Make the flow run as system so the grant always lands."sys_user_permission_set(as intosys_user_position,sys_invitationorsys_member) is refused withPERMISSION_DENIED— elevation does not lift a governed identity write, a dedicated system subflow included. Emits therecord_changeflow withrunAs: 'user': itscreate_recordonsys_user_permission_setis judged by the delegated-administration gate as the user whose write fired the flow, recorded as the grant'sgranted_by; a user the gate would not let grant the set is refused, which is the rule, not a defect to route around."must_contain:runAs: 'user',sys_user_permission_set,PERMISSION_DENIED,delegated-administration,granted_by.must_not_contain:runAs: 'system',sudo. A script checked that the expected output carries everymust_containstring and neithermust_not_containstring.scripts/check-skills-token-ratchet.mjs: the two rows of the files above, raised under ruling A. Each row comment carries its arithmetic and the tap..changeset/26502-automation-skill-identity-assignment-refusal.md: apatchchangeset for@objectstack/skills, with both declaration lines.skills/**publishes: the package's build (packages/skills/scripts/sync-catalog.mjs) copies the catalog into itsdist, which itsfileslist ships. So this PR carries a changeset and noskip-changesetlabel.Duplicate scan (ruling A, first step)
SKILL.md: read in full. TherunAsguidance sits at L164 to L201 (the readonly strip, elevate the write, pin the organization,requiredPermissions, hookrunAs). No sentence in the file restates another, and none names the four objects or the refusal before this PR. Nothing to cut, 0 bytes.evals/flows-triggers-approvals.json: the ten existing evals share no sentence. Eval 1 teachesrunAs: 'system'for a readonly sweep; eval 11 is its counter-case, not a restatement. Nothing to cut, 0 bytes.Ratchet arithmetic
Ruling: the maintainer's tap on the seat's decision card 「skills 修复卡的教学和 eval 都撞 token 天花板,怎么付?」, 2026-10-27 01:21Z, verbatim and untranslated: 「A:先削重复,余额按实测提高」. Option A in full: 「八张卡的 PR 各自削重复后,把所改文件的天花板行提高恰好差额,正文引用你这句;教学和 eval 都落。」
SKILL.md(priced, the 20-byte stamp line excluded)evals/flows-triggers-approvals.jsonBoth rows had 0 tokens of headroom. Each ceiling is ceil(bytes / 4) of the new file, pinned AT the measurement.
Size readings:
SKILL.mdlinesreferences/**/*.md, linesTests
No runtime code changes, so no package tests apply. The skill's own checks ran on
caee07d4(the card commit6609364dplus a merge oforigin/mainatab3c776a); the ratchet gate ran again on head4b5b0436, which adds only the changeset:Card-named checks
node scripts/check-skills-token-ratchet.mjs: exit 0,✓ check-skills-token-ratchet: 81 authored bundle file(s) within their ceilings; 10 generator-owned file(s) measured, not ratcheted.node scripts/check-skills-token-ratchet.mjs --self-test: exit 0,79 cases pass.pnpm check:role-word: exit 0. Neither file contains the word.pnpm check:skill-frame-sync,pnpm check:skill-compatibility,pnpm check:skill-top-level-keys,pnpm check:pm-skill-ratchet: exit 0 each.pnpm --filter @objectstack/spec check:skill-examples: exit 0,265 prose examples type-check across 3 surface(s).pnpm --filter @objectstack/spec run check:skill-docs: exit 0.Acceptance notes
flow-system-identity-write-refusal.tsapplies, with the same six verbs, the four objects and the code. It gives the remedy the refusal prescribes for a flow, and the membership remedy fromidentity-assignment-body-writes.ts.hooks.mdxandactions.mdxthrough PR docs: a system-elevated hook or action body is refused identity-assignment writes #26501, and this skill's hook paragraph points to objectstack-data. Noted, not filed.Verification
Derived gate run on 4b5b043
node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstackderived 52 families oncaee07d4and 63 on4b5b0436; the 11 the changeset added ran on4b5b0436. 62 ran locally with exit 0.pnpm check:dual-build-cjs-loadsis NOT MEASURED: it needs the whole tree built, and CI's Build Core runs it.--ranreconciliation:✓ dispatch-gates --ran: 63 derived famil(ies) accounted for — 62 run, 1 NOT-MEASURED.pnpm check:pm-dispatch-gatesran detached; its verdict line reads✓ dispatch-gates self-test (fast tier): 1935 cases pass. The build closure for the client, client-react, lint and formula packages ran under the verify lock withVERDICT command-exit 0.Tier H:
skills/**is a governed surface. This PR stays a draft until an authorized approver reviews it.Generated by Claude Code