Skip to content

feat(objectql,runtime,lint): tighten views: to the container-only contract; assembled manifests travel non-container view artifacts in viewItems: - #8572

Merged
qq9340100 merged 7 commits into
mainfrom
claude/issue-5320-views-vocabulary-and-tighten
Aug 13, 2026
Merged

feat(objectql,runtime,lint): tighten views: to the container-only contract; assembled manifests travel non-container view artifacts in viewItems:#8572
qq9340100 merged 7 commits into
mainfrom
claude/issue-5320-views-vocabulary-and-tighten

Conversation

@qq9340100

Copy link
Copy Markdown
Collaborator

Fixes#5320. Fixes#8070.

Stacked on #8564 (the spec vocabulary, claude/issue-5320-spec-view-vocabulary) — this branch contains those commits; land #8564 first and this PR's diff reduces to the consumer half. The Fixes #8070 claim is made because the export half is complete here: the exporter partitions, and the export→import round trip is probed end to end (below).

The ruled sequence (2026-08-12 fork ruling: option B + A's mechanical half, then the tighten)

  1. B — the vocabulary — in feat(spec): declare the viewItems channel — a portable home for non-container view artifacts in runtime-assembled manifests #8564 (AssembledViewArtifactSchema, partitionAssembledViewArtifacts, isViewContainerShaped, the machine-only viewItems: key).
  2. A's mechanical half (packages/runtime/src/domains/packages.ts): GET /packages/:id/export partitions view artifacts — containers in views:, expanded items the container re-derives exactly are folded away, standalone ViewItems / overlays / edited expansions travel in viewItems:.
  3. The tighten (packages/objectql/src/engine.ts, registerMetadataCollections — the single body both seams run, [finding] the nested-plugin seam does not expand an aggregated views container — a nested plugin's per-view items never reach the registry, so getViewsByObject() / GET /meta/view?object= answer with the container alone #7163 kept): a non-container views: entry is refused with the ADR-0112 envelope (INVALID_METADATA / 422) and the wrap-it prescription; viewItems: entries are validated against AssembledViewArtifactSchema and the parsed body registers — declared = enforced in both directions. The judgement is deliberately shape-class (the same isViewContainerShaped the producers partition with), not a full ViewSchema.parse: which class an entry belongs to is this seam's contract; container internals stay the authoring/publish doors' job.
  4. Third-gate alignment (packages/lint/src/validate-view-containers.ts): a viewKind-bearing views: entry is now an error with the wrap-it prescription (previously skipped as "registered as-is" — a description of the undeclared wider acceptance, not of the contract); a hand-authored viewItems: is flagged machine-assembled-only, so os lint (which never parses) reaches the schema's verdict too.

Fixture disposition (ruled, verbatim)

engine-nested-plugin-view-expansion.test.ts:204-226 — the #7163 control block pinning "a standalone ViewItem registers as-is through both seams" — is replaced wholesale with the rejection pin: both seams refuse with code + status + prescription, the same artifact is accepted through viewItems:, and an undeclared bag in viewItems: is refused with the envelope. Not deleted, not loosened.

Fixture sweep by the rule's consumption radius: multiline grep for views: [ … viewKind … ] across packages/**, examples/**, apps/**, scripts/** — the only hits were the two files this PR updates. No other fixture feeds a non-container entry through the narrowed seam.

Acceptance measurements (the fork's probes, inverted — executed against built dists, directions predicted first)

P1 round-trip all-entries-land: PASS source=account,account.default,account.form,account.hot
target=account,account.default,account.form,account.hot
folded=account.default,account.form
P2 standalone survives export→import: PASS
P3 authored bare ViewItem in views: refused (INVALID_METADATA/422 + defineView prescription): PASS

Also pinned as tests: engine-assembled-views-roundtrip.test.ts (the end-to-end round trip through the real loop on both ends), and reverse verification run from the committed state — restoring origin/main's engine.ts turned exactly the predicted 7 tests red (3 refusal pins, 2 channel tests, 2 round-trip) and left the 9 expansion/parity tests green.

Verification (real numbers)

  • @objectstack/spec — 395 files / 10502 tests + typecheck green (on the stacked base)
  • @objectstack/objectql — 201 files / 3556 tests + typecheck green
  • @objectstack/runtime — 154 files / 2366 tests + typecheck green
  • @objectstack/lint — 72 files / 2017 tests + typecheck green
  • @objectstack/cloud-connection (marketplace-install suites incl. marketplace-install-local-bundle) — 19 files / 138 tests green
  • Corpus validate ×3: app-crm, app-showcase, app-todo — all Validation passed
  • Gate families (derived via dispatch-gates.mjs over the changed paths): check:cross-package-test-inputs, check:durability-log-level, check:error-code-casing, check:route-envelope, check:stack-collection-maps, check:engine-split-ratio, check:query-options-erasure, check:type-check-coverage, check:doc-formula-expressions, check:merge-driver, check:spec-parsed-alias, check:type-source-resolution — all green locally.

Migration consequence, stated plainly

A manifest assembled by an older runtime (an export product carrying expanded viewKind items inside views:) is refused on import with the prescription (re-export with a runtime that writes viewItems:). The marketplace rehydrate loop catches per-entry errors, so a stale cached manifest logs an error at boot instead of aborting boot. Authored stacks are unaffected — defineStack already refused every shape the loop now refuses. Cross-repo residual: the cloud repo's artifact-kernel-factory assembles env artifacts from the same registry reads; it must adopt partitionAssembledViewArtifacts before cloud envs carrying expanded items boot against a runtime with this tighten — filed as a follow-up issue and flagged for the landing relay.

Not addressed here, deliberately: ARTIFACT_FIELD_TO_TYPE (the packages/metadata compiled-artifact ingest) does not map viewItems — compiled artifacts come from objectstack build over authored stacks (containers only, post-defineStack), so no producer emits the key on that path today; adding it there widens what a sealed runtime serves and per the #6242 gate's own waiver discipline needs its own measured change.

Generated by Claude Code


Generated by Claude Code

…facts in assembled manifests (#5320)
Option B of the 2026-08-12 fork ruling on #5320: runtime-assembled manifests
(package export, environment artifacts) get a DECLARED home for the view
artifacts the authored stack vocabulary refuses — expanded viewKind items,
tenant-authored standalone ViewItems, flattened overlays.
- AssembledViewArtifactSchema: the non-container branches of the view metadata
vocabulary, built from VIEW_METADATA_MEMBERS minus container (no drift).
- partitionAssembledViewArtifacts: producer-side re-aggregation (A's mechanical
half) — containers travel in views:, exactly-derivable expanded items fold
away, everything else travels in viewItems:.
- ObjectStackDefinition.viewItems: declared always-refusing (machine-assembled
only) so a hand-authored viewItems fails tsc and parse with the prescription
instead of being silently stripped.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012MNV7ZSCjNfA38eDCjsXQL
…lias, root re-exports, INVALID_METADATA provenance row (#5320)
- isViewContainerShaped: ONE classifier for producers (partition) and the
consumer (the registration loop's views: tighten) — two classifiers would let
an assembler emit an entry the importer refuses.
- AssembledViewArtifactParsed (ADR-0122 alias convention).
- Root index re-exports the assembled-views vocabulary (the engine imports
from the package root).
- ERROR_CODE_LEDGER: INVALID_METADATA provenance row under @objectstack/objectql
(third emitter — the views: tighten and the viewItems: channel refuse 422).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012MNV7ZSCjNfA38eDCjsXQL
…xport partition + lint alignment (#5320)
- engine.ts registerMetadataCollections: non-container views: entries refused
(INVALID_METADATA/422, wrap-it prescription); viewItems: entries validated
against AssembledViewArtifactSchema and registered parsed (both seams, one
body — #7163 kept).
- runtime assemblePackageManifest: views partitioned via
partitionAssembledViewArtifacts — containers in views:, derivable expansions
folded, the rest in viewItems:.
- lint validate-view-containers: viewKind entries in views: now error with the
wrap-it prescription; hand-authored viewItems: flagged machine-assembled-only.
- engine-nested-plugin-view-expansion.test.ts: the #7163 control block replaced
WHOLESALE with the rejection pin (code+status), per the ruled fixture
disposition; new engine-assembled-views-roundtrip.test.ts runs the fork's
acceptance probes inverted (round trip end-to-end through the new channel).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012MNV7ZSCjNfA38eDCjsXQL
@vercel

vercelBot commented Aug 13, 2026

Copy link
Copy Markdown

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

1 Skipped Deployment
ProjectDeploymentActionsUpdated (UTC)
objectstackIgnoredIgnoredAug 13, 2026 10:41pm

Request Review

@github-actions

github-actionsBot commented Aug 13, 2026

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 3 package(s): @objectstack/lint, @objectstack/objectql, @objectstack/runtime.

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

  • content/docs/api/client-sdk.mdx(via packages/runtime)
  • content/docs/api/index.mdx(via @objectstack/runtime)
  • content/docs/api/wire-format.mdx(via @objectstack/runtime)
  • content/docs/automation/hook-bodies.mdx(via @objectstack/lint, @objectstack/runtime)
  • content/docs/concepts/metadata-lifecycle.mdx(via @objectstack/objectql, @objectstack/runtime)
  • content/docs/concepts/north-star.mdx(via packages/runtime)
  • content/docs/data-modeling/drivers.mdx(via @objectstack/runtime)
  • content/docs/data-modeling/formulas.mdx(via packages/objectql)
  • content/docs/deployment/index.mdx(via @objectstack/runtime)
  • content/docs/deployment/migration-from-objectql.mdx(via @objectstack/objectql)
  • content/docs/deployment/production-readiness.mdx(via @objectstack/runtime)
  • content/docs/deployment/single-project-mode.mdx(via @objectstack/runtime)
  • content/docs/deployment/validating-metadata.mdx(via packages/lint)
  • content/docs/deployment/vercel.mdx(via @objectstack/objectql, @objectstack/runtime)
  • content/docs/getting-started/your-first-project.mdx(via @objectstack/runtime)
  • content/docs/kernel/cluster.mdx(via @objectstack/runtime)
  • content/docs/kernel/contracts/data-engine.mdx(via @objectstack/objectql)
  • content/docs/kernel/runtime-services/examples.mdx(via packages/objectql)
  • content/docs/kernel/services-checklist.mdx(via @objectstack/objectql)
  • content/docs/kernel/services.mdx(via @objectstack/objectql)
  • content/docs/permissions/authentication.mdx(via @objectstack/objectql, @objectstack/runtime)
  • content/docs/permissions/authorization.mdx(via @objectstack/lint, packages/runtime)
  • content/docs/permissions/system-context.mdx(via packages/objectql, packages/runtime)
  • content/docs/plugins/index.mdx(via @objectstack/objectql)
  • content/docs/plugins/packages.mdx(via @objectstack/objectql, @objectstack/runtime)
  • content/docs/protocol/kernel/http-protocol.mdx(via @objectstack/runtime)
  • content/docs/protocol/kernel/index.mdx(via @objectstack/objectql, @objectstack/runtime)
  • content/docs/protocol/kernel/lifecycle.mdx(via @objectstack/runtime)
  • content/docs/protocol/objectql/query-syntax.mdx(via packages/objectql)
  • content/docs/protocol/objectql/state-machine.mdx(via @objectstack/objectql)

2 release-owned page(s) also reference the affected code. These are read-only:

  • content/docs/releases/implementation-status.mdx(via @objectstack/objectql, @objectstack/runtime)
  • content/docs/releases/v17.mdx(via @objectstack/lint, @objectstack/runtime)

content/docs/releases/ is RELEASE-OWNED (AGENTS.md "Documentation Guardrails"): release
notes are written centrally at release time, and a code PR that edits them is the exact PR
that guardrail exists to stop. They are still audited — read-only. If one of them is actually
wrong, file an issue or open a dedicated docs-only PR; do not edit it here.

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.

@qq9340100
qq9340100 marked this pull request as ready for review August 13, 2026 23:18
@qq9340100
qq9340100 added this pull request to the merge queueAug 13, 2026
Merged via the queue into main with commit 89be40cAug 13, 2026
27 checks passed
@qq9340100
qq9340100 deleted the claude/issue-5320-views-vocabulary-and-tighten branch August 13, 2026 23:31
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment