Uh oh!
There was an error while loading. Please reload this page.
feat(core): declare component deprecation in registry metadata, readable by a gate - #6822
Merged
Merged
Conversation
…ble by a gate A deprecated component type was stated in exactly two places, neither of which a gate, a test or a type can consult: a `console.warn` string literal inside the renderer, and the word "(Deprecated)" inside a human-readable `label`. Both gates that touch component types ask whether the type RESOLVES, and a deprecated type resolves — which is how one was authored 85 times across 27 shipped exemplars with every check green. - `@object-ui/core`: `AuthoringSurface` + `ComponentDeprecation`, the `deprecated` key on `RegistryComponentMetaExtras`, and `Registry.deprecationFor(type, surface)` to read it back. The declaration carries the surfaces it applies to rather than being a boolean, because objectui#4000 ruled that `div`/`span` are deprecated on the JSON authoring surface and are permanent vocabulary of the `kind:'html'` tier. - `@object-ui/components`: `div` and `span` now declare the deprecation their notices already state, and their provenance tests pin the declaration to the runtime `isHtmlTierNode` exemption so neither can move alone. - The catalog ratchet's premise arm stops reading the renderer's source for a console literal and asks the registry; a new arm catches a loaded declaration the hand-kept list omits. Nothing new is deprecated and no build starts failing. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CRJge11jso9TpXRWFt1Z49
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 was referenced Aug 29, 2026
os-sam
marked this pull request as ready for review
August 30, 2026 03:17
Uh oh!
There was an error while loading. Please reload this page.
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 freeto 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#6674
Authored by the
domain:uiexecution seat, sessionsession_01CRJge11jso9TpXRWFt1Z49.Verified on
eb852a052— every number below was read from a run on that commit.The question a gate can now ask, and could not before
"Is this component type deprecated?"
Before this PR nothing could ask it. A deprecation was stated in exactly two
places, neither of which a gate, a test or a type can consult:
console.warnstring literal inside the renderer (div.tsx,span.tsx), andlabel.Both gates that touch component types ask a different question — whether the
type resolves — and a deprecated type resolves. The card demonstrated the
cost rather than arguing it: the catalog suite passes 583/583 with 85 authored
divnodes present. The green was the finding. Triage's sharpening is theuseful frame: this lane's usual defect is declared but enforced nowhere; this
one was a layer below — nothing was declared to enforce.
What landed
@object-ui/core—AuthoringSurface('json' | 'html'),ComponentDeprecation, thedeprecatedkey onRegistryComponentMetaExtras,and
Registry.deprecationFor(type, surface)to read it back.The declaration carries the surfaces it applies to rather than being a
boolean, and that is the load-bearing design decision. A bare flag would restate
as a contract the exact falsehood the maintainer ruled against on 2026-08-10
(#4000):
divandspanare deprecated on the JSON authoring surface and areat the same time permanent, first-class vocabulary of the
kind:'html'tier,where our own parser compiles the plain tag straight through and no other
spelling exists to migrate to.
div.tsxsays it in prose already — "a noticethat says the type is deprecated FULL STOP is therefore false for one of its two
readers". Putting the scope in the declaration means no gate re-derives that
exemption locally, which is how the same exemption ends up written N times and
wrong in N-1 of them.
@object-ui/components—divandspannow declare the deprecation theirnotices already state. This deprecates nothing new: it transcribes an existing,
already-ruled deprecation into a form a machine can read.
The pin triage flagged in advance —
packages/core/src/registry/__tests__/component-meta-derives-from-canonical.test.tsenumerates the registry-only key set as a literal union, so the new key updates
it in the same batch (four names to five, plus
REGISTRY_MEMBERSand theregistration literal). The two recorded measurements in that file's header
(the readings taken on the tree before and after #6067) are deliberately left
alone and annotated — editing a recorded reading to match today's tree would
destroy the only evidence that the assignability pair was green on the diverged
one.
The premise moved under the card, in the direction that helps
The card says "nothing stops the 49th authored
div". That was true when it wasfiled (measured on
f55d6661, 2026-08-28) and is no longer true:546f61099landed the catalog ratchet at 04:14 on 2026-08-29, between the filing and this
dispatch. Its own header names this card's gap as the reason for its shape —
its
DEPRECATED_TYPESlist is hand-kept, and its premise arm read therenderer's source and regex-matched the console literal, because that string
was the closest thing to asking the question that existed.
So the highest-value place to spend this card is that gate, and this PR rewires it:
the deprecation this ratchet mirrors is still declarednow asksComponentRegistry.deprecationFor(type, 'json')instead of grepping a.tsx.no LOADED registration declares a deprecation this list omits.That direction did not exist before: with a console string as the only
statement, nothing could enumerate what was deprecated, only re-check what
the list already named. A third deprecated type could have been added to
@object-ui/componentsand the ratchet would have gone on refusing exactly two.DEPRECATED_TYPESdeliberately stays hand-kept. Deriving it wholesale fromthe registry looks like the obvious next step and is a regression: that file
loads
@object-ui/componentsand nothing else, so a type declared deprecated bya plugin package it does not import would drop out of a derived list and the
census would shrink to green. The list is the ratchet's authority because it is
complete by construction; what the declaration buys is that it can now be
checked, in both directions, against something a machine reads.
Nothing goes red, and the count is unchanged
⛔ No build starts failing and nothing new is deprecated. Re-measured
structurally on this branch: 85
divnodes in 27 files across 10 categories,0
spannodes — the card's numbers reproduced exactly. The ratchet alreadyfreezes that stock (80 baselined + 5 in the
components-basic-div/doc-exemptcategory) and draining it stays #3965's worklist, which is not touched here and
stays open.
Reverse-verification
Three ablations, each with the mutation confirmed on disk in both directions and
the restore confirmed by
git diff HEADplus a blob-hash comparison againstthe
HEADblob.A — remove the declaration from
div's registration. Predicted red; red:The control that makes this the load-bearing reading: the mutation left the
console.warnliteral untouched (verified, still 1 occurrence), so theold source-grep premise arm would have stayed green on this exact
mutation. That contrast is the whole delivery, in one measurement.
B — drop
divfrom the hand-kept list. The new arm reports it:C — cross-package, against the EMITTED declaration.
packages/components/tsconfig.jsonoverrides the root
paths, so@object-ui/coreresolves through the workspacelink to
packages/core/dist/registry/Registry.d.ts(measured: 93 coredist.d.tsfiles in the program, 0 coresrcfiles). Pasting shapes the typemust reject into the real registration:
A green there would have meant the key reached the emitted
.d.tsasany, ornot at all.
Verification (all on
eb852a052)Gate family derived from the actual diff, each quoting its own verdict line:
check:control-bytescheck:doc-typescheck:readme-exportscheck:self-importcheck:phantom-depscheck:esm-specifierscheck:side-effects-arraycheck-changeset-presencecheck-changeset-no-majormajorbump.Two coverage checks that are easy to get wrong, both measured rather than
assumed:
packages/components/tsconfig.jsonexcludessrc/__tests__, so thetwo edited provenance tests are covered by the second leg (
tsc -p tsconfig.test.json) — confirmed with--listFiles, 1 hit each; likewise thenew core test file and the updated pin, 1 hit each in
packages/core/tsconfig.test.json.check:readme-exportsreported exit 1 on apartially-built tree ("8 unbuilt") — a prerequisite, not a red gate; it is green
above after a full workspace build.
Notes for review
examples/schema-catalog/, but adifferent file (
components-overlay-context-menu/basic-context-menu.jsonplusa new test); this PR edits
test/deprecated-component-types.test.ts, so thereis no textual overlap.
deprecated-component-types.test.tsarms now import@object-ui/componentsat module scope (registration happens at load; not ina hook — test: fix five load-sensitive flaky tests by moving module loads out of timed windows #3010/test: retire four raised hook timeouts by importing at module scope #3021). Both
@object-ui/componentsand@object-ui/corearealready declared devDependencies of that package, and
check:phantom-depsisgreen.
DIV_DEPRECATION_NOTICE/SPAN_DEPRECATION_NOTICEonto the declaration'sreplacementso the guidance is stated once. It is the right direction, butthe notice text is pinned byte-for-byte by four existing tests and the churn
does not belong in this card. Also untouched: whether the flag should drive
anything at author time (the
objectui validatepath, the save gate) — thecard fences that out explicitly as a separate and larger question.
div组件类型,docs 站每张缩略图都刷一条 deprecation warning #3965.Generated by Claude Code
Generated by Claude Code