Skip to content

test(types): pin the PartialSchema collapse, plus the #5155 sequencing note - #6433

Merged
os-support-ai merged 1 commit into
mainfrom
claude/issue-6397-partialschema-collapse-pin
Aug 26, 2026
Merged

test(types): pin the PartialSchema collapse, plus the #5155 sequencing note#6433
os-support-ai merged 1 commit into
mainfrom
claude/issue-6397-partialschema-collapse-pin

Conversation

@claude

@claudeclaudeBot commented Aug 26, 2026

Copy link
Copy Markdown
Contributor

Fixes#6397

Pins the PartialSchema< T > collapse and records the objectui#5155 sequencing note.
Nothing about the type changes. The declaration is byte-identical, no export is added,
removed, deprecated or narrowed, and the whole src/index.ts diff sits inside a JSDoc block
(mechanically checked: every added/removed line in that file is inside a comment).

Scope — and what is deliberately NOT here

Triage's 2026-08-25 re-judgement (objectui#6397) withdrew the retirement default and narrowed
this card to the option-3 floor. So this PR does not retire, remove, deprecate or narrow
the alias, and adds no @deprecated tag. Removing a published export of @object-ui/types is
a breaking removal of published capability and sits on the human floor; and once objectui#5155
lands the alias works as written, which is why the removal question is being left alone rather
than escalated. What ships here is the retirement of the one impermissible state —
declared, published, collapsed, and unpinned.

⚠️ Generic parameters are written spaced (Omit< T, K >) below, per the card's own
convention — GitHub's body sanitizer eats a fragment that opens with an identifier in angle
brackets.

The two readings, quoted

What the alias promises — its own doc comment, "all properties optional except the type".
That is the reading you get when keyof T resolves to the literal member names. Measured on a
control type that declares no index signature:

PartialSchema< IndexFreeSchema > -> 4 declared: ["alpha","beta","gamma","type"] stringIndex=false

What it delivers — measured through the TypeScript checker against the emitted
index.d.ts, the same instrument that produced objectui#6269's 61 -> 0 reading:

PartialSchema< ObjectGridSchema > -> 1 declared: ["type"] stringIndex=true (source: 61)
PartialSchema< ObjectFormSchema > -> 1 declared: ["type"] stringIndex=true (source: 67)
PartialSchema< ObjectViewSchema > -> 1 declared: ["type"] stringIndex=true (source: 42)
PartialSchema< ButtonSchema > -> 1 declared: ["type"] stringIndex=true (source: 27)

Omit< T, K > is Pick< T, Exclude< keyof T, K > >, and keyof T on a type carrying a string
index signature is string | number — the literal member names are absorbed. Every
T extends BaseSchema inherits BaseSchema's [key: string]: any (objectui#5155), so
Partial< Omit< T, 'type' > > rebuilds a type holding the index signature and none of the named
members. The explicit { type: T['type'] } half is the only reason the count is 1 and not 0.
Same mechanism as objectui#6151 (heritage clause) and objectui#6269 (property position); this
is its third position, a generic mapped-type alias, which is why neither of their guards sees
it — #6151's walks the LayoutSchema union, #6269's reads ObjectViewSchema's two slots.

Census — zero in-repo instantiations, stated rather than passed over

Re-run on this branch across packages/, apps/, examples/, content/, docs/ and
scripts/, excluding node_modules and dist: exactly one occurrence of the identifier,
and it is the declaration itself
(packages/types/src/index.ts). There is no call site, no
re-export under another name, no doc page and no test. (The card counted two because its grep
included the package's own emitted dist/index.d.ts; a fresh worktree has no dist/.)

So there is no real usage to pin against, and rather than let that pass unremarked: the four
types measured are chosen deliberately. They are the four the card itself measured, they are
real published schemas of this package spanning four families, and they are the population an
"editor partial schema" alias would actually be pointed at. The synthetic IndexFreeSchema
appears only as the control, never as the subject.

The pin

packages/types/src/__tests__/partial-schema-collapse-pin.test.ts — 31 assertions in four
sections. It emits declarations with the package's own tsconfig into a scratch dir and
measures those, for the reason recorded in stack-schema-emitted-members.test.ts and
object-view-slot-key-lists.test.ts: the per-PR test job runs with no build ahead of it, so
a guard reading dist/ would be absent-or-stale on a cold cache — vacuous exactly where it is
needed. PartialSchema is generic, so the instantiations are made in a probe source file
written next to the emitted index.d.ts.

  1. Non-vacuity — the probe reports zero semantic errors, resolved ./index to the freshly
    emitted file (not dist/, not a node_modules copy), and the four source schemas still
    declare 20+ members each.
  2. The control — the same alias, the same checker, an index-signature-free T: 4 declared
    members, no index signature, everything but type optional.
  3. The measurement — each instantiation declares exactly ["type"], drops 20+ named
    members the source declared, and carries a live string index signature.
  4. The objectui#5155 tripwireBaseSchema still declares [key: string]: any.

The sequencing note lives in two places: the pin's header (with an explicit removal condition)
and the alias's own doc comment, which now ships in the published .d.ts — confirmed on a real
pnpm --filter @object-ui/types build, with the declaration itself emitted verbatim.

This file is expected to go red when objectui#5155 lands. That is the point. The header
says so and says what to do: delete the file, do not relax the assertions.

Ghost-assertion guard — direction predicted before each run

A pin on a collapsed type is easy to write vacuously, so both legs were run against a
committed tree and restored by hash, never by exit code.

Ablation 1 — the objectui#5155 counterfactual. Removed [key: string]: any from
BaseSchema, which is what makes keyof T resolve the way the alias's author intended.
Predicted: RED, with the four counts jumping from 1 to their source counts and every
stringIndex assertion flipping to false.
Observed: RED, exactly that17 failed | 14 passed:

expected [ 'aggregations', 'ariaLabel', …(59) ] to deeply equal [ 'type' ] (61, PartialGrid)
expected [ 'allowSkip', 'ariaLabel', …(65) ] to deeply equal [ 'type' ] (67, PartialForm)
expected [ 'allowCreateView', …(41) ] to deeply equal [ 'type' ] (42, PartialView)
expected [ 'ariaLabel', 'body', …(25) ] to deeply equal [ 'type' ] (27, PartialButton)
carries a live string index signature -> expected false to be true (all four)
BaseSchema still declares `[key: string]: any` -> expected false to be true

The 14 that stayed green are sections 0 and 1 — the instrument and the control never depended
on that index signature, which is the positive half of the guard: what failed was the collapse
reading and only the collapse reading.

Ablation 2 — retire the alias. Deleted the PartialSchema declaration.
Predicted: RED at section 0, the probe's import failing to resolve.Observed: RED, that
plus every downstream assertion.
So the pin also notices a silent retirement, not only a
silent repair.

Where I was wrong: nowhere in direction — both legs landed where predicted. One correction
to the card's own numbers rather than to a prediction: it recorded ObjectViewSchema as
"27+"; measured today it is 42, and 27 is ButtonSchema's count.

Each leg proved its mutation on disk before reading anything — grep counts of both the
removed and the injected text, plus a changed git hash-object — and each restored under a
trap … EXIT INT TERM with absolute paths, verified afterwards by git rev-parse HEAD:<path>
matching git hash-object <path> and an empty git diff HEAD. No dist/ leg is involved:
the pin emits from source at test time, so a mutation is picked up with nothing to rebuild.

The pin is inside the type-check program

Not assumed from a green gate — measured:

$ tsc -p packages/types/tsconfig.test.json --noEmit --listFiles # exit 0, 511 files
…/src/__tests__/partial-schema-collapse-pin.test.ts # line 363

File surface

packages/types/src/index.ts, a new test file, and a changeset. It does not touch
packages/types/src/data-display.ts
, so there is no overlap with objectui#6373 in this batch.

Verification — union run at 2ec7800b0 (the final commit)

gateverdict
pnpm exec vitest run packages/types/Test Files 63 passed (63) / Tests 743 passed (743)
pnpm --filter @object-ui/types run type-checkexit 0 (tsc --noEmit && tsc -p tsconfig.examples.json && tsc -p tsconfig.test.json)
pnpm --filter @object-ui/types run lint✖ 244 problems (0 errors, 244 warnings), zero in the edited files
node scripts/check-control-bytes.mjs✅ OK (scanned 5313 tracked text file(s))
node scripts/check-changeset-presence.mjs✅ 2 source file(s) … declares 1 changeset(s)
node scripts/check-changeset-fixed.mjs / check-changeset-no-major.mjsexit 0 / exit 0
node scripts/check-spec-symbol-derivation.mjsexit 0

Declared narrowing of the lint run. Repo-wide pnpm lint is turbo run lint, i.e. each
package running its own eslint .; my diff touches exactly one package, so its own lint run is
the complete lint for the changed surface. Three pieces of evidence, not two: (1) the population
comes from eslint's own config resolution, not my guess about which files count; (2)
eslint . --format json inside packages/types reports 125 files linted, 0 errors, 244
warnings
, all pre-existing no-explicit-any in src/zod/**; (3) eslint.config.js declares
no projectService / parserOptions.project, so linting is not type-aware and a type-level
edit here cannot move any untouched file's verdict. The .changeset/*.md file is outside every
eslint glob (no markdown processor is configured).

NOT MEASURED, with the reason:pnpm check:readme-exports exits 1 in a fresh worktree —
all 378 findings are its type entry ./dist/index.d.ts is not on disk -- run pnpm build first, naming 36 packages this PR never touches. That is a prerequisite failure, not a red
gate; CI builds before it runs. Recorded rather than quietly counted as green.

Everything else in the gate farm is CI's run.

Not marked ready by design

Draft, no auto-merge, not self-merged — the PM lands this one.


Generated by Claude Code

…g note
`PartialSchema<T>` declares exactly ONE property for every instantiation and
carries a live `[key: string]: any`, so it accepts anything. Measured through the
checker against the emitted `index.d.ts`:
PartialSchema<ObjectGridSchema> -> 1 declared property: type (source: 61)
PartialSchema<ObjectFormSchema> -> 1 declared property: type (source: 67)
PartialSchema<ObjectViewSchema> -> 1 declared property: type (source: 42)
PartialSchema<ButtonSchema> -> 1 declared property: type (source: 27)
`keyof T` on a type carrying a string index signature is `string | number`, so
`Partial<Omit<T, 'type'>>` rebuilds the index signature and none of the named
members. objectui#6151's collapse in a heritage clause and objectui#6269's in
property position, here in a generic mapped-type alias.
The declaration is deliberately unchanged: retiring a published export sits on
the human floor, in-place repair is unavailable for a generic `T`, and
objectui#5155 is expected to make the alias work as written with no edit. What
this removes is the one impermissible state -- declared, published, collapsed,
and unpinned.
Part of #6397
@github-actions

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

MetricValueBudget
Eager closure (gzip, 52 chunks)3233.6 KB3266.6 KB
Main entry chunk (gzip)157.4 KB350 KB
Entry fileindex-BFbGiWVj.js
StatusPASS

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

PackageSizeGzipped
app-shell (consoleActionDispatch.js)0.20KB0.19KB
app-shell (index.js)11.30KB4.28KB
app-shell (runtime-config.js)18.10KB6.51KB
app-shell (types.js)0.01KB0.04KB
app-shell (urlParams.js)10.06KB3.86KB
auth (ActiveOrganizationStorage.js)25.05KB9.16KB
auth (AuthContext.js)0.31KB0.24KB
auth (AuthGuard.js)2.07KB1.00KB
auth (AuthProvider.js)40.18KB10.59KB
auth (AuthShell.js)3.49KB1.40KB
auth (ForgotPasswordForm.js)12.21KB3.45KB
auth (LoginForm.js)18.15KB5.39KB
auth (PreviewBanner.js)0.90KB0.50KB
auth (RegisterForm.js)6.65KB2.22KB
auth (SocialSignInButtons.js)9.61KB3.89KB
auth (UserMenu.js)3.41KB1.23KB
auth (auth-gate-events.js)1.29KB0.66KB
auth (authStyles.js)5.04KB1.72KB
auth (createAuthClient.js)40.21KB10.80KB
auth (createAuthenticatedFetch.js)8.46KB3.43KB
auth (index.js)3.19KB1.44KB
auth (invitation-status.js)1.22KB0.70KB
auth (org-roles.js)6.66KB2.78KB
auth (phone-identifier.js)1.11KB0.66KB
auth (types.js)0.59KB0.35KB
auth (useAuth.js)5.30KB1.02KB
auth (useWorkspaceAdminStatus.js)5.13KB2.35KB
collaboration (CommentThread.js)26.08KB7.56KB
collaboration (LiveCursors.js)3.17KB1.27KB
collaboration (PresenceAvatars.js)6.49KB2.64KB
collaboration (PresenceProvider.js)2.79KB1.13KB
collaboration (index.js)1.68KB0.73KB
collaboration (useCollaborationTranslation.js)6.05KB2.52KB
collaboration (useCommentSearch.js)1.98KB0.88KB
collaboration (useConflictResolution.js)7.75KB1.86KB
collaboration (useMentionNotifications.js)1.81KB0.68KB
collaboration (usePresence.js)6.33KB1.84KB
collaboration (useRealtimeSubscription.js)7.91KB2.01KB
components (index.js)505.86KB114.58KB
core (index.js)5.30KB2.13KB
create-plugin (index.js)10.08KB3.26KB
data-objectstack (index.js)173.10KB47.96KB
fields (index.js)238.89KB60.02KB
i18n (LocalizationContext.js)1.76KB0.96KB
i18n (currency.js)1.22KB0.64KB
i18n (fallbackInterpolation.js)6.25KB2.77KB
i18n (i18n.js)4.28KB1.75KB
i18n (index.js)3.44KB1.39KB
i18n (pickLocalized.js)7.62KB3.26KB
i18n (provider.js)26.89KB9.04KB
i18n (useDisplayLocale.js)2.85KB1.45KB
i18n (useObjectLabel.js)33.40KB8.71KB
i18n (useSafeTranslation.js)5.60KB2.33KB
layout (index.js)38.95KB10.97KB
mobile (MobileProvider.js)0.92KB0.49KB
mobile (ResponsiveContainer.js)0.94KB0.38KB
mobile (breakpoints.js)1.51KB0.70KB
mobile (createOfflineDataSource.js)5.61KB1.75KB
mobile (index.js)1.55KB0.62KB
mobile (offlineQueue.js)3.91KB1.35KB
mobile (pwa.js)0.97KB0.49KB
mobile (serviceWorker.js)1.48KB0.62KB
mobile (serviceWorkerSource.js)3.41KB1.48KB
mobile (useBreakpoint.js)1.54KB0.65KB
mobile (useGesture.js)6.96KB1.98KB
mobile (useOfflineSync.js)1.99KB0.72KB
mobile (usePullToRefresh.js)2.53KB0.85KB
mobile (useResponsive.js)0.72KB0.42KB
mobile (useResponsiveConfig.js)1.37KB0.63KB
mobile (useSpecGesture.js)4.32KB1.64KB
mobile (useTouchTarget.js)1.01KB0.54KB
permissions (MePermissionsProvider.js)9.53KB3.38KB
permissions (PermissionContext.js)0.31KB0.25KB
permissions (PermissionGuard.js)0.89KB0.45KB
permissions (PermissionProvider.js)4.64KB1.50KB
permissions (evaluator.js)5.12KB1.74KB
permissions (index.js)0.93KB0.41KB
permissions (store.js)0.91KB0.42KB
permissions (useFieldPermissions.js)1.28KB0.53KB
permissions (usePermissions.js)1.93KB0.88KB
plugin-ai (index.js)15.75KB3.80KB
plugin-calendar (index.js)46.66KB12.84KB
plugin-charts (index.js)64.66KB18.32KB
plugin-chatbot (index.js)188.60KB44.82KB
plugin-dashboard (index.js)133.46KB34.48KB
plugin-designer (index.js)211.90KB42.74KB
plugin-detail (index.js)245.10KB62.31KB
plugin-editor (index.js)2.46KB1.10KB
plugin-form (index.js)131.78KB32.19KB
plugin-gantt (index.js)164.14KB39.87KB
plugin-grid (index.js)201.79KB54.60KB
plugin-kanban (index.js)53.16KB14.65KB
plugin-list (index.js)112.63KB27.45KB
plugin-map (index.js)20.09KB6.62KB
plugin-markdown (index.js)13.72KB4.69KB
plugin-report (index.js)43.49KB11.93KB
plugin-timeline (index.js)26.72KB7.71KB
plugin-tree (index.js)9.26KB3.13KB
plugin-view (index.js)84.55KB20.74KB
providers (DataSourceProvider.js)0.75KB0.39KB
providers (MetadataProvider.js)1.37KB0.59KB
providers (ThemeProvider.js)1.90KB0.85KB
providers (UploadProvider.js)11.66KB3.50KB
providers (index.js)0.45KB0.23KB
providers (types.js)0.01KB0.04KB
react-runtime (index.js)5.62KB2.34KB
react (LazyPluginLoader.js)4.47KB1.63KB
react (SchemaRenderer.js)54.84KB18.43KB
react (data-invalidation.js)5.05KB2.08KB
react (index.js)1.35KB0.70KB
react (schema-input.js)2.32KB1.24KB
react (spec-input.js)0.20KB0.18KB
sdui-parser (codegen.js)5.41KB2.34KB
sdui-parser (dashboard-widget-options.js)3.08KB1.30KB
sdui-parser (index.js)4.93KB2.24KB
sdui-parser (input-type.js)2.84KB1.40KB
sdui-parser (parse.js)12.13KB3.65KB
sdui-parser (provenance.js)3.66KB1.82KB
sdui-parser (types.js)0.28KB0.23KB
sdui-parser (validate.js)7.54KB2.63KB
types (ai.js)0.20KB0.17KB
types (api-types.js)0.20KB0.18KB
types (app.js)2.87KB0.99KB
types (base.js)0.20KB0.18KB
types (blocks.js)0.20KB0.18KB
types (complex.js)2.74KB1.41KB
types (crud.js)0.20KB0.18KB
types (dashboard-filter-alias.js)6.23KB2.74KB
types (data-display.js)3.75KB1.85KB
types (data-protocol.js)0.20KB0.19KB
types (data.js)0.20KB0.18KB
types (designer.js)1.85KB0.85KB
types (disclosure.js)0.20KB0.18KB
types (error-code.js)1.54KB0.88KB
types (feedback.js)0.20KB0.18KB
types (field-types.js)0.20KB0.18KB
types (form.js)0.20KB0.18KB
types (http-inflight.js)8.87KB3.73KB
types (http-retry.js)4.32KB2.02KB
types (icon-key-migration.js)4.26KB1.63KB
types (index.js)4.72KB2.24KB
types (layout.js)0.20KB0.18KB
types (managed-by.js)0.19KB0.18KB
types (mobile.js)2.59KB1.31KB
types (navigation.js)0.20KB0.18KB
types (objectql.js)0.20KB0.18KB
types (overlay.js)0.20KB0.18KB
types (permissions.js)0.20KB0.18KB
types (plugin-scope.js)0.20KB0.18KB
types (record-components.js)0.20KB0.19KB
types (record-semantics.js)1.28KB0.67KB
types (registry.js)0.20KB0.18KB
types (reports.js)0.20KB0.18KB
types (spec-report.js)5.05KB1.93KB
types (spec-ui-namespace.js)0.20KB0.19KB
types (system-fields.js)3.33KB1.54KB
types (theme.js)6.28KB2.87KB
types (ui-action.js)3.40KB1.71KB
types (views.js)0.20KB0.18KB
types (widget.js)0.20KB0.18KB

Size Limits

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

@os-support-ai
os-support-ai marked this pull request as ready for review August 26, 2026 00:13
@os-support-ai
os-support-ai added this pull request to the merge queueAug 26, 2026
Merged via the queue into main with commit c8ea8afAug 26, 2026
29 checks passed
@os-support-ai
os-support-ai deleted the claude/issue-6397-partialschema-collapse-pin branch August 26, 2026 00:25
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

2 participants

@os-support-ai@claude