Repository navigation
docs(skills): the security rule states a grant's uniqueness by the declared unique: 'organization' index, in place of the retired permission_set_id column (#23615) - #23669
Conversation
…clared `unique: 'organization'` index, in place of the retired `permission_set_id` column `skills/objectstack-data/rules/security.md`'s grant paragraph closed with a sentence naming `permission_set_id` as a legacy column not to write. The grant object no longer declares that column (a write naming it is refused `400 INVALID_FIELD`), so the sentence taught an AI author a key the declared shape does not have. One line replaces it: one grant per user, set and organization, enforced by the join object's `unique: 'organization'` index on (`user_id`, `permission_set`, `organization_id`). Net 0 lines; the token ratchet reads 2494 -> 2502 against ceiling 2543. The file ships in `@objectstack/skills` (`dist/skills/**` via sync-catalog), so a patch changeset accompanies it. Co-authored-by: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VqGhCg9wdsBXPz54uAEWg7
维护者速读改了什么 — 为什么改 — 这份技能包随 风险与代价(含回滚) — 纯文本,不改任何行为、代码或数据。token 棘轮 2494 → 2502(上限 2543 不动,余量 49 → 41)。回滚:revert 本 PR 即可。 席位意见 — 建议批准。席位对着 diff 逐句核过:新句的三个限定(用户、权限集、组织)与索引字段一一对应;被删的旧句在 你要做的 — 对 PR #23669 给一个 APPROVED review。批准后由席位落地(ready、入队),不需要其他动作。 席位核对Seat Implemented-by:
Generated by Claude Code |
Fixes #23615
Clause-②: no
What
skills/objectstack-data/rules/security.mdL49 read "permission_set_idis a legacy column: do not write it." The grant objectsys_user_permission_set(packages/plugins/plugin-security/src/objects/sys-user-permission-set.object.ts) no longer declares that column — a write naming it is refused400 INVALID_FIELDas an undeclared field (grant-permission-set-name.test.ts, the C7b NEGATIVE case) — so the sentence taught an AI author a key the declared shape does not have.One line replaces it, in the paragraph that already teaches the by-name reference (
permission_settakes the set'sname) and its400 VALIDATION_FAILEDrefusals:Each clause checked against the declared shape at
origin/main1ced0f82b: the object'sindexescarry{ fields: ['user_id', 'permission_set', 'organization_id'], unique: 'organization' }(L267; the module header L16–21 says the same), and the duplicate refusal — organization-scoped, platform-wide (organization NULL) and via update — is pinned ingrant-permission-set-name.test.tsL282–347 (409,UNIQUE_VIOLATIONon the wire). The retired column is not named: the reader is an AI author, and the refusal it would meet is already loud.unique: 'organization'and its NULL-safety are taught in this package atrules/indexing.mdL53 and L71, so the sentence does not restate them.Text only; no behaviour changes. One other file:
.changeset/23615-grant-unique-index-skill.md(@objectstack/skillspatch). The edited file ships:packages/skills/package.jsonfiles[]isdist, andsync-catalogcopiesskills/**intodist/skills/**byte for byte. Measured afterpnpm --filter @objectstack/skills build(65 files copied, read back byte-identical): the new sentence is indist/skills/objectstack-data/rules/security.md(1 hit) andpermission_set_idis not (0 hits).Readings (
skills/**)1ced0f82b)a3f679931)security.mdlinesskills/objectstack-data/**/*.mdlines (the package)skills/*/SKILL.mdlines (the catalog)check-skills-token-ratchet,security.mdVerdict lines verbatim — before:
✓ check-skills-token-ratchet: skills/objectstack-data/rules/security.md is 2494 tokens (ceiling 2543; headroom 49).— after:✓ check-skills-token-ratchet: skills/objectstack-data/rules/security.md is 2502 tokens (ceiling 2543; headroom 41).No ceiling moves. The replaced line is 89 characters, inside the file's existing range (its longest line is 93); no other line was re-wrapped.Verification
Derived at
a3f679931bynode scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack(no paths; change set from the merge base1ced0f82b: 2 files, +10/−1): 41 commands — the dispatch's 29 plus 12 the changeset adds. Each ran in the foreground with its exit code captured before any pipe, then--ranreconciled the record:41 derived famil(ies) accounted for — 39 run, 2 NOT-MEASURED (2 DERIVED from a recorded exit 3).check-skills-token-ratchet(and its--self-test),check:skill-compatibility,check:skill-frame-sync,check:skill-identifier-liveness,check:pm-skill-id-lint,check:doc-authoring,check:nul-bytes,check:role-word,check-adr-0087-registration --base origin/main,check-changeset-no-major --base origin/main,check-empty-changeset --base origin/main,check:published-files,check:pm-changeset-deadline-census,check:objectui-changeset, andcheck:doc-formula-expressions(afterturbo run build --filter=@objectstack/formula --filter=@objectstack/lintunder the shared verify lock, the fix its refusal named).pnpm check:dual-build-cjs-loadsandpnpm check:lean-entry-closureexit 3 (PREREQUISITE NOT MET: they load every package's builtdist/, which only a whole-workspace build supplies; not built here for a markdown edit). CI'sLint & Repo Gatesbuilds and runs them; its check-run is the reading.grep -naPover both changed files finds none.packages/*source, no generated artifact.CI runs the full farm; the
os-dev-reportcomment on #23615 cites this PR's check-runs by name and conclusion.Acceptance notes
skills/namespermission_set_id(git grepat1ced0f82b: one hit, this line).skills/**), Tier H: this PR stays a draft until an authorized approval. No label written: the changeset is present, soskip-changesetdoes not apply.维护者速读(草稿)
改了什么 —
skills/objectstack-data/rules/security.md权限集授予段落的最后一句。原句写「permission_set_id是遗留列,不要写它」;现在改为「同一用户、同一权限集、同一组织只允许一条授予记录:由unique: 'organization'索引强制」。只改这一行,文件行数不变;另加一个@objectstack/skills的 patch changeset。为什么改 — 这份技能包随
npx skills add发到客户项目,读者是写元数据的 AI。permission_set_id列在 #23503 之后已从对象声明中删除(写它会被400 INVALID_FIELD拒绝),原句教给 AI 一个它看不到、也不能用的键;新句子陈述的是声明形状里真实存在、并有测试钉住的规则(每用户、每权限集、每组织一条授予,重复写入返回 409)。风险与代价(含回滚) — 纯文本改动,不改任何行为与代码。token 棘轮读数 2494 → 2502(上限 2543,余量 49 → 41),上限不动。回滚:revert 本 PR 即可,无数据或迁移影响。
席位意见 — (留空)
你要做的 — Tier H 面(
skills/**):审阅上面那一行英文是否准确;同意则给 APPROVED review,由席位落地。不需要其他动作。Generated by Claude Code