Skip to content

fix(spec): systemFields.owner guidance no longer claims ownership: 'org' picks a principal (#6365) - #6423

Merged
os-project-manager merged 1 commit into
mainfrom
claude/issue-6365-systemfields-owner-guidance
Aug 7, 2026
Merged

fix(spec): systemFields.owner guidance no longer claims ownership: 'org' picks a principal (#6365)#6423
os-project-manager merged 1 commit into
mainfrom
claude/issue-6365-systemfields-owner-guidance

Conversation

@os-project-manager

Copy link
Copy Markdown
Collaborator

Fixes #6365

The defect

packages/spec/src/data/object.zod.ts, in the systemFields strictObject's guidance block — the message an author gets when they write the non-existent systemFields: { owner: ... } key — said:

owner_id injection is governed by the object-level ownership property (ownership: 'none' skips it; 'user'/'org' choose the principal).

The second half is false. ownership: 'org' does not choose a different principal; it injects no owner_id at all. The authority applySystemFields consumes — resolveInjectedSystemColumns in packages/spec/src/data/injected-system-columns.ts — admits exactly two spellings:

const owner = ownershipEligible && (ownership === undefined || ownership === 'user');

The ownership property's own JSDoc, ~90 lines above the guidance, already stated it correctly (org / none — no per-record owner; owner_id is NOT injected). So the guidance contradicted a sibling stanza in the same file, and the guidance was the wrong side.

Why it was worth fixing

This is not dormant prose. It is the error text an author — or an AI writing metadata — is handed at the exact moment they are already confused about where owner injection is configured, and it sent them to ownership: 'org' expecting an owner column keyed to the organization. Nothing rejects ownership: 'org', so the mistake ships silently and every owner-keyed feature quietly does nothing: owner-scoped RLS, "My" views, owner reports, the first-admin bootstrap handoff. That is the failure mode the surrounding guidance machinery exists to prevent, inverted — a wrong-key rescue handing out a second wrong answer.

What changed

Two strings, nothing else.

guidance.owner now states the rule as the authority implements it: 'user' (or omitted) injects owner_id, while 'org' and 'none' both skip it and no owner_id is injected at all. The two skipping values stay visibly distinct in intent ('org' for an org-wide catalog, Dataverse-style; 'none' for a junction/link table), since that distinction is the reason the enum carries both.

guidance.ownership is widened in the same pass. It was not wrong, only out of date: since #5677 / ADR-0117 D1 the ownership property governs both record-ownership anchors, so the message now says it decides whether owner_id and owning_business_unit_id are injected, rather than naming only the first.

Deliberately untouched per the issue's scope ruling: the ownership enum's own error text and describe() (#5678's surface), and any mention of the business_unit tier.

The acceptance surface does not move

Text only. Every value ObjectSchema accepted before is accepted now, every value it rejected is still rejected, and the injection behaviour is untouched. git status after a full build carries only the three files in this diff — in particular authorable-surface.base.json is byte-identical and content/docs/references/** did not regenerate, which confirms the expectation that a guidance string is an error-message template rather than a .describe() input.

Tests

The batch-20 pin gains two cases. They assert the message's substance against resolveInjectedSystemColumns rather than echoing the sentence, so the prescription can only stay green while it still describes what the injection pass really does:

  • 'org' and 'none' both resolve owner: false, 'user' and omitted resolve owner: true — and the message names the two skipping values together, states the absence as an absence, keeps them distinct in intent, and no longer contains the word principal.
  • Across the whole authorable enum the two anchors move together (plan.owningBusinessUnit === plan.owner) — and the message names both.

Reverse verification, direction predicted before running: red. Restoring the old string turns exactly those two new cases red and leaves the other 43 in the file green, so the pins are load-bearing and additive rather than a re-spelling of an existing assertion.

× `systemFields.owner`'s prescription matches the injection authority … (#6365)
× `systemFields.ownership` names BOTH ownership anchors … (#6365)
Tests  2 failed | 43 passed (45)

With the fix in place:

pnpm --filter @objectstack/spec test
Test Files  338 passed (338)
     Tests  8651 passed (8651)

pnpm --filter @objectstack/spec typecheck   →  PASS (tsc --noEmit + tsconfig.test.json)
pnpm --filter @objectstack/spec check:generated  →  All 10 generated artifacts are up to date.

Gates enumerated from .github/workflows/lint.yml and run one by one: all 30 ESLint-job check:* steps pass, plus the TypeScript-job set (type-check-coverage, driver-conformance, stall-guard, skill-frame-sync, skill-compatibility, exported-any, dual-source-exports, skill-examples, doc-formula-expressions, type-check-debt, i18n, i18n-coverage) and pr-automation.yml's check-adr-0087-registration (0 declared-breaking changesets — this is a patch).

One note on build state: check:i18n and check:i18n-coverage first reported red in the fresh worktree because they run the built CLI, which did not exist yet. Both are green after turbo run build — the AGENTS.md §9 stale/absent-artefact trap, not a finding.

Changeset

.changeset/systemfields-owner-guidance-org-skips-owner-id.md@objectstack/spec: patch. An author-visible error-message change earns a real changeset; no ADR-0087 marker is required because nothing is declared breaking.


Generated by Claude Code

… 'org'` picks a principal (#6365)

The `guidance.owner` prescription on the `systemFields` strictObject said
`'user'`/`'org'` "choose the principal". That is false: `'org'` injects no
`owner_id` at all. The authority `applySystemFields` consumes —
`resolveInjectedSystemColumns` — admits exactly `undefined` and `'user'`:

    const owner = ownershipEligible && (ownership === undefined || ownership === 'user');

and the `ownership` JSDoc ~90 lines above already said so correctly, so the
guidance was the wrong side of a contradiction inside one file.

It matters because this is the text an author (or an AI writing metadata) is
handed at the moment they are already confused about where owner injection is
configured. It sent them to `ownership: 'org'` expecting an org-keyed owner
column; nothing rejects that value, so the mistake ships and every owner-keyed
feature quietly does nothing.

The sibling `guidance.ownership` message is widened in the same pass — not
wrong, only out of date: since #5677 / ADR-0117 D1 the property governs both
ownership anchors, so it now names `owning_business_unit_id` alongside
`owner_id`.

Text only — the acceptance surface does not move. `check:generated` is green
with no artifact rewritten (these are error-message templates, not
`.describe()` inputs, so `content/docs/references/**` does not regenerate, and
`authorable-surface.base.json` is byte-identical).

Tests: the batch-20 pin gains two cases that assert the message's SUBSTANCE
against `resolveInjectedSystemColumns` rather than echoing the sentence.
Reverse-verified in the predicted direction: restoring the old string turns
exactly those two red and leaves the other 43 green.

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

vercel Bot commented Aug 7, 2026

Copy link
Copy Markdown

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

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
objectstack Ignored Ignored Aug 7, 2026 5:31pm

Request Review

@github-actions

github-actions Bot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 1 package(s): @objectstack/spec.

112 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 @objectstack/spec)
  • content/docs/automation/connectors.mdx (via @objectstack/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 packages/spec)
  • content/docs/concepts/north-star.mdx (via @objectstack/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 @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/cli.mdx (via @objectstack/spec)
  • content/docs/deployment/tenancy-modes.mdx (via @objectstack/spec)
  • content/docs/deployment/troubleshooting.mdx (via @objectstack/spec)
  • content/docs/deployment/validating-metadata.mdx (via @objectstack/spec)
  • content/docs/getting-started/build-with-claude-code.mdx (via @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/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 @objectstack/spec)
  • content/docs/kernel/index.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/data-service.mdx (via @objectstack/spec)
  • content/docs/kernel/runtime-services/email-service.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/examples.mdx (via @objectstack/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 @objectstack/spec)
  • content/docs/kernel/runtime-services/sms-service.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/storage-service.mdx (via @objectstack/spec)
  • content/docs/kernel/services-checklist.mdx (via @objectstack/spec)
  • content/docs/kernel/services.mdx (via @objectstack/spec)
  • content/docs/permissions/authorization.mdx (via @objectstack/spec)
  • content/docs/permissions/permission-sets.mdx (via @objectstack/spec)
  • content/docs/permissions/permissions-matrix.mdx (via @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/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/spec)
  • content/docs/plugins/packages.mdx (via @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/http-protocol.mdx (via @objectstack/spec)
  • content/docs/protocol/kernel/i18n-standard.mdx (via @objectstack/spec)
  • content/docs/protocol/kernel/index.mdx (via @objectstack/spec)
  • content/docs/protocol/kernel/lifecycle.mdx (via @objectstack/spec)
  • content/docs/protocol/kernel/plugin-spec.mdx (via @objectstack/spec)
  • content/docs/protocol/knowledge.mdx (via @objectstack/spec)
  • content/docs/protocol/objectql/index.mdx (via @objectstack/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 @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/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/v16.mdx (via @objectstack/spec)
  • content/docs/releases/v17.mdx (via @objectstack/spec)
  • content/docs/releases/v9.mdx (via @objectstack/spec)
  • content/docs/ui/actions.mdx (via @objectstack/spec)
  • content/docs/ui/apps.mdx (via @objectstack/spec)
  • content/docs/ui/create-vs-edit-form.mdx (via @objectstack/spec)
  • content/docs/ui/dashboards.mdx (via @objectstack/spec)
  • content/docs/ui/field-grouping-and-order.mdx (via @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.

@github-actions github-actions Bot added size/m documentation Improvements or additions to documentation protocol:data tests tooling labels Aug 7, 2026
@os-project-manager
os-project-manager marked this pull request as ready for review August 7, 2026 19:12
@os-project-manager
os-project-manager added this pull request to the merge queue Aug 7, 2026
Merged via the queue into main with commit be87153 Aug 7, 2026
26 checks passed
@os-project-manager
os-project-manager deleted the claude/issue-6365-systemfields-owner-guidance branch August 7, 2026 19:25
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:data size/m tests tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[spec] systemFields owner guidance misstates ownership: 'org' — tells authors org "chooses the principal" when it injects no owner_id at all

2 participants