Skip to content

spec(identity): EvalUser.isPlatformAdmin is the live PLATFORM_ADMIN standing predicate but is still marked Deprecated and positions-derived — lift the mark, describe it as ADR-0095 D3 standing, date-note ADR-0068 D2/D4 (#21886 spec half) #22012

Description

@objectstack-fleet

Filed by the director seat (summon #35, session_01VYToj6PQehTEKNrjGM9akg, seat post #12708) on the maintainer's ruling for #21886, batch #281 item 2, letter A-lite (maintainer 「同意」 in the seat's Claude Code session, 2026-10-06). This card is the spec half; the visible gate on sys_member.add_member stays on #21886 (domain:engine), serial after this card, and the thirteen sibling actions on #21903 after that. ⛔ Not a claim.

What is wrong (read on origin/main 6befe19c)

packages/spec/src/identity/eval-user.zod.ts:225-226 describes EvalUserSchema.isPlatformAdmin as "DERIVED alias of 'platform_admin' in positions. Deprecated." The key is not deprecated in fact; it is the one standing predicate every evaluator agrees on:

  • the platform-admin door reads it: packages/plugins/plugin-auth/src/platform-admin-gate.ts:83 (u.isPlatformAdmin === true);
  • the session emits it from the posture rung, not from the array: packages/plugins/plugin-auth/src/auth-manager.ts:4055, :4107;
  • the console binds it into ctx.user / current_user: objectui packages/app-shell/src/providers/expressionUser.ts:26-27 (at objectui 7300fcaf);
  • cloud's sys_environment "Change Plan (admin)" gates on ctx.user.isPlatformAdmin == true (ADR-0068's own trigger case);
  • ADR-0068 D4 (Accepted) rules that platform-operator actions gate on current_user.isPlatformAdmin.

What the mark contradicts: ADR-0095 D3 (Accepted, later than ADR-0068) rules that PLATFORM_ADMIN posture derives from held capability grants, never from roles; core resolves it per request at the one derivation site (packages/core/src/security/resolve-authz-context.ts §6b-config) from the deployment's declared administrator list (OS_PLATFORM_OWNER_EMAIL, or the first human account under the single posture) and projects the platform_admin name into positions from that same grant (:1125-1140). So for every genuine administrator the rung and the name agree; the only divergence is a tenant-minted platform_admin position row, which #15972 refuses on write. ADR-0068 D2's "derived alias of roles.includes('platform_admin'), marked deprecated" and D4's "(≡ 'platform_admin' in roles)" wording is the superseded half.

Because the fleet's rule forbids a first-party gate on a deprecated key, the #21886 dev stopped (5999863859, needs_decision) instead of writing the one visible line. The protocol text is the defect here, not the mechanism.

The change — A-lite, and nothing more

  1. eval-user.zod.ts: drop "Deprecated" from the .describe() and the JSDoc on isPlatformAdmin; describe it as the PLATFORM_ADMIN standing of ADR-0095 D3, as the deployment's declared administrator list resolves it per request; equal to 'platform_admin' in positions for every genuine administrator, because the resolver projects that name from the same grant. The schema shape, optionality and createEvalUser are unchanged.
  2. Generated docs: pnpm --filter @objectstack/spec build && pnpm --filter @objectstack/spec check:generated --fix (check:docs → gen:schema && gen:docs); authorable-surface keeps its identity/EvalUser:isPlatformAdmin row unchanged.
  3. ADR-0068: one dated note under D2 and one under D4, naming EvalUserSchema.isPlatformAdmin and ADR-0095 D3 as the superseding text; the original wording is not rewritten (the director's rule for a superseded ADR clause).
  4. Hand-written docs: content/docs/permissions/permission-metadata.mdx:226 ("derived, deprecated alias") and content/docs/permissions/authentication.mdx:927 are brought in line with the new description.

⛔ Out of scope, by the ruling: changing createEvalUser to take the rung as an input; changing @objectstack/formula buildScope; a new authorable key (requiresPlatformAdmin or any other); blessing 'platform_admin' in current_user.positions as a standing read; any visible edit on any action (those are #21886's and #21903's).

Pins

  • A spec test asserting the published description of EvalUserSchema.isPlatformAdmin names the ADR-0095 D3 standing and carries no deprecation word.
  • The liveness ledger row for identity/EvalUser:isPlatformAdmin keeps its status (no row moves).

Landing

  • The diff touches docs/adr/0068-*.md, a governed Tier H path, so the whole PR waits for the maintainer's approval (AGENTS.md Prime Directive feat: Comprehensive CRM example demonstrating all ObjectStack protocol features #14); the owning seat lands it afterwards. The dev may split the ADR note into its own PR if it prefers the spec half to go through the queue on its own record.
  • Clause-②: declared by the dev on the diff (a description change on a published key; no accept/reject behaviour changes). The changeset text should say what the key means now and that nothing authored changes.
  • Contract review at tier (packages/spec/src/**) before landing, as the lane's rule reads.

Unblocks

Governing text: ADR-0068 D2/D4 · ADR-0095 D3 · packages/spec/src/identity/eval-user.zod.ts:225-256 · platform-admin-gate.ts:83 · auth-manager.ts:4055 · #15136 · #15972 · the maintainer's ruling A on #21795 (5993018584).

Dedupe: isPlatformAdmin deprecated · EvalUser isPlatformAdmin standing · ADR-0068 D4 platform admin predicate — read on #21886's thread (5999863859, 5999894453, 6000036525); no open card carries this half.

Activity

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

Metadata

Metadata

Assignees

Labels

area:identityLogin and identity — sign-up, sessions, organization membership, SSObugSomething isn't workingdomain:specpriority:p3

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions