feat(types): derive ObjectSchemaMetadata from the spec's ServiceObject; settle listViews spelling (#5362) - #5860
Merged
Conversation
…ceObject (#5362) Retire the hand-written object-document mirror. The interface declared none of titleFormat/listViews/icon (all three read by the shipped runtime) while declaring nine members nothing reads and the spec does not know. Now: ObjectSchemaMetadata = ServiceObject & ObjectSchemaClientExtensions where the extension is the measured client delta ({ editMode } — read by app-shell recordFormNavigation/AppContent; rejected by the spec's strict parse, pinned in the new guard). Spelling settled per the spec artifact: listViews (camel) is canonical; list_views appears nowhere in spec 17.2.0. Guard: object-schema-metadata-spec-derivation.test.ts pins the structural derivation, the three keys, the snake-key absence, the nine retired members, and the extension surface.
#5362) The spec canonized camelCase `listViews` (snake `list_views` appears nowhere in @objectstack/spec 17.2.0). Settlement, subject to the stored-data caveat: - Producers: the CRUD guide's TaskSchema and its pinned transcription in guideCrudAppRenders.test.tsx now author `listViews`; console-architecture doc updated. objectui's own synth (MetadataProvider) already emitted camel. - Reads: every runtime dual-spelling read keeps its snake fallback — stored app data published before the settlement has never been censused (objectstack#7917), so retiring the READ blind is refused. Each site now documents the tolerance and forbids WRITING the snake key. - Pin: ElementDataSourceGate.test.tsx gains a compatibility test proving a snake-served document still resolves, so the fallback cannot be retired as a silent cleanup — removal needs the census as evidence. Changeset: types minor (surface change), app-shell/react patch.
Contributor
✅ Console Performance Budget
The eager closure is every chunk the entry reaches through static imports — what the browser fetches and parses before the app renders. The entry chunk on its own is a small fraction of it. 📦 Bundle Size Report
Size Limits
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #5362
Clause-②: yes— this is the consumer half of a ruled contract-first split; it moves@object-ui/types' published surface.Direction is the maintainer's 2026-08-20 ruling (reading 3, verbatim 「其他接受你的建议。」): the object document type belongs to
@objectstack/spec; objectui derives rather than hand-copies. The spec half was carved as objectstack-ai/objectstack#10144 (closed completed), which is what unblocked this card.What changed
packages/types/src/field-types.ts):ObjectSchemaMetadata = ServiceObject & ObjectSchemaClientExtensions, whereServiceObjectis@objectstack/spec/data's authoring shape (z.input) and the extension is the measured client delta — exactly{ editMode?: 'modal' | 'page' }, the one retired-mirror member with a live runtime read (app-shell/src/utils/recordFormNavigation.ts:57, routed byAppContent'shandleEdit). Same layer split as objectui#3074 (PageNodeSchema) and objectstack#4115 (ObjectIndex, in this very file).icon/titleFormat/listViews.extends,triggers,primary_key,relationships,name_field(spec spelling isnameField),soft_delete,audit_trail,version,cache. (ObjectSchemaMetadataitself had zero in-repo consumers — positive control: the grep corpus found its declaration and index re-export.)packages/types/src/__tests__/object-schema-metadata-spec-derivation.test.ts): pins the structural derivation (Equaltype assertion), the three keys (compile-time fixture + runtime spec-shape introspection with a live-corpus positive control), the snake-key absence (@ts-expect-error+ shape assertion), the nine retired members' absence (plusnameFieldpresence), the extension surface (keyofequality — growing it is a conscious promote-or-justify decision), and — measured during this work — that the spec's strict parse rejectseditModewithunrecognized_keys: ['editMode'](objectstack#4001 strictness), i.e. the extension is client-side only.TaskSchemaand its pinned transcription (plugin-grid/src/__tests__/guideCrudAppRenders.test.tsx) now authorlistViews;console-architecture.mdupdated. objectui's own synth (MetadataProvider) already emitted camelCase — producer check done per theReferenceRailEntryis owned by @objectstack/spec as of 17.1.0 and objectui's local copy declares an extraiconkey the spec's strict schema refuses #5494 lesson.ElementDataSourceGate.test.tsxgains a test proving a snake-served document still resolves, so the fallback cannot be retired as a silent cleanup — its removal needs the census as evidence.@object-ui/typesminor (surface change stated plainly, no major per the version-alignment convention), app-shell/react patch.Independent pin-gate + spelling measurement (with controls)
Verified at my base (
da8db03a6), against the artifact this worktree actually resolves (node_modules/@objectstack/spec, version 17.2.0; both packages declare^17.0.0):titleFormat: 66 occurrences indist/**/*.d.ts;iconandlistViewspresent in the object type's own key union (ObjectSchemaBaseatdist/object.zod-DE7xve55.d.ts).list_views(snake): 0 ·listViews(camel): 76 — matches the dispatch measurement exactly; same corpus serves as the positive control for the zero. The spec canonized camelCase.name/fieldsbefore any absence is asserted.Reverse verification (ablation, trap-guarded restore)
Mutation: replaced the derivation alias with a hand-written mirror (
/* ABLATION-5362 */marker). Disk-confirmed by anchored grep before each reading (marker count 1 / derivation-line count 0; editor exit codes not used as evidence). No build leg applies: the guard imports../field-types.jsrelatively andtsconfig.test.jsoncompiles source directly — the tsc run IS the consumption of the mutated bytes.pnpm --filter @object-ui/types type-check→ exit 2, six errors all inside the guard (Equalfails TS2344;listViews/icon/titleFormat/editModeTS2339 on the fixtures). Direction: compile half red as designed; the runtime (zod-introspection) half reads the spec artifact and is deliberately unaffected by a client-type ablation.git checkout <branch> -- <file>; anchored greps invert (marker 0 / derivation line 1);git diffvs the commit = 0 lines (byte identity); type-check exit 0.Verification at final HEAD
c77f01427(union re-run after the last commit)All heavy runs serialized through the shared verify lock; verdicts read from each gate's own printed line, exit codes captured before any pipe.
vitest run packages/types/ packages/react/ packages/plugin-grid/src/__tests__/guideCrudAppRenders.test.tsx→ Test Files 102 passed (102) · Tests 1275 passed (1275) (HEAD echoedc77f01427inside the same run).type-checkfor@object-ui/types,@object-ui/app-shell,@object-ui/react,@object-ui/plugin-grid→ each echoedtype-check: Done(script names confirmed; zero-match trap avoided).check-spec-symbol-derivation.mjs(thecheck:spec-symbolscarried by CI Type Check, directly relevant here) → ✅, ledger counts unchanged vs base (13 dialects / 3 untriaged / 2 copies / 18 unbacked claims): the derivation binds to the spec's definition and adds no debt.check-changeset-presence.mjs→ ✅ (10 source files of 4 released packages, 1 changeset).check-changeset-no-major.mjs→ ✅.check-doc-links.mjs→ ✅ (13 scan roots).check-doc-component-types.mjs→ ✅.list_viewsmentions repo-wide (sources+docs, CHANGELOGs excluded), every one a deliberate read-fallback leg, its documentation, or a pin — enumerated in my report onObjectSchemaMetadatadeclares neithertitleFormatnorlist_views/listViewsnoricon, and the runtime reads all three #5362.Declared narrowings (each with its reason)
type-check(which CI's Type Check runs) is green. CI runs the full suite regardless.eslinton all 10 changed TS files instead, with the three-evidence narrowing — ① corpus iseslint.config.jsapplied per-file (rootlint=eslint . --no-inline-config), ② 10 files linted per--format jsoncount, ③ no type-aware linting is enabled (noparserOptions.project/projectServicein the config), so this diff cannot move untouched files' verdicts. Result: 0 findings on any line this diff adds (cross-referenced added-line numbers against the JSON); the 2 inherited severity-2 findings sit on lines byte-identical at base....@object-ui/types, i.e. dependents) belongs to CI: the retired members and the mirror type had zero measured in-repo references, and the three consumer packages this PR edits type-check green.CI reading notes (gates by name)
main(Build Docsis red onmain:fsreaches the browser bundle via@objectstack/spec→pg-connection-string#5668, inherited; ~10 s turbo-cached greens are not evidence either way) — excluded with cause; this PR is not "green on it" and does not claim to be.Out-of-scope findings (filed unassigned)
editModeis read off the object document by objectui's runtime but the strict parse rejects it — declare or rule out objectstack#11408 —editModeis read off the object document by objectui's runtime but the spec's strict parse rejects it; declare-or-rule-out, the #10144 residue (measured here, pinned by the new guard).ObjectTriggerandObjectRelationshipare orphaned hand-written exports after the ObjectSchemaMetadata derivation (#5362) #5859 (finding) —ObjectTrigger/ObjectRelationshipare orphaned hand-written exports after the mirror retirement; deliberately not removed in this PR.Serial constraint
Siblings #5821 (
packages/types/src/zod/data-display.zod.ts,data-display.ts,static-table-narrow-surface.test.ts) and #5830 (packages/types/src/complex.ts) — no overlap: this PR touchesfield-types.ts,index.ts(one added export line in its own block), one new test file, plus app-shell/react/plugin-grid/docs. #5859 is a follow-up, not addressed here; objectstack#7917 remains open.Generated by Claude Code