Uh oh!
There was an error while loading. Please reload this page.
docs(plugin-form): real object-form catalog entries, and declare both plugin packages in the gallery host - #6314
Merged
os-support-ai merged 3 commits intoAug 25, 2026
Conversation
`plugin-form` was the last category still ledgered in `OWN_PLUGIN_DEBT`: both
entries authored a root `type: "form"` with `input` / `select` / `checkbox` /
`textarea` fields, every one of them registered by `@object-ui/components` and
none by `@object-ui/plugin-form`. They sat on `content/docs/plugins/
plugin-form.mdx` inside a `PluginLoader plugins={['form']}` wrapper neither of
them used.
Replaced by two entries that read the docs gallery's demo data source through
the registered `object-form` renderer, the way objectui#5113 did for
`object-view` and objectui#5856 for `object-grid`. The two hand-built forms are
re-seated into `components-form-form` rather than deleted, so none of the
corpus-wide node counters moves.
Two measurements changed how this landed, both recorded in the code:
- `object-form` already resolved in the gallery WITHOUT this change — measured
with exactly the eleven imports the host used to carry — because
`@object-ui/plugin-view` imports `ObjectForm` from `@object-ui/plugin-form`.
So declaring the package is a statement of what the gallery depends on, not
a fix for a red tile.
- the pin's DATA half read `container.textContent`, which a form's record
never reaches: it lands in `input.value`. The instrument now reads both, and
a control case pins that it still fails on a form with no record behind it.
`renderEntry` also settles past `Loading form...` now. Without it the two new
entries' provenance cases passed in a whole-file run and failed under `-t`,
because the placeholder is real DOM that satisfies `drewSomething`.
Claude-Session: https://claude.ai/code/session_011SfZeFWrhGLHmfq61xbz4q
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>`object-grid` reached the gallery's registry only because
`packages/plugin-view/src/ObjectView.tsx:37` imports `ObjectGrid` — a component
import in another package, not a plugin dependency of the host. Since
objectui#5856 the two `plugin-grid` catalog entries are real `object-grid`
nodes, so the gallery genuinely depends on that path: a refactor of
`object-view` that stopped drawing a grid itself would turn two tiles into
OBJUI-001 panels, with the cause several files from the symptom.
`registerCatalogBlocks.ts` now names the package, and `HOST_PACKAGES` mirrors
it. Nothing renders differently — measured with exactly the eleven packages the
host used to carry, `object-grid` and every `@object-ui/plugin-form` key already
resolved.
That measurement is also why the judge for this is NOT
`ComponentRegistry.get('object-grid')`: it is truthy in the declared world and
in the transitive one alike, so it cannot fail in either and judges nothing
here. The case added instead reads the host's DECLARATION — every `plugin-*`
category with catalog entries must be loaded by name — and leans on the
existing parity case that ties `HOST_PACKAGES` to the host file's literal
import list. The rule is derived from the categories, so a new plugin category
with entries picks it up with no edit.
Claude-Session: https://claude.ai/code/session_011SfZeFWrhGLHmfq61xbz4q
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>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 25, 2026
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
|
os-support-ai
marked this pull request as ready for review
August 25, 2026 12:50
Uh oh!
There was an error while loading. Please reload this page.
os-support-ai
deleted the
claude/issue-6167-plugin-form-catalog-entries
branch
August 25, 2026 13:06
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#6167
Fixes#6025
Two cards, one branch, one commit each — they edit the same import list in
apps/site/app/components/registerCatalogBlocks.tsand the same mirroredHOST_PACKAGESarray in
examples/schema-catalog/test/catalog-gallery-render.test.tsx, which a parity caserequires to move together. Split, they would conflict by construction.
74879a009— Bothplugin-formcatalog entries authorform(a@object-ui/componentstype), neverobject-form— the third instance of #5113's class #6167: the twoplugin-formcatalog entries become realobject-formnodes.778aaf135— finding(apps/site): the catalog gallery registersobject-gridonly transitively —registerCatalogBlocks.tsnever imports@object-ui/plugin-grid#6025: the gallery host declares@object-ui/plugin-gridinstead ofinheriting
object-gridfromplugin-view's component import.Verified on
778aaf135(every number below is from that tree unless it says otherwise).Premise correction — read this before the rest
#6167's stated reason for widening the fix to the host is false on today's
main, andwas false when the card was filed. The card says
object-form"is not in the gallery'sregistration set at all" and that a rewritten entry "would paint the OBJUI-001 panel".
Measured, importing exactly the eleven packages the host carried before this PR and nothing
else:
object-form,plugin-form:object-form,embeddable-form,form-analytics,object-master-detail-form,record:line_items,view:form,object-gridandimport-wizardall resolved, and all four candidateobject-formtiles rendered withno OBJUI-001, no error boundary and no
DataSource required. The reason is one line abovethe one #6025 is filed on:
packages/plugin-view/src/ObjectView.tsx:38doesimport { ObjectForm } from '@object-ui/plugin-form', and importing that entry runs itsComponentRegistry.registercalls. Both lines predate the card.The defect #6167 names is real and is fixed here; what changes is why the host edit belongs
in the diff. It is not a fix for a red tile — it is #6025's fix applied to the second
package that had the same latent shape. That is the honest framing for both cards, and it
is why the judge for #6025 is not "is the type registered".
#6167 — the entries
Both entries authored a root
type: "form"withinput/select/checkbox/textareafields: every one of those registered by@object-ui/components, none of themby
@object-ui/plugin-form, whose own keys areobject-form,embeddable-form,form-analytics,object-master-detail-form,record:line_itemsandview:form. They saton
content/docs/plugins/plugin-form.mdxinsidePluginLoader plugins={['form']}.basic-formandcontact-formmove tocomponents-form-formas
basic-formanddemo-request-form(renames, byte-identical). They are legitimate@object-ui/componentsexamples filed under the wrong plugin. Deleting them would movecorpus-wide counters for a non-coverage reason:
NODE_CENSUSinlayout-dom-leak-5574.test.tsxand inform-control-dom-leak-5632.test.tsx(that onecounts
input/checkbox/textareanodes across the whole catalog, which an in-placerewrite would have moved), plus the
className-carrying layout node andstacknodefloors in
layout-props-conversion.test.tsx. All are unchanged and no floor was edited —1798/1798 tests green across the 13 files in
examples/schema-catalog/test/.plugin-form/object-form-record(oneusersrecord,mode: 'edit',fields derived from the object's metadata,
fields/columnsshaping the grid) andplugin-form/object-form-tabbed-sections(the same record withformType: 'tabbed', sodeclared
sectionsbecome tab panels of one form). Every key is declared onObjectFormSchema; nothing invented. They bindusersbecause that is the one object thegallery fixture serves — verified against
apps/site/app/components/galleryDataSource.tsand its mirror, not assumed from the card. They deliberately author no
selectfield: thefixture declares
role/statusas selects with nooptions, so those controls wouldrender "No options available" in the docs gallery. Fixing the fixture is out of scope here.
OWN_PLUGIN_DEBTlines are gone, so the entries are now held toSTRUCTURE, MOUNT and DATA like every other one, and the coverage-split literal moves to
structure+mount+data: { categories: ['plugin-form', 'plugin-grid', 'plugin-view'], entries: 7 }with
ledgered-debt: [].Two instrument defects found on the way, both fixed here
container.textContent, and a form'srecord never lands there — it lands in
input.value. Measured:Alice Johnsonarrives asinput[name].valuewhile the whole tile's text isNameEmailDepartmentCancelSave changes.carriesFixtureRecordnow reads text or control values. The widening is a superset, soit relaxes nothing for the five entries that passed before, and a new control case pins
that it still discriminates: the same renderer, same object, same mode, with a
recordIdthe fixture does not serve — its controls render (asserted first, or the case would be a
degenerate control) and hold nothing.
renderEntrysettled on a loading frame.ObjectFormholds its first paint behindLoading form..., which is 5 elements of real DOM and therefore satisfieddrewSomething.The two new entries' provenance cases passed in a whole-file run and failed under
-t—an order-dependent green, measured in both directions.
renderEntrynow settles past thatplaceholder as well; both cases then pass in isolation.
#6025 — declared, not transitive
registerCatalogBlocks.tsnames@object-ui/plugin-grid(and@object-ui/plugin-form), andHOST_PACKAGESmirrors both in the host's order.The judge is deliberately not
expect(ComponentRegistry.get('object-grid')).toBeTruthy():per the measurement above that is truthy in the declared world and in the transitive one, so
it cannot fail in either and proves nothing about declaration — a ghost for this question. What
is asserted instead is the host's declaration: every
plugin-*category with catalog entriesmust be loaded by name, derived from the categories rather than enumerated, leaning on the
existing parity case that ties
HOST_PACKAGESto the host file's literal import list.Ablation — one leg at a time, restored under
trap … EXIT INT TERMMutation proven on disk each way by comparing
git hash-objectagainst the path'sHEADblob(an empty hash is treated as failure), restore by
git checkout HEAD --naming the pathabsolutely, and
git diff HEAD --statempty at the end.object-form-recordreverted to its oldformschemaauthors a node whose type its own package registers,mounts that node where the tile actually paints,states its own coverage split(3 failed / 570 passed)plugin-grid/plugin-viewHOST_PACKAGESentry all removedevery plugin category with catalog entries is loaded BY NAME by the host(1 failed / 573 passed)object-gridstill resolves transitively, which is the pointHOST_PACKAGESleft naming itloads every package this pin loads, in this pin's order(1 failed / 573 passed)Leg A predicted four reds and produced three: the DATA case does not go red, it disappears —
an entry that stops authoring
objectNamedrops out ofdataBound, and the coverage-splitliteral is what catches the lost half. That is the tiering working as designed, and it is why
the split case exists.
Cost, and the #4600 separation
check:eager-closurecannot see this change, and the card's note that it "measures thatbudget" is stale. The gate reads
apps/console/dist/eager-closure.json(
scripts/check-eager-closure-budget.mjs:292) andperformance-budget.ymltriggers onpackages/**,apps/console/**,pnpm-lock.yaml. This PR touchesapps/site, so the gatemeasures a bundle the diff cannot move; it will run in CI (the lockfile changed) and pass
unchanged. Running it locally would have been a green in both worlds. Reported rather than
raised or worked around — no budget was touched.
route's eager closure through
@object-ui/plugin-view(import [WIP] Update documentation for project #11), which importsObjectGridandObjectFormat module scope. An ES module executes once, so the two newside-effect imports add a declaration, not a payload, and re-run no registration.
plugin-dashboardexamples are refused by the spec'sDashboardSchema— the AI few-shot corpus teaches the pre-ADR-0021 widget shape #4600's separation still holds:InteractiveDemo.tsxandLiveSplitDemo.tsxstill do notimport this module — asserted by the existing case, which is unchanged and green. Per-page
demos keep opting in through
PluginLoader.Gates run locally, at
778aaf135examples/schema-catalog/test/(13 files, 1798 tests) ·catalog-index-regenerable-4633+site-playground-layout-registration-3904(2 files, 17 tests) ·type-checkfor@object-ui/example-schema-catalog(tsc --noEmit && tsc -p tsconfig.test.json, with itsdependency closure built) ·
lintfor@object-ui/example-schema-catalogand for@object-ui/site(0 errors; 7 pre-existing warnings, none in a file this PR touches) ·check:doc-types("✅ Every documented component type is registered") ·check-doc-links("Links are valid across 17 scan roots") ·
check:doc-fences·check-control-bytes("✅ scanned 5199 tracked text file(s)") ·
check:phantom-deps("✅ Every in-scope import is declared by the package that publishes it") ·
regenerate-catalog-index.py --check("index.ts is up to date (430 entries)") ·check-changeset-no-major·check-changeset-presence("✅ No source of a released package changed in this range, so no changeset is owed" — two
changesets with empty frontmatter are included anyway, releasing nothing, the way #6028 did).
Draft on purpose: not ready, not enqueued, no auto-merge.
Generated by Claude Code