Repository navigation
docs(skills): objectstack-automation teaches the emailField recipient, flow requiredPermissions, excludeSubmitter and the screen file field - #26390
Conversation
…, flow requiredPermissions, excludeSubmitter and the screen file field
Four audit rows the package taught nowhere, each in the fewest lines an AI
author needs:
- `notify.recipients` has a fourth form, `{ emailField }` — an `email`-typed
field of the trigger record, for a person who is not a user; the node then
names `channels: 'email'` alone. A CEL envelope must yield user ids, and an
address no user holds fails the node at run time (the trap SKILL.md's
"id, list, or envelope" line set).
- flow-level `requiredPermissions` — who may START a flow, checked at every
door that starts it by name; not a `current_user.positions` check inside it.
- `excludeSubmitter` in the approval config table — segregation of duties;
refused beside `onEmptyApprovers: 'auto_approve'`.
- the screen field typed `file` — the run resumes with the `sys_file` id,
which a later record write claims.
Three eval prompts, one per teaching. Paid down first: the CRM Blueprint's
approval row that restated the approvals reference, and Best Practices 1 and
4 that restated the Branching section; the measured remainder raises the
three token-ratchet rows, quoting the maintainer's ruling.
Claude-Session: https://claude.ai/code/session_01JQwxbXsLdroTYaf1DRqVUG
Co-authored-by: Claude <noreply@anthropic.com>
Contract reviewReviewed at 2026-10-27T02:05Z — card #26298, PR #26390, independent contract review at the ceiling tier; read-only, adversarial, built from REST reads and Served-tier: Inputs read: card #26298 body and all four comments (dispatch order 6430836374, claim 6430944943, claim amendment 6431455570 2026-10-27T01:28Z, os-dev-report 6431766118 2026-10-27T01:52Z); audit Part A on #26184 comment 6425678185, § objectstack-automation rows A1–A6; the PR body, file list, diff, reviews, issue events and the head's check-runs over REST; the spec and runtime on ① Derived judgments(a) Every new sentence is true of the spec on
(b) The cuts are duplicates with a surviving home, not lost rules (ruling A).
(c) Ratchet rows pinned at the measurement, ruling quoted where the script requires.
(d) Evals. Ids 1–8 unique and sequential; evals 6, 7, 8 follow the file's shape ( (e) Wanted met, nothing beyond. Four files, all inside the claim + amendment surface ( (f) PR body. Line 1 is the (g) Report shape and claim. os-dev-report 6431766118: first line Check-runs on ② Semver level
③ Boundary flags
Implemented-by: Implemented by the card thread session_01JQwxbXsLdroTYaf1DRqVUG (mode:thread) on that branch; reviewed by session_01LqKsGyMNFwwnbF5FTAqyPn (independent contract-review subagent). VERDICT: PASS |
维护者速读改了什么:objectstack-automation 技能包补上四条审计缺口—— 席位核对ACCEPT ·
Generated by Claude Code |
Resolves scripts/check-skills-token-ratchet.mjs: the sibling rows that landed around the automation rows (objectstack-api 1234, objectstack-data 1095) are kept with their comments, beside this PR's three automation rows. Claude-Session: https://claude.ai/code/session_01JQwxbXsLdroTYaf1DRqVUG Co-authored-by: Claude <noreply@anthropic.com>
席位核对ACCEPT (addendum, pinned to the merge head) · Generated by Claude Code |
Brings in main's re-measured authz census (#26406), the fix for main's own dogfood red (#26400) that the full battery on this branch showed. Main's automation skill change (#26390) left the approvals reference two bytes under its token ceiling, so the queue approver row is shortened to fit (members of the named ownership queue at node entry; an empty queue adds nobody). Claude-Session: https://claude.ai/code/session_01GTntg542RUmmRRbMY6wMZD Co-authored-by: Claude <noreply@anthropic.com>
Resolves the adjacent-row conflict in scripts/check-skills-token-ratchet.mjs: main's objectstack-automation row (#26390) and this branch's objectstack-data examples-objects.md row both kept. Claude-Session: https://claude.ai/code/session_01JQwxbXTWvHG6MXFD7Gywf2 Co-authored-by: Claude <noreply@anthropic.com>
Requested by Warren · project thread
Fixes #26298
Clause-②: no
Metadata-protocol: none
维护者速读
notify收件人的第四种写法{ emailField }(给非用户的申请人发邮件;CEL 信封算出的地址若无用户持有,节点运行时失败)、流程级requiredPermissions(谁能启动流程)、审批节点excludeSubmitter(提交人不能批自己的单;与auto_approve并写被拒)、屏幕字段type: 'file'(续跑拿到sys_fileid,后续写入记录即认领文件);每条配一条 eval。recipients信封现在会在运行时失败,不写excludeSubmitter则提交人可自批。skills/objectstack-automation/SKILL.md(notify代码块与requiredPermissions引言段)、references/state-machines-and-approvals.md(配置表新行、删掉的两条最佳实践)、scripts/check-skills-token-ratchet.mjs(三行上限)。node scripts/check-skills-token-ratchet.mjs—— 预期末行81 authored bundle file(s) within their ceilings,automation 三行 headroom 0。skills/**是 Tier H,席位不入队。What changes
Four rows from the skills gap audit (#26184, Part A § objectstack-automation, rows A1–A4), each taught in the fewest lines an AI author needs:
{ emailField }SKILL.mdnotifyblock, therecipientsline{ emailField: 'applicant_email' }(anemail-typed field of the trigger record, for a non-user),channels: 'email'alone beside it, and that a CEL envelope must yield user ids — an address no user holds fails the node (packages/spec/src/automation/io-node-config.zod.tsNotifyEmailFieldRecipientSchema, therecipientsdescribe and thechannelsrefinement)requiredPermissionsSKILL.md, a blockquote after Elevate the write, not the flowrequiredPermissionsis checked at every door that starts the flow by name; an action starting it inherits the list; asubflownode is not a door; gate an elevatedscreen/apiflow here, never oncurrent_user.positions(flow.zod.tsrequiredPermissions, ADR-0066 D4)filefieldSKILL.mdnode table, thescreenrowconfig.fields[]shape;type: 'file'renders the upload widget and resumes with thesys_fileid bound toname; a latercreate_record/update_recordwrites it into afilefield, which claims the file — collect first, write after the last screen (builtin-node-config.zod.tsScreenFieldConfigSchema.type)excludeSubmitterreferences/state-machines-and-approvals.md, the Node Config tableonEmptyApproversroute;onEmptyApprovers: 'auto_approve'is refused beside it (approval.zod.tsexcludeSubmitter,checkExcludeSubmitterPolicyPairing)Three eval prompts in
evals/flows-triggers-approvals.json, in the file's existing shape: #6 the card's acceptance eval (email the applicant →recipients: { emailField: … }), #7requiredPermissions+excludeSubmitteron one approval, #8 the screenfilefield written by a latercreate_record.Paid down first (surviving homes named):
SKILL.mdCRM Blueprint, the Approval flow row restatedapprovers/behavior/lockRecord/approvalStatusFieldand theapprove/rejectbranching — cut to a pointer; the surviving home isreferences/state-machines-and-approvals.md§ Node Config (ApprovalNodeConfigSchema) and § Branching, side-effects & rejection.references/state-machines-and-approvals.mdApproval Best Practices 1 (Gate entry on the edge) and 4 (Model rejection as a visible branch) restated § Branching's Conditional step, Roll back on reject and Hard reject bullets and the section lead "wired on the graph, not in node config" — deleted; items 2, 3, 5 (each carrying a rationale found nowhere else) stay, renumbered.SKILL.mdline 1 (theversion:stamp PR chore: version packages #25640 owns) is untouched.Token ratchet (
scripts/check-skills-token-ratchet.mjs), the measured remainder per file, under the maintainer's ruling. The decision card asked 「skills 修复卡的教学和 eval 都撞 token 天花板,怎么付?」; Warren's tap, 2026-10-27, verbatim: 「A:先削重复,余额按实测提高」.skills/objectstack-automation/SKILL.mdskills/objectstack-automation/references/state-machines-and-approvals.mdskills/objectstack-automation/evals/flows-triggers-approvals.jsonreferences/examples-flows.md,references/_index.md(generated)SKILL.md+references/**/*.md+rules/**/*.md)Why
The audit measured 0 hits in the package for
requiredPermissions,excludeSubmitterandemailField;SKILL.md'srecipientscomment read "id, list, or envelope", which sinced1e329e96dsends an author mailing an applicant into a run-time failure; the approval config table had noexcludeSubmitterrow, so a submitter could approve their own request; screen field types were not enumerated. The premise was re-read onorigin/mainat756220c4before the first edit and holds (the seat's read-only check of 2026-10-27 00:36Z, re-measured here:grep -rnof the three keys overskills/objectstack-automation/→ 0 hits; the screenfiletype's spec location isScreenFieldConfigSchema.typeinpackages/spec/src/automation/builtin-node-config.zod.ts, which the seat had not located).Tests
No runtime code changes; the eval file parses (
python3 -c json.load→ ok) and the package gates below read the new text. The three eval prompts are the test surface for the teachings.Acceptance notes
check:skill-exampleshas three surfaces; the skills + docs surface is the one this PR touches. Its verdict needspackages/spec,@objectstack/clientand@objectstack/client-reactbuilt first (it refuses with exit 3,PREREQUISITE NOT MET, otherwise) — see Verification for the run against the built tree.49653f9181,4bcc4df649,6021b5e837,d1e329e96d,6d9d3ef857,f1ddace887) are outside this container's shallow clone (git cat-file -e→ missing); the spec text onmainwas read directly instead, so the teachings quote whatmainholds, not the commits.Verification
Gate list derived with
node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstackon the final tree (83b5ec5e), 54 commands, every exit code captured before any pipe, reconciled with--ran.Derived gates — 53 commands, 52 run green, 1 NOT MEASURED (
--ranexit 0)node scripts/pm/dispatch-gates.mjs --ran ran.list --repo objectstack-ai/objectstack→53 derived famil(ies) accounted for — 52 run, 1 NOT-MEASURED (1 DERIVED from a recorded exit 3), exit 0; change set4 path(s) vs merge base 756220c4a,changed lines: 85 (+72 / -13).pnpm check:dual-build-cjs-loads→ exit 3,PREREQUISITE NOT MET — some package has no dist/(33 packages unbuilt in this container; a repo-wide build is CI's run). CI'sLint & Repo Gatescarries it.node scripts/check-comment-mask-corpus.mjs(first runENOENT … packages/spec/.examples-build/…, a transient dir the concurrentcheck:skill-examplesrun was materialising; re-run exit 0,18308 files, 0 disagree, 0 unparseable);pnpm check:dts-closure(first run while@objectstack/client-reactwas mid-build under the verify lock; re-run exit 0,38 built package(s) swept - 160/160 declared declaration file(s) present).node scripts/check-skills-token-ratchet.mjsexit 0 —81 authored bundle file(s) within their ceilings; automation rows6004 / 6004 (+0),1823 / 1823 (+0),5587 / 5587 (+0);--self-testexit 0,79 cases pass.pnpm check:pm-dispatch-gatesexit 0,pnpm check:pm-governed-mergesexit 0,pnpm check:ratchet-remedy-authorityexit 0 (all in the batch).The card's three package gates and the liveness gate
pnpm --filter @objectstack/spec check:skill-docsexit 0 —✅ Skill docs in sync.pnpm --filter @objectstack/spec check:skill-refsexit 0 —✅ 9 generated files in sync with packages/spec(references/_index.mdunchanged, nothing to regenerate).pnpm --filter @objectstack/spec check:skill-examplesexit 0 afterpnpm --filter @objectstack/spec build(lockVERDICT command-exit 0, 88 s) andpnpm --filter "@objectstack/client-react..." build(VERDICT command-exit 0, 304 s) —✅ 264 prose examples type-check across 3 surface(s); the two earlier runs on an unbuilt tree exited 3 (PREREQUISITE NOT MET), not findings.pnpm check:skill-identifier-livenessexit 0 —Leg 1: 491 citation(s) over 69 published file(s) … Leg 2: 8 registered exhaustive section(s), 0 ledgered gap(s).pnpm lint,test:repo, the full battery.Human Minimum
packages/specholds no runtime logic. (no schema change)pnpm lintis CI's run (repo-level scan, not owed locally per.claude/agents/os-dev.md).main, one pull request.skills/**carries nopackage.json);skip-changeset, and both declaration lines are above.packages/specuntouched.content/docs/references/,packages/*/CHANGELOG.mdorcontent/docs/releases/.Generated by Claude Code