Repository navigation
docs(spec): the permission set name describe and the permission sets page say one holder per namespace - #33384
Conversation
…space A permission set is identified by its package and name, so a name has one holder per namespace. The `name` describe, its generated reference row and the permission sets guide say so; positions and capabilities keep one name per deployment, and a set is still never overridden under its own name, not even from `.custom` (ADR-0146 D6). Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FEkQ5nvMv3rqz7e8UKwxD9
📓 Docs Drift CheckThis PR changes 1 package(s): 1 hand-written doc(s) NAME something this change touched and may need an implementation-accuracy re-verification:
⛔ 3 release-owned page(s) also name something this change touched. These are read-only:
What this run could not see
Coarse fallback — 172 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 dd9a08d9d1bf4a5aa5f37078d39a0f45e84d805b && git checkout dd9a08d9d1bf4a5aa5f37078d39a0f45e84d805b
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin df9fe9463020a58b29a61f98605b91e7fbb307c1 aeb3c973e6549ffa66d66b05601f30b3af3d8cd2 && git checkout -B drift-repro df9fe9463020a58b29a61f98605b91e7fbb307c1 && git merge --no-ff aeb3c973e6549ffa66d66b05601f30b3af3d8cd2
node scripts/docs-audit/affected-docs.mjs --json df9fe9463020a58b29a61f98605b91e7fbb307c1
|
|
domain:spec#1 · os-project-manager · session_01FEkQ5mswnWm181XgYcCUag Contract reviewServed-tier: No file in this diff implements or enforces the describe: the code it describes ( Inputs read: card #32758 body and its five comments (6837778026, 6847899833, claim 6881630925, report 6882046858, seat answers 6882071328), PR #33384 body, file list (4 files, +26 / -6) and net diff against ① Derived judgments
② Semver level
Clause-②: no — agreed. Neither a widening nor a narrowing: the text now states what #32742 ( ③ Boundary flags
④ Design judgment
Sentence by sentence against
Attempts to break it:
Findings:
No must-fix, no should-fix. The describe, its generated row and the guide state what the predicate and the two refusals on Implemented-by: VERDICT: PASS |
|
domain:spec#1 · os-project-manager · session_01FEkQ5mswnWm181XgYcCUag ACCEPT · PR #33384 (#32758) · head
|
Requested by Leehom · project thread
Fixes #32758
Clause-②: no
Metadata-protocol: none
维护者速读
name字段的 describe 不再说「在环境的安全目录里唯一」,改成「权限集按 (包, 名字) 识别,每个命名空间一个持有者」;参考文档那一行重新生成;权限集指南里「权限集、岗位、能力每个部署一个名字」改成权限集按命名空间、岗位和能力仍按部署。skills/objectstack-platform/SKILL.md已经按 (包, 名字) 讲,没有改。packages/spec/src/security/permission.zod.ts里name的 describe;其次content/docs/permissions/permission-sets.mdx改动的那一段。grep -n "one holder per namespace" content/docs/references/security/permission.mdx,预期name行命中一次,且与permission.zod.ts的 describe 逐字一致。What changes
packages/spec/src/security/permission.zod.ts: thenamedescribe()and its JSDoc line. FROM "Permission set name, unique within the security catalog the environment serves (lowercase snake_case)" TO "Permission set name (lowercase snake_case). A set is identified by its package and name: a name has one holder per namespace, so packages of two namespaces may each hold a set of one name, while two packages of one namespace, a package with no namespace, a platform package (base, system, sys), the environment and the platform-requested guest_portal share one set of it". The holder list is the one feat(core, objectql, metadata, metadata-protocol, plugin-security): a permission-set name is held once per namespace, judged by one predicate (ADR-0150 child B) #32742's save-door sentence andpermissionSetHoldersMeet(@objectstack/core) state. The//comment above the field gains one line pointing at ADR-0150 D2/D9 and that predicate.SnakeCaseIdentifierSchemaand the field are unchanged.content/docs/references/security/permission.mdx: the generatednamerow, regenerated (pnpm gen:schema && pnpm gen:docsinpackages/spec). No other generated file carries the string;json-schema/is untracked build output.content/docs/permissions/permission-sets.mdx(the "set shipped in code cannot be edited" bullet): FROM "A set is never overridden under its own name, not even from.custom: permission sets, positions and capabilities hold one name per deployment (ADR-0146 D6)." TO: the set is still never overridden under its own name, now for the reason that holds (a permission set takes no override, ADR-0146 D6, and a set of the shipped set's name saved into the pair is refused403 NOT_OVERRIDABLE); a permission set is identified by its package and name (ADR-0150 D2), one holder per namespace, with the one-holder cases listed; positions and capabilities keep one name per deployment..changeset/32758-permission-set-name-describe.md:@objectstack/specpatch, since the describe ships in specdist.Why
PR #32742 (merged 2026-11-12,
5defbfeb) made a permission-set name one holder per namespace: two packages of two namespaces may each hold a set of one name, judged bypermissionSetHoldersMeet. Both texts still said one name per deployment.The
.customsentence, measured against #32742. The order asked whether "a set is never overridden under its own name, not even from.custom" is still true. The pair's namespace isNAMESPACE_custom(the base's namespace plus_custom), a different namespace from its base, so the name rule alone would admit a second set there. A probe on this head (the real protocol over the realObjectQLengine and an in-memory driver, the harness ofprotocol-custom-override-bare-slot-envelope.test.ts; basecom.example.showcase, namespaceshowcase, shippingshowcase_reader; pair created byensureCustomizationPackage, namespaceshowcase_custom) answered:showcase_readerinto the pair, nooverrides403 NOT_OVERRIDABLE("provided by a managed package and is sealed against in-place edits. Clone it under a new name…")overrides: { package: BASE, basedOn: '1.0.0' }403 NOT_OVERRIDABLE("a permission takes no override (ADR-0146 D6)…")403 NOT_OVERRIDABLE(sealed)403 ITEM_LOCKEDAfter the refused pair save, the base's set still read "Shipped label". So the point stays true and is kept; only its reason changed. The probe was a scratch file, deleted before the commit.
Tests
git greponorigin/main: only the source, the generated row and released CHANGELOGs).854b36e4:pnpm --filter @objectstack/spec typecheckexit 0;pnpm --filter @objectstack/spec exec vitest run --maxWorkers=2 src/security/permission: Test Files 4 passed (4), Tests 164 passed (164).Acceptance notes
Outside this card's surface, present-tense "one name per deployment" for permission sets remains in:
packages/spec/src/migrations/entries/semantic/18.security-catalog-environment-overlay-refused.ts(reason: "Positions, permission sets and capabilities hold one name per deployment"). A migration entry's text, left alone per the order; in the report'sopen_questions.packages/spec/src/kernel/customization-package.ts:251-252(theadr_0146_d6_security_catalogbasis: "D6: one name per deployment (permission sets, positions, capabilities)"). It describes ADR-0146 D6's basis as written; inopen_questions.packages/objectql/src/registry.ts:2818and:2880(the boot and hot-install refusal sentences for an environment item against a package holder). The environment still meets every holder, so the refusal stays right, but its reason says an assignment names a permission set by its bare name.packages/spec/src/contracts/security-service.ts:419(PlatformBaselineSetContribution.name, "unique in the security catalog"). A platform-baseline set lives in a platform namespace, which keeps one holder, so this stays true for what it describes.showcase-security.ts:32/showcase-d7-default-profile.dogfood.test.ts:65: decision records and test comments, not touched.skills/objectstack-platform/SKILL.md:125already teaches that permission sets "are identified by package and name", and:129that a permission set is never overridden; no skills change.Verification
On
854b36e4:node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstackderived 103 commands. 102 exit 0.pnpm --filter @objectstack/spec run check:generatedexited 1 in the loop becausecheck:test-typecheck'stsc -pdied without diagnostics while other gates ran beside it; run alone after the loop it exited 0 ("All 14 generated artifacts are up to date").pnpm check:dual-build-cjs-loadsexited 3 (PREREQUISITE NOT MET: it needs every package'sdist; only the spec, lint, objectql and client closures were built), so it is NOT MEASURED here and left to CI.--ranreconciliation: "103 derived famil(ies) accounted for — 102 run, 1 NOT-MEASURED".node scripts/check-nul-bytes.mjsexit 0.🤖 Generated with Claude Code
https://claude.ai/code/session_01FEkQ5nvMv3rqz7e8UKwxD9