Skip to content

feat(identity): implement ADR-0068 unified user-context contract (D1–D4)#2312

Merged
os-zhuang merged 4 commits into
mainfrom
worktree-adr-0068-unified-user-context
Jun 25, 2026
Merged

feat(identity): implement ADR-0068 unified user-context contract (D1–D4)#2312
os-zhuang merged 4 commits into
mainfrom
worktree-adr-0068-unified-user-context

Conversation

@os-zhuang

@os-zhuang os-zhuang commented Jun 25, 2026

Copy link
Copy Markdown
Contributor

Summary

Implements ADR-0068 — a unified EvalUser contract so a predicate authored once evaluates identically across server-formula, server-RLS, and client. Identities are modelled as roles (roles: string[]), not booleans.

Decisions implemented

  • D1 — EvalUser contract (@objectstack/spec): new eval-user.zod.ts (canonical roles[], deprecated singular role, derived isPlatformAdmin alias, built-in role constants/metadata, mapMembershipRole(), createEvalUser()). formula mounts current_user / user / ctx.user / os.user as the same object; deprecated role kept read-only for migration.
  • D2 — Built-in roles + normalization: plugin-security seeds sys_role rows; plugin-auth customSession emits one canonical roles[] and removes the role='admin' overwrite footgun; runtime normalizes better-auth owner/admin/memberorg_* and derives platform_admin from an unscoped admin_full_access grant.
  • D3 — Role-definition authority: sys_role gains a managed_by provenance field.
  • D4 — Role-catalog validation: formula/validate.ts closed-enum check rejects unknown role names in predicates.

Verification

  • Tests: formula 206, plugin-auth 120, plugin-security 143, runtime 432 — all green.
  • Full turbo build 77/77 (incl. all DTS typechecks).

Rollout notes

  • D4 blast radius audited — effectively zero today. Scanned all three repos (framework / objectui / cloud) for the 4 D4 predicate syntaxes against role-name literals. The only matches are docs, tests, and one schema-description example (now fixed to the canonical 'org_admin' in current_user.roles). No production RLS/permission predicate references a role by literal, and no caller supplies roleCatalog yet, so D4 is opt-in/dormant — enabling it is safe without a grace period. Re-run the audit before wiring roleCatalog into a live validator path.
  • Client counterpart: feat(identity): align client user-context with ADR-0068 objectui#1990 (not publish-gated on this release).
  • Follow-up: a stale comment in cloud auth-proxy-plugin.ts still describes the removed role='admin' synthesis (comment-only; tracked separately).

🤖 Generated with Claude Code

Implements the unified EvalUser contract so a predicate authored once
evaluates identically across server-formula, server-RLS, and client.
Identities are modelled as roles (roles: string[]), not booleans.

D1 — EvalUser contract (@objectstack/spec)
  - New eval-user.zod.ts: EvalUser schema, canonical roles[], deprecated
    singular `role`, derived isPlatformAdmin alias, built-in role
    constants/metadata, mapMembershipRole(), createEvalUser() factory.
  - formula: buildScope mounts current_user / user / ctx.user / os.user as
    the SAME EvalUser object; deprecated `role` scalar kept read-only for
    back-compat during migration.

D2 — Built-in roles + normalization
  - plugin-security: bootstrap-builtin-roles seeds sys_role rows.
  - plugin-auth: customSession emits one canonical roles[]; removes the
    `role='admin'` overwrite footgun; platform_admin derived.
  - runtime: normalize better-auth owner/admin/member -> org_*; derive
    platform_admin from an UNSCOPED admin_full_access grant.

D3 — Role-definition authority
  - sys_role gains a `managed_by` provenance field (system/declared/user).

D4 — Role-catalog validation (anti-hallucination)
  - formula/validate.ts: closed-enum roleCatalog check rejects unknown
    role names referenced in predicates.

Tests: formula 206, plugin-auth 120, plugin-security 143, runtime 432.
Full `turbo build` 77/77 (incl. all DTS typechecks).
@vercel

vercel Bot commented Jun 25, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
spec Ready Ready Preview, Comment Jun 25, 2026 5:19am

Request Review

@github-actions github-actions Bot added documentation Improvements or additions to documentation tests size/l labels Jun 25, 2026
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 5 package(s): @objectstack/formula, @objectstack/plugin-auth, @objectstack/plugin-security, @objectstack/runtime, @objectstack/spec.

99 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:

  • content/docs/concepts/architecture.mdx (via @objectstack/spec)
  • content/docs/concepts/cloud-artifact-api.mdx (via packages/runtime, packages/spec)
  • content/docs/concepts/cluster-semantics.mdx (via @objectstack/spec)
  • content/docs/concepts/design-principles.mdx (via packages/spec)
  • content/docs/concepts/implementation-status.mdx (via @objectstack/plugin-auth, @objectstack/plugin-security, @objectstack/runtime, @objectstack/spec)
  • content/docs/concepts/index.mdx (via @objectstack/spec)
  • content/docs/concepts/metadata-driven.mdx (via @objectstack/spec)
  • content/docs/concepts/metadata-lifecycle.mdx (via packages/spec)
  • content/docs/concepts/north-star.mdx (via packages/runtime, packages/spec)
  • content/docs/concepts/packages.mdx (via @objectstack/formula, @objectstack/plugin-auth, @objectstack/plugin-security, @objectstack/runtime, @objectstack/spec)
  • content/docs/concepts/setup-app.mdx (via @objectstack/spec)
  • content/docs/concepts/skills.mdx (via @objectstack/spec)
  • content/docs/concepts/webhook-delivery.mdx (via @objectstack/spec)
  • content/docs/getting-started/architecture.mdx (via @objectstack/spec)
  • content/docs/getting-started/cli.mdx (via @objectstack/plugin-auth, @objectstack/plugin-security, @objectstack/spec)
  • content/docs/getting-started/core-concepts.mdx (via @objectstack/spec)
  • content/docs/getting-started/examples.mdx (via @objectstack/spec)
  • content/docs/getting-started/quick-start.mdx (via @objectstack/spec)
  • content/docs/guides/adding-a-metadata-type.mdx (via @objectstack/spec)
  • content/docs/guides/ai-capabilities.mdx (via @objectstack/spec)
  • content/docs/guides/airtable-dashboard-analysis.mdx (via @objectstack/spec)
  • content/docs/guides/analytics-datasets.mdx (via @objectstack/spec)
  • content/docs/guides/api-reference.mdx (via @objectstack/runtime, @objectstack/spec)
  • content/docs/guides/auth-sso.mdx (via @objectstack/plugin-auth)
  • content/docs/guides/authentication.mdx (via @objectstack/plugin-auth, @objectstack/runtime)
  • content/docs/guides/business-logic.mdx (via @objectstack/spec)
  • content/docs/guides/cheatsheets/backward-compatibility.mdx (via @objectstack/spec)
  • content/docs/guides/cheatsheets/error-catalog.mdx (via @objectstack/spec)
  • content/docs/guides/cheatsheets/field-type-gallery.mdx (via @objectstack/spec)
  • content/docs/guides/cheatsheets/field-validation-rules.mdx (via @objectstack/spec)
  • content/docs/guides/cheatsheets/permissions-matrix.mdx (via packages/plugins/plugin-security, @objectstack/spec)
  • content/docs/guides/cheatsheets/protocol-diagram.mdx (via packages/spec)
  • content/docs/guides/cheatsheets/query-cheat-sheet.mdx (via @objectstack/spec)
  • content/docs/guides/cheatsheets/quick-reference.mdx (via @objectstack/spec)
  • content/docs/guides/client-sdk.mdx (via @objectstack/spec)
  • content/docs/guides/cloud-deployment.mdx (via @objectstack/runtime)
  • content/docs/guides/common-patterns.mdx (via @objectstack/spec)
  • content/docs/guides/contracts/auth-service.mdx (via packages/spec)
  • content/docs/guides/contracts/cache-service.mdx (via packages/spec)
  • content/docs/guides/contracts/data-engine.mdx (via @objectstack/spec)
  • content/docs/guides/contracts/index.mdx (via @objectstack/spec)
  • content/docs/guides/contracts/metadata-service.mdx (via packages/spec)
  • content/docs/guides/contracts/storage-service.mdx (via packages/spec)
  • content/docs/guides/data-modeling.mdx (via @objectstack/spec)
  • content/docs/guides/deployment-vercel.mdx (via @objectstack/runtime, @objectstack/spec)
  • content/docs/guides/driver-configuration.mdx (via @objectstack/runtime, @objectstack/spec)
  • content/docs/guides/error-handling-client.mdx (via @objectstack/spec)
  • content/docs/guides/error-handling-server.mdx (via @objectstack/spec)
  • content/docs/guides/external-datasources.mdx (via @objectstack/spec)
  • content/docs/guides/formula.mdx (via @objectstack/formula, @objectstack/spec)
  • content/docs/guides/hook-bodies.mdx (via @objectstack/runtime, packages/spec)
  • content/docs/guides/kernel-services.mdx (via @objectstack/plugin-auth, @objectstack/spec)
  • content/docs/guides/metadata/dashboard.mdx (via @objectstack/plugin-security, @objectstack/spec)
  • content/docs/guides/metadata/field.mdx (via @objectstack/spec)
  • content/docs/guides/metadata/flow.mdx (via @objectstack/spec)
  • content/docs/guides/metadata/index.mdx (via @objectstack/spec)
  • content/docs/guides/metadata/object.mdx (via @objectstack/spec)
  • content/docs/guides/metadata/validation.mdx (via @objectstack/formula, @objectstack/spec)
  • content/docs/guides/metadata/workflow.mdx (via @objectstack/spec)
  • content/docs/guides/packages.mdx (via @objectstack/formula, @objectstack/plugin-auth, @objectstack/plugin-security, @objectstack/runtime, @objectstack/spec)
  • content/docs/guides/plugin-chatbot-integration.mdx (via @objectstack/runtime)
  • content/docs/guides/plugin-development.mdx (via @objectstack/spec)
  • content/docs/guides/plugins.mdx (via @objectstack/plugin-auth, @objectstack/plugin-security, @objectstack/spec)
  • content/docs/guides/production-readiness.mdx (via @objectstack/plugin-auth, @objectstack/runtime)
  • content/docs/guides/project-scoping.mdx (via @objectstack/spec)
  • content/docs/guides/public-forms.mdx (via @objectstack/spec)
  • content/docs/guides/runtime-services/email-service.mdx (via packages/spec)
  • content/docs/guides/runtime-services/index.mdx (via packages/spec)
  • content/docs/guides/runtime-services/queue-service.mdx (via packages/spec)
  • content/docs/guides/runtime-services/sharing-service.mdx (via packages/spec)
  • content/docs/guides/runtime-services/storage-service.mdx (via packages/spec)
  • content/docs/guides/security.mdx (via @objectstack/plugin-security, @objectstack/spec)
  • content/docs/guides/seed-data.mdx (via @objectstack/spec)
  • content/docs/guides/single-project-mode.mdx (via @objectstack/runtime)
  • content/docs/guides/skills.mdx (via @objectstack/spec)
  • content/docs/guides/standards.mdx (via @objectstack/spec)
  • content/docs/guides/troubleshooting.mdx (via @objectstack/spec)
  • content/docs/guides/validating-metadata.mdx (via @objectstack/spec)
  • content/docs/protocol/knowledge.mdx (via @objectstack/spec)
  • content/docs/protocol/objectos/config-resolution.mdx (via @objectstack/spec)
  • content/docs/protocol/objectos/http-protocol.mdx (via @objectstack/runtime)
  • content/docs/protocol/objectos/i18n-standard.mdx (via @objectstack/spec)
  • content/docs/protocol/objectos/index.mdx (via @objectstack/runtime)
  • content/docs/protocol/objectos/lifecycle.mdx (via @objectstack/runtime, @objectstack/spec)
  • content/docs/protocol/objectos/plugin-spec.mdx (via @objectstack/spec)
  • content/docs/protocol/objectos/runtime-capabilities.mdx (via @objectstack/spec)
  • content/docs/protocol/objectql/index.mdx (via packages/spec)
  • content/docs/protocol/objectql/query-syntax.mdx (via @objectstack/spec)
  • content/docs/protocol/objectql/schema.mdx (via @objectstack/spec)
  • content/docs/protocol/objectql/security.mdx (via packages/spec)
  • content/docs/protocol/objectql/state-machine.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/actions.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/concept.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/index.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/layout-dsl.mdx (via packages/spec)
  • content/docs/protocol/objectui/record-alert.mdx (via @objectstack/formula, @objectstack/spec)
  • content/docs/protocol/objectui/widget-contract.mdx (via @objectstack/spec)
  • content/docs/releases/index.mdx (via @objectstack/spec)
  • content/docs/releases/v9.mdx (via @objectstack/plugin-auth, @objectstack/spec)

Advisory only. To re-verify, run the docs-accuracy-audit workflow scoped to these files:
node scripts/docs-audit/affected-docs.mjs origin/main → pass the list as args.docs.

Comment thread packages/formula/src/validate.ts Fixed
…ample

ADR-0068 D4 follow-up. The embedded `describe()` example shipped the
non-canonical, non-catalog pattern `os.user.role == "admin"`; users
copy-paste these. Switch to `'org_admin' in current_user.roles` so the
shipped example matches the canonical contract and passes role-catalog
validation.
The TypeScript Type Check CI job runs check:api-surface, which flagged
26 additive exports (EvalUser contract, built-in role constants/metadata,
createEvalUser/mapMembershipRole) with 0 breaking. Regenerate the
committed snapshot so the guard passes.
CodeQL flagged js/polynomial-redos (high) on ROLE_EXISTS_RE: the
unbounded greedy [^,]* + lazy [^)]*? scanners backtrack O(n^2) on
adversarial input like repeated 'user.roles.exists('. Bound both
quantifiers ({0,64}/{0,128} — CEL exists bodies are tiny) and exclude
'=' from the pre-operator class so the run is linear and unambiguous.
Capture groups unchanged; 206 formula tests pass; a 720k-char
pathological probe now returns in ~14ms.
@os-zhuang
os-zhuang merged commit 17d0ed4 into main Jun 25, 2026
17 checks passed
@os-zhuang
os-zhuang deleted the worktree-adr-0068-unified-user-context branch June 25, 2026 05:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation protocol:ui size/l tests

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants