feat(types,react,core,plugin-dashboard)!: a node slot and SchemaRenderer's schema prop take the declared-node union, V1; the dashboard producers name declared nodes and an envelope's object-metric retires (objectui#11466) - #11512
objectstack-fleet[bot] wants to merge 18 commits into
Conversation
… the declared-node union (objectui#11466) `SchemaNode`'s object arm is `DeclaredNode`: the discriminated union, keyed by the literal `type`, of the component schemas `AnySchema` declares (without its `BaseSchema` arm, whose `type` is `string`), the spec-declared `AuthoringNode`s and the types an application declares in the new `CustomNodeRegistry` interface. `SchemaRendererProps.schema` takes the same type beside a string. No `type: string` arm, no index signature. The cycle: `SchemaNode` names `AuthoringNode`, whose `FlexBlockNode` is the input of `FlexBlockSchema`, whose bag names `SchemaNodeSchema`, whose type names `SchemaNode`. `FlexBlockNode` becomes an interface (members resolved lazily), and `zod/base.zod.ts` writes the node slot's zod type out through type aliases. Typing only; no schema object moves. Claude-Session: https://claude.ai/code/session_01XvhGmGAP79ZB8swnkapxPC Co-authored-by: Claude <noreply@anthropic.com>
…ui#11466) `AppComponentSchema` (the app.json document, read structurally by `AppSchemaRenderer`, never dispatched by `ComponentRegistry`) is not a node, so `DeclaredNode` leaves it out: the registry's `app` key serves the page kind. `PageDocumentNode` admits every page kind but the interface-mode `list`, which `PageView` renders through `InterfaceListPage` and never hands to `SchemaRenderer`; the registry's `list` key is the `list` node's. Narrowing a `DeclaredNode` on `type === 'app'` now gives `PageDocumentNode` alone (was `AppComponentSchema | PageDocumentNode`), and on `'list'` gives `ListSchema` alone (was `ListSchema | PageDocumentNode`). `SchemaByType` reads `AnySchema` and does not move. Claude-Session: https://claude.ai/code/session_01XvhGmGAP79ZB8swnkapxPC Co-authored-by: Claude <noreply@anthropic.com>
…fter validateTree; the builder's node slots take DeclaredNode (objectui#11466) - `kind: 'html'` pages: the runtime-parsed `SchemaElement` tree becomes a `DeclaredNode` at ONE documented boundary, reached only when `compile`'s `validateTree` reported no error (seat answer Q2 A on objectui#11479). - `@object-ui/core`'s schema builder: `.child()` / `.children()` (grid, flex) and the card's `.content()` take `DeclaredNode` instead of `BaseSchema`, so a child passed in is checked against its own type. Claude-Session: https://claude.ai/code/session_01XvhGmGAP79ZB8swnkapxPC Co-authored-by: Claude <noreply@anthropic.com>
…input crosses one helper, and the old-shape pins state the declared-node union (objectui#11466)
- `@object-ui/test-support` gains `undeclaredNode`, THE one crossing for
deliberately undeclared node input in a test: unknown or retired types,
refused spellings (`props` / `visibility` on `element:text`, a node-level
`params`, a retired `drillDown`), the three runtime-flat action suites,
a host slot merged into a node, bare `{ type }` smoke nodes.
- Types a test registers with `ComponentRegistry` are declared in
`CustomNodeRegistry`, as an application would (react: test-widget,
test-debug-div, crashing-widget / stable-widget, test-component,
probe-7088, test-4548-div, identity-probe / self-updating-probe,
test:probe-4795, valid-host / host-wrap, test-ctx-consumer, probe-3955,
probe-7530, test:schema-input-bridge-8908).
- Fixtures that are declared nodes name their type: plugin-gantt and
plugin-map's propertiesBag fixtures (bag node and TS twin), the four
`home` page documents (now with the spec-required `label`).
- Pins: react propsResolution and schema-input.bridgeFidelity state
`DeclaredNode`; types overlay-trigger-union-7081 likewise;
node-recursion-point-8344 states the measured exclusion set the
`BaseSchema` arm used to hide; zod-mirror-parity records the two Wider
rows the `component` slot's `BaseSchema` fallback produces (objectui#8347's).
- New pin `node-slot-union-11466.test.ts`: a nested misspelling on a
closed node is refused with the signature present, no `type: string`
arm, the `app` / `list` arms, registry entries join under their key.
Claude-Session: https://claude.ai/code/session_01XvhGmGAP79ZB8swnkapxPC
Co-authored-by: Claude <noreply@anthropic.com>
…is declared in CustomNodeRegistry (objectui#11466) - Examples that held a node as `BaseSchema` or as an unannotated literal name `DeclaredNode` (the schema-rendering, expressions, architecture, data-source and runner guides; the root, components, data-objectstack and react READMEs; the blocks index). - `schema-renderer.mdx`'s custom widget declares `MyWidgetSchema` in `CustomNodeRegistry` beside its `ComponentRegistry.register` call. - `data-source.md` teaches a node that reads `objectName` (`object-grid`, its props in the bag) instead of `table`. - `plugin-detail`'s related-list example writes its props in the `properties` bag; the types README's `data-table` carries its required `columns`. - The schema reference, the types README and the react README describe `SchemaNode`, `DeclaredNode` and `CustomNodeRegistry` as they now are. Claude-Session: https://claude.ai/code/session_01XvhGmGAP79ZB8swnkapxPC Co-authored-by: Claude <noreply@anthropic.com>
…tries its change falsifies One changeset (types, react, core minor with the breaking meaning stated; components patch). Dated, append-only notes on the pending entries whose standing reading of `SchemaNode`, the prop union, the bridge's types or the node-recursion pin this change makes false: 11364, 8331, 8908, 4622, 7767, 11479, 8572. Claude-Session: https://claude.ai/code/session_01XvhGmGAP79ZB8swnkapxPC Co-authored-by: Claude <noreply@anthropic.com>
…e`; two source pins and the schema reference follow (objectui#11466)
- `DeclaredNode` excludes the app-level document as
`Exclude<AnySchema, { type: 'app' }>` rather than by name, so `base.ts`
does not name that interface (the `AppComponentSchema.actions[]` reader
census in handler-keys-string-any-mirrors-7344 keys on the name).
- page-body-arity-8310 reads the root README's typed example
(`const schema: DeclaredNode = {`); overlay-node-slot-doc-types-7082
reads `SchemaNode`'s new spelling in `base.ts`.
- The schema reference points at the SchemaRenderer page's registration
walkthrough instead of a placeholder `my-widget` block.
Claude-Session: https://claude.ai/code/session_01XvhGmGAP79ZB8swnkapxPC
Co-authored-by: Claude <noreply@anthropic.com>
…typed example (objectui#11466) Claude-Session: https://claude.ai/code/session_01XvhGmGAP79ZB8swnkapxPC Co-authored-by: Claude <noreply@anthropic.com>
…onger uses (objectui#11466) Claude-Session: https://claude.ai/code/session_01XvhGmGAP79ZB8swnkapxPC Co-authored-by: Claude <noreply@anthropic.com>
…op as `BaseSchema` (objectui#11466) 8310-page-node-body-arity and 11354-plugin-form-literals each said, in the present tense, that `SchemaRenderer`'s `schema` prop is typed `BaseSchema`. After this change it is `DeclaredNode | string | null | undefined`. Each entry gets an append-only dated note; no existing line moves. Claude-Session: https://claude.ai/code/session_01XvhGmGAP79ZB8swnkapxPC Co-authored-by: Claude <noreply@anthropic.com>
|
changeset-claim-re-read
|
ℹ️ Console Performance Budget — not measuredThis run did not produce a console bundle to measure, so there is no pass/fail verdict for the performance budget. This is not a budget violation. Nothing was measured — the numbers a real violation would carry are simply absent.
See the workflow run for details. No package size report: it is only generated from a complete package build, so a partial one is never shown. |
…ctui#11466) One textual conflict, packages/types/src/__tests__/zod-mirror-parity.test.ts, resolved as the union of both sides' WiderThanDeclared rows: main's objectui#11515 entry (app.zod.ts#AppSchemaRendererNodeSchema::schema, one SCHEMA-NODE arm) and this branch's two objectui#11466 entries (complex.zod.ts#DashboardComponentSchema::widgets and complex.zod.ts#DashboardWidgetSchema::component, two CONCRETE arms each). The header bullet reads the union's figures, with both histories in landing order; the file's own header-figures pin re-derives them. Claude-Session: https://claude.ai/code/session_01XvhGmGAP79ZB8swnkapxPC Co-authored-by: Claude <noreply@anthropic.com>
ℹ️ Console Performance Budget — not measuredThis run did not produce a console bundle to measure, so there is no pass/fail verdict for the performance budget. This is not a budget violation. Nothing was measured — the numbers a real violation would carry are simply absent.
See the workflow run for details. No package size report: it is only generated from a complete package build, so a partial one is never shown. |
…5 twinned (objectui#11466) objectui#11515 gave detail-section, app-schema-renderer and cloud:plan-status their TypeScript twins and joined them to AnySchema, so their zod output is assignable to SchemaNode and the two-way ratchet went red on the merged tree (TS2344 at NodeRecursionPointDeclarationDrift). The three names leave the measured set; a dated note records why, and the first measurement's bullet is kept as that change's reading. Claude-Session: https://claude.ai/code/session_01XvhGmGAP79ZB8swnkapxPC Co-authored-by: Claude <noreply@anthropic.com>
ℹ️ Console Performance Budget — not measuredThis run did not produce a console bundle to measure, so there is no pass/fail verdict for the performance budget. This is not a budget violation. Nothing was measured — the numbers a real violation would carry are simply absent.
See the workflow run for details. No package size report: it is only generated from a complete package build, so a partial one is never shown. |
…NodeRegistry, the static pivot names PivotTableSchema, and the SchemaRenderer casts go (objectui#11466) - widgetDispatch.ts: DASHBOARD_NODE_TYPES keeps literal values (a string-keyed view serves the by-type lookup), and DashboardMetricNodeSchema, typed by MetricWidget's props, is entered in @object-ui/types' CustomNodeRegistry under plugin-dashboard:metric (objectui#11479 Q1 A). The entry exports it so the published typings load the declaration. - Both surfaces' getComponentSchema return SchemaRendererProps['schema'], so each node is checked against its declared type where it is built; the metric arms narrow widgetType for the required label. - DashboardGridLayout's static pivot states the keys PivotTableSchema declares and PivotTable draws, read from options, instead of spreading options whole. - The `as BaseSchema | string | null | undefined` cast in DashboardGridLayout and the `as BaseSchema` cast in DashboardRenderer are gone. No new cast. - index.tsx: ObjectMetricBlock's docblock no longer names the dashboard grid path as a host (objectui#11525 retired it). One line remains in DashboardRenderer: the filter broadcast's object-metric member writes a flat `filter` onto an object-metric node, which the declared node (the spec's bag form) refuses by name. Held for a decision, reported on objectui#11466. Claude-Session: https://claude.ai/code/session_01XvhGmGAP79ZB8swnkapxPC Co-authored-by: Claude <noreply@anthropic.com>
ℹ️ Console Performance Budget — not measuredThis run did not produce a console bundle to measure, so there is no pass/fail verdict for the performance budget. This is not a budget violation. Nothing was measured — the numbers a real violation would carry are simply absent.
See the workflow run for details. No package size report: it is only generated from a complete package build, so a partial one is never shown. |
…d dated notes on three pending entries (objectui#11466)
- New .changeset/11466-dashboard-metric-node.md (@object-ui/plugin-dashboard
minor): DashboardMetricNodeSchema, the static pivot's stated keys and
what no longer rides along, and the casts gone.
- Dated, append-only notes:
- 8310-page-node-body-arity.md: the root README's Basic Usage example
authors `children`, not `body` (already so at this branch's base);
- 10528-grid-object-table-fetch.md and 11514-dashboard-slot-entry-types.md:
their "unchanged" / "draws as before" readings for the grid's static
pivot, whose node now states its keys.
- DashboardGridLayout.tsx: the pivot comment names the keys it states.
Claude-Session: https://claude.ai/code/session_01XvhGmGAP79ZB8swnkapxPC
Co-authored-by: Claude <noreply@anthropic.com>
ℹ️ Console Performance Budget — not measuredThis run did not produce a console bundle to measure, so there is no pass/fail verdict for the performance budget. This is not a budget violation. Nothing was measured — the numbers a real violation would carry are simply absent.
See the workflow run for details. No package size report: it is only generated from a complete package build, so a partial one is never shown. |
…ope draws the retired-format placeholder, and leaves the filter broadcast (objectui#11466) The maintainer's ruling A on objectui#11466 (comment 5966278275), which extends ruling C on objectui#11525 to the last inline metric form. - legacyRetiredWidget.ts: isRetiredEnvelopeNode, shared by both surfaces, answers an object-metric node (bare key or the registration's full name) read from a widget's legacy `component` envelope. - DashboardRenderer and DashboardGridLayout return the imported LEGACY_RETIRED_WIDGET_SCHEMA for it, before the envelope pass-through. - DashboardRenderer: object-metric leaves FilterableComponentType / FILTERABLE_COMPONENT_TYPES, so the flat-filter write the declared object-metric node refuses is gone with no cast. The docblock now names what the broadcast covers. - inlineObjectMetricRetired-11525: the envelope case flips to the placeholder on both surfaces (dated note in the header), and a control keeps the envelope's object-chart and object-data-table receiving the filter bar's value. Untouched: the envelope's other node types, the authored object-metric block on pages, and every zod and TypeScript authoring face. Claude-Session: https://claude.ai/code/session_01XvhGmGAP79ZB8swnkapxPC Co-authored-by: Claude <noreply@anthropic.com>
…e README and guide, its changeset, and dated notes on three pending entries (objectui#11466) - New .changeset/11466-envelope-object-metric-retired.md (@object-ui/plugin-dashboard minor): before, now, the fix (bind a dataset) and what does not move. - README.md and content/docs/plugins/plugin-dashboard.mdx: the envelope paragraph names the one retired node and what still draws. - Dated, append-only notes: 11525-inline-metric-retired.md (the envelope object-metric no longer receives the filter bar's values), 11348-dashboard-widget-reads.md (the broadcast narrows over two types, not three), 11514-dashboard-slot-entry-types.md (an envelope's object-metric draws the placeholder). Claude-Session: https://claude.ai/code/session_01XvhGmGAP79ZB8swnkapxPC Co-authored-by: Claude <noreply@anthropic.com>
✅ 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
|
schema prop take the declared-node union, V1 (objectui#11466)schema prop take the declared-node union, V1; the dashboard producers name declared nodes and an envelope's object-metric retires (objectui#11466)
✅ 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
|
…ctui#11466) Brings in objectui#10813 (PR #11555), which landed after the previous merge. No textual conflict. Claude-Session: https://claude.ai/code/session_016tKoy8NJa35Yih1FdzrVmn Co-authored-by: Claude <noreply@anthropic.com>
✅ 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
|
Contract reviewServed-tier: What was read: card objectui#11466 (its body and all 19 comments), PR #11512 (its body, its 88-file list, and its net diff against the merge-base ① Derived judgments1. The narrowing (TypeScript face only).
2. New public types and exports.
3. The plugin-dashboard producers.
4. The runtime move: the static pivot.
5. The ledgers.
6. The flex bag's array child list.
7. The tests.
8. The check-runs. 39 success, 3 skipped (two coverage jobs and dependabot) and 1 failure,
② Semver level
③ Boundary flags
Implemented-by: VERDICT: PASS |
Fixes #11466
This PR carries ruling ① (V1) and the card's residue, with
mainmerged in, the plugin-dashboard producers closed, and the maintainer's ruling A on the last inline metric form (comment 5966278275). The census reads 0 lines across all 88 workspace type-check programs, withBaseSchema's index signature present.Clause-②: yes (narrowing)
Depends on objectui#11543 (governed PR #11558).
Skill Example Checkstays red on this PR until it lands: three marked fences inskills/objectui/guidespass aBaseSchematoSchemaRenderer, which V1 refuses. Atcb687dfadthe gate reads 18 of 18 fences judged, 3 failed, and nothing else in CI is red.What changes
@object-ui/typesexportsDeclaredNode. It is the discriminated union, keyed by the literaltype, of:AnySchemadeclares, minus itsBaseSchemaarm (whosetypeisstring) and minus the app-level document, which is left out by{ type: 'app' }(AppSchemaRendererreads that document structurally andComponentRegistrynever dispatches it);AuthoringNode;CustomNodeRegistryinterface. An entry joins under its KEY: the arm is the entry intersected with{ type: KEY }, so even a loose entry adds notype: stringarm.SchemaNodeisDeclaredNode | string | number | boolean | null | undefined. It wasBaseSchema | string | number | boolean | null | undefined.SchemaRendererProps['schema']isDeclaredNode | string | null | undefined. It wasBaseSchema | AuthoringNode | string | null | undefined.toRenderableSchemafollows by reference.@object-ui/core's schema builder takesDeclaredNodewhere it tookBaseSchema:.child()and.children()on the grid and flex builders, and the card builder's.content().@object-ui/components'kind: 'html'page crosses its runtime-parsed tree intoDeclaredNodeat ONE documented boundary, right aftervalidateTreereports no error (page.tsx, objectui#11479 Q2 A). No other cast toDeclaredNodeexists undersrc/.@object-ui/test-supportgainsundeclaredNode, the one crossing for deliberately undeclared test input (objectui#11479 Q3 A). It has 25 call sites in 15 test files, and none outside tests.@object-ui/plugin-dashboard:plugin-dashboard:metricis declared throughCustomNodeRegistry(objectui#11479 Q1 A).DashboardMetricNodeSchema, a new export, is the nodeMetricWidgetrenders under that key, with the keys it reads off the node, typed byMetricWidgetProps.widgetDispatch.tsenters it in the registry besideDASHBOARD_NODE_TYPES, whose values are now literal types (a string-keyed view serves the by-type lookup). The package entry exports the type, so its published typings load the declaration.getComponentSchemainDashboardRendererandDashboardGridLayout) returnSchemaRendererProps['schema'], so each node is checked against its declared type where it is built. The metric arms narrowwidgetTypefor the required label;classifyWidgetTypeanswersmetriconly for a named type, so no verdict moves.DashboardGridLayout's staticpivotnode states the keysPivotTabledraws (itsPivotTableSchemakeys, andclassName), read fromoptions, instead of spreadingoptionswhole, so it namesPivotTableSchemawith no cast.SchemaRendererare gone:as BaseSchema | string | null | undefinedinDashboardGridLayoutandas BaseSchemainDashboardRenderer. No new cast.object-metricnode in a widget's legacycomponentenvelope drawsLEGACY_RETIRED_WIDGET_SCHEMAon both surfaces (the maintainer's ruling A on objectui#11466, extending ruling C on objectui#11525), under its bare key and underplugin-dashboard:object-metric, and sends no query. One shared detector,isRetiredEnvelopeNodeinlegacyRetiredWidget.ts, is read by both surfaces before the envelope pass-through, and the placeholder is the same imported object the metric and pivot arms return.object-metricleaves the filter broadcast'sFilterableComponentType/FILTERABLE_COMPONENT_TYPES, so the flat-filterwrite the declaredobject-metricnode refuses is gone. The broadcast now coversobject-chartandobject-data-table, built by the renderer or written in an envelope.type: stringarm, an index signature, a transitionalBaseSchemaarm,BaseSchema's own index signature, and thecomponentslot'sBaseSchemafallback (all objectui#8347's). Every zod face and every TypeScript authoring face ofobject-metricstays as it was, and so does the authoredobject-metricblock on a page. Two runtime moves, both in@object-ui/plugin-dashboard: an option key the static pivot does not state no longer reaches its node, and an envelope'sobject-metricdraws the rebind prompt.The accept set, before and after (TypeScript face only)
Judged by
packages/types/src/__tests__/node-slot-union-11466.test.ts, by the react prop pin, and by the premise probes below.type, nested or at the prop, e.g.{ type: 'card', children: [{ type: 'txt' }] }. Before: compiles through theBaseSchemaarm. After: TS2322.BaseSchemaat the prop or in a slot. Before: compiles. After: refused, because it names no declared type.AuthoringNode, or a closedCustomNodeRegistryentry), nested at any depth. Before: compiles through theBaseSchemaarm. After: refused, because the slot discriminates ontype.BaseSchema. Before: compiles. After: still compiles, through that type's own index signature, until objectui#8347 removes it. Measured below as the signature-present control leg.BaseSchemaarm. After: refused. Examples: a storedhomepage withoutlabel, adata-tablewithoutcolumns, a staticpivotwithout its axes.typecompiled. After: it compiles once declared inCustomNodeRegistry; an unregistered one is refused.plugin-dashboard:metricnode. Before: compiled through theBaseSchemaarm, like any string. After: in a program that loads@object-ui/plugin-dashboard's typings it is a declared node, checked againstDashboardMetricNodeSchema(which extendsBaseSchema, so a misspelled key still compiles until objectui#8347); in one that does not, it is refused as undeclared.type.'app'narrows toPageDocumentNode(the stored page kind) and'list'toListSchema.PageDocumentNodeexcludes the interface-modelistkind, whichPageViewrenders throughInterfaceListPageand never hands toSchemaRenderer.SchemaByTypereadsAnySchemaand does not move.The merge of
mainMeasured first with
git merge-treeagainstmainat160c6c6e: one conflict,packages/types/src/__tests__/zod-mirror-parity.test.ts, as expected.content/docs/api/schema-reference.md,packages/core/src/builder/schema-builder.ts,packages/plugin-detail/README.mdandpackages/types/src/index.tsauto-merged. The merge is the merge commitc7c37b73; no rebase, no force-push.The resolution is the union, re-derived on today's
main.WiderThanDeclaredholds main's objectui#11515 entry (app.zod.ts#AppSchemaRendererNodeSchema::schema, one SCHEMA-NODE arm) and this branch's two objectui#11466 entries (complex.zod.ts#DashboardComponentSchema::widgetsandcomplex.zod.ts#DashboardWidgetSchema::component, two CONCRETE arms each). The header bullet reads the union's figures, with both histories in landing order; the file's own pin 'the WIDER ledger's header figures are derived from its ARMS' re-derives them fromWIDER_ARMSand the mirrors, and the type-level ratchet confirms each entry against the mirrors (typestsconfig.test.jsonand vitest, both green). objectui#11514'sKnownDriftmove (typeleftcomplex.zod.ts#DashboardWidgetSchema's entry) merged without conflict.MeasuredArmDrift11466(node-recursion-point-8344.test.ts) dropsdetail-section,app-schema-rendererandcloud:plan-status, which objectui#11515 twinned and joined toAnySchema. On the merged tree before that edit the two-way ratchet read red (TS2344 atNodeRecursionPointDeclarationDrift), which is what the ratchet is for; a dated note records the reconciliation.Landing-prep round (director seat, claim
5970151706; dev report5970915352): two more merge commits, both conflict-free, withpnpm installleaving the lockfile unchanged.5afa0269amergesmain154075ab1: objectui#11533, the@objectstack/spec17.6.0 bump objectui#11531, objectui#11547, finding(app-shell):applyViewItemmakes a container's FIRST named form its create/edit.formwhen no item is default — the first-named promotion objectstack#21500 removes from the spec #11539, plugin-form: the tabbed Edit/New form dialog renders no tab for a{ group }form section, so group-referenced fields have no editing surface there (moved from objectstack-ai/objectstack#21543, item 1) #11542, objectui#11344 and objectui#11068.cb687dfadmergesd0c0c7fe9, objectui#10813.mainbrought no new V1 producer.H1: the cycle
tsc -p packages/types/tsconfig.json), there were 9 errors: TS2456 onFlexBlockNode,AuthoringNode,DeclaredNodeandSchemaNode; TS4109 inzod/base.zod.ts; TS7022 onFlexSchema,FLEX_BAG_CHILDREN,FlexPropsBagandFlexBlockSchema.FlexBlockNodeis an interface that extends the closed arm input ofFlexBlockSchema, with no members of its own;zod/base.zod.tswrites the node slot's zod type out through two type aliases (SchemaNodeZodType,NodeSlotZodType). The schema objects do not change.tsconfig.jsonand intsconfig.examples.json, on the merged tree as well.H3: premise ②, re-run on the merged tree
Throwaway probe files, never committed: 40 type-level rows in
@object-ui/typesand 15 in@object-ui/react, each labelled OK (must compile) or REFUSE (must error), each run on two legs atb13093d6.BaseSchema's index signature deleted; restore proven by blobc0d9ad44equal before and after, signature lines back to 2): types 40 of 40 as labelled, react 15 of 15, with no error on an unlabelled probe line. So (a) a nested misspelling is refused at every slot depth and at the prop, and (b) a registered custom type is authorable, its misspelling refused, and its keys do not escape onto a declared type.BaseSchema, which is the signature objectui#8347 removes. Undeclared types, wrong-value keys, the tombstone,AuthoringNodebag misspellings and unregistered custom types are refused on both legs.mainat160c6c6eagainst this branch atb13093d6. Instantiations are deterministic (one value across 3 runs each); seconds are medians of 3 on a shared box, so read them as ratios:tsconfig.jsontsconfig.examples.jsontsconfig.test.jsontsconfig.jsontsconfig.test.jsontsconfig.jsontsconfig.test.jsonThe first fork read +23.95% (react src), +19.01% (react tests) and +6.48% / +5.83% (components). Memory medians moved between 0.0% and +6.7%.
H2: the census
The instrument is objectui#11479's census, copied: all 88 workspace type-check programs, each run on its own, after a full build.
BaseSchema's index signature is present on every reading.c7c37b73): 9 lines in 3 of 88 programs. plugin-dashboardtsc --noEmit4 andtsconfig.test.json4 (the fourSchemaRendererrender sites, two per surface, fed by the two casts); typestsconfig.test.json1 (MeasuredArmDrift11466).f90ba8d2(the previous round): 2 lines in 2 of 88 programs, both the return ofDashboardRenderer's filter merge, whoseobject-metricmember wrote a flatfilteronto anobject-metricnode. Those programs read a plugin-dashboarddistbuilt with a census-only cast at that line, restored blob-equal before the census.cb687dfad(this head, after the landing-prep merges): 0 lines across all 88 programs, the same at5afa0269a.BaseSchema's index signature is present (2 lines in src, 2 in dist), and this round adds no cast.fab635a2(the previous head): 0 lines; all 88 programs exit 0. No census-only cast: plugin-dashboard's own build, which fails on a type error in its declaration program, passes.The corpus, re-judged
SchemaRenderer.propsResolution(the prop equality, andBaseSchemais not an arm);node-recursion-point-8344(the measured set of zod arms no declared node type admits, nowapp,record,home,utility,page,dashboardand the retired kanban arm);overlay-trigger-union-7081,overlay-node-slot-doc-types-7082andpage-body-arity-8310;zod-mirror-parity's Wider ledger (the union above);authoring-nodes-11364(dated note); newnode-slot-union-11466.CustomNodeRegistry(13 files); deliberately undeclared input crossesundeclaredNode(15 files); stored page fixtures gained the requiredlabel; the plugin-gantt and plugin-map bag fixtures are annotated with their declared node types.content/docs/plugins/plugin-dashboard.mdxname the one retired envelope node and what still draws. 14 documents name the declared node type; a registered custom type is shown declared inCustomNodeRegistry(core/schema-renderer.mdx). The two blocks held at the first round (vscode-extension.mdx, the plugin-detail README) now compile, answered by their owner card (objectui#11515).11364,8331,8908,schema-input-bridge-permanent-4622,7767,11479,8572,8310(twice: the prop's annotation, and the root README's example authorschildren, notbody),11354,10528-grid-object-table-fetchand11514-dashboard-slot-entry-types(their "unchanged" / "draws as before" readings of the grid's static pivot), and for the envelope retirement11525-inline-metric-retired(its envelopeobject-metric"still receives the dashboard filter bar's values"),11348-dashboard-widget-reads(the broadcast's guard over "the same threeobject-*types", now two) and11514-dashboard-slot-entry-typesagain (an envelope "draws under its card heading as before" whatever it held). New entries:.changeset/11466-node-slot-union.md(types, react and coreminor; componentspatch),.changeset/11466-dashboard-metric-node.mdand.changeset/11466-envelope-object-metric-retired.md(plugin-dashboardminoreach, the second stating before, now and the fix: bind a dataset). Each states its breaking meaning in the body, because objectui never declaresmajor.The envelope's
object-metric(the maintainer's ruling A)The previous round held one line: the filter broadcast kept
object-metricin its filterable set for a node in a widget's legacycomponentenvelope (objectui#11525 kept it), and wrote a flatfilterthat the declaredobject-metricnode (the spec'spropertiesbag,ObjectMetricBlockNode) refuses by name on both faces. The maintainer ruled A (comment 5966278275): that envelope node is the last inline metric form, retired as ruling C retired the rest.object-metricinside acomponentenvelope appears in 1 file across objectui and objectstack, the objectui#11525 pin itself, against a control of 3 files holding an envelope of another type. Stored customer dashboards are unmeasured, the gap ruling C accepted.inlineObjectMetricRetired-11525.test.tsxcarries a dated note in its header. Its envelope case flips: on both surfaces, under both keys, the envelope node yields the placeholder object (checked by identity), the prompt is on screen, and noaggregateorfindcall is made. A new control keeps the broadcast on the envelope'sobject-chartandobject-data-table, which still receive the filter bar's value.20fb2278) with a trap-restored mutation.isRetiredEnvelopeNodewas forced false (anchor hit once, marker on disk 1, blob71c7335ctoc2706404). Expected direction: the four retired-envelope cases red and everything else green. Read: "Tests 4 failed | 30 passed (34)", exactly those four (both keys on both surfaces). Restore: blob71c7335cequals HEAD,git diff HEAD0 bytes, marker 0.Gates
HEAD is
cb687dfad(landing-prep round, report5970915352). The readings below were taken atfab635a2unless the report re-measured them atcb687dfad. Toolchain: the container's Node v22.22.0 (the merged lockfile carries objectui#11366's lowered jsdom floor). Heavy runs went through the shared verify lock.packages/plugin-dashboard/, every reader test of the dashboard README, guide and touched changesets, and the changeset-reading script suites, atfab635a2: 182 files passed (2,325 tests, 6 skipped).packages/types/,packages/react/,packages/core/src/builder/, every reader test of a doc, README or changeset the earlier rounds touched, and the changeset suites, atf90ba8d2, before the last round, whose diff touches plugin-dashboard's sources, its README and guide, and changesets, all re-read by the run above: 542 files and 14,116 tests passed.check:doc-snippetsexit 0, "777 of 777 block(s) judged, 0 failed";check:doc-examplesexit 0;check:doc-typesexit 0.check-changeset-no-major0,check-changeset-presence0 (3 changesets declared),check-changeset-fixed0,check:pending-changeset-literals0,check-changeset-overwrite0 (report-only),check:changeset-claims0 (report-only),check:new-line-citations0 (0 new),check:control-bytes0,check:component-surface-parity0..ts/.tsxfiles: 0 errors, and the same warning count per file as before the change (the last round's four files againstf90ba8d2; the previous round's six againstmainandff7f748e).eslint.config.jssets no parserproject, so linting is not type-aware and these diffs cannot move the verdict on an untouched file. The repo-wide lint is CI's.check:sdui-registration-pins, which needs a console build (exit 2, prerequisite); no registration input moved.Acceptance notes
5970915352): the flex bag's child list isunknown[] | SchemaNodeon the TS face. A SINGLE child is checked, and under the objectui#8347 mutation a misspelled key on it is refused (the earlier f03). An ARRAY of children isunknown[]and unchecked (probe f02 compiles under the mutation, atcb687dfadand atfab635a2). That comes fromFLEX_BAG_CHILDREN'sz.array(z.unknown())arm, which is onmainand untouched here. With the signature present, no reading moves today. The arm is carried by objectui#11564, ordered before objectui#8347's removal PR (seat ruling A on the report's open question).cb687dfad: under the P1 mutation, types reads 39/40 (f02, the array arm above) and react 15/15. The control leg reads 29/40 and 9/15.DeclaredNodehas same-typepairs that are intended:flex(FlexSchemaandFlexBlockNode) and theobject-*renderer faces next to their authored bag nodes.PivotTable's such asrowLabels, or aBaseSchemanode key other thanclassNamesuch asid,styleorhidden) no longer reaches the node. Each stated key draws as before;DashboardGridLayout.objectProviderFetch-10528andDashboardGridLayout.datasetPathpass.DashboardGridLayout.tsxkeeps twelve stale cross-file line addresses, none in a paragraph this PR edits, so they are listed on the card for a later edit of that file rather than repaired here: four in thedataSourceprop's docblock (intoDashboardRenderer,DatasetWidget, andSchemaRenderertwice) and eight in the render-site comments (five intoDashboardRenderer, three intolegacyRetiredWidget).Generated by Claude Code