Skip to content

test(types): re-derive ObjectViewSchema's side of the #6058 split as LOCAL and pin the header counts (objectui#7279) - #7776

Merged
os-justin merged 3 commits into
mainfrom
claude/issue-7279-object-view-unmirrored-route
Sep 5, 2026
Merged

test(types): re-derive ObjectViewSchema's side of the #6058 split as LOCAL and pin the header counts (objectui#7279)#7776
os-justin merged 3 commits into
mainfrom
claude/issue-7279-object-view-unmirrored-route

Conversation

@os-justin

Copy link
Copy Markdown
Collaborator

Fixes #7279

What this is

A test-file routing record, not a mirror edit. packages/types/src/__tests__/zod-mirror-parity.test.ts recorded objectui#6058's SPEC-DERIVED / LOCAL split of the UnmirroredDeclared ledger with ObjectViewSchema on the SPEC-DERIVED side — a routing that rested on the text-scanner false positive #6705 (PR #7277) dropped from SPEC_DERIVED_PAIRS without settling the routing. This PR re-derives that side on the tree and through the installed spec pin, records the route at the four sites in the file that state it, corrects the split's counts by deriving them from the ledger objects and SPEC_DERIVED_PAIRS membership, and pins the header's figures against that derivation so the prose cannot drift silently again.

Clause-② no: no mirror, declaration, validator, MIRRORS, EXCLUSIONS, ledger key set or SPEC_DERIVED_PAIRS membership moves. The ten-key widening this reading implies is a remedy on the manual floor (triage 5548347502's boundary) and is NOT performed here. #6152 remains open; #2231 remains open.

Re-derivation

(a) Declared vs mirrored, key by key — every declared key accounted for exactly once

packages/types/src/objectql.ts interface ObjectViewSchema extends BaseSchema declares 25 own members; packages/types/src/zod/objectql.zod.ts export const ObjectViewSchema = BaseSchema.extend({…}) declares 13 own members plus BaseSchema's. Every Spec… token in that file's neighbourhood (KanbanConfig, CalendarConfig, GalleryConfig, TimelineConfig, ViewKindEnum) is a private const feeding ListViewSchema; the mirror references none of them. The pair is not in SPEC_DERIVED_PAIRS, and the existing SPEC_DERIVED_PAIRS matches what the mirror sources actually do case agrees on this tree.

declared key mirror ledger row
type, objectName, title, description, layout, showSearch, showFilters, showSort, showCreate, showRefresh, operations (11) mirrored, same shape none
className (1) mirrored through BaseSchema none
table, form (2) mirrored as z.lazy to the sibling mirror, wider than the declared Partial-of-Pick slot WiderThanDeclared (SCHEMA-NODE, PR #7758)
onNavigate (1) not mirrored — callback; objectql.zod.ts carries no on* by policy RuntimeOnlyDeclared (#6152)
allowCreateView, defaultListView, defaultViewType, filterableFields, listViews, navigation, searchableFields, showViewSwitcher, viewActions, viewTabBar (10) not mirrored UnmirroredDeclared — the ten this card is about

25 = 11 + 1 + 2 + 1 + 10. The pair has no KnownDrift row.

(b) Does the installed spec model the ten keys on a View-shaped schema?

Read THROUGH THE PIN — @objectstack/spec@17.2.0, resolved from packages/types (node_modules/.pnpm/@objectstack+spec@17.2.0_…/dist/ui/index.js, the ui entry) — by walking all 122 exported zod object schemas' .shape. Control keys hit as expected (objectName on 10 exports, columns on 16, type on 35, label on 43). View-shaped exports present: ViewSchema, ListViewSchema, ObjectListViewSchema, FormViewSchema, ViewTabSchema, ViewFilterRuleSchema, ViewSharingSchema.

key spec models it where and shape note for whoever mirrors
navigation yes ListViewSchema.navigation and ObjectListViewSchema.navigation: optional NavigationConfigSchema (mode, view, preventNavigation, openNewTab, size, width) the declaration already types it as the spec's NavigationConfig (ViewNavigationConfig alias, imported from @objectstack/spec/ui) — take the shape by reference
searchableFields yes ListViewSchema, ObjectListViewSchema, ObjectGridPropsSchema: optional array of string same shape as declared
filterableFields yes ListViewSchema, ObjectListViewSchema: optional array of string; the spec's own description calls it a legacy shorthand for userFilters.fields same shape as declared; the legacy note is the spec's, recorded not acted on
listViews yes, by name ViewSchema.listViews: optional record from string to a spec list-view object the declaration's VALUE is the local NamedListView (label / type / columns / filter / sort / options / show-flags), not the spec's list view — the value type is a unification question a mirror edit must not paper over with z.any()
allowCreateView no plain hand-written omission
defaultListView no plain hand-written omission
defaultViewType no plain hand-written omission
showViewSwitcher no plain hand-written omission
viewActions no plain hand-written omission
viewTabBar no plain hand-written omission

Route on the evidence

The SPEC-DERIVED route exists for a mirror that IS the spec schema by reference, where growing a key means diverging from the spec and the question becomes whether the local declaration should keep it (#2231). This mirror takes no shape from the spec, so it can grow any key without touching the spec: the entry is LOCAL, and its remedy is the ordinary local route (#6152's worklist). The spec reading does not change the route; it is recorded on the entry as a 4 / 6 reading for whoever mirrors — four keys take their shape by reference from the spec slot that models them (with the listViews value-type caveat), six are plain hand-written omissions. DashboardWidgetSchema reconfirmed spec-derived by code reference (specFieldsExcept(SpecDashboardWidgetSchema.shape, …), complex.zod.ts:627).

Not decided here: whether each of the six unmodelled keys should be mirrored or retired (the #7129 route) — that is per-key liveness work on #6152's worklist, and the seat raises the follow-up.

Corrected counts — derived, not restated

UnmirroredDeclared on this tree, entry by entry: ChatbotSchema 3, ChatbotFloatingSchema 2, DashboardWidgetSchema 2, DataTableSchema 17, FormFieldSchema 1, FormSchema 8, InputSchema 1, LabelSchema 1, PaginationSchema 1, ObjectFormSchema 21, ObjectGridSchema 15, ObjectViewSchema 10, ReportComponentSchema 3, DetailViewSchema 11 — 14 entries, 96 keys. SPEC_DERIVED_PAIRS intersected with those entries is exactly complex.zod.ts#DashboardWidgetSchema.

  • SPEC-DERIVED: 1 entry / 2 keys (the header said 2 / 12)
  • LOCAL: 13 entries / 94 keys (the header said 12 / 84)
  • totals: 14 entries / 96 keys (unchanged; the top-of-file line already said so)

Sites corrected (all in zod-mirror-parity.test.ts)

  1. The header split paragraph — both labels' counts, the ObjectViewSchema paragraph replaced by the re-derived reading and its evidence, the totals sentence put on one line so the pin can read it, history sentences kept and extended (the header is cumulative by design).
  2. The UnmirroredDeclared entry docblock — LOCAL, with the 4 / 6 per-key reading.
  3. The SPEC_DERIVED_PAIRS comment — the consequence finding(gate): zod-mirror-parity's SPEC_DERIVED_PAIRS scans raw text between export const boundaries, so a Spec-token mentioned in PROSE is attributed to the neighbouring export #6705 left open is settled and points at the pin.
  4. The RuntimeOnlyDeclared ObjectViewSchema docblock — a fourth site the dispatch did not enumerate. It read "This pair is ALSO spec-derived … stay routed to objectui#2231" and would have contradicted the other three; prose only, the key did not move. Declared as a deviation in the report.

Pin — describe('… (objectui#7279)'), two cases

ledgerEntryMembers() reads each UnmirroredDeclared property signature's union of string literals off this file's AST — the same instrument ledgerEntryKeys already uses; a non-literal arm is a hard error, not a skipped row. The split is derived from it by SPEC_DERIVED_PAIRS membership and compared with four figures read off the header on disk, each of which must occur exactly once (a stale copy standing beside a corrected one is red): the SPEC-DERIVED label, the LOCAL label, the one-line totals sentence, and the top-of-file UnmirroredDeclared count. A non-vacuity case checks the reader agrees with ledgerEntryKeys on the entry list, that both halves are non-empty, and that unions are actually walked.

Verification — exit codes captured before any pipe; verdict lines quoted from the tools

Final head 627d1881 = 5ff08d22 (the change) + two merges of origin/main (4388f713, then 16a725f9 after a sibling fetch advanced the shared ref between two of my commands); neither merge touched the parity file.

  • pnpm exec vitest run --maxWorkers=2 packages/types/ under os-verify-lock.sh @ 627d1881: VERDICT command-exit 0Test Files 124 passed (124), Tests 2196 passed (2196)
  • same, packages/types/src/__tests__/zod-mirror-parity.test.ts @ 5ff08d22: VERDICT command-exit 0Tests 20 passed (20) (18 existing + 2 new)
  • pnpm --filter @object-ui/types type-check @ 627d1881: exit 0 (three tsc projects; tsc -p tsconfig.test.json --listFiles lists the parity file, so the type-level ledgers are compiled)
  • pnpm --filter @object-ui/types lint @ 627d1881: exit 0 (pre-existing no-explicit-any warnings in examples and other tests; none in the parity file)
  • node scripts/check-changeset-presence.mjs @ 627d1881: exit 0 — "1 source file(s) of 1 released package(s) changed, and this change declares 1 changeset(s): .changeset/7279-object-view-split-route-pin"; check-changeset-fixed, check-changeset-no-major, check-changeset-overwrite: exit 0 each
  • node scripts/check-control-bytes.mjs @ 627d1881: exit 0 — "OK (scanned 6338 tracked text file(s); skipped 85 binary)"
  • pnpm check:spec-symbols @ 627d1881: exit 0 — "no comment cites a key its spec symbol does not declare"
  • governed-surface predicate (objectstack scripts/pm/check-governed-merges.mjs --test on both paths): "0 of 2 path(s) hit the register — NOT governed"

Ablation — committed first; restore is git checkout HEAD -- path, proven by blob hash

  • Leg 1 — mutate one header figure (LOCAL (13 entries, 94 keys) to 12 entries): on-disk proof target 1 → 0, injected 0 → 1; VERDICT command-exit 1, 1 failed | 19 passed — exactly the new pin. Restored: git diff HEAD empty, blob 52de7cc2 equals the HEAD blob.
  • Leg 2 — drop complex.zod.ts#DashboardWidgetSchema from SPEC_DERIVED_PAIRS (membership feeds the split): on-disk proof target 1 → 0; VERDICT command-exit 1, 3 failed | 17 passed — the new pin, its non-vacuity twin, and the existing SPEC_DERIVED_PAIRS matches what the mirror sources actually do. Restored the same way, same hash.

No dist is involved (the test reads src and the installed spec pin), so no build preflight applies; the on-disk proof is the grep -c pair above.

Not in this PR

packages/types/src/zod/** untouched. #6152's worklist, the 23-callback ruling, DashboardWidgetSchema's entry beyond reconfirmation, and #2231 are out of scope and remain open. Placeholders in this body are spelled as words (Partial-of-Pick, record from string to …) because the GitHub body sanitizer eats angle-bracket shapes.

Session: https://claude.ai/code/session_01BAZFhALsQsGqxui8sNqM8s — the dispatching seat's session; the dev is its subagent and its identity is the branch.

🤖 Generated with Claude Code

https://claude.ai/code/session_01BAZFhALsQsGqxui8sNqM8s


Generated by Claude Code

…LOCAL and pin the header counts

The zod-mirror-parity header routed ObjectViewSchema's ten unmirrored declared
keys as SPEC-DERIVED on a scanner false positive that #6705 removed from
SPEC_DERIVED_PAIRS without settling the routing. Re-derived on the tree: the
mirror is BaseSchema.extend of local literals and z.lazy siblings and takes no
shape from the spec; read through the @objectstack/spec@17.2.0 pin, the spec
models four of the ten keys on View-shaped schemas and six nowhere. The entry
is LOCAL; the 4 / 6 reading is recorded on it for whoever mirrors. The split's
counts (1 / 2 spec-derived, 13 / 94 local, 14 / 96 total) are now derived from
the ledger and SPEC_DERIVED_PAIRS membership and pinned against the header read
off disk, so the prose can no longer drift silently. Test only.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BAZFhALsQsGqxui8sNqM8s
@github-actions

github-actions Bot commented Sep 5, 2026

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

Metric Value Budget
Eager closure (gzip, 50 chunks) 3187.1 KB 3191.4 KB
Main entry chunk (gzip) 143.2 KB 350 KB
Entry file index-mHyqluY3.js
Status PASS

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

Package Size Gzipped
app-shell (consoleActionDispatch.js) 0.20KB 0.19KB
app-shell (index.js) 15.67KB 5.75KB
app-shell (runtime-config.js) 20.68KB 7.36KB
app-shell (types.js) 0.01KB 0.04KB
app-shell (urlParams.js) 10.06KB 3.86KB
auth (ActiveOrganizationStorage.js) 25.05KB 9.16KB
auth (AuthContext.js) 0.31KB 0.24KB
auth (AuthGuard.js) 2.07KB 1.00KB
auth (AuthProvider.js) 40.18KB 10.59KB
auth (AuthShell.js) 3.49KB 1.40KB
auth (ForgotPasswordForm.js) 12.21KB 3.45KB
auth (LoginForm.js) 18.15KB 5.39KB
auth (PreviewBanner.js) 0.90KB 0.50KB
auth (RegisterForm.js) 6.65KB 2.22KB
auth (SocialSignInButtons.js) 9.61KB 3.89KB
auth (UserMenu.js) 3.41KB 1.23KB
auth (auth-gate-events.js) 1.29KB 0.66KB
auth (authStyles.js) 5.04KB 1.72KB
auth (createAuthClient.js) 40.21KB 10.80KB
auth (createAuthenticatedFetch.js) 8.46KB 3.43KB
auth (index.js) 3.19KB 1.44KB
auth (invitation-status.js) 1.22KB 0.70KB
auth (org-roles.js) 6.66KB 2.78KB
auth (phone-identifier.js) 1.11KB 0.66KB
auth (types.js) 0.59KB 0.35KB
auth (useAuth.js) 5.30KB 1.02KB
auth (useWorkspaceAdminStatus.js) 5.13KB 2.35KB
collaboration (CommentThread.js) 26.08KB 7.56KB
collaboration (LiveCursors.js) 3.17KB 1.27KB
collaboration (PresenceAvatars.js) 6.49KB 2.64KB
collaboration (PresenceProvider.js) 2.79KB 1.13KB
collaboration (index.js) 1.68KB 0.73KB
collaboration (useCollaborationTranslation.js) 6.05KB 2.52KB
collaboration (useCommentSearch.js) 1.98KB 0.88KB
collaboration (useConflictResolution.js) 7.75KB 1.86KB
collaboration (useMentionNotifications.js) 1.81KB 0.68KB
collaboration (usePresence.js) 6.33KB 1.84KB
collaboration (useRealtimeSubscription.js) 7.91KB 2.01KB
components (index.js) 510.60KB 116.20KB
core (index.js) 6.96KB 2.79KB
create-plugin (index.js) 10.08KB 3.26KB
data-objectstack (index.js) 182.08KB 50.62KB
fields (index.js) 242.44KB 61.25KB
i18n (LocalizationContext.js) 1.76KB 0.96KB
i18n (builtinAggregateLabels.js) 0.86KB 0.49KB
i18n (currency.js) 1.22KB 0.64KB
i18n (fallbackInterpolation.js) 6.25KB 2.77KB
i18n (i18n.js) 4.28KB 1.75KB
i18n (index.js) 3.65KB 1.47KB
i18n (pickLocalized.js) 7.62KB 3.26KB
i18n (provider.js) 26.89KB 9.04KB
i18n (useDisplayLocale.js) 2.85KB 1.45KB
i18n (useObjectLabel.js) 34.34KB 9.17KB
i18n (useSafeTranslation.js) 5.60KB 2.33KB
layout (index.js) 38.98KB 10.98KB
mobile (MobileProvider.js) 0.92KB 0.49KB
mobile (ResponsiveContainer.js) 0.94KB 0.38KB
mobile (breakpoints.js) 1.51KB 0.70KB
mobile (createOfflineDataSource.js) 5.61KB 1.75KB
mobile (index.js) 1.99KB 0.87KB
mobile (offlineQueue.js) 3.91KB 1.35KB
mobile (pwa.js) 0.97KB 0.49KB
mobile (serviceWorker.js) 1.48KB 0.62KB
mobile (serviceWorkerSource.js) 3.41KB 1.48KB
mobile (useBreakpoint.js) 1.54KB 0.65KB
mobile (useGesture.js) 6.96KB 1.98KB
mobile (useOfflineSync.js) 1.99KB 0.72KB
mobile (usePullToRefresh.js) 2.53KB 0.85KB
mobile (useResponsive.js) 0.72KB 0.42KB
mobile (useSpecGesture.js) 4.39KB 1.66KB
mobile (useTouchTarget.js) 1.01KB 0.54KB
permissions (MePermissionsProvider.js) 11.71KB 4.29KB
permissions (PermissionContext.js) 0.31KB 0.25KB
permissions (PermissionGuard.js) 0.89KB 0.45KB
permissions (PermissionProvider.js) 6.24KB 2.16KB
permissions (discardProofCache.js) 1.04KB 0.55KB
permissions (evaluator.js) 5.12KB 1.74KB
permissions (index.js) 0.93KB 0.41KB
permissions (store.js) 0.91KB 0.42KB
permissions (useFieldPermissions.js) 1.28KB 0.53KB
permissions (usePermissions.js) 4.83KB 2.27KB
plugin-ai (index.js) 15.75KB 3.80KB
plugin-calendar (index.js) 47.87KB 13.31KB
plugin-charts (index.js) 70.92KB 19.75KB
plugin-chatbot (index.js) 196.19KB 46.37KB
plugin-dashboard (index.js) 132.88KB 34.69KB
plugin-designer (index.js) 212.86KB 43.19KB
plugin-detail (index.js) 250.55KB 64.06KB
plugin-editor (index.js) 2.46KB 1.10KB
plugin-form (index.js) 132.87KB 32.66KB
plugin-gantt (index.js) 167.26KB 41.00KB
plugin-grid (index.js) 209.29KB 56.78KB
plugin-kanban (index.js) 52.71KB 14.55KB
plugin-list (index.js) 113.28KB 27.59KB
plugin-map (index.js) 20.44KB 6.78KB
plugin-markdown (index.js) 13.93KB 4.81KB
plugin-report (index.js) 43.59KB 11.97KB
plugin-timeline (index.js) 30.84KB 8.85KB
plugin-tree (index.js) 9.20KB 3.19KB
plugin-view (index.js) 85.24KB 20.94KB
providers (DataSourceProvider.js) 0.75KB 0.39KB
providers (MetadataProvider.js) 1.37KB 0.59KB
providers (ThemeProvider.js) 1.90KB 0.85KB
providers (UploadProvider.js) 11.66KB 3.50KB
providers (index.js) 0.45KB 0.23KB
providers (types.js) 0.01KB 0.04KB
react-runtime (index.js) 5.62KB 2.34KB
react (LazyPluginLoader.js) 4.47KB 1.63KB
react (SchemaRenderer.js) 81.07KB 26.86KB
react (data-invalidation.js) 5.05KB 2.08KB
react (index.js) 4.63KB 2.18KB
react (schema-input.js) 2.32KB 1.24KB
react (spec-input.js) 0.20KB 0.18KB
sdui-parser (codegen.js) 5.41KB 2.34KB
sdui-parser (dashboard-widget-options.js) 3.08KB 1.30KB
sdui-parser (index.js) 4.93KB 2.24KB
sdui-parser (input-type.js) 2.84KB 1.40KB
sdui-parser (parse.js) 20.57KB 5.88KB
sdui-parser (provenance.js) 3.66KB 1.82KB
sdui-parser (types.js) 0.28KB 0.23KB
sdui-parser (validate.js) 10.35KB 3.60KB
types (ai.js) 0.20KB 0.17KB
types (api-types.js) 0.20KB 0.18KB
types (app.js) 2.87KB 1.00KB
types (base.js) 0.20KB 0.18KB
types (blocks.js) 0.20KB 0.18KB
types (complex.js) 2.74KB 1.41KB
types (crud.js) 0.20KB 0.18KB
types (dashboard-filter-alias.js) 6.23KB 2.74KB
types (data-display.js) 3.75KB 1.85KB
types (data-protocol.js) 0.20KB 0.19KB
types (data.js) 0.20KB 0.18KB
types (designer.js) 1.85KB 0.85KB
types (disclosure.js) 0.20KB 0.18KB
types (error-code.js) 1.54KB 0.88KB
types (expression.js) 0.20KB 0.18KB
types (feedback.js) 0.20KB 0.18KB
types (field-types.js) 0.20KB 0.18KB
types (form.js) 0.20KB 0.18KB
types (http-inflight.js) 8.87KB 3.73KB
types (http-retry.js) 4.32KB 2.02KB
types (icon-key-migration.js) 4.26KB 1.63KB
types (index.js) 4.74KB 2.25KB
types (layout.js) 0.20KB 0.18KB
types (managed-by.js) 0.19KB 0.18KB
types (mobile.js) 4.73KB 2.28KB
types (navigation.js) 0.20KB 0.18KB
types (objectql.js) 0.20KB 0.18KB
types (overlay.js) 0.20KB 0.18KB
types (permissions.js) 0.20KB 0.18KB
types (plugin-scope.js) 0.20KB 0.18KB
types (record-components.js) 0.20KB 0.19KB
types (record-semantics.js) 1.28KB 0.67KB
types (registry.js) 0.20KB 0.18KB
types (reports.js) 0.20KB 0.18KB
types (select-option.js) 0.20KB 0.19KB
types (spec-report.js) 5.05KB 1.93KB
types (spec-ui-namespace.js) 0.20KB 0.19KB
types (system-fields.js) 3.33KB 1.54KB
types (theme.js) 6.28KB 2.87KB
types (ui-action.js) 8.11KB 3.32KB
types (views.js) 0.20KB 0.18KB
types (widget.js) 0.20KB 0.18KB

Size Limits

  • ✅ Core packages should be < 50KB gzipped
  • ✅ Component packages should be < 100KB gzipped
  • ⚠️ Plugin packages should be < 150KB gzipped

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

finding: #6058's SPEC-DERIVED remedy split routes ObjectViewSchema's unmirrored keys on a scanner false positive — it references no spec schema

2 participants