Skip to content

feat(types): ObjectChartSchema.chartType declares the @objectstack/spec chart families plugin-charts draws (objectui#11513) - #11518

Merged
objectstack-fleet[bot] merged 3 commits into
mainfrom
claude/issue-11513-object-chart-families
Oct 3, 2026
Merged

objectstack-fleet[bot] merged 3 commits into
mainfrom
claude/issue-11513-object-chart-families

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Fixes #11513

Clause-②: yes (widening)

Why yes (widening): both faces now accept five spec families they refused. Nothing narrows. The changeset is minor.

Dispatched by the domain:spec @ objectui seat (objectui#10217) under the seat's ruling A in the card body, claim comment 5962492298, session https://claude.ai/code/session_01XvhGmGAP79ZB8swnkapxPC. This card prepares objectui#11466's V1 (draft PR #11512). objectui#11514, the dashboard producers, is blocked on it.

The accept-set change

surface before (base 059bf1b5) after (head ae16cff8)
zod ObjectChartSchema.chartType (@object-ui/types/zod) a local z.enum of 8: bar, column, horizontal-bar, line, area, pie, donut, scatter. Zod's default refusal. stripImportedDefaults(SpecChartTypeSchema).extract(OBJECT_CHART_FAMILIES, { error }): the spec's 13 families plugin-charts draws. The refusal names the set.
authored bag ObjectChartBlockSchema, properties.chartType the same member, by reference (8) the same member, by reference (13)
TS ObjectChartSchema['chartType'] a literal union of the 8 Extract of the spec's ChartType over the 13
TS ObjectChartBlockNode (derived from the zod arm) 8 13. A throwaway probe: sankey compiles and gauge is refused.
specType (the react tier's key) the spec's ChartTypeSchema, by reference (20) unchanged
  • Newly accepted: funnel, treemap, sankey, combo, radar.
  • Still refused: gauge, solid-gauge, metric, kpi, bullet, table, pivot, and every off-spec spelling.
  • .extract is the by-reference spelling. It throws when the module loads if the spec drops a member. A spec bump that adds a family declares nothing new here.

The refusal, read at head: code invalid_value, at path properties.chartType in the bag and chartType on the flat mirror. Its values are the 13. Message:

chartType on an object-chart is one of bar, horizontal-bar, column, line, area, pie, donut, funnel, scatter, treemap, sankey, combo, radar (objectui#11513): the @objectstack/spec chart families this chart block draws. The spec's single-value and tabular families draw no chart here: write a single number as an object-metric, rows as an object-data-table, a cross-tab as an object-pivot.

Render time does not change. plugin-charts is read and probed only, and no renderer file is edited.

Measurements (dispatch zone 2)

H1, the installed spec. The lockfile pins @objectstack/spec 17.5.0, and packages/types resolves 17.5.0 (17.6.0 is not installed). Its ChartTypeSchema.options, read at runtime, are 20: bar, horizontal-bar, column, line, area, pie, donut, funnel, scatter, treemap, sankey, combo, gauge, solid-gauge, metric, kpi, bullet, radar, table, pivot.

H2, what plugin-charts draws. A throwaway probe (never committed) rendered an object-chart for each of the 20 families plus off-spec sunburst. It went through the real SchemaRenderer, SchemaRendererProvider and this package's registrations, with recharts' container fixed at 480x320. Each family was rendered in five spellings:

  • flat inline rows;
  • the authored properties bag;
  • the dashboard producer's exact node (objectName + aggregate + xAxisKey + series[{dataKey}], rows served by the data source's aggregate);
  • specType;
  • a dimensionless dataset node.

Controls:

  • Stability: the whole matrix ran twice in one process. 0 of the 105 cells differed, after stripping the React useId in the chart's style tag.
  • Lit: bar draws bar marks.
  • Dark: sunburst draws the unknown-type note.
family chartType (flat, bag and producer arms) class
bar, column bar marks, categories on the x axis, one value axis drawn
horizontal-bar bar marks, categories on the y axis drawn
line / area line / area marks drawn
pie, donut pie sectors. The DOM cannot tell a donut's hole apart; the family value is pinned by objectui#7401's normalizeChartSchema row. drawn
funnel funnel trapezoids drawn
scatter scatter symbols drawn
treemap treemap cells drawn
sankey sankey nodes and links drawn
combo bar + line marks on two value axes (two series). One series draws its first mark on the two axes. drawn
radar radar polygon drawn
gauge, solid-gauge, bullet, metric, kpi advanced-chart-single-value: one number from row 0's first series. On the producer's grouped aggregate it is the first bucket's value (1 of buckets 1/2/3). substituted
table, pivot advanced-chart-tabular-notice ("render it with the data-table / pivot components") nothing

The declared set is the 13 drawn families, a strict subset of the spec's 20.

H3, by reference. A strict subset, so .extract off stripImportedDefaults(SpecChartTypeSchema). The wrap keeps objectui#8317's import-boundary census green, and the strip is reference-equal here because the enum carries no default. The subset is pinned against the spec, with the complement named, in object-chart-families-11513.test.ts. specType stays the spec's enum by identity, and that is pinned too.

H4, readers of ObjectChartSchema['chartType']. Each was measured with a type-check after the change (a type-checker census).

  • ChartRendererProps.schema.chartType (plugin-charts): ObjectChart hands ChartRenderer a spread of the node. Its declared domain is exactly the 13, so it needs nothing. @object-ui/plugin-charts type-check is green. A reverse leg in that program, with throwaway @ts-expect-errors, left the funnel directive unused and the gauge one used, which proves it read the rebuilt .d.ts.
  • chartTypeIgnoresCompareTo (@object-ui/core): it takes a string, so it needs nothing.
  • FilterableComponentSchema in DashboardRenderer: it reads filter, so it needs nothing. @object-ui/plugin-dashboard type-check is green.
  • ObjectChartBlockNode / ObjectChartBlockSchema: they widen with the member by reference, so no edit.
  • Producers that widen with it:
    • DashboardRenderer and DashboardGridLayout emit widgetDispatch.SERIES_CHART_TYPES (12 families, all inside the 13). Today they build the node untyped; objectui#11514 types them.
    • The list-view relays in app-shell ObjectView, plugin-list ListView and plugin-view ObjectView write chartCfg.chartType || 'bar' from any. The spec's list-view chart config extracts bar, line, pie, area and scatter, all declared. They need nothing, and plugin-list, plugin-view and app-shell type-checks are green.
  • Not readers: CHART_TYPE_MAP in DatasetWidget feeds a bare chart node (ChartRenderer), not ObjectChartSchema. WidgetConfigPanel's CHART_TYPES is the dashboard widget picker.

V1 compile probe (objectui#11466, PR #11512, never committed from)

I added a throwaway detached worktree at the V1 tip ff7f748e, applied this branch's diff, and added a throwaway types test.

  • It assigns the 12 producer families to NonNullable of ObjectChartSchema['chartType'].
  • It builds an ObjectChartSchema node with chartType: 'sankey'.
  • It assigns that node, and an inline treemap node, to V1's DeclaredNode with no cast.
  • It holds a gauge node behind @ts-expect-error.

Results:

  • @object-ui/types type-check is green.
  • Control leg: the same tree with V1's own objectql.ts and objectql.zod.ts (the 8-family face) is red on exactly the producer list, the sankey node and the treemap node (TS2322). It is also red on this PR's two Equal assertions.
  • Deviation: V1's base predates objectui#11366's jsdom pin, so pnpm install in that probe tree ran with --config.engine-strict=false. Only in the probe; the probe tree is removed.

Pins

  • packages/types/src/__tests__/object-chart-families-11513.test.ts (new):
    • Type level, read by tsc -p tsconfig.test.json: TS = zod = the 13. Every declared family is a spec ChartType, and the declared and undeclared lists cover the spec. Two non-vacuity rows check that Equal can fail.
    • Runtime: the set read off the mirror is the 13. It is a strict subset of the installed spec, with the complement named. specType keeps its identity.
    • Each of the 13 parses in the bag on safeValidateSchema and on StrictAnyComponentSchema, and on the flat mirror.
    • Each undeclared spec family, plus sunburst, Bar and bar-chart, is refused at properties.chartType with values equal to the 13 and a message naming each of them. The flat mirror refuses at chartType, with a lit control.
  • packages/plugin-charts/src/__tests__/object-chart-declared-families-11513.test.tsx (new):
    • Every family of the installed spec is authored as a bag document on the inline object path, parsed on both faces, and rendered through the real SchemaRenderer.
    • The pin is two-way: a family parses exactly when it draws a chart. A declared family must draw its own marks, so a family silently drawn as a bar fails. An undeclared one must render the number card or the tabular notice.
    • Lit control bar, dark control sunburst.
  • Re-judged fixtures:
    • object-chart-properties-bag-11276.test.ts: the "outside the vocabulary" row and the flat-mirror refusal move from radar (now declared) to gauge. The TS twin equality pin now reads TS = zod; the members are held by the new file.
    • plugin-charts ObjectChart.schemaAnchor-7946.test.ts: its @ts-expect-error family moves from radar to gauge, with the reason in the directive.

Reverse verification and ablation

  • Runtime ablation, at committed 0703053b (the mirror's blob is the same at head ae16cff8), through objectstack's scripts/ablation-replace.mjs (wrap mode, anchor hit 1 to 0, blob 04c4bbc2 to 9c207bd2):
    • The mutation replaced the mirror's .extract(OBJECT_CHART_FAMILIES, { error: OBJECT_CHART_FAMILY_REFUSAL }) with .extract([... the old 8 ...]).
    • Both new pins ran: 24 failed and 25 passed. The red rows are the 5 new families (parse and render, twice each), the set and subset rows, and every refusal row (its values became the 8). The 8 old families stayed green.
    • Restore was proven: blob equals HEAD 04c4bbc2, and git diff HEAD is empty.
    • Direction: turned red, as expected.
  • Type-level: the V1 control leg above is red on both Equal rows when the face reverts.
  • Docs: content/docs/plugins/plugin-charts.mdx's new typed snippet with chartType: 'gauge' fails pnpm check:doc-snippets (TS2322 at that block, 777 judged and 1 failed). Restore was proven the same way. So the block is on the gate's surface.

Corpus re-judged

  • objectui: no authored object-chart document names a family outside the old 8. git grep over examples/, apps/, content/, skills/ and packages/*/examples/ found one hit, chart-examples.ts's radar, and that is a bare chart node.
  • objectstack showcase (examples/**): its object-chart nodes use bar, donut and area. The react-tier ObjectChart block with type="bar" goes through specType, which is unchanged.
  • Runs: examples/schema-catalog is green (40 files, 2259 tests). So are the 19 downstream test files that name object-chart (597 tests), across app-shell, core, plugin-dashboard, plugin-list, plugin-view, react and sdui-parser.

Pending changesets read

I read every .changeset/*.md that names chartType, object-chart, ObjectChartSchema or a chart family (58 entries besides this PR's), and none is made false. The ones that state something about this key, left alone:

  • 5927-zod-mirror-group-a-widenings.md lists what that change added (column, horizontal-bar, donut). It is still the reading of that change.
  • objectchart-schema-anchor-7946.md: "chartType must be the declared union" still holds.
  • 10770-object-chart-react-tier-node.md: specType is unchanged, and so is chartType's optionality.
  • 11276-object-chart-properties-bag.md: "unchanged in shape" is about the key set, which does not move.
  • 11468-bag-carrier-node-types.md: ObjectChartBlockNode is "derived by reference", and it widened by that derivation.
  • 10584-object-chart-series-describe.md: it is about the per-series chartType override (bar / line / area), not this member.

pnpm check:changeset-claims named 30 entries by file name (objectql.ts, objectql.zod.ts). Each is about another key (forms, kanban, grid, drill-down, tree, gallery, the bare chart node's data model), so all were left alone.

Gates

The source gates ran at 0703053b and were re-run at head ae16cff8, which adds only .md / .mdx. The doc gates and suites ran at head ae16cff8.

  • pnpm --filter @object-ui/types run type-check: exit 0. @object-ui/plugin-charts and @object-ui/plugin-dashboard: exit 0 at head. plugin-list, plugin-view and app-shell: exit 0. The dependency closures were built first.
  • pnpm exec vitest run packages/types/: 343 files, 9158 passed.
  • pnpm exec vitest run packages/plugin-charts/: 87 files, 1043 passed and 9 skipped. The skips are the existing describe.runIf(DRIVEN) in AdvancedChartImpl.dateOnlyZone-10866.test.tsx.
  • pnpm exec vitest run examples/schema-catalog/: 40 files, 2259 passed.
  • These gates exited 0 with their own verdict lines:
    • pnpm check:doc-snippets (777 of 777 judged, 0 failed) and pnpm check:doc-examples (every covered example compiles or fails as its ledger row says);
    • pnpm check:doc-types, node scripts/check-changeset-no-major.mjs and node scripts/check-changeset-presence.mjs;
    • pnpm check:new-line-citations (0 new) and pnpm check:control-bytes;
    • pnpm check:spec-symbols, check:vi-mock-specifiers, check:vi-mock-inherit and check:vi-mock-override-shape;
    • check:test-path-roots, check:self-import, check:doc-fences and check:pending-changeset-literals;
    • check:phantom-deps, check:installed-pin-claims, check:doc-example-ids and check:unreferenced-sources.
  • Not reached: check:component-surface-parity and check:sdui-registration-pins. No registration's inputs move, because object-chart's registration declares no chartType input.
  • Lint, a declared narrowing: eslint --no-inline-config --format json ran over the 6 changed TS files, read as 6 entries in the JSON. It found 0 errors and 39 warnings, all no-explicit-any. Two are in the new plugin-charts pin's vi.mock('recharts') block, the sibling pattern. eslint.config.js sets no parserOptions.project / projectService, so linting is not type-aware and this diff cannot move a verdict on an untouched file. The repo-wide pnpm lint belongs to CI.

Acceptance notes

  1. Found, not fixed here (plugin-charts is read-only for this card). A spec single-value or tabular family named through specType silently draws a BAR chart. Through chartType, the same family draws a number or a notice.
    • Probe specType arm: gauge, solid-gauge, metric, kpi, bullet, table and pivot each drew bar marks on one value axis, with no note.
    • Both faces accept { "type": "object-chart", "properties": { "specType": "gauge", … } } (measured on the built dist).
    • Mechanism: normalizeChartSchema reads specType but gates it to unset when it is not RENDERABLE. ChartRenderer's schema.chartType ?? spec.chartType is then unset, and AdvancedChartImpl defaults to bar.
    • Seam: spec:ChartConfigSchema.type (ChartTypeSchema) → runtime:normalizeChartSchema RENDERABLE gate, ChartRenderer chartType fallback | renderer:AdvancedChartImpl default bar.
    • The report carries it for the seat to file.
  2. Found, not fixed here (the chart node, another schema). content/docs/api/schema-reference.md's ChartSchema table lists chartType values ending in "heatmap".
    • safeValidateSchema({ type: 'chart', chartType: 'heatmap', … }) refuses it at chartType (invalid_value, measured).
    • The table also omits families the node accepts and draws (funnel, treemap, sankey, combo, column, horizontal-bar).
    • The report carries it for the seat.
  3. The substituted and nothing families on chartType (H2) have no reach after this PR:
    • the face refuses them at chartType;
    • the dashboard routes the single-value families to the metric card and the tabular ones to the table and pivot (widgetDispatch);
    • the spec's list-view chart config extracts only bar, line, pie, area and scatter.
      Noted, not filed.

Generated by Claude Code

claude added 3 commits October 2, 2026 22:49
…milies plugin-charts draws (objectui#11513)

Both faces declared eight families. The zod mirror now picks the thirteen
families plugin-charts draws as a chart out of @objectstack/spec's
ChartTypeSchema (.extract); the TS twin Extracts the same set from the
spec's ChartType. The single-value and tabular spec families stay
undeclared, refused with the set named.

The 11276 and 7946 fixtures that used `radar` as the family outside the
vocabulary move to `gauge`, which is still outside it.

Claude-Session: https://claude.ai/code/session_01XvhGmGAP79ZB8swnkapxPC
Co-authored-by: Claude <noreply@anthropic.com>
…es its chartType declares (objectui#11513)

Every installed-spec ChartTypeSchema family is authored as an object-chart
bag document on the inline object path and rendered through the real
SchemaRenderer: a declared family parses on both faces and draws its own
marks, an undeclared one is refused and draws a number or a notice. bar
is the lit control, the off-spec sunburst the dark one.

Claude-Session: https://claude.ai/code/session_01XvhGmGAP79ZB8swnkapxPC
Co-authored-by: Claude <noreply@anthropic.com>
…ectui#11513 changeset

plugin-charts.mdx gains an Object Charts section naming the families
chartType takes, what the spec families it refuses render instead, and a
JSON and a typed example.

Claude-Session: https://claude.ai/code/session_01XvhGmGAP79ZB8swnkapxPC
Co-authored-by: Claude <noreply@anthropic.com>
@github-actions github-actions Bot added documentation Improvements or additions to documentation package: types plugin plugin: charts tests labels Oct 2, 2026
@github-actions

github-actions Bot commented Oct 2, 2026

Copy link
Copy Markdown
Contributor

changeset-claim-re-read

⚠️ 30 pending changeset(s) describe a file this change touches

Their bodies publish verbatim into the CHANGELOG at the next release, so this is a request to re-read them against your diff — addressed here because you are the one seat that can answer it without re-deriving anything.

⛔ Nothing here blocks, and nothing here is a verdict on your change. This gate exits 0, is not a required context, and judges name resolution, never meaning: it asked whether a pending body names a file you touched. "Is this sentence still true?" is the one question it will not answer, and the one you are being asked to answer.

.changeset/10872-container-children-channel.md

  • names objectql.zod.ts → packages/types/src/zod/objectql.zod.ts — edited by this change

    Also in this change, with no behaviour change: objectql.zod.ts's two public-block arms (object-metric, object-master-detail-form) build their properties member with the same propsBag helper as the other public-block arms, instead of a byte copy of it. The member's description text is unchanged.

.changeset/5903-objectgantt-declared-keys.md

  • names packages/types/src/objectql.ts → packages/types/src/objectql.ts — edited by this change

    Both halves move together. The TS declaration (packages/types/src/objectql.ts) and its zod mirror (src/zod/objectql.zod.ts) gain the same ten keys at the same requiredness — all optional — and no KnownDrift entry is added. navigation is taken from @objectstack/spec's NavigationConfigSchema by reference rather than restated, matching ObjectGridSchema.navigation.

  • names src/zod/objectql.zod.ts → packages/types/src/zod/objectql.zod.ts — edited by this change

    Both halves move together. The TS declaration (packages/types/src/objectql.ts) and its zod mirror (src/zod/objectql.zod.ts) gain the same ten keys at the same requiredness — all optional — and no KnownDrift entry is added. navigation is taken from @objectstack/spec's NavigationConfigSchema by reference rather than restated, matching ObjectGridSchema.navigation.

.changeset/6152-object-form-unmirrored-members.md

  • names objectql.ts → packages/types/src/objectql.ts — edited by this change

    ObjectFormSchema in @object-ui/types (objectql.ts) declared a set of members that its zod mirror in @object-ui/types/zod had never heard of. Every one of them is read by the object-form renderer (ObjectForm in @object-ui/plugin-form). The two published faces answered differently:

.changeset/6940-rowactions-boolean-mirror.md

  • names zod/objectql.zod.ts → packages/types/src/zod/objectql.zod.ts — edited by this change

    The list view's same-named rowActions in zod/objectql.zod.ts — z.array(z.string()), the legacy bare-name action list on ObjectGridSchema — is a different key that is correct as it stands, is in parity with its own TS twin (rowActions?: string[]), and is not touched.

.changeset/7113-chart-data-model.md

  • names objectql.zod.ts → packages/types/src/zod/objectql.zod.ts — edited by this change

    .extend() with a NEW key still works and preserves the fold and the refinement; .optional(), z.discriminatedUnion, z.toJSONSchema and safeValidateSchema are all unaffected. Nothing in this repository calls the throwing combinators on either const, and the published surface already ships refined mirrors (objectql.zod.ts, complex.zod.ts, form.zod.ts, app.zod.ts), so the class is not new — but it is a real behaviour change on a published export and it belongs in the release note rather than in a reviewer's file.

.changeset/7200-object-form-section-style-keys-undeclared.md

  • names zod/objectql.zod.ts → packages/types/src/zod/objectql.zod.ts — edited by this change

    The authored-metadata type now agrees with @objectstack/spec, whose FormSectionSchema is a strict object declaring neither key, and with the ruling's rationale (maintainer 2026-09-01, verbatim): "retire the reads … Declaring the keys was weighed and not adopted: it would formally invite free Tailwind strings into authored metadata, the exact class the boundary exists to keep out." A ?: never tombstone was not used: ObjectFormSection has no zod mirror (ObjectFormSchema in zod/objectql.zod.ts does not declare sections), so there is no parse door to refuse at, and a tombstone is still a declaration in completion and in the published .d.ts.

.changeset/7265-types-user-filter-field-derives.md

  • names zod/objectql.zod.ts → packages/types/src/zod/objectql.zod.ts — edited by this change

    zod/objectql.zod.ts declared two schemas under names @objectstack/spec/ui already exports. They were triaged separately, by reading their sites, and went different ways.

.changeset/7322-object-kanban-group-by-limit.md

  • names objectql.ts → packages/types/src/objectql.ts — edited by this change

    Breaking for authored metadata: ObjectKanbanSchema.groupField is RETIRED (objectui#7322, ADR-0049 enforce-or-remove), and the two keys the object-kanban renderer actually reads — groupBy and limit — are now DECLARED and validated on both published faces: the TypeScript interface in objectql.ts and the Zod mirror in zod/objectql.zod.ts.

  • names zod/objectql.zod.ts → packages/types/src/zod/objectql.zod.ts — edited by this change

    Breaking for authored metadata: ObjectKanbanSchema.groupField is RETIRED (objectui#7322, ADR-0049 enforce-or-remove), and the two keys the object-kanban renderer actually reads — groupBy and limit — are now DECLARED and validated on both published faces: the TypeScript interface in objectql.ts and the Zod mirror in zod/objectql.zod.ts.

.changeset/7352-drill-down-config-mirror.md

  • names zod/objectql.zod.ts → packages/types/src/zod/objectql.zod.ts — edited by this change

    DrillDownConfigSchema is the zod mirror of DrillDownConfig, and both declarations that carry drillDown reference it — ChartSchema (zod/data-display.zod.ts) and ObjectDataTableSchema (zod/objectql.zod.ts) — so the published validator under @object-ui/types/zod reads the key for the first time (objectui#7352).

.changeset/7363-objectql-union-arms.md

  • names objectql.ts → packages/types/src/objectql.ts — edited by this change

    ObjectGallerySchema and ObjectDataTableSchema are members of ObjectQLComponentSchema on both faces — the TS union in objectql.ts and the zod union in zod/objectql.zod.ts — so AnyComponentSchema, and with it validateSchema / safeValidateSchema / objectui validate, has an arm for object-gallery and object-data-table nodes (objectui#7363).

  • names zod/objectql.zod.ts → packages/types/src/zod/objectql.zod.ts — edited by this change

    ObjectGallerySchema and ObjectDataTableSchema are members of ObjectQLComponentSchema on both faces — the TS union in objectql.ts and the zod union in zod/objectql.zod.ts — so AnyComponentSchema, and with it validateSchema / safeValidateSchema / objectui validate, has an arm for object-gallery and object-data-table nodes (objectui#7363).

.changeset/7632-shared-record-source-config.md

  • names packages/types/src/objectql.ts → packages/types/src/objectql.ts — edited by this change

    That ladder is published contract on both faces — packages/types/src/objectql.ts and its zod mirror both ship .describe() strings naming getDataConfig's order (77cb489b4, maintainer ruling 2026-09-02), pinned by objectql-record-source-refinement-6939.test.ts — and it was hand-copied into five plugin components with no gate holding them together. A change to the ruled order had five edit sites and nothing that noticed a missed one; that is the AGENTS.md #0.1 drift class.

.changeset/7804-objectql-handler-key-arms.md

  • names objectql.ts → packages/types/src/objectql.ts — edited by this change

    The four plain objectql.ts node faces declare the nine handler keys their registered renderers read (the objectql.ts slice): ObjectFormSchema.onCancel / .onError / .onOpenChange / .onStepChange / .onSuccess, ObjectGallerySchema.onCardClick / .onRowClick, ObjectGridSchema.onNavigate and ObjectViewSchema.onNavigate.

.changeset/7804-tree-view-handler-slot.md

  • names objectql.ts → packages/types/src/objectql.ts — edited by this change

    'runtime-slot' and not 'retired', measured at this key's own channel. 'retired' publishes "no renderer reads this key, so nothing could ever run it" — true of the two siblings already tombstoned on this arm (onSelectChange, onExpandChange) and flatly false here, since the read is live and INVOKED. ⚠️ No in-repo host builds a tree-view node carrying the key: the channel is wired end to end and only the supplier is absent, which is the same shape as ObjectFormSchema.onStepChange in this card's objectql.ts slice and is not evidence of a dead read. The TypeScript declaration is unchanged and still callable, so a programmatic host supplies it exactly as before.

.changeset/7917-export-breadcrumb-object-tree-zod-schemas.md

  • names objectql.zod.ts → packages/types/src/zod/objectql.zod.ts — edited by this change

    AnyComponentSchema declares 107 node component types. 105 of them could be named on the ./zod barrel — ButtonSchema.safeParse(node), which is what a designer, a form builder or a targeted test needs. The arms declaring type: 'breadcrumb' (navigation.zod.ts) and type: 'object-tree' (objectql.zod.ts) could not: both were already export const in their own module, but index.zod.ts — the package's only zod entry point — did not re-export them, so the schemas existed, were maintained, and were applied by the union while no consumer could name them.

.changeset/7963-alert-dialog-footer-keys-retired.md

  • names objectql.ts → packages/types/src/objectql.ts — edited by this change

    Nothing else moves. These spellings are overloaded across the tree and every other owner is a live key on a different declaration — FormSchema.cancelLabel, objectql.ts's confirmLabel, plugin-designer's ConfirmDialog React props, plugin-grid's def.confirmLabel, and plugin-form's ModalForm / DrawerForm, which build a local cancelLabel from schema.cancelText. None is an AlertDialogSchema; none is touched, and a pin asserts it. No fixture, catalog schema, example app or doc fence authored any of the three on an alert-dialog node, so no shipped document is stranded.

.changeset/8478-describe-line-addresses.md

.changeset/8735-objectql-mirror-docblocks-not-defaulted.md

  • names zod/objectql.zod.ts → packages/types/src/zod/objectql.zod.ts — edited by this change

    Correct four zod/objectql.zod.ts docblocks that described the behaviour objectui#8317 removed. Since that change the zod mirrors strip imported @objectstack/spec defaults at this package's import boundary, but the docblocks on HttpRequestSchema, ListColumnSchema, SelectionConfigSchema and PaginationConfigSchema still said, in the present tense, that method, prefix.type, type and pageSize are defaulted on parse — the opposite of what each export does. Each now says the key is declared and accepted but NOT defaulted on parse.

.changeset/8767-object-grid-refuses-string-sort.md

  • names packages/types/src/objectql.ts → packages/types/src/objectql.ts — edited by this change

    Migration. Write the array: sort: [{ field: 'name', order: 'desc' }]. Both keys are required. SortConfig.order carries no ? in @object-ui/types (packages/types/src/objectql.ts) and no .optional() in its zod mirror, and the protocol's own reusable SortItemSchema requires order as well — measured: that schema refuses [{ field: 'name' }] with invalid_value at 0.order. Do not omit it: this block's array arm interpolates whatever is present, so an omitted order lowers to $orderby: 'name undefined' today. That is pre-existing behaviour on the arm this change does not touch, and it is filed as a successor card rather than widened into here.

.changeset/8801-object-kanban-allow-collapse-retired.md

  • names packages/types/src/objectql.ts → packages/types/src/objectql.ts — edited by this change

    • the declarations retired here — packages/types/src/objectql.ts and its mirror packages/types/src/zod/objectql.zod.ts; - the pins that assert the retirement — object-kanban-allow-collapse-retired-8801.test.ts and bare-kanban-node-key-retired-8802.test.ts; - a comment in packages/types/src/zod/complex.zod.ts, recording that the deleted retiredZeroReadKanbanKey helper once carried this spelling on the SIBLING arm; - one row of content/docs/api/schema-reference.md; - the .changeset/ release notes that discuss it — this one, the two historical entries covering the sibling arm's own spelling, and objectui#9629's note recording the correction to this paragraph.
  • names packages/types/src/zod/objectql.zod.ts → packages/types/src/zod/objectql.zod.ts — edited by this change

    • the declarations retired here — packages/types/src/objectql.ts and its mirror packages/types/src/zod/objectql.zod.ts; - the pins that assert the retirement — object-kanban-allow-collapse-retired-8801.test.ts and bare-kanban-node-key-retired-8802.test.ts; - a comment in packages/types/src/zod/complex.zod.ts, recording that the deleted retiredZeroReadKanbanKey helper once carried this spelling on the SIBLING arm; - one row of content/docs/api/schema-reference.md; - the .changeset/ release notes that discuss it — this one, the two historical entries covering the sibling arm's own spelling, and objectui#9629's note recording the correction to this paragraph.

.changeset/8885-object-chart-drilldown-title-compareto.md

  • names packages/types/src/objectql.ts → packages/types/src/objectql.ts — edited by this change

    ObjectChart.tsx reads all three off schema, and until now neither published copy declared any of them: not the TS interface (packages/types/src/objectql.ts) and not the zod mirror (packages/types/src/zod/objectql.zod.ts). They rode BaseSchema's index signature / .passthrough() and arrived unvalidated. drillDown was the sharpest case — this component's registry inputs advertise it to the designer palette, and @objectstack/spec publishes ChartDrillDownSchema for exactly this carrier, so an author was offered a key that neither published shape mentioned.

  • names packages/types/src/zod/objectql.zod.ts → packages/types/src/zod/objectql.zod.ts — edited by this change

    ObjectChart.tsx reads all three off schema, and until now neither published copy declared any of them: not the TS interface (packages/types/src/objectql.ts) and not the zod mirror (packages/types/src/zod/objectql.zod.ts). They rode BaseSchema's index signature / .passthrough() and arrived unvalidated. drillDown was the sharpest case — this component's registry inputs advertise it to the designer palette, and @objectstack/spec publishes ChartDrillDownSchema for exactly this carrier, so an author was offered a key that neither published shape mentioned.

.changeset/8913-object-kanban-columns-declared.md

  • names objectql.ts → packages/types/src/objectql.ts — edited by this change

    What moved. ObjectKanbanSchema gains columns on both halves that move together — the TypeScript interface (objectql.ts) and its Zod mirror (zod/objectql.zod.ts). Retiring the bare kanban node type key (objectui#8802) removed the only face that judged a lane, and object-kanban had never declared the key, so it rode BaseSchema's [key: string]: any / .passthrough(): read by the renderer at three sites, named by no published face.

  • names zod/objectql.zod.ts → packages/types/src/zod/objectql.zod.ts — edited by this change

    What moved. ObjectKanbanSchema gains columns on both halves that move together — the TypeScript interface (objectql.ts) and its Zod mirror (zod/objectql.zod.ts). Retiring the bare kanban node type key (objectui#8802) removed the only face that judged a lane, and object-kanban had never declared the key, so it rode BaseSchema's [key: string]: any / .passthrough(): read by the renderer at three sites, named by no published face.

.changeset/8990-object-kanban-groupby-optional.md

  • names packages/types/src/objectql.ts → packages/types/src/objectql.ts — edited by this change

    @objectstack/spec declares the key optional — groupBy: z.string().optional() on ObjectKanbanPropsSchema — while this package required it on the TypeScript declaration (packages/types/src/objectql.ts) and on the Zod mirror (packages/types/src/zod/objectql.zod.ts). objectui was therefore narrower than the protocol on a published key: ObjectKanbanSchema.safeParse and safeValidateSchema refused an object-kanban node the protocol accepts, and such a node could not be annotated with its own type.

  • names packages/types/src/zod/objectql.zod.ts → packages/types/src/zod/objectql.zod.ts — edited by this change

    @objectstack/spec declares the key optional — groupBy: z.string().optional() on ObjectKanbanPropsSchema — while this package required it on the TypeScript declaration (packages/types/src/objectql.ts) and on the Zod mirror (packages/types/src/zod/objectql.zod.ts). objectui was therefore narrower than the protocol on a published key: ObjectKanbanSchema.safeParse and safeValidateSchema refused an object-kanban node the protocol accepts, and such a node could not be annotated with its own type.

.changeset/8992-user-actions-collapse-and-docblock.md

  • names objectql.zod.ts → packages/types/src/zod/objectql.zod.ts — edited by this change

    objectql.zod.ts's UserActionsSchema read stripImportedDefaults(Spec).extend({ group, hideFields, rowColor }), an extension that existed only because @objectstack/spec did not declare those three keys while normalizeListViewSchema folded objectui's legacy showGroup / showHideFields / showColor onto them. The protocol adopted all three in 17.3.0 (objectui#5435's ruling), so the extension is now a second local copy of a protocol declaration — the shape two faces start drifting from — and it collapses into the plain by-reference re-export its own note always said it would become.

.changeset/9092-inline-locale-declared-face.md

  • names objectql.ts → packages/types/src/objectql.ts — edited by this change

    • AppComponentSchema.label (app.ts) - ObjectGridSchema.label and .description (objectql.ts) - PageNodeSchema.aria.ariaLabel (layout.ts)

.changeset/9309-object-gallery-filter-destination-typed.md

  • names objectql.ts → packages/types/src/objectql.ts — edited by this change

    ObjectGallerySchema.filter is typed as the destination its own docblock names — QueryParams['$filter'] — on both faces, the TS interface in objectql.ts and the zod mirror in zod/objectql.zod.ts (objectui#9309).

  • names zod/objectql.zod.ts → packages/types/src/zod/objectql.zod.ts — edited by this change

    ObjectGallerySchema.filter is typed as the destination its own docblock names — QueryParams['$filter'] — on both faces, the TS interface in objectql.ts and the zod mirror in zod/objectql.zod.ts (objectui#9309).

.changeset/9511-record-id-is-a-string.md

  • names objectql.ts → packages/types/src/objectql.ts — edited by this change

    The three authorable keys, each on BOTH faces. ObjectFormSchema.recordId (objectql.ts + zod/objectql.zod.ts), DetailViewSchema.resourceId (views.ts + zod/views.zod.ts) and DetailSchema.resourceId (crud.ts + zod/crud.zod.ts). ⚠️ The crud pair is DetailSchema, not DetailViewSchema, and it reaches the same renderer — not by symbol but by data flow: plugin-detail registers the 'detail' node type onto DetailView. A read that follows TypeScript symbols alone finds two keys and is incomplete.

  • names zod/objectql.zod.ts → packages/types/src/zod/objectql.zod.ts — edited by this change

    The three authorable keys, each on BOTH faces. ObjectFormSchema.recordId (objectql.ts + zod/objectql.zod.ts), DetailViewSchema.resourceId (views.ts + zod/views.zod.ts) and DetailSchema.resourceId (crud.ts + zod/crud.zod.ts). ⚠️ The crud pair is DetailSchema, not DetailViewSchema, and it reaches the same renderer — not by symbol but by data flow: plugin-detail registers the 'detail' node type onto DetailView. A read that follows TypeScript symbols alone finds two keys and is incomplete.

.changeset/9549-tree-filter-declared.md

  • names objectql.ts → packages/types/src/objectql.ts — edited by this change

    ObjectTreeSchema.filter is declared on both faces, in the shape objectui#9309 settled for ObjectGallerySchema.filter: QueryParams['$filter'] by indexed access on the TS interface in objectql.ts, and the same two-arm union (array first) on the zod mirror in zod/objectql.zod.ts (objectui#9549).

  • names zod/objectql.zod.ts → packages/types/src/zod/objectql.zod.ts — edited by this change

    ObjectTreeSchema.filter is declared on both faces, in the shape objectui#9309 settled for ObjectGallerySchema.filter: QueryParams['$filter'] by indexed access on the TS interface in objectql.ts, and the same two-arm union (array first) on the zod mirror in zod/objectql.zod.ts (objectui#9549).

.changeset/9550-object-tree-root-barrel.md

  • names objectql.ts → packages/types/src/objectql.ts — edited by this change

    ObjectQLComponentSchema declares the node types an ObjectQL block may be. Every one of its arms was a named export of this package's root barrel except ObjectTreeSchema, which was declared in objectql.ts, applied by the union, and re-exported by the ./zod barrel (objectui#7917) — while no TypeScript consumer could name it. There is no ./objectql subpath to reach around the barrel: the package's exports map is pinned by packages/types/src/__tests__/package-exports-manifest.test.ts, and the root barrel was the only route to this type.

.changeset/9606-object-kanban-card-title.md

  • names zod/objectql.zod.ts → packages/types/src/zod/objectql.zod.ts — edited by this change

    Both published faces of the object-kanban arm now name the key: the zod mirror ObjectKanbanSchema in zod/objectql.zod.ts and its TypeScript twin, the ObjectKanbanSchema interface in objectql.ts. Both declare it OPTIONAL, at the same requiredness the other face uses, so the two faces accept and refuse the same documents. (Located and cited by SYMBOL: line addresses in zod/objectql.zod.ts have drifted before, and this change is itself about a drifted mirror.)

  • names objectql.ts → packages/types/src/objectql.ts — edited by this change

    Both published faces of the object-kanban arm now name the key: the zod mirror ObjectKanbanSchema in zod/objectql.zod.ts and its TypeScript twin, the ObjectKanbanSchema interface in objectql.ts. Both declare it OPTIONAL, at the same requiredness the other face uses, so the two faces accept and refuse the same documents. (Located and cited by SYMBOL: line addresses in zod/objectql.zod.ts have drifted before, and this change is itself about a drifted mirror.)

.changeset/9628-kanban-column-collapsed-honoured.md

  • names objectql.ts → packages/types/src/objectql.ts — edited by this change

    The key was declared on both published faces of the object-kanban arm — the lane element of ObjectKanbanSchema (objectql.ts and its Zod mirror) and the runtime lane KanbanColumn (complex.ts and its mirror) — and read by KanbanEnhanced alone, a module no production source imports. An authored { "id": "todo", "title": "To Do", "collapsed": true } therefore parsed green on both faces and reached a board that did nothing with it: KanbanImpl's only collapse is the SWIMLANE row's, held in viewer state under objectui:kanban-collapsed:ANGLE-BRACKETS(swimlaneField) and never keyed to a lane's declared value. That is the ADR-0049 declared-but-unhonoured shape.

Read the paragraph, not the line: both false halves of the objectui#8617 claim sat in one paragraph, and correcting either alone would have left it asserting the same wrong thing.

If a claim did go false, correct the body. That is precedented and prose-only, frontmatter untouched; check-changeset-overwrite.mjs will report the correction as its own case 2 ("correcting a declaration on purpose … legitimate"), which is the intended shape — one gate asks for the read, the other records the write.

Not covered, stated so nobody reads this as more: a born-false claim that spells no line address at all (objectui#9495 coordinated one by ORDINAL — "a grep finds that member first" — and deciding that means reading what the sentence means), a claim spelled as a symbol or a package rather than a backticked file name, and a file named ambiguously.

Angle-bracketed names in the quoted prose above are rewritten as ANGLE-BRACKETS(name): GitHub deletes tag-shaped fragments from a stored body, and a quote that silently loses the identifier it is about is worse than a visible repair.

Compared the checked-out tree with 059bf1b59 (merge-base with origin/main): 7 file(s) changed outside .changeset/, read against 2056 pending declaration(s) that publish a body (2687 pending in total). · run

@github-actions

github-actions Bot commented Oct 2, 2026

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

Metric Value Budget
Eager closure (gzip, 330 chunks) 3551.1 KB 3574.6 KB
Main entry chunk (gzip) 150.3 KB 350 KB
Entry file index-C2gvkZAP.js —
Status PASS —

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

Package Size Gzipped
app-shell (consoleActionDispatch.js) 0.20KB 0.19KB
app-shell (index.js) 16.88KB 6.25KB
app-shell (runtime-config.js) 20.68KB 7.36KB
app-shell (types.js) 0.01KB 0.04KB
app-shell (urlParams.js) 10.11KB 3.87KB
auth (ActiveOrganizationStorage.js) 27.95KB 10.04KB
auth (AuthContext.js) 0.31KB 0.24KB
auth (AuthGuard.js) 2.07KB 1.00KB
auth (AuthProvider.js) 40.22KB 10.61KB
auth (AuthShell.js) 3.49KB 1.40KB
auth (ForgotPasswordForm.js) 12.21KB 3.45KB
auth (LoginForm.js) 18.17KB 5.40KB
auth (PreviewBanner.js) 0.90KB 0.50KB
auth (RegisterForm.js) 6.72KB 2.24KB
auth (SocialSignInButtons.js) 9.70KB 3.93KB
auth (UserMenu.js) 3.39KB 1.21KB
auth (auth-gate-events.js) 1.29KB 0.66KB
auth (authStyles.js) 5.04KB 1.72KB
auth (createAuthClient.js) 40.70KB 10.94KB
auth (createAuthenticatedFetch.js) 8.54KB 3.46KB
auth (index.js) 3.63KB 1.64KB
auth (invitation-status.js) 1.22KB 0.70KB
auth (org-roles.js) 6.66KB 2.78KB
auth (phone-identifier.js) 1.11KB 0.66KB
auth (types.js) 0.59KB 0.35KB
auth (useAuth.js) 5.30KB 1.02KB
auth (useWorkspaceAdminStatus.js) 11.08KB 4.58KB
collaboration (CommentThread.js) 27.11KB 7.97KB
collaboration (LiveCursors.js) 3.17KB 1.27KB
collaboration (PresenceAvatars.js) 6.28KB 2.60KB
collaboration (PresenceProvider.js) 2.79KB 1.13KB
collaboration (index.js) 1.68KB 0.73KB
collaboration (useCollaborationTranslation.js) 6.50KB 2.52KB
collaboration (useCommentSearch.js) 1.98KB 0.88KB
collaboration (useConflictResolution.js) 7.75KB 1.86KB
collaboration (useMentionNotifications.js) 1.81KB 0.68KB
collaboration (usePresence.js) 6.33KB 1.84KB
collaboration (useRealtimeSubscription.js) 7.91KB 2.01KB
components (index.js) 571.09KB 136.86KB
core (index.js) 10.00KB 3.96KB
create-plugin (index.js) 27.94KB 9.51KB
data-objectstack (index.js) 230.46KB 63.94KB
fields (index.js) 261.51KB 66.22KB
i18n (LocalizationContext.js) 1.76KB 0.96KB
i18n (builtinAggregateLabels.js) 0.86KB 0.49KB
i18n (currency.js) 2.59KB 1.22KB
i18n (fallbackInterpolation.js) 6.25KB 2.77KB
i18n (i18n.js) 8.87KB 3.64KB
i18n (index.js) 5.24KB 2.27KB
i18n (pickLocalized.js) 9.86KB 3.95KB
i18n (provider.js) 39.35KB 12.88KB
i18n (translateFn.js) 0.20KB 0.18KB
i18n (useDisplayLocale.js) 3.52KB 1.76KB
i18n (useObjectLabel.js) 34.49KB 9.23KB
i18n (useSafeTranslation.js) 7.14KB 2.92KB
layout (index.js) 39.47KB 11.25KB
mobile (MobileProvider.js) 0.92KB 0.49KB
mobile (ResponsiveContainer.js) 0.94KB 0.38KB
mobile (breakpoints.js) 1.51KB 0.70KB
mobile (createOfflineDataSource.js) 5.61KB 1.75KB
mobile (index.js) 1.99KB 0.87KB
mobile (offlineQueue.js) 3.91KB 1.35KB
mobile (pwa.js) 0.97KB 0.49KB
mobile (serviceWorker.js) 1.48KB 0.62KB
mobile (serviceWorkerSource.js) 3.41KB 1.48KB
mobile (useBreakpoint.js) 1.54KB 0.65KB
mobile (useGesture.js) 6.96KB 1.98KB
mobile (useOfflineSync.js) 1.99KB 0.72KB
mobile (usePullToRefresh.js) 6.62KB 2.45KB
mobile (useResponsive.js) 0.72KB 0.42KB
mobile (useSpecGesture.js) 5.52KB 2.10KB
mobile (useTouchTarget.js) 1.01KB 0.54KB
permissions (MePermissionsProvider.js) 13.86KB 5.00KB
permissions (PermissionContext.js) 0.31KB 0.25KB
permissions (PermissionGuard.js) 0.89KB 0.45KB
permissions (PermissionProvider.js) 6.52KB 2.26KB
permissions (discardProofCache.js) 1.04KB 0.55KB
permissions (evaluator.js) 8.33KB 3.07KB
permissions (index.js) 0.93KB 0.41KB
permissions (store.js) 0.91KB 0.42KB
permissions (useFieldPermissions.js) 1.28KB 0.53KB
permissions (usePermissions.js) 4.83KB 2.27KB
plugin-ai (index.js) 16.04KB 3.92KB
plugin-calendar (index.js) 53.17KB 15.46KB
plugin-charts (index.js) 83.53KB 22.84KB
plugin-chatbot (index.js) 198.22KB 46.97KB
plugin-dashboard (index.js) 142.17KB 38.28KB
plugin-designer (index.js) 231.28KB 48.76KB
plugin-detail (index.js) 245.43KB 64.53KB
plugin-editor (index.js) 2.23KB 1.05KB
plugin-form (index.js) 172.73KB 44.50KB
plugin-gantt (index.js) 179.16KB 45.06KB
plugin-grid (index.js) 233.13KB 63.89KB
plugin-kanban (index.js) 49.51KB 15.54KB
plugin-list (index.js) 116.63KB 28.97KB
plugin-map (index.js) 25.60KB 8.62KB
plugin-markdown (index.js) 13.88KB 4.80KB
plugin-report (index.js) 44.12KB 12.29KB
plugin-timeline (index.js) 38.80KB 11.71KB
plugin-tree (index.js) 14.51KB 5.15KB
plugin-view (index.js) 90.23KB 22.73KB
providers (DataSourceProvider.js) 0.75KB 0.39KB
providers (MetadataProvider.js) 1.37KB 0.59KB
providers (ThemeProvider.js) 1.90KB 0.85KB
providers (UploadProvider.js) 11.81KB 3.58KB
providers (index.js) 0.45KB 0.23KB
providers (types.js) 0.01KB 0.04KB
react-runtime (index.js) 5.62KB 2.34KB
react (LazyPluginLoader.js) 4.47KB 1.63KB
react (SchemaRenderer.js) 120.63KB 39.56KB
react (data-invalidation.js) 5.05KB 2.08KB
react (index.js) 4.50KB 2.06KB
react (schema-input.js) 4.25KB 2.04KB
react (spec-input.js) 0.20KB 0.18KB
sdui-parser (body-dialect.js) 4.50KB 1.99KB
sdui-parser (codegen.js) 9.45KB 3.76KB
sdui-parser (dashboard-widget-options.js) 3.08KB 1.30KB
sdui-parser (index.js) 6.06KB 2.68KB
sdui-parser (input-type.js) 2.84KB 1.40KB
sdui-parser (parse.js) 25.28KB 7.80KB
sdui-parser (provenance.js) 3.84KB 1.90KB
sdui-parser (types.js) 0.28KB 0.23KB
sdui-parser (validate.js) 21.42KB 7.05KB
types (ai.js) 4.39KB 2.17KB
types (api-types.js) 0.20KB 0.18KB
types (app.js) 4.12KB 1.61KB
types (authoring-nodes.js) 0.20KB 0.19KB
types (base.js) 0.20KB 0.18KB
types (blocks.js) 0.20KB 0.18KB
types (complex.js) 4.14KB 1.96KB
types (crud.js) 0.20KB 0.18KB
types (dashboard-filter-alias.js) 6.23KB 2.74KB
types (dashboard-widget-layout.js) 2.06KB 0.96KB
types (data-display.js) 3.75KB 1.85KB
types (data-protocol.js) 0.20KB 0.19KB
types (data.js) 0.20KB 0.18KB
types (designer.js) 1.85KB 0.85KB
types (disclosure.js) 0.20KB 0.18KB
types (error-code.js) 1.54KB 0.88KB
types (expression.js) 0.20KB 0.18KB
types (feedback.js) 0.20KB 0.18KB
types (field-types.js) 0.20KB 0.18KB
types (form.js) 0.20KB 0.18KB
types (http-inflight.js) 8.87KB 3.73KB
types (http-retry.js) 4.32KB 2.02KB
types (icon-key-migration.js) 4.26KB 1.63KB
types (index.js) 5.07KB 2.39KB
types (layout.js) 0.20KB 0.18KB
types (managed-by.js) 0.19KB 0.18KB
types (mobile.js) 5.00KB 2.39KB
types (navigation.js) 0.20KB 0.18KB
types (objectql.js) 0.20KB 0.18KB
types (overlay.js) 0.20KB 0.18KB
types (permissions.js) 2.52KB 1.31KB
types (plugin-scope.js) 0.20KB 0.18KB
types (record-components.js) 0.20KB 0.19KB
types (record-semantics.js) 1.28KB 0.67KB
types (registry.js) 0.20KB 0.18KB
types (reports.js) 0.20KB 0.18KB
types (select-option.js) 0.20KB 0.19KB
types (spec-report.js) 4.99KB 1.96KB
types (spec-ui-namespace.js) 0.20KB 0.19KB
types (strict-authoring-face.js) 19.93KB 7.25KB
types (system-fields.js) 3.33KB 1.54KB
types (theme.js) 6.28KB 2.87KB
types (ui-action.js) 8.11KB 3.32KB
types (views.js) 0.20KB 0.18KB
types (widget.js) 0.20KB 0.18KB

Size Limits

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

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

Contract review

Served-tier: CONTRACT_REVIEW_TIER
Head-sha: ae16cff80317e5da1ae439bcb706b42e647f0d2f
Local-runs: none

Inputs: card #11513 (body and both comments: claim 5962492298, os-dev-report 5963089665); PR #11518 (body, 8-file list, +512/-12, net diff against main 059bf1b5 at ae16cff8); the check-runs on ae16cff8, read twice; the head's .changeset tree (sha 583f8adb8d6678b5a10ab55081afee9d8152ebf1, 2,689 entries, not truncated), every entry read as text with its blob sha verified against the tree; packages/spec/src/ui/chart.zod.ts at tag @objectstack/spec@17.5.0; head sources read for context only (objectql.ts, objectql.zod.ts, plugin-charts normalizeChartSchema.ts / AdvancedChartImpl.tsx / ChartRenderer.tsx, plugin-dashboard widgetDispatch.ts, pnpm-lock.yaml). Nothing built, run or re-run.

① Derived judgments

Ground: the lockfile resolves @objectstack/spec 17.5.0 only (packages/types range ^17.5.0). ChartTypeSchema at that tag is 20 families: bar, horizontal-bar, column, line, area, pie, donut, funnel, scatter, treemap, sankey, combo, gauge, solid-gauge, metric, kpi, bullet, radar, table, pivot.

  1. zod flat mirror ObjectChartSchema.chartType: a local z.enum of 8 becomes stripImportedDefaults(SpecChartTypeSchema).extract(OBJECT_CHART_FAMILIES, { error }), 13 families. RIGHT. Pure widening: funnel, treemap, sankey, combo and radar join; the 8 stay. stripImportedDefaults is the identity on an enum leaf (the default arm of imported-defaults.ts is never reached), so the extract is taken off the spec's own enum, which is the by-reference spelling for a strict subset.
  2. Authored bag ObjectChartBlockSchema.properties.chartType and the strict authoring face: widen by reference, no edit. RIGHT. ObjectChartPropsBag = z.looseObject(ObjectChartSchema.shape).omit(OBJECT_CHART_NODE_LEVEL_KEYS) (head objectql.zod.ts:3673), so the bag reads the same enum object. The new types pin parses each of the 13 on safeValidateSchema, StrictAnyComponentSchema and the flat mirror.
  3. Refusal of an undeclared spelling: invalid_value at properties.chartType (bag) and chartType (flat), values equal to the 13, message naming each. RIGHT; the card's pin "an undeclared spelling is refused with the set named" is met, with the 7 spec families plus sunburst, Bar and bar-chart as rows.
  4. TS ObjectChartSchema['chartType']: the literal union of 8 becomes an Extract of the spec's ChartType over the 13 literals. RIGHT. All 13 are spec members, so Extract drops none; SpecChartType is already imported at objectql.ts:175 (objectui#10770). TS = zod is pinned by invariant Equal rows in the new file and in the re-judged objectui#11276 twin row.
  5. ObjectChartBlockNode (TS, derived from the zod arm's input): widens by derivation. RIGHT.
  6. specType: unchanged, the spec's 20 by reference, identity-pinned. RIGHT (objectui#10770's ruling untouched).
  7. Readers: ChartRendererProps.schema.chartType (ChartRenderer.tsx:49) already declares exactly these 13, so ObjectChart's spread assigns with no edit. A grep of the head tree finds no non-test consumer that reads ObjectChartSchema['chartType'] exhaustively (no Record keyed by it, no exhaustive switch); plugin-report's treemap/sankey switch is on the bare chart node. RIGHT: no further public surface moves. The .describe() text now lists the 13; a documentation surface, consistent with the enum.
  8. Boundary note, declared 13 vs refused 7 against the measured render classification: the declared 13 equal plugin-charts' own RENDERABLE set (normalizeChartSchema.ts:77), and each has its own arm in AdvancedChartImpl.tsx (pie/donut 2087, funnel 2160, treemap 2242, sankey 2277, radar 2406, scatter 2447, combo 2622, the cartesian bar / horizontal-bar / line / area arm from 2705, column mapped to the vertical bar). The refused 7 equal SINGLE_VALUE_CHART_TYPES (gauge, solid-gauge, metric, kpi, bullet, rendered as advanced-chart-single-value: one number from row 0) plus TABULAR_CHART_TYPES (table, pivot, rendered as advanced-chart-tabular-notice). 13 + 7 is the spec's 20 with no remainder. The pin object-chart-declared-families-11513.test.tsx re-derives this two-way on every spec family through the real SchemaRenderer, with a lit control (bar) and a dark control (sunburst, advanced-chart-unknown-type), requires each declared family's OWN marks (a family silently drawn as a bar fails), and holds the DRAWS_ITS_OWN_MARKS key set equal to the declared set. No declared family fails to draw; no refused family draws. The 12 dashboard producer families (widgetDispatch.SERIES_CHART_TYPES) sit inside the 13. The ruling's "a family nothing draws is reported as a finding with its family name" is met (report drawn map; PR body H2 table). RIGHT. Two notes, not findings: donut's own-marks predicate is the pie predicate because the DOM cannot see the hole; donut was already declared and its family value is pinned at normalizeChartSchema by objectui#7401. combo with one measure draws a bar on two value axes and the predicate separates it from bar by the axis count; combo has its own renderer arm and is a producer family, so it is required for V1.
  9. Docs: content/docs/plugins/plugin-charts.mdx gains an object-chart section naming the 13 and the refused 7 with a typed snippet on the doc-snippets gate (green). A tree grep finds no other doc or skill restating the old 8 for object-chart, and zod-mirror-parity.test.ts carries no family-set row. RIGHT.
  10. File surface against the claim: plugin-charts is touched by test files only (one new pin, one re-judged @ts-expect-error fixture moved from radar to gauge); no renderer source edited. Inside the claim's "Tests". RIGHT.

② Semver level

  • .changeset/11513-object-chart-families.md: '@object-ui/types': minor, with the house banner that the TS union widens for an exhaustive consumer. The diff publishes a surface change in @object-ui/types alone (plugin-charts: tests; the mdx: docs). Level and package set RIGHT. Changeset Declaration, Bump Policy, Claim Re-read, Fixed Group Check and Overwrite Report are all green on the head.
  • Clause-②: yes (widening) on the claim, the PR body and the changeset agree. RIGHT: both zod faces accept five spellings they refused; nothing narrows; specType is unchanged.
  • Pending-changeset sweep, done independently rather than taken from the report: 2,689 entries at the head's .changeset tree, all read; grepped by chartType (32 entries), object-chart (24), ObjectChartSchema (19), ObjectChartBlock (6), ChartTypeSchema (3) and each family word. 16 entries name object-chart or ObjectChart together with chartType; 7 together with radar / funnel / treemap / sankey / combo. None states the 8-family set, names a now-accepted family as refused on object-chart, or describes the bag's family set. Read in full: 5927-zod-mirror-group-a-widenings (lists what it added, column / horizontal-bar / donut, still accepted, still that change's reading); objectchart-schema-anchor-7946 ("chartType must be the declared union", still true); 10770-object-chart-react-tier-node (specType by reference, chartType optional, unchanged); 11276-object-chart-properties-bag ("unchanged in shape" is the key set, which does not move; its own objectui#11070 note is the precedent that a key-set move is what earns a note there); 11468-bag-carrier-node-types (ObjectChartBlockNode derived by reference, and it widened by that derivation); 10584-object-chart-series-describe (the per-series override on the dataKey arm); 8885-object-chart-block-props. 7495-compareto-one-predicate (pie, donut, funnel, scatter) is the core predicate, unchanged. No pending reading is made false, so no dated note is owed, and the dev's "touched none" is verified. ② holds.

③ Boundary flags

  • open_questions: none declared, and nothing in the diff needed one.
  • Dev deviations, each judged: (a) the installed spec is 17.5.0, not 17.6.0 — verified in the lockfile, and the card itself says the installed version binds; resolved. (b) plugin-charts touched by tests only — verified against the file list; resolved. (c) the V1 probe's engine-strict install, the pin-style model (objectui#11474 in place of the named objectui#11476) and the attribution trailer — process, not contract; no bearing.
  • out_of_scope_findings, outside this card's accept set, escalated to the seat and not blocking: (1) class a — a single-value or tabular family written as specType (gauge, solid-gauge, metric, kpi, bullet, table, pivot) parses on both faces, because specType stays the spec's 20 under objectui#10770, and the renderer silently draws a BAR (the RENDERABLE gate leaves the family unset, ChartRenderer falls through, AdvancedChartImpl defaults to bar). This PR does not touch specType; the seat should file it. (2) class b — schema-reference.md's bare chart table lists heatmap (refused) and omits accepted families; the seat should file it. (3) the substituted families have no reach through chartType after this PR; noted.
  • Check-runs on ae16cff8. First read 2026-10-02T23:32:38Z: 29 success, 3 skipped (the matrix placeholder, coverage, dependabot), 10 in_progress (Lint, Spec Main Shape Gate, Test shards 1-8, Type Check). Second read 2026-10-02T23:41:52Z, just before this post: 38 success, 3 skipped, 1 in_progress (Test shard 4/8), 0 red. The families that bear on this contract are green: Type Check (the Equal rows holding TS = zod = the 13 and the Extract twin), Lint, Spec Main Shape Gate, Doc Snippet Type Check (the new typed object-chart snippet), every Changeset gate, Test (dist pins) and Test shards 1-3 and 5-8. The one pending shard is not awaited (no loop); the two new pins are reported green at head by the dev (85 + 22 rows, with a runtime ablation that turned 24 of them red and a proven restore), and this verdict rests on the derived judgments above. A red on shard 4/8 would re-open this record; nothing else is pending.

Implemented-by: claude/issue-11513-object-chart-families
Reviewed-by: session_01XvhGmGAP79ZB8swnkapxPC

VERDICT: PASS

@objectstack-fleet
objectstack-fleet Bot marked this pull request as ready for review October 2, 2026 23:45
@objectstack-fleet
objectstack-fleet Bot enabled auto-merge October 2, 2026 23:45
@objectstack-fleet
objectstack-fleet Bot added this pull request to the merge queue Oct 2, 2026
Merged via the queue into main with commit 95e58a3 Oct 3, 2026
45 checks passed
@objectstack-fleet
objectstack-fleet Bot deleted the claude/issue-11513-object-chart-families branch October 3, 2026 00:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

2 participants