Skip to content

feat(spec)!: strict view/page schemas — mis-layered visibility keys are loud errors (ADR-0089 D3a) - #2943

Merged
os-zhuang merged 2 commits into
mainfrom
claude/adr-0089-visibility-schema-q7gz10
Jul 15, 2026
Merged

feat(spec)!: strict view/page schemas — mis-layered visibility keys are loud errors (ADR-0089 D3a)#2943
os-zhuang merged 2 commits into
mainfrom
claude/adr-0089-visibility-schema-q7gz10

Conversation

@os-zhuang

Copy link
Copy Markdown
Contributor

Implements ADR-0089 D3a (#2902) — the final enforcement leg of the visibility-predicate unification.

What & why

FormFieldSchema, FormSectionSchema (view.zod.ts) and PageComponentSchema (page.zod.ts) run zod's default strip mode, so a key they don't declare — a visibleWhen typo, a page-only visibility pasted onto a view field (or vice-versa), or a key surviving past its deprecation window — is silently dropped, shipping inert metadata with no diagnostic. For an AI author that's the worst failure mode: no signal to self-correct from (ADR-0049 enforce-or-remove, ADR-0078 no-silently-inert).

This flips those three schemas to .strict(), so a mis-layered / stale key is a loud parse error.

Changes

  • .strict() on the three view/page schemas (before the existing normalizeVisibleWhen transform).
  • strictVisibilityError — a new zod error map (shared/visibility) wired as each schema's error. It names the offending key(s) and, when a key looks like the conditional-visibility predicate, points the author at the canonical visibleWhen (noting visibleOn / visibility remain accepted aliases). Mirrors the UNKNOWN_KEY_GUIDANCE tombstone precedent in object.zod.ts.
  • Back-compat preserved: the deprecated visibleOn / visibility aliases are declared keys, so .strict() keeps accepting them and they still normalize to visibleWhen (D2 unchanged).

Blast-radius sweep (ADR requires sweep-before-flip)

Built the full monorepo and ran every metadata-parsing consumer suite under strict. The entire framework + examples surfaced exactly one offender:

  • objectqlprotocol-meta.test.ts fixture lead_form_only used { id, title } on a form section instead of the canonical { name, label } — those keys were being silently stripped (the test only asserted success). Fixed to name/label.

Everything else — app-showcase (4 views / 28 pages), app-crm, platform-objects, metadata-core, rest, cli, metadata-protocol, sdui-parser, mcp, core, dogfood — is green under strict, and the showcase compiles to objectstack.json cleanly.

Tests

New ADR-0089 D3a describe blocks in view.test.ts and page.test.ts: strict rejects an unknown key; a visibility-ish typo is rejected with a message pointing at visibleWhen; a non-visibility unknown key is rejected without the hint; the deprecated aliases still parse; cross-layer aliases (visibility on a view field, visibleOn on a page component) are rejected. Full spec suite green (6787 passed); tsc --noEmit clean.

Release

Ships as a major@objectstack/spec15.0.0 (MAJOR changeset included). ADR-0089 status flipped to reflect D3a done; layout-dsl.mdx documents the strict behavior.

Follow-up (separate)

The sibling objectui repo consumes @objectstack/spec; it should pick up the 15.0.0 bump on its own release cycle. objectui parses the pre-compiled objectstack.json artifact (already validated) rather than re-parsing through these schemas at runtime, so no break is expected — but the bump should be verified there when it lands.

Parent: #2642 · builds on #2900 (D1/D2/D3b) · sibling #2904 (renderers, merged via objectstack-ai/objectui#2490).

🤖 Generated with Claude Code

https://claude.ai/code/session_01R7oGohmS4pT9H73zoV6Jdb


Generated by Claude Code

…re loud errors (ADR-0089 D3a)
BREAKING CHANGE: FormFieldSchema, FormSectionSchema (view.zod.ts) and
PageComponentSchema (page.zod.ts) are now `.strict()`. A key these schemas
do not declare — a `visibleWhen` typo, a page-only `visibility` on a view
field (or vice-versa), or a stale key past its deprecation window — was
silently dropped by zod's default strip mode, shipping inert metadata with
no diagnostic (ADR-0049 enforce-or-remove, ADR-0078 no-silently-inert). It
is now a loud parse error.
- Deprecated `visibleOn` / `visibility` aliases are declared keys, so they
keep parsing and normalizing to `visibleWhen` (D2 unchanged).
- New `strictVisibilityError` zod error map (shared/visibility) names the
offending key(s) and, when one looks like the visibility predicate, points
the author at the canonical `visibleWhen`.
- Monorepo + examples sweep found one offender: an objectql test fixture
using `id`/`title` on a form section instead of `name`/`label` — fixed.
Ships as a major (`@objectstack/spec` 15.0.0). Full spec suite green
(6787), plus showcase/crm/platform-objects/objectql/metadata/rest/cli/
dogfood suites green under strict.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01R7oGohmS4pT9H73zoV6Jdb
@vercel

vercelBot commented Jul 15, 2026

Copy link
Copy Markdown

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

ProjectDeploymentActionsUpdated (UTC)
specReadyReadyPreview, CommentJul 15, 2026 3:45am

Request Review

@github-actionsgithub-actionsBot added documentation Improvements or additions to documentation tests protocol:ui tooling size/m labels Jul 15, 2026
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 2 package(s): @objectstack/objectql, @objectstack/spec.

102 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/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/authentication.mdx(via @objectstack/objectql)
  • 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/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/objectql, @objectstack/spec)
  • content/docs/plugins/packages.mdx(via @objectstack/objectql, @objectstack/spec)
  • content/docs/protocol/backward-compatibility.mdx(via @objectstack/spec)
  • content/docs/protocol/diagram.mdx(via packages/spec)
  • content/docs/protocol/knowledge.mdx(via @objectstack/spec)
  • content/docs/protocol/objectos/config-resolution.mdx(via @objectstack/spec)
  • content/docs/protocol/objectos/i18n-standard.mdx(via @objectstack/spec)
  • content/docs/protocol/objectos/index.mdx(via @objectstack/objectql)
  • content/docs/protocol/objectos/lifecycle.mdx(via @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/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/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/create-vs-edit-form.mdx(via @objectstack/spec)
  • content/docs/ui/dashboards.mdx(via @objectstack/spec)
  • content/docs/ui/forms.mdx(via @objectstack/spec)
  • content/docs/ui/index.mdx(via @objectstack/spec)
  • content/docs/ui/setup-app.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.

Additive-only public API change (0 breaking, 1 added) from the new
`strictVisibilityError` export (ADR-0089 D3a). Regenerated via
`pnpm --filter @objectstack/spec gen:api-surface`.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01R7oGohmS4pT9H73zoV6Jdb
@os-zhuang
os-zhuang marked this pull request as ready for review July 15, 2026 04:47
@os-zhuang
os-zhuang merged commit 28b7c28 into mainJul 15, 2026
17 checks passed
@os-zhuang
os-zhuang deleted the claude/adr-0089-visibility-schema-q7gz10 branch July 15, 2026 04:47
xuyushun441-sys pushed a commit that referenced this pull request Jul 17, 2026
…ole coverage
The previous revision under-covered the line in three ways, now fixed:
1. 15.0.0 was missing everything outside the ADR-0095 theme from the
14.8.0..15.0.0 range: the strict view/page schema BREAKING change
(ADR-0089 D3a, #2943) with its migration, the per-row import automation
chain + skipAutomations + runAutomations-default-ON behavior change
(#2922), the sys_position/sys_capability system-row write guardrail
(#2930), the bidirectional visibility lint (#2931), and the explain
posture-label alignment (#2949).
2. 15.0.0 had NO Console section at all, despite bundling the objectui 14.0
major (13.2.0→14.0.0, ~73 commits — first release-page disclosure since
much of it rode unversioned in the 14.8.0 pin): the ADR-0057 ChatDock
consolidation (including its breaking cleanup #2475), the Gantt batch,
lists/forms/auth/Studio/i18n enhancements, two security fixes
(#2485/#2410), and the six early-14.1 commits the 15.0.0 pin picked up.
3. The 15.1.0 sections were over-compressed; every domain is now expanded to
its full changeset detail, and the Console 14.1 section covers all eight
areas of the 94-commit range instead of seven bullets.
465 → ~1000 lines; structure mirrors v14.mdx (per-minor annotations inside
one major page, per docs/releases-maintenance.md).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
os-zhuang added a commit that referenced this pull request Jul 17, 2026
…ole coverage (#3082)
* docs(releases): expand v15 page to full 14.8→15.0→15.1 backend + Console coverage
The previous revision under-covered the line in three ways, now fixed:
1. 15.0.0 was missing everything outside the ADR-0095 theme from the
14.8.0..15.0.0 range: the strict view/page schema BREAKING change
(ADR-0089 D3a, #2943) with its migration, the per-row import automation
chain + skipAutomations + runAutomations-default-ON behavior change
(#2922), the sys_position/sys_capability system-row write guardrail
(#2930), the bidirectional visibility lint (#2931), and the explain
posture-label alignment (#2949).
2. 15.0.0 had NO Console section at all, despite bundling the objectui 14.0
major (13.2.0→14.0.0, ~73 commits — first release-page disclosure since
much of it rode unversioned in the 14.8.0 pin): the ADR-0057 ChatDock
consolidation (including its breaking cleanup #2475), the Gantt batch,
lists/forms/auth/Studio/i18n enhancements, two security fixes
(#2485/#2410), and the six early-14.1 commits the 15.0.0 pin picked up.
3. The 15.1.0 sections were over-compressed; every domain is now expanded to
its full changeset detail, and the Console 14.1 section covers all eight
areas of the 94-commit range instead of seven bullets.
465 → ~1000 lines; structure mirrors v14.mdx (per-minor annotations inside
one major page, per docs/releases-maintenance.md).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* docs(releases): note post-14.1 fixes carried by the final Console pin (#2615/#2617/#2619/#2620/#2621/#2623)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* docs(releases): add v15 to the releases index; mark v14 line final at 14.8.0
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
---------
Co-authored-by: Jack Zhuang <277994282+os-zhuang@users.noreply.github.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

allow-majordocumentationImprovements or additions to documentationprotocol:uisize/mteststooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@os-zhuang@claude