feat(types,mobile)!: retire the MobileOverrides type and its mount point (#4919) - #5941
Merged
Merged
Conversation
…int (#4919) `MobileOverrides` published a six-key mobile override surface — including a three-value `navigation` vocabulary — from `@object-ui/types` and, re-exported, from `@object-ui/mobile`. Nothing read any of it: measured on current `main` the type had exactly four mentions repo-wide (declaration, the single `MobileComponentConfig.mobileOverrides` mount point, two barrel re-exports), and a sweep of the example apps and the `objectstack` sibling checkout found zero authors. All three `navigation` values were spellings of the same no-op. Removed rather than narrowed (the #3985 lineage's "narrow to the implemented values" rule terminates in deletion when the implemented set is empty), and removed rather than `?: never`-tombstoned: a tombstone in this package steers authors to a named live replacement (`confirm` -> `confirmText`; `hoverable`/`striped` -> `data-table`), and there is no successor here. Same zero-pull, no-successor shape as the retired `AccordionItem.icon` (#4652) and `ToggleGroupItem.icon` (#4632), which were removed outright. Runtime behaviour is unchanged; what changes is that the contract stops claiming otherwise, so authoring the key becomes a compile-time error instead of a silent no-op. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EuPCi56cnGyykygi3z9w4m
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 #4919
Carries the recorded maintainer ruling on that card (comment 5339691949, 「全部接受」): retire the whole
MobileOverridestype — the declaration, itsmobileOverrides?mount point, and both barrel re-exports. The three-valuenavigationvocabulary is not narrowed and not kept in any form. Implementing mobile overrides was rejected there and is not attempted here.Which tombstone branch, and the precedent that decided it
Branch (a): one-stage removal. This PR completes the card; there is no stage 2 outstanding.
The dispatch required this be measured, not assumed — specifically, not assumed from the metadata-spec
retiredKey()/ ADR-0087 registry path, which governs spec keys rather than TypeScript types. It does not apply here:packages/types/src/mobile.tshas no Zod twin (there is nomobile.zod.tsinpackages/types/src/zod/), so the "loud parse rejection in the Zod twin" half of that discipline has nothing to attach to.What this repo actually does when retiring a published TS surface is two coexisting forms, and the discriminator is not chronology — both are live and interleaved:
ToggleGroupItem.icon(objectui#4632, 2026-08-14)AccordionItem.icon(objectui#4652, 2026-08-15)BaseFieldMetadata.indexedindexesspacing/breakpoints/densityconfirm(objectui#4314, 2026-08-18)ActionRunnerread itconfirmText?: nevertombstonehoverable/striped(objectui#5474, 2026-08-23)data-table/className?: nevertombstonefontSize/fontWeightcustomVars, byte-for-byte?: nevertombstoneThe rule the table shows: a
?: nevertombstone exists to steer authors to a named live replacement, or to keep loud a key the docs actively taught. Outright removal is for zero pull with no successor.This card is the second row's shape exactly.
AccordionItem.iconstates it in its own changeset: it "had zero measured pull anywhere in the corpus and no established convention to lean on, so under this platform's declared=enforced doctrine it is removed rather than speculatively implemented."MobileOverrideshas zero pull, was never documented anywhere, and has no successor spelling — the ruling explicitly forbids keeping the vocabulary in any form. Verified in source:iconis fully absent from bothAccordionItemandToggleGroupItemtoday — no?: never, no@deprecatedresidue.There is no two-stage
@deprecated-then-remove convention in this repo. Every@deprecatedinpackages/types/srcis one of two things, and neither is a stage 1 of retirement: a still-working legacy alias (app.tsmenu,base.tsvisibleOn, theMenuItemandActionSchemainterfaces — all still typed and still read), or a tag applied in the same commit as the?: neverretyping, where the tombstone is the terminal state. Deprecating a no-op for a release cycle would ship a release in whichmobileOverridesstill type-checks and still does nothing — prolonging the exact declare-without-enforce shape the ruling exists to close.Re-verified zero-read measurement
The card is dated 2026-08-17, so its premise was re-measured against
origin/mainated35c23bbbefore anything was deleted. It holds.MobileOverrideshad exactly four mentions repo-wide, none of them a read:The lower-case property name — the spelling a renderer would actually read — appeared only in that declaration. A case-insensitive sweep across every file type (not just
.ts/.tsx) found no JSON metadata, no docs, no schema-catalog entry, and no example app authoring it. Theobjectstackandobjectstack-aisibling checkouts: zero hits.Of the three
navigationvalues,bottom-tabsandhamburgeroccur nowhere else in source except the declaration line itself. The otherhamburgerhits belong toMobileNavModeinpackages/layout— the objectui#3985 sibling, a different type on a different consumption path, untouched here.dist evidence — before and after, same grep
Proving the type is gone from
src/proves nothing about what consumers see, so the emitted declarations were measured on both sides of the change. Identical pattern, identical scope (packages/*/dist --include='*.d.ts'), rebuilt each time:Before (the control — the instrument demonstrably sees the case):
After (
pnpm --filter @object-ui/types --filter @object-ui/mobile build, exit 0):The source retirement note left in
mobile.tsnames the type in a comment; the zeroMobileOverridescount indistconfirms it does not leak into the published.d.ts.The loud-signal requirement, measured rather than asserted
The ruling asks that external
.d.tsconsumers "get a loud signal rather than a silent no-op". That was tested with a real consumer compiled against the built.d.ts, on both sides of the change, with a control:import type { MobileOverrides } from '@object-ui/types'mobileOverrides: { navigation: 'bottom-tabs' }on aMobileComponentConfigresponsive(a still-live key on the same interface)Row B before the change is the card's defect reproduced exactly: it type-checked, it built, and nothing happened. The control matters — on its first run the whole probe failed on a config error rather than on the retirement, which would have made row A's "failure" indistinguishable from success; C staying green is what shows the instrument is measuring the right thing.
Excess-property checking is load-bearing for row B, so it was confirmed that
MobileComponentConfigcarries no index signature and noextends— nothing to swallow the diagnostic. (BaseSchema's[key: string]: anydoes exactly that for top-level component-schema keys; this interface is not in that family.)The before leg reverted the three files to
origin/main, confirmed the mutation on disk by anchored counts on both the deleted and injected text, rebuilt so the mutation actually reacheddist/, and ran under a restore trap. Restore was verified byte-exact:git statusclean against the commit, anddistback to zero hits.Verification
Ran from the repo root with path filters, per AGENTS.md.
pnpm --filter @object-ui/types --filter @object-ui/mobile build— exit 0pnpm --filter @object-ui/types --filter @object-ui/mobile type-check— exit 0 (both script names echoed, so this was not a zero-match silent pass)pnpm exec vitest run packages/types/ packages/mobile/ --maxWorkers=2—Test Files 56 passed (56),Tests 601 passed (601). 56 = 52 types + 4 mobile, so the filter matched these packages rather than someone else'spnpm --filter @object-ui/types --filter @object-ui/mobile lint— exit 0;0 errors, 253 warnings(types) and0 errors, 18 warnings(mobile), all pre-existing inexamples/and__tests__/, none in the changed filescheck-control-bytes— OK, 4929 tracked text files scanned; plus a manual control-byte scan of the four changed filescheck-changeset-presence— 1 changeset for 3 source files of 2 released packagescheck-changeset-no-major— no changeset declaresmajorcheck-spec-symbol-derivation,check-published-dist-tooling,check-doc-component-types— all exit 0All gate results are quoted from each gate's own verdict line, with exit codes captured before any pipe.
One honest note on the lint run: an earlier pass used
--no-inline-config, which is not this repo's lint command (eslint .is), and it reported one error inpackages/types/src/index.ts:1179by disabling a documented, pre-existingeslint-disableblock for aFormFieldspec import at line 1178 — unrelated to this change and present onmain. Under the repo's actual command that file is clean.Verification union ran against the final commit,
da50609e0.Scope
Three source files and one changeset.
packages/app-shellwas never path-widened into.The changeset is
minor, notmajor, per this repo's version-alignment rule, which reservesmajorfor following@objectstackacross a major — the same classificationAccordionItem.iconused for an identically breaking type removal. It records the change as breaking for TypeScript authors ofmobileOverridesonly, with runtime behaviour unchanged.Out of scope, and deliberately left alone here:
MobileComponentConfigitself now has zero mount points and zero readers — it is declared and re-exported twice and nothing consumes it. Same family as this card but a different type, and the #4919 ruling does not cover it, so it is filed for triage as #5942 rather than widened into this PR.Generated by Claude Code