Skip to content

feat(plugin-list)!: a chart list view binds only an ADR-0021 dataset; the legacy chart binding retires on every route (objectui#6152, round 15) - #12060

Merged
objectstack-fleet[bot] merged 3 commits into
mainfrom
claude/issue-6152-r15-legacy-chart
Oct 9, 2026
Merged

objectstack-fleet[bot] merged 3 commits into
mainfrom
claude/issue-6152-r15-legacy-chart

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Fixes #6152
Clause-②: no

Round 15 of objectui#6152: class D of the round-13 census (the legacy chart binding), plus the two items round 14's ACCEPT (6079839306, item 3) carried here. Claim 6080177854; rulings 6077535247 (Q1 → C, Q2 → A). Base: main at 3fd8625. Every gate below was read at head 48f102b.

What changes

A chart list view binds only an ADR-0021 dataset, on every route. The pre-ADR-0021 inline axes (xAxisField / categoryField, yAxisFields / valueField, aggregation) are refused by name at every door: the spec's ListChartConfigSchema is a strict object of chartType / dataset / dimensions / values, and the options bag is that block's own partial. Three routes still read them and drew an inline aggregate, floored at 'name' / 'value' when the block declared nothing. All three are retired:

  • @object-ui/plugin-list, ListView.tsx: resolveListChartBinding loses its legacy leg. ListChartBinding loses categoryField / valueField, and its shape is 'dataset' | 'unbound'. The capability gate asks the same resolver, so it no longer offers Chart for a legacy block. case 'chart' loses the legacy return and its floors. A block that names no dataset builds the UNBOUND node: { type: 'object-chart', objectName, chartType, filter }.
  • @object-ui/app-shell, views/ObjectView.tsx: the object page's own chart branch in renderListView is retired too. It read xAxisField, yAxisFields[0], aggregation, and series / filter off the block. The census did not list it as a reader (H1 below). It now builds the same unbound node, without a filter.
  • @object-ui/plugin-view, ObjectView.tsx: the same retirement in generateViewSchema's case 'chart'.

ObjectChart refuses the unbound node on screen with its objectui#8168 screen (chart-missing-category-axis, role="alert"). It no longer aggregates on a name nobody wrote.

Carried from round 14 (ACCEPT item 3):

  • plugin-view's kanban branch stops reading kanban.conditionalFormatting (H3 below). The view-level conditionalFormatting of the active host views entry is the one place the key is read.
  • The development-only flat-key warnings in generateViewSchema and app-shell's renderListView no longer name keys every per-kind block refuses. They used to tell an author to move those keys into the block.
    • plugin-view drops dateField, groupBy, groupField, imageField and subtitleField.
    • app-shell drops those five plus xAxisField, subjectField, endField, cardFields, yAxisFields, aggregation and series.
    • Each remaining key is declared by some spec per-kind block. Each list was checked once against the spec 17.7.0 block shapes; no instrument re-derives it.

Prose: comments that said the list-view relays still read the axes were updated in:

  • ListView.tsx;
  • objectql.zod.ts and objectql.ts (@object-ui/types, comments only);
  • ObjectChart.tsx (@object-ui/plugin-charts): the resolveChartCategoryField docblock and the 8168 docblock, comments only. The refusal path's code is untouched.
  • the headers of the re-judged tests.

The pending .changeset/6152-list-view-readers-retired.md and .changeset/6152-list-view-options-bag.md each gain an append-only dated note, because their "the legacy chart axes are still read" sentence goes false. The new .changeset/6152-list-view-legacy-chart-retired.md declares:

  • minor for plugin-list, app-shell and plugin-view (breaking for a stored chart view that names no dataset);
  • patch for plugin-charts and types (comments only);
  • the FROM → TO table, with production stated as NOT MEASURED.

Measured before any edit

H2: what a chart view with no dataset renders once the legacy branch is gone. A scratch probe rendered the real ListView and the real ObjectChart (deleted afterwards):

  • Doors. objectui's ListViewSchema ACCEPTS viewType: 'chart' with no block, and options: { chart: { chartType } } with no dataset. The spec's view write door (VIEW_METADATA_MEMBERS.listOverlay) ACCEPTS both too. So door-legal views reach this path, besides stored legacy rows.
  • On main. Those views drew an aggregate grouped by name that counted value: the floors.
  • Three candidate node shapes, through the real ObjectChart:
    1. An object-bound node naming no category gives the 8168 refusal, loud (role="alert"). Its remedy reads "Declare one of: aggregate.groupBy, xAxisKey, xAxis.field", which is ObjectChart's vocabulary, not the list view's dataset block.
    2. A node with neither objectName nor dataset renders blank.
    3. A case 'chart' that returns nothing leaves the memo undefined, and the render site dereferences viewComponentSchema.type: a crash (read from source).

So shape 1 is the only loud answer within this surface. It is what is built. Naming the dataset block on screen would need new release text in every locale pack, which is outside this surface. That is open question Q1 in the report on objectui#6152, with options.

H3: does any door that feeds plugin-view's kanban branch accept kanban.conditionalFormatting? Each door was read with a control:

  • Refused (unrecognized_keys at the block; each control accepted): the named-view record (the spec's ViewSchema.listViews, and objectui's ObjectViewSchema / StrictAnyComponentSchema / safeValidateSchema over it), the spec's authoring ListViewSchema, the view write door (listOverlay), and objectui's ListViewSchema in both nestings.
  • Host views entry (ObjectViewProps['views']). It declares no kanban member, only [key: string]: any. A tsc probe compiled kanban.conditionalFormatting, the round-14-retired kanban.groupField and an arbitrary kanban.zzz_not_a_key alike. Its control is the one declared block, tree: it refused parentFeild (TS2561).
  • Reading. That entry judges nothing under kanban. It admits keys round 14 retired on this same branch, so it does not count as a door that accepts the key. Every door that judges the key refuses it, so the read retires. ObjectKanbanSchema does declare conditionalFormatting, but that is the object-kanban NODE's member, not the list view's block.

Fixtures re-judged (three dispositions)

file disposition
plugin-list ListView.chart-capability-7544 Turned: the two "offers Chart for a legacy block" arms now assert it is NOT offered, and a bag arm is added. The two lone-axis arms are kept and renamed. Two render arms are replaced: a legacy block and no block both build the unbound node, with no aggregate and no axis.
plugin-list ListView.searchWithheldTreeChart-10326, ListView.datasetChartToolbarFilter-10327, ListView.datasetChartAppliedFilter-10512, ListView.selfQueryingViewsToolbarState-10250 Re-spelled: "a chart bound to the list object" was spelled with the legacy axes and is now a chart view naming no dataset. The switch case uses the dataset block, the only one the gate offers.
app-shell ObjectView.chartRelay-7823 Turned: the toggle for a legacy block now reads false. The pointer still carries the block whole.
app-shell ObjectView.chartConfigForward-7891 Turned: the legacy positive control now asserts the unbound node. Added: two unbound arms, plus a describe for the flat-key warning.
app-shell ObjectView.refreshInPlace-10035 Re-spelled to the dataset block.
app-shell ObjectView.calendarBinding-7029, ObjectView.galleryBinding-7547, ObjectView.ganttBinding-7070 Converted, as each case instructs: see the note after this table.
plugin-view ObjectView.kanbanConditionalFormatting Turned: the nested rule no longer reaches the node, and the view-level rule is the one read. The header, the failure-message remedy and a stale round-14 note were corrected.
plugin-charts ObjectChart.absentCategoryAxisRefusal-8168 Replaced: the three relay transcriptions pinned branches this PR deletes. They move to a describe that asserts the refusal FIRES on each relay's unbound node, with a control.
plugin-view ObjectView.namedViewProtocolKeys-8980, types object-chart-legacy-axis-keys-retired-10608 Prose only.
new: app-shell __tests__/listViewLegacyChartRetired-6152 The real ListView and the real ObjectChart. Five shapes with no dataset each give the refusal and no aggregate query; the dataset block, as control, is not refused. It lives in app-shell because plugin-list does not depend on plugin-charts, so plugin-list's type-check refused it (TS2882).
new: plugin-view ObjectView.legacyChartRetired-6152 The chart branch (three legacy shapes build the unbound node; the dataset block is the control) and the warning (five refused keys are not named; titleField is the lit control).

Source scans: no fabricated binding floor remains. The same-class control of the three app-shell source scans was anchored on the chart branch's || 'value' measure floor, and this PR deletes it. No one-rung fabricated binding floor remains in app-shell's ObjectView.tsx. What is left floors:

  • a display title or label at 'name';
  • a view type at 'grid';
  • a chart family at 'bar'.

As instructed, the calendar and gallery cases now assert that NONE remains. Each still has a machinery control on 'name'. The gantt control moves to that anchor beside the same assertion.

Census candidates left unchanged and still right: CreateViewDialog.chartBinding-11576 and ObjectView.createChartView-11576 (the writer writes the dataset block), and InterfaceListPage.treeChartRelay-11572.

Ablations (reverse verification)

Each leg went through objectstack scripts/ablation-replace.mjs in wrap mode. That tool carries its own EXIT/INT/TERM trap and proves its restore; a belt trap in the driver restored every path too. Every leg hit its anchor exactly once. After every leg the blob equalled HEAD and git diff HEAD was empty for all three source files. No dist is involved: the suites resolve these packages to src through the vitest aliases.

leg mutation predicted observed
A1 ListView's unbound node grows the name / value floors back red 7 red: five arms in the real-route pin, two in 7544. The dataset control stayed green.
A2 the resolver's legacy resolves comes back red 6 red: four in 7544, two in 7823. The lone-axis arms stayed green, as predicted.
A3 plugin-view reads kanban.conditionalFormatting again red 2 red
A4 plugin-view's warning names groupField again red 1 red
A5 app-shell's unbound node grows an aggregate from the axes red 2 red
A6 app-shell's warning names xAxisField again red 1 red
A7 plugin-view's unbound node grows the floors back red 3 red

Gates (head 48f102b)

  • Test battery (vitest from the repo root, --maxWorkers=2, under os-verify-lock): 648 files in four chunks. The battery is every test that imports or names ListView.tsx, either ObjectView.tsx, ObjectChart.tsx, objectql.ts or objectql.zod.ts by relative path, or the plugin-list / plugin-view / plugin-charts package names; every changed test; and the whole scripts/__tests__ suite. Result: 646 files passed and 2 skipped; 15019 tests passed and 2 skipped. Every chunk printed VERDICT command-exit 0. The first run of chunk 0 found the three source-scan controls above red; they were converted and the chunk re-run green at this head.
  • type-check after building the console's closure (turbo run build --filter='@object-ui/console^...' --concurrency=2, exit 0): exit 0 at this head for @object-ui/types, plugin-charts, plugin-list, plugin-view, app-shell and @object-ui/console. Each run echoed its type-check script.
  • eslint (--no-inline-config --format json) on the 23 changed TS files: 0 errors. The modified files carry 574 warnings at this head, the same 574 as on main; the two new test files add 7 no-explicit-any warnings (the house harness). The linted population is eslint.config.js's **/*.{ts,tsx} globs. Linting is not type-aware (no parserOptions.project), so no untouched file's verdict can move. Repo-wide pnpm lint is CI's.
  • Changeset gates exit 0: check-changeset-presence, -no-major, -fixed, -claims, -overwrite (report-only: the two dated notes, declarations unchanged) and check-pending-changeset-literals.
  • Eager closure (H4), console built under the lock: main 3,240,183 B gzip; head 3,239,902 B; delta −281 B. Headroom to MAX_EAGER_CLOSURE_GZIP_BYTES (3,281,467, untouched): 41,565 B. check-eager-closure-budget exit 0.
  • Other gates, exit 0:
    • check-sdui-registration-pins;
    • check-control-bytes;
    • check-new-cross-file-line-citations (0 new);
    • check-vi-mock-specifiers / -inherit / -override-shape;
    • check-test-path-roots;
    • check-type-check-coverage and check-lint-coverage;
    • check-phantom-dependencies;
    • check-handler-key-read-sites;
    • check-unreferenced-sources;
    • check-i18n-call-site-keys;
    • check-spec-symbol-derivation;
    • check-object-metadata-write-doors;
    • check-element-data-source-declaration;
    • check-governed-queue-guard --test (NOT GOVERNED).
  • No README or doc page changes, so the doc gates are not owed.

Acceptance notes

  • Wasted fetch. On the unbound node, the 8168 screen still lets ObjectChart issue one find of the object's rows (no $top) before it refuses. The probe measured one find and no aggregate. This PR makes every chart view that names no dataset reach that path. It is in the report on objectui#6152 as a finding and as part of Q1.
  • UnifiedViewConfig.chart in @object-ui/types (designer.ts) still types the legacy axes. It is exported and has no consumer in this repository. Noted, not filed.
  • The object-chart tombstone messages still describe xAxisField / yAxisFields / aggregation as "the list-view chart block's spelling". That is published refusal text, left unchanged here.
  • The flat-key warnings stay coarse per kind. They name a key declared by any block (for example startDateField on a kanban view) and point at the view's own kind. This predates this PR and is development-only console text.

Session: https://claude.ai/code/session_01CijGnfWLxTLUFcJkY2ouUw (a subagent run for the domain:spec @ objectui seat).


Generated by Claude Code

claude added 3 commits October 9, 2026 12:10
…bjectui#6152, round 15)

A chart list view binds only an ADR-0021 dataset. ListView's
resolveListChartBinding loses its legacy leg (xAxisField / categoryField,
yAxisFields / valueField, aggregation) and the chart branch its inline
aggregate with the 'name' / 'value' floors; app-shell's object page and
plugin-view's generateViewSchema lose the same path. A chart block that names
no dataset now builds the unbound node, which ObjectChart refuses on screen
(objectui#8168).

plugin-view's kanban branch stops reading kanban.conditionalFormatting, which
every door that judges the list view's kanban block refuses. The
development-only flat-key warnings on both object-view routes stop naming keys
every per-kind block refuses.

Fixtures re-judged; prose that said the axes are still read updated; dated
notes on two pending changesets; one new changeset.

Claude-Session: https://claude.ai/code/session_01CijGnfWLxTLUFcJkY2ouUw
Co-authored-by: Claude <noreply@anthropic.com>
…ListView and ObjectChart (objectui#6152, round 15)

plugin-list does not depend on plugin-charts, so its type-check refused the
pin's side-effect import. app-shell depends on both, so the real-route pin
lives there; the node each relay composes stays pinned beside each relay.

Claude-Session: https://claude.ai/code/session_01CijGnfWLxTLUFcJkY2ouUw
Co-authored-by: Claude <noreply@anthropic.com>
…remains (objectui#6152, round 15)

The three object-page source scans anchored their same-class control on the
chart branch's `|| 'value'` measure floor, which this round retired. As each
case instructed: no fabricated binding floor remains in this face, so the
calendar and gallery cases now assert that none does, and the gantt control
moves to the permanent display-name anchor beside the same assertion.

Claude-Session: https://claude.ai/code/session_01CijGnfWLxTLUFcJkY2ouUw
Co-authored-by: Claude <noreply@anthropic.com>
@github-actions

github-actions Bot commented Oct 9, 2026

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

Metric Value Budget
Eager closure (gzip, 289 chunks) 3164.0 KB 3204.6 KB
Main entry chunk (gzip) 72.7 KB 350 KB
Entry file index-B9zUbsJw.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) 19.52KB 7.19KB
app-shell (runtime-config.js) 22.59KB 7.89KB
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.15KB 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) 41.19KB 11.12KB
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) 587.83KB 141.44KB
core (index.js) 10.00KB 3.96KB
create-plugin (index.js) 27.94KB 9.51KB
data-objectstack (index.js) 240.39KB 67.09KB
fields (index.js) 268.74KB 68.04KB
i18n (LocalizationContext.js) 2.92KB 1.42KB
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.52KB 2.39KB
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) 36.87KB 9.88KB
i18n (useSafeTranslation.js) 7.14KB 2.92KB
layout (index.js) 41.50KB 11.82KB
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.43KB 15.54KB
plugin-charts (index.js) 84.71KB 23.25KB
plugin-chatbot (index.js) 201.52KB 47.99KB
plugin-dashboard (index.js) 144.20KB 38.95KB
plugin-designer (index.js) 233.53KB 49.80KB
plugin-detail (index.js) 248.57KB 65.47KB
plugin-editor (index.js) 2.23KB 1.05KB
plugin-form (index.js) 177.11KB 45.88KB
plugin-gantt (index.js) 179.17KB 45.07KB
plugin-grid (index.js) 249.62KB 69.16KB
plugin-kanban (index.js) 52.77KB 16.56KB
plugin-list (index.js) 120.10KB 30.28KB
plugin-map (index.js) 27.24KB 9.03KB
plugin-markdown (index.js) 13.88KB 4.80KB
plugin-report (index.js) 44.12KB 12.29KB
plugin-timeline (index.js) 39.06KB 11.80KB
plugin-tree (index.js) 15.07KB 5.33KB
plugin-view (index.js) 91.79KB 23.21KB
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.31KB 2.07KB
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.07KB 1.30KB
sdui-parser (index.js) 7.30KB 3.12KB
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) 23.87KB 7.83KB
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 (cloud.js) 0.20KB 0.18KB
types (complex.js) 4.44KB 2.07KB
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) 1.13KB 0.65KB
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.78KB 2.70KB
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 (node-slots.js) 7.18KB 2.34KB
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.26KB
types (system-fields.js) 3.33KB 1.54KB
types (theme.js) 6.28KB 2.87KB
types (ui-action.js) 8.48KB 3.50KB
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: 48f102b5febeab42a9075588cdfebf5168150e91
Local-runs: none

Read: card objectui#6152 (body and all 93 comments; the round-13 to round-15 rulings and reports are comments 6077447919, 6077535247, 6079839306, 6080145603, 6080177854, 6081672623 and the seat's Q1 answer 6081752038), PR objectui#12060 (body, the 26-file list, the net diff against its merge base, which is round 14's landing), the three changed source files and the five named packages' manifests at this head, the spec's list-view blocks in the sibling checkout for the warning lists, and this head's check-runs. Nothing built, run or re-run. An isolated subagent of the seat session signed below; the dispatch order and the seat's own conclusions were not inputs.

Check-runs on this head, read at 2026-10-09T13:33Z: 43 runs, one head: 40 success, 3 skipped by design (dependabot, Test (coverage), Test (coverage shard N/4)), 0 in progress, 0 failed. Success includes Type Check, Lint, Spec Main Shape Gate, Build and E2E, Test (dist pins), Governed Surface Queue Guard, Line Citation Gate, Bundle Analysis, the five changeset gates (Declaration, Bump Policy, Fixed Group Check, Claim Re-read, Overwrite Report) and all 8 Test shards and the Test aggregate. Every gate-carrying run has concluded, none red. The verdict below is the contract face; the gate verdicts are the runs' own conclusions.

① Derived judgments

Every accept-set or surface change the diff implies, each judged against the tree at this head:

  1. plugin-list, resolveListChartBinding. A chart block that names no dataset now resolves shape: 'unbound', resolves: false; the legacy leg that read xAxisField / categoryField and yAxisFields[0] / valueField in both nestings is deleted, and ListChartBinding loses categoryField, valueField and the 'legacy' arm. The capability gate (availableViews) asks the same resolver, so a view of another type carrying only a legacy block is no longer offered Chart. Right. The spec's ListChartConfigSchema is a strictObject of chartType, dataset (required), dimensions and values, so every door refuses the axes by name, and a renderer-side alias is what AGENTS.md #0.1 forbids. Neither the function nor the interface is exported (plugin-list's index.tsx re-exports ListView, three normalisers, the translations and two types), so no published type face moves.

  2. plugin-list, case 'chart'. The unbound node is { type: 'object-chart', objectName, chartType, filter: selfQueryFilter, className }: no aggregate, no xAxisKey, no series, and the 'name' / 'value' floors are gone. Right. Read at this head, ObjectChart computes drawsFetchedObjectRows as object-bound, dataset-less and without authored rows, and refuses when resolveChartCategoryField finds no category, so the node reaches the objectui#8168 screen (chart-missing-category-axis, role alert). The switcher's viewType leg still offers Chart to a view whose viewType is chart (untouched; pinned as a control in the 7544 file), so a door-legal view with no block renders the refusal, the H2 outcome the seat accepted.

  3. app-shell, renderListView chart branch. A reader the census did not list. The inline translation from xAxisField, yAxisFields[0] and aggregation, and the block-level series / filter forwarding, retire; the dataset leg directly above it is untouched (read at this head). Right. The object-page node now carries no filter at all; moot for drawing, since the node is refused, and relevant only to the wasted find the seat filed as objectui#12061.

  4. plugin-view, generateViewSchema case 'chart'. The same retirement; the dataset leg is untouched. Right. This branch is reachable only through a host views prop (the objectui#5321 record), so the changeset's plugin-view entry is the notice that route gets.

  5. plugin-view, kanban conditionalFormatting. The nested kanban.conditionalFormatting read is gone; activeView?.conditionalFormatting is the one read. A host that passed the nested key through the views entry's index signature loses it silently. Right. Every door that judges the list view's kanban block refuses the key (the dev measured each with an accepted control, the seat checked them), ObjectKanbanSchema.conditionalFormatting is the object-kanban NODE's member, and app-shell's delegation still forwards the view-level key (viewDef.conditionalFormatting ?? listSchema.conditionalFormatting, unchanged), so the two routes now answer alike. The changeset's plugin-view bullet states it.

  6. The two development-only flat-key warnings. I re-read the spec's list-view blocks (packages/spec/src/ui/view.zod.ts in the sibling checkout, whose manifest is the 17.7.0 version objectui installs): every kept key is declared by a list-view block (gantt: startDateField, endDateField, progressField, dependenciesField, colorField, titleField; calendar: startDateField, endDateField, colorField, allDayField; map: latitudeField, longitudeField, locationField, descriptionField, zoom, center, titleField; chart: chartType), and none of the twelve dropped keys is declared by any list-view block (dateField, groupBy, groupField, cardFields, aggregation and series are declared only on other surfaces, components, charts, dashboards and reports; subtitleField, subjectField, endField, imageField, xAxisField and yAxisFields on none). Right. Console text, not a published surface. Nothing re-derives the lists, and the PR body says so (完善设计器的每一个细节 #9).

  7. Residue. At this head no code line of the three source files reads xAxisField, yAxisFields, categoryField, valueField or aggregation (comment lines excluded). Right.

  8. Fixtures. The 7544, 7823 and 7891 arms are TURNED with the old reading recorded; the 10250, 10326, 10327, 10512 and 10035 fixtures are re-spelled to the shapes the population became; the 8168 file moves the three relay transcriptions into a describe where the refusal FIRES on each relay's unbound node, with a drawing control; the three app-shell source scans are converted to "none remains" as each case's own text instructed, each keeping its machinery control on 'name' (the converted regex carves out titleField / labelField, which are label floors, not binding floors); the two new pins (app-shell: real ListView plus real ObjectChart, five shapes and a dataset control; plugin-view: the node shapes and the warning) each carry a lit control. Right. No turned arm lost its control.

  9. Comments only in plugin-charts and types. resolveChartCategoryField is exported and the objectql.ts docblocks ship in the .d.ts, so this is published text; no key, export, verdict or message moves. Right.

② Semver level

  • New changeset 6152-list-view-legacy-chart-retired.md: minor for @object-ui/plugin-list, @object-ui/app-shell and @object-ui/plugin-view; patch for @object-ui/plugin-charts and @object-ui/types. All five are in the one fixed group (40 packages), none is private, and each has an exports map at this head (. for the three plugins, . plus ./styles.css for app-shell, . plus eleven subpaths for types). Matches what the diff publishes: the three minor packages change behaviour for a stored chart view naming no dataset and for a host's nested kanban rule, a break stated as "Changed (breaking ...)" with the FROM → TO table and production stated NOT MEASURED, which is what the round-13 ruling required; under objectui's no-major policy a break is minor. patch for the two comment-only packages is right (shipped .d.ts text, and a declaration is owed anyway because their test files under src/ changed).
  • The two dated notes on the pending round-11 and round-12 changesets are append-only; declarations unchanged (Changeset Overwrite Report: success).
  • Clause-②: no on the claim (comment 6080177854), on the PR body's second line and in the changeset; the three agree. Right: the diff narrows a published accept set (the legacy axes bind nothing; the nested kanban rule is not read) and widens no public face (no new export, key, message or error code; the ListChartBinding shape change is internal). A narrowing is no by the rule. The optional (narrowing) arm is absent on all three; the dev copies the claim's line verbatim, so that is the claim's spelling, not a defect.
  • Not a governed diff: none of the 26 paths is a governed surface (Governed Surface Queue Guard: success). Changed lines 1,166, under the 5,000-line class. A dispatched dev's PR, so the ready flip and the queue are the seat's acts, on this record and green runs.

③ Boundary flags

Dev deviations (report 6081672623), each answered:

  1. File-surface additions (plugin-charts comments and the 8168 test; types comments and the 10608 pin; the app-shell 7823, 7891 and 10035 tests and the three scans; four plugin-list fixtures): inside the claim's "fixture candidates plus what the dev's grep adds" and "prose that says the axes are still read" clauses. Answered. The two pending changesets gained dated notes where the claim named one new changeset; that is the round-11 shape the seat set again in round 14 (comment 6079839306, item 1). Answered.
  2. The real-route pin moved from plugin-list to app-shell (TS2882; plugin-list does not depend on plugin-charts): right, a test imports only a declared dependency. Answered.
  3. The three source scans converted on the battery's red: as each case's own text instructed, and said in the PR body. Answered.
  4. Warning lists narrowed by hand, nothing re-derives them: re-read above (① 6), holds; the PR body states the non-derivation per 完善设计器的每一个细节 #9. Answered.
  5. Changeset levels: ② above. Answered.
  6. First line Fixes #6152: the seat's Q1 → A (comment 6081752038) keeps the PR as built, so the close stands with this round; nothing of the round-13 taxonomy (classes A to F) or round 14's item 3 remains after it. Answered.
  7. Worktrees and scratch probes removed: housekeeping. Answered.

Open question Q1 (what a dataset-less chart view shows): the seat answered A (the built objectui#8168 refusal), with C filed as objectstack#22491 for the spec seat and B not taken. Agreed: the built shape is loud and none of the dispatch's stop shapes; closing the door (C) is the contract-first half (#0.1); a list-view-only screen (B) would add release text in every locale for a population with zero writers in reach. The dev's H3 reading (the host views entry judges nothing under kanban, so it is not a door that accepts the key): agreed, see ① 5.

Out-of-scope findings:

  • The unbounded find that ObjectChart issues before refusing: filed by the seat as objectui#12061. Answered; a cost, not a wrong answer, so it does not hold this PR.
  • The door accepting a chart view with no binding: objectstack#22491. Answered.
  • Escalated, one item. Two pieces of PUBLISHED text still present the retired axes as a live spelling and were left "noted, not filed": UnifiedViewConfig.chart in packages/types designer.ts (exported; declares xAxisField, yAxisFields, aggregation, series, config and filter; zero in-repo consumers), and the three object-chart tombstone messages in objectql.zod.ts, whose clause calls each key "the list-view chart block's spelling" (their xAxis: { field } style remedies stay right). A published .d.ts member that invites a key no route reads is the declared-but-unread shape this card's family exists to close, and AGENTS.md [WIP] Enhance every detail of the designer #10 files an authoring trap rather than noting it. Both predate this PR and change nothing it does, so they do not hold it; the seat should file them as one finding (a type retirement with its tombstone, plus the prose repair) rather than leave them as notes.
  • The warnings pointing a key at the view's own kind, and the metadata-admin comments citing chart.xAxisField: acceptance-note level, not published surfaces. Answered.

Implemented-by: claude/issue-6152-r15-legacy-chart
Reviewed-by: session_01CijGnfWLxTLUFcJkY2ouUw

VERDICT: PASS


Generated by Claude Code

@objectstack-fleet
objectstack-fleet Bot marked this pull request as ready for review October 9, 2026 13:36
@objectstack-fleet
objectstack-fleet Bot added this pull request to the merge queue Oct 9, 2026
Merged via the queue into main with commit 0253416 Oct 9, 2026
45 checks passed
@objectstack-fleet
objectstack-fleet Bot deleted the claude/issue-6152-r15-legacy-chart branch October 9, 2026 13:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

121 declared-but-unmirrored keys across 16 schema pairs — the lane #6058's new UnmirroredDeclared ledger made visible

2 participants