Repository navigation
docs(skills): objectstack-data teaches the field permission when and when to pick it over a validation rule - #26393
Conversation
…d when to pick it over a validation rule `rules/security.md` gains a section on the row-conditioned edit lock: the choice rule (a lock for everyone is a validation rule; a lock that depends on who edits is `when` on that set's field entries, never both), the contract example, the four boundaries (edit vote only, same object, pre-image on update, locks and never grants) and the docs pointers. `SKILL.md`'s `readonlyWhen` line names the per-role alternative inside the file's headroom. One eval case pins the contract prompt. The two touched token-ratchet rows are raised by the measured remainder under the maintainer's ruling quoted beside them. Claude-Session: https://claude.ai/code/session_01JQwxbakp4nDuCkULsj7Fyr Co-authored-by: Claude <noreply@anthropic.com>
`check:role-word` (ADR-0090 D3) refused the new teaching's wording in `rules/security.md` and `SKILL.md`; the choice rule now says "permission set". The security.md ceiling row follows the landed count (2956). Claude-Session: https://claude.ai/code/session_01JQwxbakp4nDuCkULsj7Fyr Co-authored-by: Claude <noreply@anthropic.com>
Contract reviewReviewed at 2026-10-27T02:05Z · PR #26393 · card #26179 · independent contract-review subagent of seat Served-tier: Inputs read: card #26179 body and all five comments (triage 6419206885, dispatch order 6430830929, claim 6430921692, claim amendment 6431446401, os-dev-report 6431770879); audit #26184 comment 6425678185 § objectstack-data (row D1 names this card) and the shared Acceptance of the eight cards; the PR body, file list, diff and reviews; the head's check-runs; every tree read via ① Derived judgments(a) Every new sentence is true of the spec and the implementation on
(b) Cuts. The diff removes nothing (the one (c) Ratchet rows pinned at the measurement; ruling quoted where the script requires. Byte counts of the head blobs, folded by (d) Eval. Eval 5 is in the file's shape ( (e) Wanted 1-4, nothing beyond. 1 the (f) PR body. Lines 1-2 are the harness-written attribution comment and (g) Report and claim. os-dev-report 6431770879 carries every key of the os-dev.md JSON template plus Check-runs on ② Semver level
③ Boundary flags
Implemented-by: VERDICT: PASS |
维护者速读改了什么: 席位核对ACCEPT ·
Generated by Claude Code |
Requested by Warren · project thread
Fixes #26179
Clause-②: no
Metadata-protocol: none
维护者速读
skills/objectstack-data/rules/security.md新增一节「字段权限的行条件when」:先写选择规则(所有人都锁 → 验证规则;按角色锁 → 该权限集字段项上的when,二者不并用),再给合同示例,再列四条边界(只管编辑、仅同对象字段、按更新前的行判定、只锁不授),末尾指向文档与配方。SKILL.md的readonlyWhen一行加一句「对所有人;按角色用when」(在余量内,不抬上限)。eval 文件加第 5 题(合同提示,期望when+readable: true,不得出现验证规则或readonlyWhen)。两行 token 上限按实测抬高,裁决原文写在行旁。首轮门禁check:role-word拒了「按角色」的英文拼法(保留词),已改为 permission set。when已随 18.2 发布但技能没教「选它」,能力就一直用不上。skills/objectstack-data/rules/security.md新节(选择规则两条、示例一段、边界四条);②scripts/check-skills-token-ratchet.mjs两行上限及其注释引的裁决;③evals/hooks-security-seeds-datasources.json第 5 题。node scripts/check-skills-token-ratchet.mjs→ 末行81 authored bundle file(s) within their ceilings,其中rules/security.md is 2956 tokens (ceiling 2956; headroom 0)、hooks-security-seeds-datasources.json is 1095 tokens (ceiling 1095; headroom 0)。skills/**),请 approve 或直接 Merge when ready。What changes
Card #26179, items 1–4:
rules/security.md— awhensection (placed before "Sensitive fields"): what it is (a row condition on a field entry's edit vote, in the canonical CEL ofrowLevelSecurity[].using), the choice rule stated first, the contract example from the card ('clm_contract.governing_law': { readable: true, editable: false, when: "status in ['approved', 'signing', 'active']" }), then the boundaries: edit vote only (readable: falsebesidewhenis refused), same-object fields (no relation reach; refused atos validate/ publish), pre-image on update (a write cannot unlock itself by movingstatusback; an insert on the row as sent), locks and never grants (unmatched rows fall back to the other grants; another held set'seditable: truestill wins).readonlyWhenlikewise strips the write for everyone); a lock that depends on who edits iswhenon the field entries of each permission set that loses the edit. Never both for one need. (check:role-word, ADR-0090 D3, refuses the reserved word in prose, so the teaching says "permission set" where the card says role.)evals/hooks-security-seeds-datasources.json, in the file's existing shape: the contract prompt; expected output nameswhenon the finance set's entries withreadable: trueand no validation rule /readonlyWhen;must_not_containpinsvalidations:andreadonlyWhen.field-level-security#row-conditioned-edit-locks-whenand the recipe anchoraccess-recipes#data-lock-fields-for-a-position-once-a-record-reaches-a-stage(both exist onmain).references/_index.mdis generator-owned (gen:skill-refsfromSKILL_MAP;permission.zod.tsis already listed), so the pointer lives insecurity.md, not the index.Also: one clause on
SKILL.md'sreadonlyWhenline — the place an author reaches for the lock-for-everyone — naming the per-set alternative. It lands inside the file's headroom (raw 6104 → 6125 tokens; the ratchet's priced count 6120, ceiling 6123), no raise.Token-ratchet rows (
scripts/check-skills-token-ratchet.mjs), per the maintainer's ruling on the seat's decision card 「skills 修复卡的教学和 eval 都撞 token 天花板,怎么付?」, tap A (2026-10-27 01:21Z), verbatim and untranslated: 「A:先削重复,余额按实测提高」. Step one, cut duplicates first: measured onorigin/main756220c4,rules/security.mdcarries no repeated sentence and nothing the package states twice (itssecret/requiredPermissionsteaching is the only full one;SKILL.md:305andfield-types.md:45are one-line table cells), and the eval file repeats nothing — so there was nothing to cut and no surviving-home list to give. Step two, raise by the measured remainder:rules/security.md2563 → 2956 (+395 landed on 2561, 2 absorbed by headroom, ceiling +393);evals/hooks-security-seeds-datasources.json894 → 1095 (+201, zero headroom). Both rows re-pinned at zero headroom; the comments beside them quote the ruling.Two readings (lines, and tokens as the ratchet counts them,
ceil(utf8 bytes / 4); the SKILL.md token reading here is the raw file, the ratchet's priced count excludes the version line):rules/security.mdSKILL.mdevals/hooks-security-seeds-datasources.json(not .md, reported for the raise)SKILL.md+references/**/*.md+rules/**/*.md, 14 files)Nothing removed: the card names no stale line in this package.
Sequencing (zero verbs beside these numbers): #26297 edits the same
rules/security.mdand is dispatched after this lands; #26244 adds a line toreferences/_index.md, which this PR does not touch; #26178 is the companion docs card, already closed.skip-changeset: the published skills packages carry nopackage.json; nothing is released from any package.Tests
node scripts/check-skills-token-ratchet.mjs— exit 0:81 authored bundle file(s) within their ceilings, the two raised rows at headroom 0,SKILL.mdat headroom 3.node scripts/check-skills-token-ratchet.mjs --self-test— exit 0,79 cases pass.pnpm --filter @objectstack/spec run check:skill-docs,check:skill-refs,check:skill-examples— see Verification (the new code block is a fragment, deliberately not markedos:check, like the file's RLS block).must_containstring occurs in it, neithermust_not_containstring does.Acceptance notes
evals/README.md(headroom 1 token) was not updated to namewhenin its topic list; a one-line mention would need another raise for five tokens. Not filed: observation only.skills/**inside the package's ceilings" cannot hold at the measured headroom (security.md 2, eval 0); the seat widened the surface to the two ratchet rows under the ruling above.Fixes #26179follows immediately.Verification
Gate list derived with
node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstackon the final tree (756220c4base, head5f62d15b), each run locally with the exit code captured before any pipe;--ranreconciliation below.Reconciliation (
node scripts/pm/dispatch-gates.mjs --ran ran.list --repo objectstack-ai/objectstack, exit 0):52 derived, 51 run, 1 NOT-MEASURED, 0 UNRUN. The one NOT MEASURED ispnpm check:dual-build-cjs-loads: its prerequisite is a whole-repo build (111 packages withoutdist/on this fresh worktree); this diff touches no package source, and CI'sLint & Repo Gatesruns it — a declared narrowing. Three derived gates refused on a missing build on the first pass (check:doc-formula-expressions,check:lean-entry-closure,check:skill-examples); the named closures were built underscripts/pm/os-verify-lock.sh(slotissue-26179: formula+lint 94 s, objectql 61 s, client-react 149 s) and the gates then exit 0 on the final head.check:role-wordwas red on the first head (the reserved word in the new prose, ADR-0090 D3) and is green on5f62d15b.check:pm-dispatch-gatesran detached on the final head: 332.2 s fast tier, 1901 cases, exit 0.Every derived command with its exit code on 5f62d15 (54 lines: the 52 derived, plus `check:skill-refs` and `check:skill-examples` the dispatch order asked for)
node scripts/check-ci-filter-parity.mjs— exit 0node scripts/check-closing-keyword-parity.mjs— exit 0node scripts/check-closing-keyword-parity.mjs --self-test— exit 0node scripts/check-comment-mask-corpus.mjs— exit 0node scripts/check-declaration-mirrors.mjs— exit 0node scripts/check-declaration-mirrors.mjs --self-test— exit 0node scripts/check-doc-route-spelling.mjs --advisory— exit 0node scripts/check-doc-route-spelling.mjs --self-test— exit 0node scripts/check-dts-emitted.mjs --self-test— exit 0node scripts/check-scripts-symbol-anchors.mjs— exit 0node scripts/check-scripts-symbol-anchors.mjs --self-test— exit 0node scripts/check-self-test-wired.mjs— exit 0node scripts/check-self-test-wired.mjs --self-test— exit 0node scripts/check-self-test-workflow-commands.mjs— exit 0node scripts/check-self-test-workflow-commands.mjs --self-test— exit 0node scripts/check-skills-token-ratchet.mjs— exit 0node scripts/check-skills-token-ratchet.mjs --self-test— exit 0node scripts/check-whole-set-label-write.mjs— exit 0node scripts/check-whole-set-label-write.mjs --self-test— exit 0node scripts/ci/assert-turbo-remote-cache.mjs --self-test— exit 0node scripts/ci/prune-turbo-cache.mjs --self-test— exit 0node scripts/pm/bare-root-worklist.mjs --self-test— exit 0pnpm --filter @objectstack/lint run check:doc-formula-expressions— exit 0pnpm --filter @objectstack/spec run check:skill-docs— exit 0pnpm check:agent-test-spelling— exit 0pnpm check:bash32-floor— exit 0pnpm check:cli-command-ids— exit 0pnpm check:corpus-claim-drift— exit 0pnpm check:cross-package-test-inputs— exit 0pnpm check:doc-authoring— exit 0pnpm check:driver-memory-census— exit 0pnpm check:dts-closure— exit 0pnpm check:dual-build-cjs-loads— NOT MEASURED (exit 3, PREREQUISITE NOT MET)pnpm check:entry-guard— exit 0pnpm check:gitlink-declared— exit 0pnpm check:lean-entry-closure— exit 0pnpm check:merge-driver— exit 0pnpm check:nul-bytes— exit 0pnpm check:parse-guard— exit 0pnpm check:pm-governed-merges— exit 0pnpm check:pm-skill-id-lint— exit 0pnpm check:pnpm-filter-targets— exit 0pnpm check:pnpm-flag-spellings— exit 0pnpm check:ratchet-remedy-authority— exit 0pnpm check:refd-timer-probe— exit 0pnpm check:role-word— exit 0pnpm check:skill-compatibility— exit 0pnpm check:skill-frame-sync— exit 0pnpm check:skill-identifier-liveness— exit 0pnpm check:sourcemap-no-sources-content— exit 0pnpm check:watch-hint-literal— exit 0pnpm --filter @objectstack/spec run check:skill-refs— exit 0pnpm --filter @objectstack/spec run check:skill-examples— exit 0pnpm check:pm-dispatch-gates— exit 0Token ratchet on 5f62d15
skills/objectstack-data/rules/security.md is 2956 tokens (ceiling 2956; headroom 0)skills/objectstack-data/evals/hooks-security-seeds-datasources.json is 1095 tokens (ceiling 1095; headroom 0)skills/objectstack-data/SKILL.md is 6120 tokens (ceiling 6123; headroom 3)81 authored bundle file(s) within their ceilings; 10 generator-owned file(s) measured, not ratcheted.--self-test:79 cases pass.check:skill-examples on 5f62d15
264 prose examples type-check across 3 surface(s) — every marked block parsed, so tsc ran the SEMANTIC pass on all of them(the new block insecurity.mdis a fragment and is deliberately unmarked, like the file's RLS block).Generated by Claude Code