Skip to content

test(security): pin server-managed field set + tenant-wall write guard; fix systemFields docs (#3058)#3168

Merged
os-zhuang merged 1 commit into
mainfrom
claude/server-hosted-fields-schema-ohgdf8
Jul 18, 2026
Merged

test(security): pin server-managed field set + tenant-wall write guard; fix systemFields docs (#3058)#3168
os-zhuang merged 1 commit into
mainfrom
claude/server-hosted-fields-schema-ohgdf8

Conversation

@os-zhuang

Copy link
Copy Markdown
Contributor

Context

Closes the actionable part of #3058. That issue proposed hoisting the three "server-managed field" special cases — owner_id (step 3.5), the public-form set (PUBLIC_FORM_SERVER_MANAGED_FIELDS), and organization_id (step 3.7) — into one declarative systemManaged schema concept with a unified enforcement point and an ADR.

After exploring the current code, the assessment is that the full declarative abstraction is not yet warranted, and the debt the issue actually names is closable without it:

This PR is the right-sized alternative: harden the drift seam, fill test gaps, and correct stale contract docs. No runtime behavior changes.

Changes

  • objectql — new conformance test (system-managed-fields-conformance.test.ts) pinning PUBLIC_FORM_SERVER_MANAGED_FIELDS to an exact partition of:

    • actively injected — derived from the real injection code (applySystemFieldsorganization_id + audit columns + owner_id) plus the __search companion and the id primary key, and
    • documented defense-in-depth reservedtenant_id / is_deleted / deleted_at.

    A newly-injected system field that isn't added to the denylist now fails here with an actionable message, instead of silently leaking through the anonymous public-form surface.

  • plugin-security — add the missing package-level write-side unit tests for the step 3.7 organization_id tenant wall (insert-forge and update-repoint denied; matching-org and absent-value writes pass; isSystem exempt). Previously only the read-side Layer 0 and the multitenant dogfood covered this.

  • spec — correct the stale systemFields JSDoc/describe on ObjectSchema to match the registry: the organization_id column is provisioned unconditionally (only its index is multi-tenant-gated), audit is a wired opt-out, and owner_id provisioning is governed by the object-level ownership property — not the owner key.

Findings surfaced (not changed here)

  • #3043 already closed the authenticated audit-column INSERT gap. The originally-planned follow-up (audit columns seedable on authenticated insert) is moot on main: readonly is now stripped on INSERT at the data-write ingress.
  • schema.ownership name collision. The property is read as 'own' | 'extend' (metadata authorship) by packages/cli/src/commands/info.ts and as 'user' | 'org' | 'none' (record-ownership model) by registry.ts applySystemFields. This is why this PR does not add a typed ownership field to ObjectSchema — that would force a premature resolution of a genuine two-meanings collision. Worth its own focused issue.

Verification

  • @objectstack/spec test — 6911 pass (describe-string change; check:liveness green).
  • @objectstack/objectql conformance + registry — pass; conformance test confirmed to bite (removing owner_id from the denylist fails with the intended message).
  • @objectstack/plugin-security — full security-plugin.test.ts 209 pass (6 new + all existing unchanged).

🤖 Generated with Claude Code

https://claude.ai/code/session_014343Qv6DFAykuAJc9yjANb


Generated by Claude Code

…d; fix systemFields docs (#3058)

#3058 proposed collapsing the three server-managed-field special cases
(owner_id / public-form set / organization_id) into one declarative `systemManaged`
schema concept. Assessment: the field roster is a closed set of platform columns,
the three enforcement semantics are genuinely heterogeneous, and the real risk the
issue names (drift between the sites) is closable without a new abstraction. This is
the right-sized alternative — it hardens the drift seams and fills test gaps without
introducing a speculative declaration layer.

- objectql: new conformance test pinning PUBLIC_FORM_SERVER_MANAGED_FIELDS to an
  exact partition of (fields actually injected by applySystemFields + `id` + the
  `__search` companion) and (documented defense-in-depth reserved names:
  tenant_id / is_deleted / deleted_at). A newly-injected system field that is not
  added to the denylist now fails loudly here instead of leaking through the
  anonymous public-form surface — the drift vector that first surfaced as #3022.
- plugin-security: add the missing package-level write-side unit tests for the
  step 3.7 organization_id tenant wall (insert forge / update re-point denied,
  matching-org and absent-value writes pass, isSystem exempt). Previously only the
  read-side Layer 0 and the multitenant dogfood covered this.
- spec: correct the stale systemFields JSDoc/describe on ObjectSchema to match the
  registry — the organization_id column is provisioned unconditionally (only its
  index is multi-tenant-gated), `audit` is a wired opt-out, and owner_id
  provisioning is governed by the `ownership` property, not the `owner` key.

No runtime behavior changes: the existing owner/tenant/public-form guards and all
209 security-plugin tests are unchanged.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014343Qv6DFAykuAJc9yjANb
@vercel

vercel Bot commented Jul 18, 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 Jul 18, 2026 6:13am

Request Review

@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 3 package(s): @objectstack/objectql, @objectstack/plugin-security, @objectstack/spec.

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

  • content/docs/ai/agents.mdx (via @objectstack/spec)
  • content/docs/ai/skills-reference.mdx (via @objectstack/spec)
  • content/docs/ai/skills.mdx (via @objectstack/spec)
  • content/docs/api/client-sdk.mdx (via @objectstack/spec)
  • content/docs/api/environment-routing.mdx (via @objectstack/spec)
  • content/docs/api/error-catalog.mdx (via @objectstack/spec)
  • content/docs/api/error-handling-client.mdx (via @objectstack/spec)
  • content/docs/api/error-handling-server.mdx (via @objectstack/spec)
  • content/docs/api/index.mdx (via @objectstack/spec)
  • content/docs/automation/approvals.mdx (via packages/spec)
  • content/docs/automation/flows.mdx (via @objectstack/spec)
  • content/docs/automation/hook-bodies.mdx (via packages/spec)
  • content/docs/automation/hooks.mdx (via @objectstack/spec)
  • content/docs/automation/index.mdx (via @objectstack/spec)
  • content/docs/automation/webhooks.mdx (via @objectstack/spec)
  • content/docs/automation/workflows.mdx (via @objectstack/spec)
  • content/docs/concepts/architecture.mdx (via @objectstack/spec)
  • content/docs/concepts/design-principles.mdx (via packages/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 @objectstack/objectql, packages/spec)
  • content/docs/concepts/north-star.mdx (via packages/spec)
  • content/docs/data-modeling/analytics.mdx (via @objectstack/spec)
  • content/docs/data-modeling/drivers.mdx (via @objectstack/spec)
  • content/docs/data-modeling/external-datasources.mdx (via @objectstack/spec)
  • content/docs/data-modeling/field-types.mdx (via @objectstack/spec)
  • content/docs/data-modeling/fields.mdx (via @objectstack/spec)
  • content/docs/data-modeling/formulas.mdx (via packages/objectql, @objectstack/spec)
  • content/docs/data-modeling/index.mdx (via @objectstack/spec)
  • content/docs/data-modeling/objects.mdx (via @objectstack/spec)
  • content/docs/data-modeling/queries.mdx (via @objectstack/spec)
  • content/docs/data-modeling/schema-design.mdx (via @objectstack/spec)
  • content/docs/data-modeling/seed-data.mdx (via @objectstack/spec)
  • content/docs/data-modeling/validation-rules.mdx (via @objectstack/spec)
  • content/docs/data-modeling/validation.mdx (via @objectstack/spec)
  • content/docs/deployment/migration-from-objectql.mdx (via @objectstack/objectql)
  • content/docs/deployment/troubleshooting.mdx (via @objectstack/spec)
  • content/docs/deployment/vercel.mdx (via @objectstack/objectql)
  • content/docs/getting-started/build-with-claude-code.mdx (via @objectstack/spec)
  • content/docs/getting-started/cli.mdx (via @objectstack/plugin-security, @objectstack/spec)
  • content/docs/getting-started/common-patterns.mdx (via @objectstack/spec)
  • content/docs/getting-started/examples.mdx (via @objectstack/spec)
  • content/docs/getting-started/quick-reference.mdx (via @objectstack/spec)
  • content/docs/getting-started/quick-start.mdx (via @objectstack/spec)
  • content/docs/getting-started/validating-metadata.mdx (via @objectstack/spec)
  • content/docs/getting-started/your-first-project.mdx (via @objectstack/spec)
  • content/docs/kernel/cluster.mdx (via @objectstack/spec)
  • content/docs/kernel/contracts/auth-service.mdx (via packages/spec)
  • content/docs/kernel/contracts/cache-service.mdx (via packages/spec)
  • content/docs/kernel/contracts/data-engine.mdx (via @objectstack/spec)
  • content/docs/kernel/contracts/index.mdx (via @objectstack/spec)
  • content/docs/kernel/contracts/metadata-service.mdx (via packages/spec)
  • content/docs/kernel/contracts/storage-service.mdx (via packages/spec)
  • content/docs/kernel/index.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/email-service.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/index.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/queue-service.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/sharing-service.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/sms-service.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/storage-service.mdx (via packages/spec)
  • content/docs/kernel/services-checklist.mdx (via @objectstack/objectql, @objectstack/spec)
  • content/docs/kernel/services.mdx (via @objectstack/objectql)
  • content/docs/permissions/access-recipes.mdx (via packages/plugins/plugin-security)
  • content/docs/permissions/authentication.mdx (via @objectstack/objectql)
  • content/docs/permissions/authorization.mdx (via @objectstack/plugin-security, @objectstack/spec)
  • content/docs/permissions/explain.mdx (via @objectstack/plugin-security)
  • content/docs/permissions/permission-sets.mdx (via @objectstack/spec)
  • content/docs/permissions/permissions-matrix.mdx (via packages/plugins/plugin-security, @objectstack/spec)
  • content/docs/permissions/positions.mdx (via @objectstack/spec)
  • content/docs/permissions/rls.mdx (via @objectstack/spec)
  • content/docs/permissions/sharing-rules.mdx (via @objectstack/plugin-security, @objectstack/spec)
  • content/docs/plugins/adding-a-metadata-type.mdx (via @objectstack/spec)
  • content/docs/plugins/development.mdx (via @objectstack/spec)
  • content/docs/plugins/index.mdx (via @objectstack/objectql, @objectstack/plugin-security, @objectstack/spec)
  • content/docs/plugins/packages.mdx (via @objectstack/objectql, @objectstack/plugin-security, @objectstack/spec)
  • content/docs/protocol/backward-compatibility.mdx (via @objectstack/spec)
  • content/docs/protocol/diagram.mdx (via packages/spec)
  • content/docs/protocol/kernel/config-resolution.mdx (via @objectstack/spec)
  • content/docs/protocol/kernel/i18n-standard.mdx (via @objectstack/spec)
  • content/docs/protocol/kernel/index.mdx (via @objectstack/objectql)
  • content/docs/protocol/kernel/lifecycle.mdx (via @objectstack/spec)
  • content/docs/protocol/kernel/plugin-spec.mdx (via @objectstack/spec)
  • content/docs/protocol/kernel/runtime-capabilities.mdx (via @objectstack/spec)
  • content/docs/protocol/knowledge.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/objectql, @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 @objectstack/spec)
  • content/docs/protocol/objectui/record-alert.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/widget-contract.mdx (via @objectstack/spec)
  • content/docs/releases/implementation-status.mdx (via @objectstack/objectql, @objectstack/plugin-security, @objectstack/spec)
  • content/docs/releases/index.mdx (via @objectstack/spec)
  • content/docs/releases/v12.mdx (via @objectstack/spec)
  • content/docs/releases/v13.mdx (via @objectstack/spec)
  • content/docs/releases/v9.mdx (via @objectstack/objectql, @objectstack/spec)
  • content/docs/ui/actions.mdx (via @objectstack/spec)
  • content/docs/ui/audience-based-interfaces.mdx (via packages/plugins/plugin-security)
  • content/docs/ui/create-vs-edit-form.mdx (via @objectstack/spec)
  • content/docs/ui/dashboards.mdx (via @objectstack/plugin-security, @objectstack/spec)
  • content/docs/ui/forms.mdx (via @objectstack/spec)
  • content/docs/ui/index.mdx (via @objectstack/spec)
  • content/docs/ui/public-data-collection.mdx (via @objectstack/spec)
  • content/docs/ui/setup-app.mdx (via @objectstack/spec)
  • content/docs/ui/translations.mdx (via @objectstack/spec)
  • content/docs/ui/views.mdx (via @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.

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

Labels

protocol:data size/m skip-changeset PR has no user-facing published change; bypasses the changeset gate tests

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants