Skip to content

feat(types)!: UnifiedViewConfig.chart retires with a tombstone naming the spec's list chart block; the object-chart legacy-axis refusals stop calling the keys a list-view spelling (objectui#12063) - #12065

Merged
objectstack-fleet[bot] merged 3 commits into
mainfrom
claude/issue-12063-unified-view-chart
Oct 9, 2026

Conversation

@objectstack-fleet

@objectstack-fleet objectstack-fleet Bot commented Oct 9, 2026 •

Copy link
Copy Markdown
Contributor

Fixes #12063
Clause-②: no

Lane domain:spec @ objectui. Claim 6083287264, amended by 6084083560 (patch round 1 adds packages/types/src/objectql.ts); ruling: triage 6082380722 (census first; with zero consumers the member retires with a tombstone naming the spec's list chart block; the three messages ride the same PR). Base: main at 2a48bd4, which carries PR objectui#12060 (0253416). The first round's gates were read at head ad25686, and patch round 1's at head dc8e887. Written by a dispatched dev run of the PM seat, session https://claude.ai/code/session_01CijGnfWLxTLUFcJkY2ouUw.

What changes

  • @object-ui/types, designer.ts: UnifiedViewConfig.chart retires. The member declared the list-view chart's pre-ADR-0021 inline query (chartType beside xAxisField, yAxisFields, aggregation, series, config, filter). No route reads those axes since objectui#6152 round 15, and every list-view door refuses them by name. The member is now chart?: never. Its docblock names the remedy: the spec's list chart block, ListChartConfig from @objectstack/spec/ui (the chart member of its ListView), { chartType, dataset, dimensions, values }. The other UnifiedViewConfig members are untouched.
  • @object-ui/types, zod/objectql.zod.ts: the object-chart refusals of xAxisField, yAxisFields and aggregation drop "is the list-view chart block's spelling". Each now opens "no object-chart reader consumes KEY". Each remedy is unchanged: xAxis: { field: 'status' }, yAxis: [{ field: 'amount' }], aggregate: { field, function, groupBy } with its function list.
  • @object-ui/types, objectql.ts (patch round 1): the TypeScript twins of those three refusals. The docblocks of ObjectChartSchema.xAxisField, yAxisFields and aggregation ship in the .d.ts and opened with the same clause ("the list-view chart block's spelling, read by no object-chart reader"). Each now opens "no object-chart reader consumes KEY". Each remedy sentence and each @deprecated line is unchanged. Nothing else in the file moves.
  • New pin: packages/types/src/__tests__/unified-view-config-chart-retired-12063.test.ts.
    • TYPE rows, read by tsc -p tsconfig.test.json: the member reads undefined; a sibling block does not (the helper can fail); an undeclared key reads any (why a deletion is no refusal); the remedy is the spec's own ListView['chart']. Three @ts-expect-error rows: the legacy block, a dataset-shaped block (the member retires whole, it is not narrowed) and a widened value.
    • RUNTIME rows, read by vitest: the remedy parses at the spec's ListChartConfigSchema, and the retired block's six axis keys are refused there by name (unrecognized_keys).
  • Changeset .changeset/12063-unified-view-config-chart-retired.md: minor for @object-ui/types. objectui's version policy never declares major; the body states the break, the remedy table and the unmeasured consumers, and names the docblocks beside the three refusals.
  • No pending changeset goes false: git grep over .changeset/ for UnifiedViewConfig, the clause and 10608 answers exit 1 (no hits).

Census (H1, H2): zero consumers, so the ruling's retire branch

Read on 2a48bd4 with git grep. Each scope is shown as files naming UnifiedViewConfig / control files naming DashboardWidgetConfig, ListViewSchema or @object-ui/types:

scope target control
packages/*/src 2 (designer.ts, index.ts) 1419
apps/*/src 0 24
tests (**/__tests__/**, *.test.*) 0 128 / 156
docs 0 7
content/docs 0 102
examples 0 26
skills 0 7

The whole tracked tree has 4 hits: the declaration and one docblock mention in designer.ts, the re-export in packages/types/src/index.ts, and one ROADMAP.md checklist line that names the type, not .chart. Nothing reads .chart off the type.

Published .d.ts reach (H2). Radius measured:

  • The objectstack checkout (e148ca98, read only): git grep UnifiedViewConfig exit 1, no hits; control @object-ui/types 39 files. No code file there imports from @object-ui/types at all; it is named only in prose.
  • Installed dependency trees. Neither shared checkout has a node_modules. This worktree's pnpm store holds 1587 packages, among them the seven @objectstack/* 17.7.0 packages: 0 files name UnifiedViewConfig. Control @object-ui/types or ListChartConfigSchema inside the @objectstack/* packages: 37 files.
  • NOT MEASURED: host applications built on the published package (production apps, hotcrm, cloud).

No named consumer turned up, so there is no stop and no re-shape.

Tombstone shape (H3)

This follows the house pattern for a type member: ?: never with a RETIRED docblock and @deprecated naming the remedy, the shape of ObjectGridSchema.resizableColumns (objectui#6152 round 7) and of the designer.ts tombstones (parentId, autoLayout, previewMode). The retire-vs-remove discriminator in complex.ts puts a tombstone on a surviving carrier when it steers to a live replacement or a deletion would keep the key silently. Both hold here. The remedy is the spec block, and UnifiedViewConfig keeps [key: string]: any, so a deleted member reads any and admits every value; ablation R2 below measures that. The interface has no zod mirror, so there is no retirementTombstone half to write.

The three messages and their pin (H4)

The three arms sit under the objectui#10608 comment block in ObjectChartSchema. One pin reads them: object-chart-legacy-axis-keys-retired-10608.test.ts. It asserts:

  • the envelope: one invalid_type at the key;
  • that the message carries the key in backticks and the remedy's spelling;
  • that the message equals the published .describe() text;
  • in block (c), the function vocabulary it PARSES out of the aggregation message, against the spec's ChartAggregateSchema.

It does not pin the dropped clause, and no test reads the objectql.ts docblocks: the pin's block (f) reads types only, and the tests that read objectql.ts off disk assert other members. Under the rule that message text is pinned only where a consumer parses it, the clause is not contract. So the pin needs no edit, and no new assertion pins the new wording. The parsed function list is byte-identical. Ablation R3 confirms the pin does not read the clause.

Reverse verification (one-time, committed first)

Each leg ran through objectstack's scripts/ablation-replace.mjs in WRAP mode. Its own EXIT/INT/TERM trap held the mutation, the anchor hit exactly once, and the write was verified on disk by blob change. A belt trap restored both files from HEAD by absolute path. No dist is involved: the pin imports ../designer and ../zod/objectql.zod from source. The predicted direction is in brackets.

  • R1 revives the old object type [red]: TS2344 on the tombstone row, plus TS2578 (unused directive) on the legacy row and the widened row.
  • R2 deletes the member instead of the tombstone [red]: TS2344, plus TS2578 on all three directive rows. The index signature admits chart as any.
  • R4 re-shapes the member to ListChartConfig instead of retiring it [red]: TS2344, plus TS2578 on the dataset-shaped row.
  • R3 restores "is the list-view chart block's spelling" in the xAxisField message [green, by design]: the 10608 pin passes, 24 of 24.
  • After every leg, blob equals HEAD for both files and git diff HEAD is empty.

A first R1 at f07e75c showed the widened row passing for a second reason: a readonly as const value is refused by the old type too. ad25686 makes that row's value mutable, and R1 at ad25686 turns it red.

Gates at ad25686 (first round)

  • vitest from the repo root, --maxWorkers=2, under os-verify-lock:
    • packages/types/ plus every test that names UnifiedViewConfig, designer.ts, objectql.zod or the messages (9 files outside the package): 377 files, 10279 tests passed.
    • The whole scripts/__tests__/ suite: 179 files passed and 2 skipped (5452 tests passed, 2 skipped).
    • Each run printed VERDICT command-exit 0.
  • pnpm turbo run type-check --filter='...@object-ui/types' --concurrency=2 --continue, under the lock: @object-ui/types and its 41 downstream packages. Each one echoed its hyphenated type-check script. Tasks: 77 successful, 77 total, VERDICT command-exit 0. tsc -p tsconfig.test.json --listFiles includes the new pin.
  • pnpm exec eslint --no-inline-config --format json on the 3 changed TS files: exit 0, 0 errors. designer.ts warnings went from 10 to 7, because the retired block's three any are gone. The new pin carries 1 no-explicit-any, the row that asserts any on purpose. The population comes from eslint.config.js files globs (**/*.{ts,tsx}). The config is not type-aware (no parserOptions.project), so an untouched file's verdict cannot move. The repo-wide pnpm lint is CI's.
  • Changeset gates, exit 0: check-changeset-presence ("3 source file(s) of 1 released package(s) changed, and this change declares 1 changeset(s)"), check-changeset-no-major, check-changeset-fixed, check-changeset-claims, check-changeset-overwrite and check-pending-changeset-literals.
  • Exit 0: check-new-cross-file-line-citations ("0 new citation(s)"), check-control-bytes, check-type-check-coverage, check-test-path-roots, check-vi-mock-specifiers, check-vi-mock-inherit, check-vi-mock-override-shape, check-spec-symbol-derivation, check-lint-coverage, check-phantom-dependencies, check-unreferenced-sources, check-shell-escape-residue, check-action-ref-convention and check-pre-install-import-graph.
  • check-governed-queue-guard --test over the 4 paths: NOT GOVERNED.
  • Doc gates and check:readme-exports: not owed. No README or doc changes, and no export is added or removed.

Patch round 1: the objectql.ts docblock twins

The claim first named only the zod messages. The first round's report raised the three docblocks as the same clause on the TypeScript face, and the seat amended the claim to add objectql.ts (6084083560). The in-place fix meets all four conditions:

  • the same defect class: the same clause, on the twin of the same three tombstones;
  • mechanical: drop the clause, keep each remedy and its @deprecated line;
  • no other claim or open PR touches objectql.ts (the seat's reading on main at 2a48bd4);
  • the same gate family: packages/types.

Body refreshed for patch round 1 at 2026-10-09T15:39Z. Gates at dc8e887:

  • pnpm --filter @object-ui/types type-check, under the lock: exit 0. It echoed tsc --noEmit && tsc -p tsconfig.examples.json && tsc -p tsconfig.test.json and printed VERDICT command-exit 0.
  • vitest over packages/types/, under the lock: 368 files and 10115 tests passed, VERDICT command-exit 0.
  • pnpm exec eslint --no-inline-config --format json packages/types/src/objectql.ts: exit 0, 0 errors; 26 warnings, the same as on main at 2a48bd4.
  • Changeset gates, exit 0: presence ("4 source file(s) of 1 released package(s) changed, and this change declares 1 changeset(s)"), no-major, fixed, claims, overwrite and pending-changeset-literals.
  • pnpm check:control-bytes and pnpm check:new-line-citations ("0 new citation(s)"): exit 0.
  • The downstream type-check was not re-run. Docblock text changes no type, so the 42-package run at ad25686 still covers every type this PR publishes.

Acceptance notes

  1. The UnifiedViewConfig interface docblock says "Used by ViewConfigPanel (create/edit)". The census reads no import of the type anywhere. That is out of this card's scope, which is the chart member only. Noted, not changed.
  2. The same census shows that nothing in reach imports the exported UnifiedViewConfig interface at all, not only its chart member. This is an observation with no carrier; only chart was this card's to retire.

Generated by Claude Code

claude added 2 commits October 9, 2026 14:56
… the spec's list chart block; the object-chart legacy-axis refusals stop calling the keys a list-view spelling

UnifiedViewConfig.chart declared the list-view chart's pre-ADR-0021 inline
query (xAxisField, yAxisFields, aggregation, series, config, filter), which
no route reads since objectui#6152 round 15. It becomes `chart?: never`,
whose docblock names the spec's list chart block (chartType, dataset,
dimensions, values) as the remedy; a deletion would have left the
interface's index signature admitting `chart` as `any`.

The three object-chart refusals of xAxisField / yAxisFields / aggregation
drop "the list-view chart block's spelling" and keep their remedies.

Claude-Session: https://claude.ai/code/session_01CijGnfWLxTLUFcJkY2ouUw
Co-authored-by: Claude <noreply@anthropic.com>
… fails on the tombstone alone

A readonly value would have been refused by the retired declaration too,
so the row could not tell a revived member from a tombstone.

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, 290 chunks) 3168.0 KB 3204.6 KB
Main entry chunk (gzip) 74.2 KB 350 KB
Entry file index-CjFoJitf.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.75KB 7.29KB
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) 269.42KB 68.20KB
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.82KB 65.56KB
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) 12.07KB 3.68KB
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

…-axis tombstones drop the list-view spelling clause

The TypeScript docblocks of ObjectChartSchema.xAxisField / yAxisFields /
aggregation opened with "the list-view chart block's spelling", the clause
the zod refusals already dropped. Each now opens "no `object-chart` reader
consumes KEY"; the remedies and @deprecated lines are unchanged. The
changeset names the docblocks beside the refusals.

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, 290 chunks) 3168.0 KB 3204.6 KB
Main entry chunk (gzip) 74.2 KB 350 KB
Entry file index-CjFoJitf.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.75KB 7.29KB
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) 269.42KB 68.20KB
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.82KB 65.56KB
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) 12.07KB 3.68KB
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: dc8e887f390a82be6cbf675acc9ec428339e9065
Local-runs: none

Inputs: card objectui#12063 (body and all five comments: triage 6082380722, claim 6083287264, first-round report 6084051741, claim amendment 6084083560, patch-round report 6084202406); PR objectui#12065 (body, file list, commits, net diff against main at 2a48bd4); the check-runs on the head. The tree was read with git show and git grep at the head and at the base in the local objectui clone; the spec's list chart block was read in the objectstack checkout at e148ca98 (spec 17.7.0, the version objectui's lockfile resolves its ^17.7.0 range against; the installed tarball is not present in this clone and was not read). Nothing was built, run or re-run locally.

Net diff: three commits, linear on the base (merge-base equals the base sha), five files, +209/-22, all under packages/types or .changeset; head repo equals base repo; no governed path (Governed Surface Queue Guard concluded success; the paths hit none of the register rows).

① Derived judgments

  1. UnifiedViewConfig.chart (packages/types/src/designer.ts): an object member becomes chart?: never with a RETIRED docblock and @deprecated naming the spec's list chart block: RIGHT. Published face: UnifiedViewConfig is re-exported by packages/types/src/index.ts, which is the . entry's dist/index.d.ts; the package is public (publishConfig.access: public, no private, in the changeset fixed group). Accept-set effect: a value typed UnifiedViewConfig that writes chart, at any value, stops compiling, on a fresh literal and through a wider variable alike (both pinned). Census re-read at the head: git grep UnifiedViewConfig over the whole tracked tree names only designer.ts (the declaration and one docblock mention), index.ts (the re-export), the new pin, the changeset and one ROADMAP.md checklist line; nothing reads .chart. The objectstack checkout at e148ca98: 0 files name the type, control @object-ui/types 39 files. So the triage ruling's retire branch applies (zero consumers, tombstone; a named external consumer would have meant re-shape), and the ADR-0049 startup-transition clause the ruling cites makes immediate retirement the default. Tombstone rather than deletion is right: the interface keeps [key: string]: any, so a deleted member would read any and admit every value; the pin's row (b) measures that on an undeclared key and the dev's R2 ablation measured it on the member. The shape is the house pattern (parentId?: never, autoLayout?: never, previewMode?: never in the same file; ObjectGridSchema.resizableColumns in objectql.ts). The remedy named is the spec's own block: ListChartConfigSchema in the spec's view.zod.ts is a strict object of chartType (an extract of five, default 'bar'), dataset (snake_case, required), dimensions (optional string list) and values (string list, at least one), exported through @objectstack/spec/ui (the ui index re-exports view.zod, and the ./ui subpath is in the spec's exports); ListViewShapeSchema, which ListViewSchema wraps, carries chart: ListChartConfigSchema.optional(), so ListView['chart'] is that block and the docblock's { chartType, dataset, dimensions, values } is the right spelling. Limit, stated rather than hidden: UnifiedViewConfig has no zod mirror (zod-mirror-parity.test.ts lists no such pair), so this retirement is compile-time only; a JSON document carrying chart on this shape is not refused at runtime by this package. That is the card's own scope (a published type) and the sibling tombstones' shape; no runtime door is in the claim.

  2. The three object-chart refusals in packages/types/src/zod/objectql.zod.ts (xAxisField, yAxisFields, aggregation): message text only: RIGHT. Accept set unchanged: each stays retirementTombstone(guidance), which is z.never({ error: guidance }).optional().describe(guidance) (zod/tombstone.zod.ts), reached from the ./zod entry (zod/index.zod.ts exports ObjectChartSchema from ./objectql.zod.js). The dropped clause is exactly the opening "KEY is the list-view chart block's spelling and no object-chart reader consumes it", now "no object-chart reader consumes KEY"; each message still carries the key in backticks and its remedy byte-for-byte (xAxis: { field: 'status' }; yAxis: [{ field: 'amount' }]; aggregate: { field, function, groupBy } with function one of count, sum, avg, min, max). The 10608 pin, read at the head, asserts the envelope, the key, the remedy, message equals .describe(), and in block (c) the function vocabulary it parses out of the aggregation message; it does not assert the dropped clause, so it holds without edit (the dev's R3 ablation agrees). The clause was false after objectui#6152 round 15, which is the card's premise, and the same pin's block (e) shows the list-view carrier refusing these names with unrecognized_keys; the correction is the one the ruling ordered. git grep for the old clause at the head returns only the changeset's own quotation of it; the one hit in plugin-charts ObjectChart.tsx is a different sentence about the authored block, not this clause.

  3. The three TypeScript docblocks of ObjectChartSchema.xAxisField, yAxisFields and aggregation in packages/types/src/objectql.ts (patch round 1): RIGHT. Comment-only (three hunks, +6/-6, all inside the docblocks); the members stay ?: never; each remedy sentence and @deprecated line is unchanged; ObjectChartSchema ships through the . entry, so the published .d.ts prose stops carrying the false clause. Inside the amended claim 6084083560 (same clause, mechanical, same gate family, no other claim on the file). No test reads these docblocks; the 10608 pin's block (f) reads types only.

  4. New pin packages/types/src/tests/unified-view-config-chart-retired-12063.test.ts: RIGHT. Compiled: tsconfig.test.json includes src/**/*.test.ts and is chained from the package's type-check script; exactOptionalPropertyTypes is set in no tsconfig at the head, so chart?: never reads undefined and the Equal rows are correct (['chart'] is undefined; ['chartt'] is any through the index signature; the kanban control is not undefined). The rows' type: 'chart' and type: 'kanban' are members of UnifiedViewType, which is the spec's VisualizationType (grid, kanban, gallery, calendar, timeline, gantt, map, chart, tree), so each @ts-expect-error row fails on the tombstone and on nothing else (the dev's R1, R2 and R4 ablations: TS2344 plus TS2578 per row, predicted and observed; the second commit made the widened row mutable for exactly that reason). Runtime rows: REMEDY (chartType: 'bar', dataset: 'task_stats', dimensions: ['status'], values: ['total_estimate']) satisfies the strict block; LEGACY_BLOCK is refused with one unrecognized_keys issue at the root naming the six retired keys, the missing dataset and values issues being filtered out by code on purpose. @objectstack/spec is a runtime dependency of the package, so the @objectstack/spec/ui import resolves.

  5. Nothing else on the public face moves: RIGHT. The exports map, main, types, files and the index re-export lists are unchanged; no export is added or removed (README Export Check concluded success); no runtime code path outside the three message strings changes.

  6. The card's Expected, both bullets, met. Bullet 1: the member follows the spec block or retires with a tombstone, this lane's census deciding; the census read zero and it retired with the tombstone naming the block. Bullet 2: the three tombstone messages stop naming a list-view spelling; done on both faces.

② Semver level

  • .changeset/12063-unified-view-config-chart-retired.md declares '@object-ui/types': minor. Right. The diff publishes a breaking narrowing of one published type member plus refusal-message and docblock prose. objectui's version policy (AGENTS.md 版本号策略, enforced by check-changeset-no-major) forbids major and spells objectui's own breaking changes as minor with the break stated in the body. The body states it as a break, carries the before / after / write-instead table (the FROM-to-TO migration an upgrading agent greps), names the one-time census and the unmeasured radius (host applications on the published package), and names the three refusals and the three docblocks beside the retirement. The package is in the fixed group, so the group bumps together, as the policy intends. Not skip-changeset: the diff publishes.
  • The five changeset check-runs on the head (Changeset Bump Policy, Changeset Declaration, Changeset Fixed Group Check, Changeset Claim Re-read, Changeset Overwrite Report) each concluded success; no other pending changeset names UnifiedViewConfig, the clause or 10608.
  • Clause-②: no. Right. The PR body's second line, the claim 6083287264 and the changeset agree. The change widens no accept set and no public face: it narrows one published member and rewords refusals whose accept set is unchanged. A narrowing of a published accept set is Clause-②: no and owes exactly this review before the queue (execution-duties: 「收窄已发布接受集的卡是 Clause-②: no,不移车道;入队前欠一次契约复审档复核」). The three commits end with the model-free trailer pair; no model identifier appears in the title, body, changeset or code.

③ Boundary flags

open_questions: [] in both reports (6084051741 and 6084202406); nothing to answer.

Deviations, first round:

  1. Downstream type-check run beyond the os-dev default (42 packages under the lock) because the dispatch asked for it: accepted; it confirms the zero-consumer census rather than discovering anything; no hold.
  2. objectql.ts left untouched under stop-on-breach: resolved. The seat amended the claim (6084083560) and patch round 1 landed the twins; verified in the net diff (judgment ①3).
  3. Two commits in round one and a third in the patch round: fine; the PR squash-lands, and every gate is quoted at ad25686 or dc8e887 as the reports say.
  4. Commit trailers follow the model-free pair, outranking the harness reminder: verified on all three commits; right under both repos' rule.
  5. Worktree removed after the push: operational, outside the contract.

Deviations, patch round:
6. The PR-body refresh was refused once and re-run with --ack-through naming the perf-budget bot comment 6084088501: right use of the tool. I read the body to its tail: the card reference line and Clause-②: no first, one session-URL footer, no second footer.
7. Worktree re-created at ad25686 and removed again: operational.

out_of_scope_findings:

  1. The objectql.ts docblock twins: absorbed by the claim amendment and patch round 1; verified (①3).
  2. The UnifiedViewConfig interface docblock still says "Used by ViewConfigPanel (create/edit)" while nothing imports the type: concur with the seat. Stale prose outside this card's member, not a defect class Prime Directive [WIP] Enhance every detail of the designer #10 files; still present at the head; no hold on this PR. Whoever next touches the interface corrects it.
  3. The whole exported UnifiedViewConfig has zero importers in reach: concur, an observation with no carrier. Retiring the interface would be its own card and its own census, not this one.

Not measured, and named as such: consumers outside the reachable checkouts (hotcrm, cloud, production apps). The triage ruling's startup-transition clause puts the burden on named external evidence, none surfaced, and the changeset says so. Right.

Check-runs on the head, read at 2026-10-09T15:54Z: 42 runs, 31 success, 3 skipped (the coverage matrix and dependabot, by design), 8 in_progress (Type Check, and Test (shard 1/8), 2/8, 3/8, 4/8, 5/8, 7/8, 8/8), 0 failures. Lint, Build & E2E, Test (dist pins), Test (shard 6/8), Build Docs, Bundle Analysis, Spec Main Shape Gate and the rest concluded success. In-progress is not a pass: this record judges the contract; the landing's second condition, every check green on this head, is read by the dispatching seat from the check-runs when they conclude, not from this record. No run on the first-round head is counted. The PR carries no needs:contract-review label, so there is none to remove.

Implemented-by: claude/issue-12063-unified-view-chart
Reviewed-by: session_01CijGnfWLxTLUFcJkY2ouUw

VERDICT: PASS

@objectstack-fleet
objectstack-fleet Bot marked this pull request as ready for review October 9, 2026 16:02
@objectstack-fleet
objectstack-fleet Bot enabled auto-merge October 9, 2026 16:02
@objectstack-fleet
objectstack-fleet Bot added this pull request to the merge queue Oct 9, 2026
Merged via the queue into main with commit c7b30bd Oct 9, 2026
45 checks passed
@objectstack-fleet
objectstack-fleet Bot deleted the claude/issue-12063-unified-view-chart branch October 9, 2026 16:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

2 participants