Skip to content

refactor(spec)!: view.exportOptions adopts the object form the renderer reads; 'pdf' leaves the format enum (#8010) - #8324

Merged
hotlong merged 3 commits into
mainfrom
claude/issue-8010-exportoptions-object-form
Aug 13, 2026
Merged

refactor(spec)!: view.exportOptions adopts the object form the renderer reads; 'pdf' leaves the format enum (#8010)#8324
hotlong merged 3 commits into
mainfrom
claude/issue-8010-exportoptions-object-form

Conversation

@hotlong

Copy link
Copy Markdown
Contributor

Fixes#8010

What

view.exportOptions adopts the object form the renderer actually reads (maintainer ruling 2026-08-12, on-card comment 5270998514, option A), and 'pdf' leaves the format enum (PDF export was declined as #1301, NOT_PLANNED; that decision is unchanged here).

  • Object form is the contract: { formats?, maxRecords?, includeHeaders?, fileNamePrefix?, streaming? } — a strict object declaring exactly the five keys the only renderer reads, re-measured on objectui origin/main@878140b (ObjectGrid.tsx:1596–1642): formats (:1596, :1605), the previously undeclaredstreaming opt-out (:1600, :1642), maxRecords (:1621), includeHeaders (:1622), fileNamePrefix (:1631). The measurement matches the ruling's five-key claim exactly; no undeclared-but-read key survives.
  • Back-compat normalization: the legacy bare format array stays accepted and lifts to { formats: [...] } at parse (z.input keeps both spellings; z.output is the object form only — ListView is z.input, ListViewParsed is z.infer, both stay coherent by construction).
  • 'pdf' removal is an enum-VALUE narrowing (the crypto.hash precedent): the format enum's error map carries the prescription keyed on issue.input, so only the spelling that used to be legal is told it "was removed"; a union-level error dispatch makes the refusal the top-level parse message in either authored form, naming [P1] export: no print / PDF export — procurement orders & audit reports cannot be delivered #1301 and the surviving formats. Not a runtime console.warn.
  • ADR-0087 kit: conversion view-export-options-pdf-removed (D2) + step-17 wiring (D3); retiredFromLoadPath — stored pre-removal rows replay clean, os migrate meta --from 16 rewrites author sources. The conversion strips only 'pdf' and deliberately does not rewrite the array spelling (back-compat, not retired). No RETIRED_KEYS_BY_MAJOR entry — an enum value is not a key, so there is no tombstone line for gate (b) to read (same as hook-body-crypto-hash-removed); the four existence ratchets are byte-identical by design for a value narrowing (crypto.hash 能力声明了、构建期还会自动推断,但沙箱从没实现 —— 调用直接抛(declared ≠ enforced) #4391 precedent).
  • Liveness view.json row re-cited to the five measured reads and re-dated; docs table + generated references updated; both example apps moved to the canonical object form (which the current renderer actually reads — the examples' XLSX menu entry was dead under the array spelling).

Scope

Spec half only, per the ruling's contract-first split: the objectui renderer/type reconciliation (the false "Aligned with @objectstack/spec" comment at types/src/objectql.ts:783–785, the as any streaming read, 'pdf' in its local type) is the PM-filed follow-up card on that repo. objectui was touched read-only for measurement.

File surface kept to the ListViewSchemaexportOptions block in view.zod.ts (plus the new module-level consts it needs), the conversion/migration registries, liveness note, changeset, tests, docs, examples. The FormSectionSchema / PageComponentSchema blocks and the shared strict-options plumbing are untouched.

Landing serialization: current origin/main (2a18012) is merged in; if #8201/#8202 (branch claude/issue-8202-per-shape-guidance-completion, same file, disjoint region) lands first, this branch re-merges before landing.

Verification

  • New pins (7): object form byte-preserved with all five keys; array lift asserted on output; 'pdf' refused in both spellings with the prescription (message substance asserted: the removal sentence, [P1] export: no print / PDF export — procurement orders & audit reports cannot be delivered #1301, the survivors, the migrate sentence); a never-legal format keeps the plain enum message (no false "was removed"); unknown key on the object form gets the strict-surface suggestion; ObjectListViewSchema copy behaves identically.
  • Reverse verification (direction predicted before running): restoring the old bare-array declaration turned exactly 6 of the 7 pins red (the never-legal-format pin is green in both worlds by design); restored byte-identical from the committed fix and re-ran green.
  • Spec suite 388 files / 10258 tests green; spec typecheck green; conversions/migrations suites green (fixture disjointness + chain replay); consumer suites (downstream direction) and both example apps' typecheck: see report comment on spec: ListView.exportOptions is typed as a bare array, but the only renderer reads exportOptions.formats #8010 for per-package readings.
  • check:generated green after regenerating exactly the four proved-stale artifacts (spec-changes, upgrade-guide, references, strictness-ledger counts); full derived gate list green except two pre-existing non-PR gates (objectui pin freshness — blocks the Version Packages PR only; dev-prereqs — local stale-dist advisory).

Generated by Claude Code

…ves the format enum (#8010)
Option A per the maintainer ruling of 2026-08-12 (comment 5270998514):
- object form declares exactly the five renderer-read keys measured on
objectui origin/main@878140b (formats, maxRecords, includeHeaders,
fileNamePrefix, streaming)
- legacy bare array stays accepted and lifts to { formats } at parse
- 'pdf' removed as an enum-VALUE narrowing (crypto.hash precedent): enum
error map + union-level dispatch carry the prescription naming #1301
and the surviving formats
- ADR-0087 conversion view-export-options-pdf-removed + step-17 wiring
- liveness note re-cited, docs table + examples moved to the object form
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Euoy6wyfzgiWtgCg4s6JK2
…trictness-ledger counts for #8010
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Euoy6wyfzgiWtgCg4s6JK2
@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 5:32am

Request Review

@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

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

106 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/permissions/system-context.mdx(via packages/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/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)

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

  • 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/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.

@github-actionsgithub-actionsBot added documentation Improvements or additions to documentation tests protocol:ui tooling labels Aug 13, 2026
@hotlong
hotlong marked this pull request as ready for review August 13, 2026 05:52
@hotlong
hotlong added this pull request to the merge queueAug 13, 2026
Merged via the queue into main with commit ddd0f06Aug 13, 2026
27 checks passed
@hotlong
hotlong deleted the claude/issue-8010-exportoptions-object-form branch August 13, 2026 06:09
os-zhuang pushed a commit that referenced this pull request Aug 13, 2026
…8315)
The merge with main was textually conflict-free, but a conflict-free merge of
two independently-regenerated projections is not the generator's output.
Measured on this tree: the plain merge result was MISSING two sibling PRs'
entries from `spec-changes.json` and `docs/protocol-upgrade-guide.md` —
`view-export-options-pdf-removed` (#8010 / PR #8324) and
`engine-dotted-projection-refused` (#7589 / PR #8327). Both are present in
origin/main's copies of those artifacts; git dropped them while reporting no
conflict.
`registry.ts` spliced correctly and regenerated byte-identical (78 semantic
entries) — the loss was confined to the two prose projections.
Not a silent class: against the un-regenerated merge, `check:spec-changes` and
`check:upgrade-guide` both FAIL (exit 1) while `check:migration-registry`
passes. So this would have been caught — in the merge queue, as an ejection.
Regenerating before arming is what makes it cost nothing.
Ran on the merged tree, merge committed first:
pnpm --filter @objectstack/spec gen:migration-registry
pnpm --filter @objectstack/spec gen:spec-changes
pnpm --filter @objectstack/spec gen:upgrade-guide
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PEVB6w7D7uCszR9Mw1BL73
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentationImprovements or additions to documentationprotocol:uisize/mteststooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

spec: ListView.exportOptions is typed as a bare array, but the only renderer reads exportOptions.formats

2 participants

@hotlong@claude