Skip to content

feat(spec,plugin-security): export the kernel platform-admin capability declaration from @objectstack/spec (#11663 Choice 6A, leg L1) - #12612

Merged
os-zhuang merged 2 commits into
mainfrom
claude/issue-11965-platform-admin-capability-export
Aug 26, 2026
Merged

feat(spec,plugin-security): export the kernel platform-admin capability declaration from @objectstack/spec (#11663 Choice 6A, leg L1)#12612
os-zhuang merged 2 commits into
mainfrom
claude/issue-11965-platform-admin-capability-export

Conversation

@os-zhuang

Copy link
Copy Markdown
Contributor

Fixes#11965

Leg L1 of the accepted platform-admin re-anchor design (#11663 stays open — it is the coordination parent, out of scope here; design doc = #11663 comment 5394453215 §4 Choice 6 / §6 row L1; maintainer acceptance = comment 5404675670, 2026-08-25, bundle 1A/2B/3A/4A/5A/6A/7A).

What

  • @objectstack/spec now exports ADMIN_FULL_ACCESS_CAPABILITIES — the kernel platform-admin capability declaration (the objects wildcard grants + systemPermissions previously inlined in plugin-security's admin_full_access declaration). Placed in packages/spec/src/identity/eval-user.zod.ts directly beside ADMIN_FULL_ACCESS (the precedent: core already imports that constant from the spec root), exported from the root entry via the same index.ts block. The 用户级 export 权限轴(接入 P1 预留的 userExportAllowed 槽) #3544/[security] org-admin sets ship object_permissions['*'].allowExport = true, so the 17.0 export gate cannot be denied for an org admin — and the sets are not_overridable (17.0.0 GA) #8681 export-axis rulings (no allowExport on the wildcard) travel verbatim with the declaration to its new home.
  • @objectstack/plugin-security's admin_full_access declaration in objects/default-permission-sets.ts now imports that list (name: ADMIN_FULL_ACCESS, ...ADMIN_FULL_ACCESS_CAPABILITIES) — exactly one copy exists.
  • Regenerated baselines: packages/spec/api-surface/{root,identity}.json, packages/spec/export-origins/{root,identity}.json (2 exports added, 0 breaking). Authorable-surface: unmovedcheck:authorable-surface green with no baseline change, confirming the design's "no new authorable key" premise on the tree.

Acceptance criterion (from the card)

git grep -n ADMIN_FULL_ACCESS packages/spec/src packages/plugins/plugin-security/src now shows the capability list declared once (eval-user.zod.ts:83) and imported — not duplicated — by plugin-security (default-permission-sets.ts:6,132). The remaining ADMIN_FULL_ACCESS hits in vama-write-path-convergence.test.ts are a test-local fixture variable, not a second declaration.

Behaviour-neutrality (pinned)

New test in default-permission-sets.test.ts parses the exact pre-move inline literal and asserts the current declaration deep-equals it, plus a no-local-fork assertion against the imported constant. New spec-side test platform-admin-capabilities.test.ts pins: exactly the two capability-bearing fields; strict-parse composition under the canonical name; #8681 no-export pin at the new home; every granted system permission resolves in the ADR-0066 PLATFORM_CAPABILITY_NAMES registry.

Verification (at merged head 0bc6a4803 = this PR's head; origin/main merged immediately before opening)

  • pnpm --filter @objectstack/spec exec vitest run src/identity/platform-admin-capabilities.test.ts — 4/4 passed
  • pnpm --filter @objectstack/plugin-security exec vitest run src/objects/default-permission-sets.test.ts src/bootstrap-platform-admin.test.ts src/bootstrap-seed-round-trips.test.ts src/bootstrap-declared-permissions.test.ts — 76/76 passed
  • pnpm --filter @objectstack/spec typecheck (incl. check:test-typecheck: "OK — test layer compiles") and pnpm --filter @objectstack/plugin-security typecheck — both green. Note: plugin-security's tsc excludes **/*.test.ts, so its edited test file is measured by vitest execution, not tsc.
  • Gates (derived via scripts/pm/dispatch-gates.mjs from the real changeset, re-run on 0bc6a4803): check:authorable-surface ("1255 default(s) unchanged"), check:api-surface ("public API surface + factory signatures unchanged ✓" after regen), check:export-origins ("5181 exports across 17 entry points resolve exactly as recorded"), check:engine-double-contract, check:where-matcher, check:i18n ("all bundles in sync"), check:i18n-stale-fill, check:query-options-erasure, check:type-check-coverage, check:type-check-debt ("31 ledger entr(ies) re-measured … none above its recorded number"), check:nul-bytes, plus the full derived lint batch (changeset gates, cross-package-test-inputs, doc-authoring, merge-driver, published-files, slot-lookup, spec-parsed-alias, test-source-alias, type-source-resolution, spec liveness/empty-state/strictness-ledger/variant-docs, ADR-0087, plugin-teardown-shape, dev-prereqs after full closure build) — all green.
  • scripts/pm/check-governed-queue-guard.mjs is CI-context-only (reads GITHUB_EVENT_PATH): NOT MEASURED locally; runs on this PR in CI (packages/spec/src/index.ts is a governed surface — clause-② applies per dispatch).

Out of scope by design: L2+ legs (core derivation is Blocked-by: this card). #11504 / #12610 / #12606 / #12515 surfaces are disjoint from this diff. Draft by dispatch contract (clause-②): stop at draft, no ready-flip.


Generated by Claude Code

…ty declaration from @objectstack/spec (#11663 Choice 6A, leg L1)
Part of #11965
- @objectstack/spec exports ADMIN_FULL_ACCESS_CAPABILITIES (objects wildcard +
systemPermissions) beside ADMIN_FULL_ACCESS in identity/eval-user.zod.ts;
the #3544/#8681 export-axis rulings travel with the declaration.
- plugin-security's admin_full_access declaration imports that list, so exactly
one copy exists. Behaviour-neutral: pinned deep-equal against the exact
pre-move inline literal in default-permission-sets.test.ts.
- api-surface / export-origins baselines regenerated (2 added, 0 breaking);
authorable-surface unmoved.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012xGvxcwPRTJfA7RfjXEYA4
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 2 package(s): @objectstack/plugin-security, @objectstack/spec, touching 18 documentable anchor(s). ⚠️5 changed file(s) yielded no anchor (packages/spec/api-surface/identity.json, packages/spec/api-surface/root.json, packages/spec/export-origins/identity.json, …), so the pages documenting them are NOT COVERED by this run — this is not a clean bill of health for those files.

22 hand-written doc(s) name something this change touched — list omitted above 15 rows. Re-derive on the tree named below: node scripts/docs-audit/affected-docs.mjs --json 146f448a502893df21e85e1038005cbccdf7e7ff.

5 release-owned page(s) also affected — read-only, see AGENTS.md Documentation Guardrails.

What this run could not see
  • 5 changed file(s) yielded no anchor (packages/spec/api-surface/identity.json, packages/spec/api-surface/root.json, packages/spec/export-origins/identity.json, …) — pages documenting those are invisible to this run
  • 1 name(s) were too generic to anchor anything (single lowercase words)
  • the SDK route bridge reached 47 of 219 client-bound route-ledger rows — the other 172 have no registrar path: tail to select them, so pages documenting THEIR client methods cannot appear above, on this or any run. Of those 172: 14 are remediable by widening that discovery convention (an in-repo file declares the path; the convention did not scan it); 56 are structural — on a ledger where NOT ONE row is declared in-repo, so no discovery change reaches them at any price; 102 are undecided (no in-repo declaration, on a ledger that has other in-repo registrars — absence and an unreadable spelling are not distinguishable here). The rows themselves: node scripts/docs-audit/affected-docs.mjs --bridge-coverage
  • a page that states a rule by its inputs shares no identifier with the emitter that implements the rule, so an emitter-only diff cannot list it — not on this run and not on any run. Measured on fix(driver-sql): emit varchar(maxLength) for a text field a declared index keys on #11430: content/docs/protocol/objectql/types.mdx documents the text-family column mapping by the ObjectQL type names it maps FROM (text / textarea / html) while the diff changed createColumn; it went unlisted, and it was the page that diff falsified, in four places. No shared token exists to detect this on, so a rule your change carries has to be re-read by hand in the pages that restate it.

Coarse fallback — 129 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): node scripts/docs-audit/affected-docs.mjs --json 146f448a502893df21e85e1038005cbccdf7e7ffpackageMentionDocs.

Which tree this was computed on

This run read content/docs from ad3a1a01fa5c2da18b30e6c75e517d8661580a0f — the merge of head 0bc6a4803a04385b1d55f4c6d9d19edad66f63c8 into base 146f448a502893df21e85e1038005cbccdf7e7ff, which is what actions/checkout gives a pull_request run. Not the PR head.

A worktree cut from an older main holds a different content/docs, so re-deriving there can legitimately return a different list — that is a different tree, not a wrong row. To answer on the same tree:

# while this PR is open — GitHub drops the merge commit once it closes
git fetch origin ad3a1a01fa5c2da18b30e6c75e517d8661580a0f && git checkout ad3a1a01fa5c2da18b30e6c75e517d8661580a0f
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 146f448a502893df21e85e1038005cbccdf7e7ff 0bc6a4803a04385b1d55f4c6d9d19edad66f63c8 && git checkout -B drift-repro 146f448a502893df21e85e1038005cbccdf7e7ff && git merge --no-ff 0bc6a4803a04385b1d55f4c6d9d19edad66f63c8
node scripts/docs-audit/affected-docs.mjs --json 146f448a502893df21e85e1038005cbccdf7e7ff

⚠️ That checkout carried uncommitted changes, so the commit above does not fully identify what was read.

Advisory only, and a precision-first one (#9192): a page is listed because it names a
symbol, wire route or SDK method this diff touched — not because it mentions a changed
package. Each row says which anchor put it there, so a wrong row is reportable rather than
merely annoying. To re-verify, run the docs-accuracy-audit workflow scoped to these files:
node scripts/docs-audit/affected-docs.mjs 146f448a502893df21e85e1038005cbccdf7e7ff → pass the list as
args.docs, on the commit named under Which tree this was computed on.

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentationImprovements or additions to documentationsize/mteststooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

platform-admin re-anchor L1 (spec seat): export the kernel platform-admin capability declaration — one list, imported by plugin-security (Choice 6A)

2 participants

@os-zhuang@claude