Skip to content

fix(charts): retire the Tremor dialect at ChartRenderer, keep the declared categories - #9367

Merged
os-sam merged 2 commits into
mainfrom
claude/issue-8650-plugin-charts-foreign-dialect
Sep 13, 2026
Merged

fix(charts): retire the Tremor dialect at ChartRenderer, keep the declared categories#9367
os-sam merged 2 commits into
mainfrom
claude/issue-8650-plugin-charts-foreign-dialect

Conversation

@os-sam

@os-sam os-sam commented Sep 13, 2026

Copy link
Copy Markdown
Collaborator

Fixes #8650

Implements the triage ruling (comment 5619609278): route to the producer, ⛔ not a declaration. The direction was not re-opened; what this PR settles is the how, and the measurement split the card's one group of four into two different answers.

⚠️ Premise falsification — all four dispatch premises, measured on origin/main 2e471dc0

# premise as dispatched verdict measurement
1 the card's «ObjectChart takes props: any» is FALSE CONFIRMED (card stale, seat correct) ObjectChart.tsx declares export interface ObjectChartProps and export const ObjectChart = (props: ObjectChartProps); the checker reads ObjectChartProps.schema as ObjectChartSchema with 37 declared named members
2 expect series to have moved to bucket (b) CONFIRMED, and wider — all THREE moved colors, compareTo and series are all declared named members of ObjectChartSchema. the colors drift was settled by objectui#7946 as well
3 question 1's premise HOLDS at the Tremor comment CONFIRMED verbatim the comment and the four casts are live, unchanged, at the lines the seat quoted
4 the card UNDER-reports the file — the census gives SEVEN FALSIFIED on today's main the undeclared population is the card's four. Of the census's seven, colors · categoryColors · categoryOrder are now declared members of ChartRendererProps.schema — they are bucket (b), not undeclared

⭐ And a fifth, which neither the card nor the dispatch had: categories is not a foreign key at all. It is a declared member of the published ChartSchema and of its zod mirror, is documented in content/docs/api/schema-reference.md as "an alternative series list", and was ruled LIVE by objectui#6896 (maintainer ruling 2026-08-31, prose follows machine). The card's headline — "four reads are an explicit FOREIGN DIALECT" — is wrong for one of its four.

The instrument, and the index-signature control

Reads: schemaReads from packages/types/src/__tests__/widget-schema-anchors-6576.test.ts, verbatim — no second scanner. Declaredness: the TypeScript checker (getPropertiesOfType / getPropertyOfType), never a grep (objectui#8410).

The confound the dispatch named is real and the instrument survives it:

ObjectChartSchema:
  string index signature                : any
  getPropertyOfType('zzqx_no_such_key') : undefined   (index signature NOT mistaken for a member)
  getPropertyOfType('type')             : DEFINED     (real member seen)
ChartRendererProps.schema:
  string index signature                : NONE        (a hand-rolled inline literal, no confound available)
  getPropertyOfType('zzqx_no_such_key') : undefined
  getPropertyOfType('type')             : DEFINED

⇒ an index signature that types any key as any still yields undefined for a nonsense key, while a real member is seen. The classification below is therefore a reading, not an artefact.

Two instrument artefacts, both disambiguated with the same instrument rather than by eye:

  • color / dataKey came back "undeclared" on ChartRenderer.tsx because schemaReads is FILE-scoped and the file declares two props types — both are declared members of ChartBarRendererProps.schema.
  • chart came back as a read on ObjectChart.tsx from a docblock sentence. Re-running the same census on a comment-stripped copy of the same source drops it and keeps chartType (non-vacuity).

Re-derived read set — ChartRenderer.tsx

key read declared on ChartRendererProps.schema declared on the published ChartSchema bucket disposition
categories yes no yes (+ zod mirror, + docs, ruled live objectui#6896) not a dialect branch removed as a duplicate read; capability untouched
category yes no no (a) retired
index yes no no (a) retired
value yes no no (a) retired
colors yes yes no (b) cast deleted
categoryColors yes yes no (b) cast deleted
categoryOrder yes yes no (b) cast deleted

Question 2 — ObjectChart's three reads, re-classified

All three are bucket (b): declared, then read through a needless cast. ⛔ Nothing was declared; three casts were deleted.

key read sites checker verdict on ObjectChartSchema bucket
colors 3 DECLARED string[] OR Record of string to string, optional (b)
compareTo 4 DECLARED { kind: previousPeriod OR previousYear; dimension?: string }, optional (b)
series 2 DECLARED Array of { dataKey: string; … }, optional (b)

ObjectChart.tsx now has zero (schema as any) reads left (one historical mention survives inside a comment). Deleting the casts is not a cosmetic change: with the casts gone, type-check now actually checks these values against their declarations — it passes, which is itself the reading that the declarations and the reads agree.

⚠️ drillDwon was met and ⛔ not re-reported: it is the deliberate misspelling inside a string-literal fixture feeding the census's own non-vacuity control.

Producer measurement — which arm, and why

A structural producer census over packages/ · apps/ · examples/ · content/ · skills/ · .claude/ · docs/5695 files, every object literal / JSON object / fenced-block node whose type is one of ChartRenderer's registry keywords (chart, chart:bar, pie-chart, donut-chart, radar-chart, scatter-chart, plus bar-chart): 74 chart nodes.

key chart nodes writing it note
category 0
value 0
index 1 this repo's own test for the adapter — a pin, not a producer
categories 4 all tests; three of them pin objectui#6896's ruling through ChartSchema, not through this branch
xAxisKey 41 ✅ positive control
series 44 ✅ positive control
chartType 40 ✅ positive control
data 52 ✅ positive control
zzqx_no_such_key 0 ✅ negative control

Documented / taught use, same corpora: xAxisKey appears in 8 doc files (positive control fires); the word "Tremor" appears in no doc, guide or skill — only in the in-source comment this PR removes; index / category / value are taught nowhere as chart-node keys; categories IS documented, and it is the one this PR does not retire. None of the three retired keys is advertised by any registry inputs.

Zero live producers, zero taught use, no published declaration, no palette advertisement for index / category / value. Per the dispatch's own rule that is the "proceed" arm, and the zero is backed by four firing positive controls and a firing negative control.

⚠️ The failure mode this degrades to was measured — and the reading above was too strong; corrected in the 欠改 round below. Dropping the axis aliases leaves AdvancedChartImpl on its default category key, name (AdvancedChartImpl.tsx:865). Only one half of that is a refusal: rows carrying no name column hit the on-screen missing-category-key refusal (that is the half the first run surfaced, and the half this PR's rows pin), while rows that do carry one plot silently against name — a wrong picture, not a refusal. The classification never rested on the loudness of the degradation, but the sentence did overstate it, and it was also in the changeset, which publishes verbatim.

Reverse verification — commit first, then ablate, with on-disk proof

The fix was committed first, so the restore leg points at a real commit. The mutation restores the pre-fix ChartRenderer.tsx from the pinned base commit 2e471dc0aa23ff807aa9960618c419ecccdfdcef, never from a remote-tracking name.

leg on-disk proof run
mutated (fix removed) schema as any count 0 → 10; is RETIRED count 1 → 0; blob 13e49a04 ≠ HEAD blob f2531d0a 4 failed / 9 passed (13) — exactly the four retirement cases: index, category, value, and the malformed-categories throw
restored blob back to f2531d0a (byte-identical to HEAD), git diff HEAD empty 13 passed (13)

⭐ The three "categories still plots" cases pass in both legs. That is the reading that matters: removing ChartRenderer's own branch did not remove the capability, because normalizeChartSchema served it all along.

⭐ The malformed-categories case failing in the mutated leg is what turns "the retired branch called .map on a string and threw" from a claim into a measurement.

The ablation script carries a trap on EXIT / INT / TERM calling a RESTORE function (the placeholder is spelled as a word on purpose — GitHub's body sanitizer eats angle-bracket-shaped tokens, backticks included) with absolute paths, verifies the mutation reached disk by marker count and by blob hash before running anything, and treats an empty hash as failure. It is a one-shot proof; no test file is left behind by it.

Gates

gate exit
lint:coverage 0
check:entry-guard 0
check:upstream-port-parity 0
check:bash32-floor 0
turbo run lint --filter=@object-ui/plugin-charts --force 0
check:vi-mock-override-shape 0
check:test-path-roots 0
check:cross-repo-closer-outcome 0
check:control-bytes 0
check:new-line-citations 0
check:spec-symbols 0
check-changeset-presence 0
check-changeset-no-major 0
@object-ui/plugin-charts type-check 0
dependency-closure build 0
vitest packages/plugin-charts/ 0 — 60 files / 541 tests (was 59 / 534)

Every exit code captured by redirect before any pipe. Doc Snippet Type Check and Skill Example Check are red on main itself (chain objectui#9308 → objectui#9346); they name no file this PR touches.

欠改 round — the three items the ceiling-tier review logged

Head c237b09e, one commit on top of the reviewed head 348a4bdf. ⛔ Not a re-litigation: the contract gate PASSed and is on record. ⛔ No accept-set change, ⛔ no declaration, ⛔ no new key, ⛔ nothing under packages/types/. Diff of this round = 3 files, +51 / -21.

# item disposition file:line
1 changeset Migration sentence overstates the failure mode qualifier added; the value sentence, which measured accurate, is byte-identical .changeset/8650-chart-foreign-dialect-retired.md:39-45
2 neverPlots is a race in the false-green direction replaced with positive readings; ablation re-run below ChartRenderer.foreignDialectRetired-8650.test.tsx:103-114, 188, 200, 217
3 now-false comment about a branch this PR removed rewritten to name the reader that does adapt categories — this file normalizeChartSchema.ts:381-389

Item 2, what changed and why it now fails the other way. The old form slept a fixed 150 ms and asserted "no surface yet", against a measured warm time-to-surface of 97–168 ms for the canonical control. It discriminated in both runs so far, but a re-added alias that plotted late on a loaded runner would have satisfied it — a pin that cannot fail. The new form waits for the positive signal: waitFor on [data-chart-error="missing-category-key"] for index / category (plus "no plot surface coexists with the refusal"), and for value the file's existing plotted helper — wait for the surface to arrive, then count marks. A slow runner now makes these slower, never green. Observable in the ablation timings: the two axis cases redden by waitFor timeout at ~1087 ms, not by beating a window.

Item 3 premise re-checked before complying, not assumed. git grep -n categories packages/plugin-charts/src/ChartRenderer.tsx returns only comment lines — the reader-side branch is gone — so the sentence was false about the very removal it sat next to. Item 1 premise likewise: AdvancedChartImpl.tsx:865 is literally xAxisKey = 'name',. Both held; neither was taken on report.

Ablation, re-run on the rewritten cases

Committed first (c237b09e), so the restore leg points at a real commit; mutation and restore are symmetric, the script carries trap … EXIT INT TERM, and every path in it is absolute.

leg on-disk proof before any result run
mutated — the retired index / category / value reads put back in ChartRenderer.tsx anchored canonical line 1 → 0; injected marker 0 → 2 lines; on-disk blob 16d9b712 ≠ HEAD blob f2531d0a exit 1Tests 3 failed / 4 passed (7): exactly index (1087 ms), category (1089 ms), value (69 ms)
restoredgit checkout HEAD -- … (⛔ never bare git checkout --, which would take the mutation back out of the index) on-disk blob f2531d0a == HEAD blob f2531d0a; canonical line back to 1, marker back to 0; git diff HEAD on the path empty exit 0Tests 7 passed (7)

The 4 that pass in both legs are the canonical control and the three categories cases — the capability this PR does not retire, unaffected by the mutation in either direction. ⚠️ Counting note, so nobody re-derives it wrong: the marker figure is grep -c, which counts lines, not occurrences — 3 injected occurrences land on 2 lines.

⭐ No build / dist preflight is owed for this ablation: the pin imports ./ChartRenderer and ./AdvancedChartImpl by relative specifier inside the same package, so the mutated source is what runs. There is no exports-resolved hop that a stale dist could keep green.

Gates — exit code captured by redirect before any pipe

cmd > log 2>&1; EXIT=$? throughout. ⛔ Not derived from lint.yml: this repo's doc and skill gates each own a workflow file, and the workflow set was enumerated from origin/main with git ls-tree, not from the working tree.

gate exit reading
check-changeset-presence 0 5 source files of 1 released package, 1 changeset
check-changeset-no-major / -fixed / -overwrite 0 / 0 / 0
check-changeset-claims 0 report-only; its 3 findings all name ObjectChart.tsx and pre-date this round
check-control-bytes 0 7540 tracked text files scanned
check-new-cross-file-line-citations 0 0 new citations
check-test-path-roots 0
check-vi-mock-override-shape / -specifiers / -inherit 0 / 0 / 0 the file's recharts mock
check-spec-symbol-derivation 0
check-comment-mask-corpus 0 4922 files; residue unchanged, within the ceiling objectui#7882 holds open
check-entry-guard · check-upstream-port-parity · check-bash32-floor 0 each
check-cross-repo-closer-outcome · check-lint-coverage · check-shell-escape-residue 0 each
turbo type-check --filter=@object-ui/plugin-charts 0 10 tasks, dependency closure built
turbo lint --filter=@object-ui/plugin-charts 0 0 errors, 338 warnings — the same warning count measured at 348a4bdf, so this round adds none
vitest run packages/plugin-charts/ (under the shared verify lock) 0 60 files / 541 tests passed

Test counts before → after: pin file 7 → 7 (it( count on both sides; assertions rewritten, no case added or removed), plugin-charts package 541 passed.

⛔ Consumer packages are not re-run this round and none is owed: the only non-test source file touched is normalizeChartSchema.ts, and every changed line in it is a comment — mechanically, changed non-comment lines = 0. The published face did not move.

⚠️ Doc Snippet Type Check and Bundle Analysis remain red from base-side debts (objectui#9308 via objectui#9346; objectui#9204 / objectui#9316). ⛔ Neither is this PR's, and neither was re-run.

⛔ Still draft. ⛔ Not enqueued, ⛔ no auto-merge, ⛔ no label added, moved or removed by this round.

Acceptance notes

Out of scope, noted, not filedChartRendererProps.schema is a hand-rolled inline object literal that does not mirror the published ChartSchema: categories is authorable and reaches normalizeChartSchema, yet the props type refuses it, which is why every in-repo caller writes as any. That is objectui#6576's class (a widget props type anchoring its schema to no named type), already ruled for two other widgets, and anchoring a third published prop type is a shape decision this card explicitly forbids taking. Carrier: whoever picks up the objectui#6576 anchoring family next; this PR deliberately adds no declaration.

Out of scope, noted, not filedBaseSchema's [key: string]: any is the reason none of this is enforceable at authoring time; the standing defect card is objectui#7927 (pm:blocked).

⛔ This PR does not put anything in packages/types/src/__tests__/undeclared-but-consumed-keys-6150.test.ts, does not fold into objectui#8347, and adds no declaration to any published type — the three outcomes the card exists to prevent.

🤖 Generated with Claude Code

https://claude.ai/code/session_01L5xpA5q533BgTTNADibEFt


Generated by Claude Code


Generated by Claude Code

…lared `categories`

The card filed four undeclared reads on `ChartRendererProps.schema` as one
group. A cast-aware read census (`schemaReads`, objectui#6576) plus a
TypeScript-checker declaredness reading (`getPropertyOfType`, never a grep --
objectui#8410) measured them apart, and they do not share one verdict:

- `index`, `category`, `value` -- declared on no published face, advertised by
  no registry `inputs`, taught by no doc or skill, and written by zero producers
  in a structural census over packages/, apps/, examples/, content/docs/ and the
  skills corpus. AGENTS.md #0.1 puts the remedy at the producer; there is no
  producer. Retired.
- `categories` -- a declared member of the published `ChartSchema` and of its
  zod mirror, documented in the schema reference, ruled LIVE by objectui#6896.
  `normalizeChartSchema`, the ONE translation point (objectui#2880 S1), already
  consumed it, so the branch here was a second, un-normalized read that no
  well-formed chart could reach, and that on malformed input threw (`.map` on a
  string) or produced a `[{ dataKey: '' }]` series. Branch removed, capability
  untouched.

Also deletes the six objectui#8327 bucket-(b) casts the published declarations
had already made unnecessary: `colors` / `categoryColors` / `categoryOrder` on
`ChartRenderer`, and `colors` / `compareTo` / `series` on `ObjectChart`, which
now has no `(schema as any)` read left.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L5xpA5q533BgTTNADibEFt
@github-actions

Copy link
Copy Markdown
Contributor

⚠️ Console Performance Budget — gauge not trustworthy

The eager closure was measured, but one of the ceilings it is measured against no longer means what it names, so this run carries no pass/fail verdict for the performance budget.

This is not a budget violation. Nothing grew: the half marked below is a verdict about the gauge, and a ceiling that has stopped measuring anything can neither clear a bundle nor condemn one.

Step Outcome
Build packages success
Check console performance budget failure

Which half objected:

Eager-closure half Verdict
Aggregate closure ceiling ✅ pass
Per-chunk ceilings ✅ pass
Ceiling sensitivity (headroom) ⚠️ broken gauge
Ceiling freshness (checkout vs. base branch) ✅ pass

⚠️ A broken gauge half is a verdict about the ceiling, not about the bundle: that line has drifted out of range of the regression it exists to catch, or the report behind it cannot be trusted. It does not say anything grew. The Check console performance budget step log carries the ceiling and the number it was compared against.

Reason: The entry chunk measured 144.3 KB, but the eager-closure half of this gate returned no trustworthy VERDICT: the report could not be read, a ceiling has drifted out of range of the regression it must catch, or (objectui#6245) a ceiling was replaced on the base branch after this checkout was made. The step log says which. This is not a passing budget — and it is not a size regression either.

See the workflow run for details.


📦 Bundle Size Report

Package Size Gzipped
app-shell (consoleActionDispatch.js) 0.20KB 0.19KB
app-shell (index.js) 16.69KB 6.21KB
app-shell (runtime-config.js) 20.68KB 7.36KB
app-shell (types.js) 0.01KB 0.04KB
app-shell (urlParams.js) 10.06KB 3.86KB
auth (ActiveOrganizationStorage.js) 25.05KB 9.16KB
auth (AuthContext.js) 0.31KB 0.24KB
auth (AuthGuard.js) 2.07KB 1.00KB
auth (AuthProvider.js) 40.18KB 10.59KB
auth (AuthShell.js) 3.49KB 1.40KB
auth (ForgotPasswordForm.js) 12.21KB 3.45KB
auth (LoginForm.js) 18.15KB 5.39KB
auth (PreviewBanner.js) 0.90KB 0.50KB
auth (RegisterForm.js) 6.65KB 2.22KB
auth (SocialSignInButtons.js) 9.61KB 3.89KB
auth (UserMenu.js) 3.41KB 1.23KB
auth (auth-gate-events.js) 1.29KB 0.66KB
auth (authStyles.js) 5.04KB 1.72KB
auth (createAuthClient.js) 40.21KB 10.80KB
auth (createAuthenticatedFetch.js) 8.46KB 3.43KB
auth (index.js) 3.19KB 1.44KB
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) 26.08KB 7.56KB
collaboration (LiveCursors.js) 3.17KB 1.27KB
collaboration (PresenceAvatars.js) 6.49KB 2.64KB
collaboration (PresenceProvider.js) 2.79KB 1.13KB
collaboration (index.js) 1.68KB 0.73KB
collaboration (useCollaborationTranslation.js) 6.05KB 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) 502.02KB 115.16KB
core (index.js) 8.52KB 3.41KB
create-plugin (index.js) 27.94KB 9.51KB
data-objectstack (index.js) 211.58KB 58.68KB
fields (index.js) 247.89KB 62.50KB
i18n (LocalizationContext.js) 1.76KB 0.96KB
i18n (builtinAggregateLabels.js) 0.86KB 0.49KB
i18n (currency.js) 1.22KB 0.64KB
i18n (fallbackInterpolation.js) 6.25KB 2.77KB
i18n (i18n.js) 8.87KB 3.64KB
i18n (index.js) 5.22KB 2.26KB
i18n (pickLocalized.js) 9.86KB 3.95KB
i18n (provider.js) 32.15KB 10.49KB
i18n (useDisplayLocale.js) 2.85KB 1.45KB
i18n (useObjectLabel.js) 34.34KB 9.17KB
i18n (useSafeTranslation.js) 5.60KB 2.33KB
layout (index.js) 38.83KB 10.95KB
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) 2.53KB 0.85KB
mobile (useResponsive.js) 0.72KB 0.42KB
mobile (useSpecGesture.js) 4.39KB 1.66KB
mobile (useTouchTarget.js) 1.01KB 0.54KB
permissions (MePermissionsProvider.js) 13.52KB 4.88KB
permissions (PermissionContext.js) 0.31KB 0.25KB
permissions (PermissionGuard.js) 0.89KB 0.45KB
permissions (PermissionProvider.js) 6.24KB 2.16KB
permissions (discardProofCache.js) 1.04KB 0.55KB
permissions (evaluator.js) 8.39KB 3.10KB
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) 14.81KB 3.63KB
plugin-calendar (index.js) 49.25KB 13.99KB
plugin-charts (index.js) 71.34KB 19.90KB
plugin-chatbot (index.js) 195.34KB 46.51KB
plugin-dashboard (index.js) 131.22KB 34.59KB
plugin-designer (index.js) 215.94KB 44.33KB
plugin-detail (index.js) 253.46KB 65.85KB
plugin-editor (index.js) 2.23KB 1.05KB
plugin-form (index.js) 136.77KB 34.17KB
plugin-gantt (index.js) 166.95KB 41.04KB
plugin-grid (index.js) 211.58KB 57.48KB
plugin-kanban (index.js) 46.01KB 14.30KB
plugin-list (index.js) 112.58KB 27.65KB
plugin-map (index.js) 20.64KB 6.86KB
plugin-markdown (index.js) 13.88KB 4.80KB
plugin-report (index.js) 43.41KB 11.93KB
plugin-timeline (index.js) 30.07KB 8.74KB
plugin-tree (index.js) 9.55KB 3.32KB
plugin-view (index.js) 84.42KB 20.79KB
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.66KB 3.50KB
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) 94.03KB 31.02KB
react (data-invalidation.js) 5.05KB 2.08KB
react (index.js) 4.63KB 2.18KB
react (schema-input.js) 4.25KB 2.04KB
react (spec-input.js) 0.20KB 0.18KB
sdui-parser (codegen.js) 6.58KB 2.74KB
sdui-parser (dashboard-widget-options.js) 3.08KB 1.30KB
sdui-parser (index.js) 5.66KB 2.50KB
sdui-parser (input-type.js) 2.84KB 1.40KB
sdui-parser (kanban-quick-add.js) 3.89KB 1.87KB
sdui-parser (parse.js) 25.28KB 7.80KB
sdui-parser (provenance.js) 3.66KB 1.82KB
sdui-parser (types.js) 0.28KB 0.23KB
sdui-parser (validate.js) 14.82KB 4.99KB
types (ai.js) 0.20KB 0.17KB
types (api-types.js) 0.20KB 0.18KB
types (app.js) 2.87KB 1.00KB
types (base.js) 0.20KB 0.18KB
types (blocks.js) 0.20KB 0.18KB
types (complex.js) 2.93KB 1.49KB
types (crud.js) 0.20KB 0.18KB
types (dashboard-filter-alias.js) 6.23KB 2.74KB
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) 4.74KB 2.25KB
types (layout.js) 0.20KB 0.18KB
types (managed-by.js) 0.19KB 0.18KB
types (mobile.js) 4.73KB 2.28KB
types (navigation.js) 0.20KB 0.18KB
types (objectql.js) 0.20KB 0.18KB
types (overlay.js) 0.20KB 0.18KB
types (permissions.js) 0.20KB 0.18KB
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) 5.05KB 1.93KB
types (spec-ui-namespace.js) 0.20KB 0.19KB
types (strict-authoring-face.js) 14.27KB 5.47KB
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

os-sam commented Sep 13, 2026

Copy link
Copy Markdown
Collaborator Author

Both reds at 348a4bdf are base-side debts — established, ⛔ neither this PR's

One comment covering both, since both are already diagnosed elsewhere and ⛔ neither is fixable from here.

This PR's file face — five files, verified from the diff

.changeset/8650-chart-foreign-dialect-retired.md
packages/plugin-charts/src/ChartRenderer.foreignDialectRetired-8650.test.tsx
packages/plugin-charts/src/ChartRenderer.specSeries.test.tsx
packages/plugin-charts/src/ChartRenderer.tsx
packages/plugin-charts/src/ObjectChart.tsx

.changeset/ + packages/plugin-charts/**, nothing else.

1 · Doc Snippet Type Check

Three TS2740 diagnostics on DataSource<any>, in content/docs/guide/schema-rendering.md (×2) and packages/react/README.md. ⛔ None of those files is in the list above, and the diagnostic subject — DataSource's six members — is a shape this diff never mentions.

Chain: objectui#7912 / PR objectui#9310's renderer-seam narrowing meeting fences already on main ⇒ carded objectui#9346 (pm:blocked), waiting on decision objectui#9308. objectui#9346 establishes that all three routes to green are refused by something already landed, so ⛔ there is no fix in existence to port. Full reading, read from the CI job log with the gate's own four controls firing: objectui#9364 comment 5651716838.

Four PRs now fail this identically, with pairwise-disjoint diffs — objectui#9349 (types/zod/**), objectui#9353 (one docs file), objectui#9364 (types decls + plugin-grid), and this one (plugin-charts). Four disjoint diffs cannot each independently break the same three fences.

2 · Bundle Analysis

Three of the four eager-closure halves pass; the objecting half is ceiling sensitivity on the ui-components per-chunk row, which the gate reports as "ALREADY declared exhausted before this run" and as "a standing debt that predates this change … measured at three gzipped bytes across five unrelated merges." ✅ Freshness passed ⇒ ⛔ not the objectui#6245 stale-ceiling shape.

This PR touches no packages/components file, which is what that chunk is built from. Its own package moved the other way: plugin-charts reads 71.34 KB / 19.90 KB gzipped here against 71.51 / 19.97 on the sibling runs — a reduction, consistent with retiring a branch.

The gate forbids the two edits that would green it and directs the reading to the chunk's own card ⇒ recorded at objectui#9204 comment 5651743555.

⛔ What was not done

⛔ Ceiling not raised. ⛔ Allowance not raised. ⛔ No re-run — both verdicts are deterministic against content and constants this PR does not touch, and the one permitted re-run is preserved for a case where it could discriminate. ⛔ No test skipped, disabled or quarantined. ⛔ No empty commit. ⛔ No new card — both debts are carded and dedupe hit.

State

Stays draft. ⛔ Not flipped ready, ⛔ not enqueued: this lane's bar is every check green, ⛔ not the required subset. The Clause-②: yes ceiling-tier contract review is the next gate and is separate from both of these; it is ⛔ not yet dispatched, because the implementing agent has not filed its report and ⛔ an absent report is never read as success.

Seat: domain:spec @ objectui, os-sam, session session_01L5xpA5q533BgTTNADibEFt, 2026-09-13T07:05Z.


Generated by Claude Code

os-sam commented Sep 13, 2026

Copy link
Copy Markdown
Collaborator Author

Contract review

Head reviewed: 348a4bdf865e6e1f40d88172a9a1a4de77063b37 — the current PR head, unmoved.
Tier: ceiling (claude-fable-5-1), context-isolated adversarial subagent, fed the card, the triage ruling and the PR only. MEASURED, strict harness-stamp form "model":"…": 141 stamps, 141 fable, 0 non-fable, control fires — across both the stalled and the resumed portion of the transcript, so every round that produced this ruling read at tier.

⚠️ This reviewer stalled once and was resumed. Its first turn ended holding mid-task state («the waiter for it is already armed … its completion notification is the one remaining input before I write the ruling») — a background waiter that cannot resume an agent whose turn has ended. It was resumed with a foreground-execution instruction and delivered the complete ruling. ⛔ Recorded because it is the second such stall in this seat's session: a completion notice whose content is mid-task state is the tell, and the remedy is to resume immediately, ⛔ never to wait.

Independence pair (machine-readable)

Implemented-by: claude/issue-8650-plugin-charts-foreign-dialect
Reviewed-by: session_01L5xpA5q533BgTTNADibEFt

⛔ Not SELF-REVIEW.

⭐ VERDICT: PASS — and the question this review existed to rule is ruled

Retiring index / category / value is the retirement of an UNDECLARED TOLERANCE, ⛔ not the removal of a published capability. ⇒ the card does not go to the maintainer's decision box on this ground.

The reviewer did not take that from the author or from this seat — it re-derived it, and the decisive reading is one neither had: the published prop type actively refused these keys at compile time. ChartRendererProps.schema is a hand-rolled literal with no index signature and 23 members; a compile probe writing index / category / value against it fails TS2353 on each, while the canonical xAxisKey + series control compiles clean. ⇒ a typed external consumer could never have written them without an as any of their own. Nothing in the published types, zod mirror, registry inputs, README, CHANGELOG, docs or skills ever taught them; the only "promise" was a source comment sitting behind casts.

⇒ the author's unanswerable question is answered on governing text rather than on the unmeasurable population: it does not need measuring. Every face such an author could have read refused or omitted the spelling, and the governing rule requires named external evidence to slow a retirement, ⛔ not to permit one.

And it corrects this seat. I rested part of my answer on «the failure mode is a named on-screen refusal, ⛔ not a silently wrong chart». Measured, that is conditional: rows lacking a name column do hit the named missing-category-key refusal, but rows that carry one make index: 'month' plot silently against name, because AdvancedChartImpl defaults xAxisKey = 'name'. The classification does not depend on it — but my stated ground was wrong, and the changeset repeats it (see below).

Carriers — cleared, ⛔ not stripped

Per 「清标即落地:PASS ⇒ 同席同笔剥双载体」, needs:contract-review is cleared from both this PR and card objectui#8650 in the same stroke as this record. Two removals seconds apart is the machine-readable signature of a clearance; a single removal would be a strip. Record id and judged head are in this comment, per the provenance rule.

⛔ Landing — pre-landing check ③ fails, so this PR does NOT enqueue

# condition reading
same-form in-seat clause-② review PASS on record, at tier ✅ this record
dual carrier cleared, machine-read --pair 9367 ✅ re-read after the write
every check green, ⛔ not the required subset Doc Snippet Type Check + Bundle Analysis, both base-side

⛔ Not flipped ready. ⛔ Not enqueued. ⛔ No auto-merge. Blocked only by objectui#9308 (via objectui#9346) and objectui#9204 / objectui#9316 — ⛔ neither this PR's.

⚠️ Three 欠改 the ruling records — and this seat is dispatching them

The reviewer judged all three non-contract and PASSed on them. ⭐ But the PR is parked behind base-side reds for an unknown period, so closing them costs no throughput and two of them are real:

  1. changeset Migration sentence — overstates the failure mode; needs the name-column qualifier. ⚠️ A changeset publishes verbatim into the CHANGELOG, so this one ships if unfixed.
  2. neverPlots is a race in the false-green direction — measured warm time-to-surface 97–168 ms (cold 578 ms) against a fixed 150 ms wait. It discriminated in both runs, but on a loaded runner a re-added alias could pass vacuously. Read the positive signal instead.
  3. normalizeChartSchema.ts:381-382 — its comment still says ChartRenderer adapts the Tremor-ish categories form. Now false; the ruling marks it the one wrong row in ①.

⛔ This is ⛔ not a re-litigation of the PASS — the contract gate is passed and recorded. The patch round closes recorded 欠改 only, and its head move will re-hang both carriers for a narrow re-review, as the rules require.


Ruling — verbatim, ⛔ unedited

⛔ The isolated ceiling-tier subagent's ruling as returned. This seat's only legal actions are verbatim adoption or wholesale voiding.


Contract review

Reviewed head: 348a4bdf865e6e1f40d88172a9a1a4de77063b37 (parent 2e471dc0, the author's pinned base). Measured in a private worktree at that head (/home/user/objectui-review-9367, pnpm install --offline, @object-ui/plugin-charts^... closure built, exit 0). origin/main = 69aa9c01 is two commits past the base and touches nothing under packages/plugin-charts or packages/types; ancestry proved on the shallow clone with a control leg (merge-base --is-ancestor 2e471dc0 origin/main → 0, PR head → 1). Nothing below is taken from the PR body, the os-dev report, or the dispatching seat's comments; each was re-derived.

⭐ The ruling this review exists for: undeclared-tolerance retirement, ⛔ not a published-capability removal

Classification: retirement of an undeclared tolerance — inside the enforce-or-remove reach the triage ruling (5619609278) invoked. It is not «删已发布能力». The card does not go to the decision box on this ground. The evidence that decides it, in order of weight:

  1. Nothing a consumer could read ever promised the three keys — and the published type face actively refused them. ChartRendererProps.schema (the exported prop type, published in dist/*.d.ts) is a hand-rolled literal with no index signature and 23 members; index, category, value are not among them (TypeScript checker, getPropertyOfTypeundefined; getIndexInfosOfType → NONE). A compile probe against the published prop type — a fresh literal with index: 'month' / value: 'revenue' / category: 'month' — fails TS2353 on each, while the canonical xAxisKey + series control compiles clean (0 errors elsewhere). So a typed React consumer could never have used these keys without an as any of their own. The published SDUI node ChartSchema (@object-ui/types) and its zod mirror declare categories, series, xAxisKey — not the three. The registry inputs for chart (namespace plugin-charts) advertise chartType/data/config/xAxisKey/series/className. The published README teaches dataKey/xAxisKey; the published CHANGELOG has no entry for a Tremor/index adapter; content/docs/** (incl. releases/), skills/**, .claude/** teach none of the three as chart-node keys (a grep for ^\s*(index|category|value)\s*: across those roots returns only non-chart contexts — registry category: 'Form', filter value: 'completed', editor value:), while the control xAxisKey is documented. GitHub issue/PR search for the Tremor adapter: 0, with a control query returning decision(plugin-charts): four reads are an explicit FOREIGN DIALECT, and AGENTS.md #0.1 says the remedy is at the producer — ⛔ not a declaration (3 of 7, objectui#8327 class (a)) #8650; code search: 3 hits, all in-source. The only "promise" that ever existed was a source comment sitting behind as any casts — not a consumer-readable face.
  2. Use alone does not make a capability here, because the accept set of the published type does not move. The keys reached the renderer only through the two blanket tolerances the repo has already ruled defective: BaseSchema's [key: string]: any (objectui#7927) and the zod BaseSchema's .passthrough() (base.zod.ts:449), with SchemaRenderer stripping none of them. Before and after this PR, index: 'x' is accepted by the published type exactly as zzqx_no_such_key: 'x' is. What changes is runtime behaviour on an undeclared key. The governing boundary sentence is SKILL.md's mechanical test — 「改动扩大接受集或公开面 ⇒ 人工;拉回已声明契约 ⇒ 代裁车道」 and 「条款②只指已发布契约面,拉回已声明契约不触它」 — and this is the pull-back arm. The decision-analysis text settles the residual: 「未声明键随实现」, 「废弃别名/拼写与能力退役默认立即退休」, and «staged 选项仅凭具名外部用户证据才可呈报» — an unnamed hypothetical population is a reason to elevate only when named, never a reason to keep a tolerance.
  3. The precedent that defines the floor confirms the line. objectui#6896 went to the maintainer because ChartDataSeries.data / categories were declared on the published type — its triage said so in as many words: «narrowing the accept set of a published type … the manual floor». The floor sentence is about the declared accept set. Here the declared accept set is untouched (the diff touches no packages/types file; the checker reads ChartRendererProps.schema at 23 members before and after).
  4. ADR-0049, read as written. Its decision is literally a spec-property gate: a declared property must be Enforced / experimental / Absent, and "parsed, unmarked, unenforced" is prohibited; its 2026-09-04 amendment records that the repo cites it as the general enforce-or-remove policy and claims no wider scope. Strictly, this PR's subject is the mirror defect — enforced-but-undeclared. The invariant the ADR protects (declared = enforced) is restored by either declaring or un-enforcing; triage removed "declare" on AGENTS.md #0.1 (a tolerant alias «fossilizes the wrong convention into a second de-facto contract»), which leaves un-enforce, and the ADR's own preference — removal over marking when nothing promised the property — points the same way. So "ADR-0049's mechanical reach" holds by the repo's cited reading; I record that the ADR's letter is about declarations so no one later reads this ruling as widening the ADR.
  5. The failure mode — measured, and it corrects the author in one respect. On head, index/category with rows lacking a name column hit the named missing-category-key refusal («This chart cannot plot its category axis: no row has a name field»), still refused at 2 s. value on a pie hits the named no-positive-magnitude refusal. But value on a bar renders an empty surface with no refusal, and rows that carry a name column make index: 'month' plot silently against name (measured: 1 bar, no error) — because AdvancedChartImpl defaults xAxisKey = 'name'. "Named refusal, not a silently wrong chart" is therefore conditional. This does not move the classification (which rests on 1–4, not on the loudness of the degradation), and the silent name default is a pre-existing property of every unbound chart rather than something this PR introduces — but the changeset's Migration sentence overstates it (see ②/③).

On the author's unanswerable question — an external @object-ui/plugin-charts author writing these keys — the answer is that the population is unmeasurable and does not need measuring: every face such an author could have read refused or omitted the spelling, the type they would have written against rejects it at compile time, and the governing text requires named external evidence to slow a retirement, not to permit one. The dispatch's zero-producer clause is met with five firing controls (below). Option A of the report stands; C would send to the decision box something that was never published.

① Derived judgments — every accept-set / public-face change in the diff

# change reading verdict
1 index read removed (ChartRenderer.tsx) undeclared on ChartRendererProps.schema, ChartSchema, zod mirror, registry inputs; producers: base tree 1 (the specSeries pin, migrated in this PR) right
2 category read removed same faces; producers: base tree 1 = packages/types/src/widget.ts:64, a RuntimeWidgetManifest docblock example whose category: 'data-visualization' is a palette category on a manifest, not a chart-node key right
3 value read removed same faces; producers 0 right
4 categories branch removed DECLARED on ChartSchema (string[], checker) and zod mirror; documented (schema-reference.md:508, "alternative series list"); ruled live by #6896 comment 5479473487 item 3; normalizeChartSchema.ts:488-492 consumes it before the old branch could run, so spec.series was populated for every well-formed list. Ablation reproduced: pre-fix renderer in → 4 failed / 3 passed (7), exactly index, category, value and the malformed-categories throw; restored → 7/7; the three "categories still plots" cases pass in both legs (blob 13e49a04f2531d0a, git diff HEAD empty). Capability untouched. One behaviour change on malformed input, named: categories: 'revenue' (a string) used to throw in render and now mounts with no series; an all-rejected list used to yield [{ dataKey: '' }] and now yields none (if (series?.length)). No contract promised a throw. right
5 six (schema as any) casts deleted colors/categoryColors/categoryOrder DECLARED on ChartRendererProps.schema (string[], Record<string,string>, string[]); colors/compareTo/series DECLARED on ObjectChartSchema = ObjectChartProps.schema (37 members, colors: string[] | Record<string,string>, compareTo: { kind; dimension? }, series: { dataKey; … }[]). Every read is the same expression minus the cast — schema.colors || […], Array.isArray(schema.colors) ? … : undefined, the object/array colors split, Array.isArray(schema.series) ? … : null, useMemo deps [schema.compareTo] / […, schema.series, …] with identical identity. type-check exit 0 is the reading that the declarations and the reads agree. No behaviour moved; nothing declared. right
6 public TS face no file under packages/types/ in the diff; ChartRendererProps unchanged (23 members before/after); no new export right
7 specSeries test indexxAxisKey migrates the one in-repo index writer (a pin) to the canonical spelling right
8 normalizeChartSchema.ts:381-382 comment still says the Tremor-ish categories form is one "ChartRenderer already adapts" now false — prose drift, non-contract wrong, 欠改

Instrument re-derived, not trusted: reads via the checker, declaredness via getPropertiesOfType/getPropertyOfType. Index-signature control holds: on ObjectChartSchema and ChartSchema (both string → any) getPropertyOfType('zzqx_no_such_key') is undefined while type is DECLARED; ChartRendererProps.schema has no index signature at all. The (a)/(b) classification is a reading. (Note for re-runners: ObjectChartProps.schema reads as 0 members until @object-ui/types' dist exists — an unresolved import, not a finding.)

Producer census re-derived structurally (object literal / JSON / fenced node whose type is one of the seven spellings; top-level keys extracted at depth 1), controls drawn from the same nodes: base tree 5,514 files / 80 chart nodes — index 1 · category 1 · value 0 · categories 4 (all tests) vs xAxisKey 31 · series 38 · chartType 35 · data 44 · zzqx_no_such_key 0; head tree 87 nodes, the only new index/category/value writers being the PR's own pin. Same shape as the author's 74/41/44/40/52; the zeros are readings.

② Semver grading vs. the changeset

Changeset: '@object-ui/plugin-charts': minor, body "Breaking, deliberately, for three keys" + a Migration paragraph. Gates run here: check-changeset-presence 0 (4 source files of 1 released package, 1 changeset), check-changeset-no-major 0, check-changeset-claims 0. plugin-charts is in the single fixed group.

Absent repo policy: by semver §1 the public API is what is declared, and the declared API of @object-ui/plugin-charts is byte-identical before and after — so the defensible strict-semver grade is minor with the behaviour change called out; only the Hyrum reading ("every observable behaviour is API") makes it a major, and under that reading the honest word is the one the changeset uses. With the policy: AGENTS.md 版本号策略 is explicit — «objectui 自身的破坏性变更也标 minor(在正文里写清 breaking 语义即可)» — so minor + the break spelled out in the body is the mandated encoding, not a compromise. The policy's existence does not change the verdict; it removes the only alternative. minor is correct and consistent with the changeset.

One owed correction to the body, because a changeset becomes the published CHANGELOG: the Migration sentence «still writes index / category binds no category axis and hits AdvancedChartImpl's existing on-screen refusal rather than drawing a wrong picture» is true only when rows lack a name column; rows carrying name plot silently on it (measured). «one that still writes value plots nothing» is accurate (bar: empty surface; pie: named refusal).

③ Boundary flags and open_questions

Not reached: the introduction history of the Tremor adapter (shallow clone, 135 commits; the published CHANGELOG carries no entry and the GitHub search is 0 with a firing control); whether pie-chart/donut-chart/radar-chart/scatter-chart are registered to ChartRenderer (only the first 130 lines of index.tsx read — the census included all seven spellings regardless); the author's lint:coverage, entry-guard, upstream-port-parity, bash32-floor, cross-repo-closer-outcome, control-bytes exits (not re-run; none contract-bearing); the external-author population (unmeasurable from here — ruled on governing text, not on a measurement).

Implemented-by: claude/issue-8650-plugin-charts-foreign-dialect
Reviewed-by: session_01L5xpA5q533BgTTNADibEFt

Verdict: PASS

裁定:index / category / value 的退役是未声明容忍的退役,在分诊引用的 enforce-or-remove 机械范围内,⛔ 不是「删已发布能力」——已发布的类型面从未声明过它们、对有类型的调用方在编译期就拒绝它们(TS2353)、无任何文档/README/CHANGELOG/registry 教过它们,已声明接受集在本 PR 前后逐字不变;本卡不因此进决策箱,本 PR 可落地。categories 能力经消融证明未动;六处 cast 删除无行为迁移、无新增声明;minor 与本仓版本策略一致。三项 欠改 随交接记录、不改变契约判词:(a) changeset Migration 句补上「行内含 name 列时静默绑到 name」的限定,(b) neverPlots 改为正向读数,(c) normalizeChartSchema.ts:381-382 陈旧注释。


Generated by Claude Code

…nces

Closes the three 欠改 the ceiling-tier contract review recorded. No accept-set
change, no declaration, no new key, nothing under packages/types/: the
retirement, the `categories` collapse and the six cast deletions are unchanged.

1. changeset Migration sentence. It said a chart still writing `index` /
   `category` "hits AdvancedChartImpl's existing on-screen refusal rather than
   drawing a wrong picture". Measured, that holds only for rows lacking a
   `name` column: `AdvancedChartImpl` defaults `xAxisKey = 'name'`
   (AdvancedChartImpl.tsx:865), so rows that CARRY one plot silently against
   `name`. A changeset publishes verbatim into the CHANGELOG, so the
   overstatement would have shipped. Qualifier added; the `value` sentence,
   which measured accurate, is byte-identical.

2. `neverPlots` was a race in the false-green direction -- a fixed 150 ms wait
   then "no surface yet", against a measured warm time-to-surface of 97-168 ms
   for the canonical control. It discriminated in two runs, but on a loaded
   runner a re-added alias would plot LATE and the pin would pass vacuously.
   Replaced with positive readings that fail the other way: `waitFor` on
   `[data-chart-error="missing-category-key"]` for `index` / `category`, and
   for `value` the existing `plotted` helper -- wait for the surface to ARRIVE,
   then count marks. A slow runner now makes these slower, never green. The
   file docblock carried the same overstatement as the changeset and is
   corrected with it.

3. normalizeChartSchema.ts:381 said the Tremor-ish `categories` form is one
   "ChartRenderer already adapts". That branch is gone as of this PR, so the
   sentence was false about the very removal it sits next to. It now names the
   reader that does adapt it -- this file, the one translation point.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L5xpA5q533BgTTNADibEFt
@github-actions

Copy link
Copy Markdown
Contributor

⚠️ Console Performance Budget — gauge not trustworthy

The eager closure was measured, but one of the ceilings it is measured against no longer means what it names, so this run carries no pass/fail verdict for the performance budget.

This is not a budget violation. Nothing grew: the half marked below is a verdict about the gauge, and a ceiling that has stopped measuring anything can neither clear a bundle nor condemn one.

Step Outcome
Build packages success
Check console performance budget failure

Which half objected:

Eager-closure half Verdict
Aggregate closure ceiling ✅ pass
Per-chunk ceilings ✅ pass
Ceiling sensitivity (headroom) ⚠️ broken gauge
Ceiling freshness (checkout vs. base branch) ✅ pass

⚠️ A broken gauge half is a verdict about the ceiling, not about the bundle: that line has drifted out of range of the regression it exists to catch, or the report behind it cannot be trusted. It does not say anything grew. The Check console performance budget step log carries the ceiling and the number it was compared against.

Reason: The entry chunk measured 144.3 KB, but the eager-closure half of this gate returned no trustworthy VERDICT: the report could not be read, a ceiling has drifted out of range of the regression it must catch, or (objectui#6245) a ceiling was replaced on the base branch after this checkout was made. The step log says which. This is not a passing budget — and it is not a size regression either.

See the workflow run for details.


📦 Bundle Size Report

Package Size Gzipped
app-shell (consoleActionDispatch.js) 0.20KB 0.19KB
app-shell (index.js) 16.69KB 6.21KB
app-shell (runtime-config.js) 20.68KB 7.36KB
app-shell (types.js) 0.01KB 0.04KB
app-shell (urlParams.js) 10.06KB 3.86KB
auth (ActiveOrganizationStorage.js) 25.05KB 9.16KB
auth (AuthContext.js) 0.31KB 0.24KB
auth (AuthGuard.js) 2.07KB 1.00KB
auth (AuthProvider.js) 40.18KB 10.59KB
auth (AuthShell.js) 3.49KB 1.40KB
auth (ForgotPasswordForm.js) 12.21KB 3.45KB
auth (LoginForm.js) 18.15KB 5.39KB
auth (PreviewBanner.js) 0.90KB 0.50KB
auth (RegisterForm.js) 6.65KB 2.22KB
auth (SocialSignInButtons.js) 9.61KB 3.89KB
auth (UserMenu.js) 3.41KB 1.23KB
auth (auth-gate-events.js) 1.29KB 0.66KB
auth (authStyles.js) 5.04KB 1.72KB
auth (createAuthClient.js) 40.21KB 10.80KB
auth (createAuthenticatedFetch.js) 8.46KB 3.43KB
auth (index.js) 3.19KB 1.44KB
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) 26.08KB 7.56KB
collaboration (LiveCursors.js) 3.17KB 1.27KB
collaboration (PresenceAvatars.js) 6.49KB 2.64KB
collaboration (PresenceProvider.js) 2.79KB 1.13KB
collaboration (index.js) 1.68KB 0.73KB
collaboration (useCollaborationTranslation.js) 6.05KB 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) 502.02KB 115.16KB
core (index.js) 8.52KB 3.41KB
create-plugin (index.js) 27.94KB 9.51KB
data-objectstack (index.js) 211.58KB 58.68KB
fields (index.js) 247.89KB 62.50KB
i18n (LocalizationContext.js) 1.76KB 0.96KB
i18n (builtinAggregateLabels.js) 0.86KB 0.49KB
i18n (currency.js) 1.22KB 0.64KB
i18n (fallbackInterpolation.js) 6.25KB 2.77KB
i18n (i18n.js) 8.87KB 3.64KB
i18n (index.js) 5.22KB 2.26KB
i18n (pickLocalized.js) 9.86KB 3.95KB
i18n (provider.js) 32.15KB 10.49KB
i18n (useDisplayLocale.js) 2.85KB 1.45KB
i18n (useObjectLabel.js) 34.34KB 9.17KB
i18n (useSafeTranslation.js) 5.60KB 2.33KB
layout (index.js) 38.83KB 10.95KB
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) 2.53KB 0.85KB
mobile (useResponsive.js) 0.72KB 0.42KB
mobile (useSpecGesture.js) 4.39KB 1.66KB
mobile (useTouchTarget.js) 1.01KB 0.54KB
permissions (MePermissionsProvider.js) 13.52KB 4.88KB
permissions (PermissionContext.js) 0.31KB 0.25KB
permissions (PermissionGuard.js) 0.89KB 0.45KB
permissions (PermissionProvider.js) 6.24KB 2.16KB
permissions (discardProofCache.js) 1.04KB 0.55KB
permissions (evaluator.js) 8.39KB 3.10KB
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) 14.81KB 3.63KB
plugin-calendar (index.js) 49.25KB 13.99KB
plugin-charts (index.js) 71.34KB 19.90KB
plugin-chatbot (index.js) 195.34KB 46.51KB
plugin-dashboard (index.js) 131.22KB 34.59KB
plugin-designer (index.js) 215.94KB 44.33KB
plugin-detail (index.js) 253.46KB 65.85KB
plugin-editor (index.js) 2.23KB 1.05KB
plugin-form (index.js) 136.77KB 34.17KB
plugin-gantt (index.js) 166.95KB 41.04KB
plugin-grid (index.js) 211.58KB 57.48KB
plugin-kanban (index.js) 46.01KB 14.30KB
plugin-list (index.js) 112.58KB 27.65KB
plugin-map (index.js) 20.64KB 6.86KB
plugin-markdown (index.js) 13.88KB 4.80KB
plugin-report (index.js) 43.41KB 11.93KB
plugin-timeline (index.js) 30.07KB 8.74KB
plugin-tree (index.js) 9.55KB 3.32KB
plugin-view (index.js) 84.42KB 20.79KB
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.66KB 3.50KB
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) 94.03KB 31.02KB
react (data-invalidation.js) 5.05KB 2.08KB
react (index.js) 4.63KB 2.18KB
react (schema-input.js) 4.25KB 2.04KB
react (spec-input.js) 0.20KB 0.18KB
sdui-parser (codegen.js) 6.58KB 2.74KB
sdui-parser (dashboard-widget-options.js) 3.08KB 1.30KB
sdui-parser (index.js) 5.66KB 2.50KB
sdui-parser (input-type.js) 2.84KB 1.40KB
sdui-parser (kanban-quick-add.js) 3.89KB 1.87KB
sdui-parser (parse.js) 25.28KB 7.80KB
sdui-parser (provenance.js) 3.66KB 1.82KB
sdui-parser (types.js) 0.28KB 0.23KB
sdui-parser (validate.js) 14.82KB 4.99KB
types (ai.js) 0.20KB 0.17KB
types (api-types.js) 0.20KB 0.18KB
types (app.js) 2.87KB 1.00KB
types (base.js) 0.20KB 0.18KB
types (blocks.js) 0.20KB 0.18KB
types (complex.js) 2.93KB 1.49KB
types (crud.js) 0.20KB 0.18KB
types (dashboard-filter-alias.js) 6.23KB 2.74KB
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) 4.74KB 2.25KB
types (layout.js) 0.20KB 0.18KB
types (managed-by.js) 0.19KB 0.18KB
types (mobile.js) 4.73KB 2.28KB
types (navigation.js) 0.20KB 0.18KB
types (objectql.js) 0.20KB 0.18KB
types (overlay.js) 0.20KB 0.18KB
types (permissions.js) 0.20KB 0.18KB
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) 5.05KB 1.93KB
types (spec-ui-namespace.js) 0.20KB 0.19KB
types (strict-authoring-face.js) 14.27KB 5.47KB
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

os-sam commented Sep 13, 2026

Copy link
Copy Markdown
Collaborator Author

Contract review

Head reviewed: c237b09ec2218cf2a8ceede3922d72ff10255f98 (previous head 348a4bdf, which PASSed the full review at record 5651915273).
Round: narrow re-review of the 欠改 round — scoped to the three items that ruling logged, plus proving nothing else moved. ⛔ The PASSed ruling was not re-litigated.
Tier: ceiling (claude-fable-5-1), context-isolated. MEASURED, strict harness-stamp form: 67 stamps, 67 fable, 0 non-fable, control fires. ⭐ No self-seeded token in this transcript.

Independence pair (machine-readable)

Implemented-by: claude/issue-8650-plugin-charts-foreign-dialect
Reviewed-by: session_01L5xpA5q533BgTTNADibEFt

⛔ Not SELF-REVIEW.

⭐ VERDICT: PASS — all three 欠改 closed, nothing else moved

Nothing-else-moved, by blob hash rather than diff shape: 348a4bdf..c237b09e is exactly three entries. Against the merge-base, the two heads' rosters differ only by the sixth file — ChartRenderer.tsx is 13e49a04→f2531d0a in both heads, ObjectChart.tsx 32b7ef61→d0936d27 in both. ⇒ the retirement, the categories collapse and the six cast deletions are byte-identical to the PASSed head. packages/types/0 changed files, control on packages/plugin-charts/ → 5.

Item 2's ablation is the strongest thing in this round, and it is bidirectional. Re-inserting the retired reads makes the rewritten cases red — and the reviewer proved they redden for the right reason rather than by timing, by running a diagnostic asserting the positive opposite on the same mutated tree: it passed (the alias plotted, 2 bars, no refusal) and then failed on the restored tree. On the restored tree the refusal arrives at 3–10 ms against a 1 s budget — two orders of magnitude inside, so load can only slow or redden it, ⛔ never green it. That is the difference between the old pin and the new one, demonstrated rather than argued.

Item 3 was proven comment-only by two independent instruments, each with a firing controlts.transpileModule with removeComments producing byte-equal output (9,263 = 9,263), with ChartRenderer.tsx and a one-token non-comment mutation both firing as controls; plus line classification (11 changed lines, 11 matching ^[+-]\s*//, 0 not). That is the whole non-regression argument for touching a sixth file, and it is measured rather than asserted.

The two corrections the author made beyond the asked three — the test docblock and PR body line 86 — are judged right and in scope: the same ruled-false sentence in two further places, one of them in a file already open, and reported rather than done silently.

Carriers — cleared, ⛔ not stripped

Both limbs, one stroke each, per 「清标即落地:PASS ⇒ 同席同笔剥双载体」. Record id and judged head are in this comment.

⛔ Landing — ③ still fails, so this PR still does not enqueue

① PASS on record at tier ✅ · ② dual carrier cleared, machine-read ✅ · ③ every check green ❌ — Doc Snippet Type Check + Bundle Analysis, both base-side, both naming no file this PR touches. ⛔ Not ready, ⛔ not enqueued. Blocked only by objectui#9308 (via objectui#9346) and objectui#9204 / objectui#9316.

⚠️ One inaccuracy recorded, ⛔ not a 欠改

The PR body's 欠改 table says the value sentence is «byte-identical». It is not — one that still writes became One that\nstill writes, a rewrap because it now opens a sentence. The published sentence is the same sentence; only the claim of byte-identity is wrong. The reviewer explicitly rules this not a 欠改 and this seat is not opening a round for it — recorded so nobody later re-derives «byte-identical» as a measurement.


Ruling — verbatim, ⛔ unedited

⛔ The isolated ceiling-tier subagent's ruling as returned. Verbatim adoption or wholesale voiding are this seat's only legal actions.


Contract review

Reviewed head: c237b09ec2218cf2a8ceede3922d72ff10255f98 (parent 348a4bdf, the PASSed head; merge-base --is-ancestor 348a4bdf c237b09e → 0). Measured in a private linked worktree at that head (/home/user/objectui-review-9367-r2, pnpm install --offline --frozen-lockfile exit 0); the shared checkout /home/user/objectui stayed at 4f2d1f4a, 0 dirty lines, before and after. Nothing below is taken from the PR body, the author's report, or the dispatching seat's comments; each item was re-derived. The PASSed ruling (5651915273) is ⛔ not re-litigated; nothing in this round's diff disturbs it (see ① B).

① Derived judgments

B first — did anything else move? Measured by blob hash, not diff shape.

git diff-tree -r 348a4bdf c237b09e lists exactly three entries: .changeset/8650-chart-foreign-dialect-retired.md (edd420dd→687df218), ChartRenderer.foreignDialectRetired-8650.test.tsx (fa69e57e→df3fae30), normalizeChartSchema.ts (32178744→49c12262); --shortstat = 3 files, +51/−21. Against the merge-base 2e471dc0, the two heads' rosters differ only by the sixth entry (normalizeChartSchema.ts): ChartRenderer.tsx is 13e49a04→f2531d0a in both heads, ObjectChart.tsx 32b7ef61→d0936d27 in both, ChartRenderer.specSeries.test.tsx 82c0ac55→64cb2d14 in both — so the retirement, the categories collapse, the six cast deletions and the migrated pin are byte-identical to the PASSed head. git diff --name-only 2e471dc0 c237b09e -- packages/types/ → 0 lines, exit 0; same command on packages/plugin-charts/ → 5 (control fires). No file under packages/types/, no .d.ts, no export, no new key. The only non-test source blob that moved is normalizeChartSchema.ts, and it moved by comments only (item 3). ⇒ Nothing outside the three items moved.

# item reading verdict
1 changeset Migration sentence Re-derived on the unmutated head through ChartRenderer, not from the report. Guard: hasNoCategoryKey (AdvancedChartImpl.tsx:2114-2123) refuses when the chart family plots a category axis, rows are non-empty, and no row carries props.xAxisKey ?? 'name'; the default is xAxisKey = 'name' (:865, :2249). Scratch test, 6 cases, exit 0: index:'month' + rows without name[data-chart-error="missing-category-key"] present, no .recharts-surface; index:'month' + rows carrying name → surface, 1 bar, no [data-chart-error], axis ticks contain Alpha/Beta and not Jan (the chart plotted against name, silently); category:'month' + name rows → same; control xAxisKey:'month' on the same name-bearing rows → ticks Jan/Feb, not Alpha (the tick reading discriminates); value:'revenue' on bar → surface, 0 bars, no refusal; value on pie → a named refusal, no surface. The new sentence (.changeset/…:38-44) — «falls back to its default category key, name … rows carrying no name column hit its existing on-screen missing-category-key refusal, while rows that DO carry one plot silently against name … One that still writes value plots nothing» — matches every reading. Frontmatter byte-identical (diff of lines 1-3 empty). right, closed
2 neverPlots race Residue: head blob df3fae30 has neverPlots 0 occurrences, setTimeout 0, it( lines 7, the refusal selector 1; old blob fa69e57e reads 3 / 2 / 7 / 0 (control fires; occurrences via grep -o | wc -l, ⛔ not grep -c). Ablation in my worktree with an EXIT/INT/TERM trap: the three retired reads (index/categoryxAxisKey, valueseries) re-inserted at the const series … / const xAxisKey … anchor; proved on disk before any run — blob 997c7691 ≠ HEAD f2531d0a, marker occurrences 0→6 (4 lines), canonical const xAxisKey line 1→0, git diff --stat HEAD 10+/2−. Mutated leg exit 1: pin 3 failed / 4 passedindex (1142 ms) and category (1076 ms) on AssertionError: expected null not to be null at the missing-category-key query, i.e. waitFor exhausted its 1 s budget with no refusal ever rendered; value (64 ms) on { bars: 1 } ≠ { bars: 0 }. Right reason, not timing: a diagnostic file run in the same invocation on the same mutated tree asserted the positive opposite — index/category rows without name → surface arrives with 2 bars and no [data-chart-error] (500 ms / 89 ms), value → exactly 1 bar — and all 3 passed; the refusal is absent because the alias plotted, not because the surface was late. Restore git checkout HEAD -- <path>: blob f2531d0a == HEAD, markers 0, git diff HEAD 0 bytes. Restored leg: pin 7 passed, the refusal arriving at 4 ms / 4 ms (value 43 ms); the diagnostic's 3 cases now fail (expected null to be truthy, expected +0 to be 1) — bidirectional. Three further pin runs on the restored tree: index 4/5/10 ms, category 3/3/4 ms, all exit 0 — two orders of magnitude inside the budget, so load can only slow or redden it, never green it. The 4 cases green in both legs are the canonical control and the three categories cases — the capability this PR does not retire. right, closed; pin discriminates
3 normalizeChartSchema.ts:381-389 comment Comment-only, mechanically: ts.transpileModule with removeComments: true (typescript 6.0.3) on blobs 32178744 vs 49c12262 → stripped outputs byte-equal (9263 = 9263, 0 differing lines); control-1 ChartRenderer.tsx 13e49a04 vs f2531d0a → not equal (39 lines, fires); control-2 head blob vs a one-token non-comment mutation (undefinednull) → not equal (1 line, fires). Second instrument: 11 changed lines in the hunk, 11 match ^[+-]\s*//, 0 do not. Truth of the replacement: the categories reader is «below, in this file» — :497-498 Array.isArray(schema.categories); ChartRenderer «carried a second, un-normalized read … until objectui#8650 retired that branch» — base blob 13e49a04 has (schema as any).categories.map(…), head f2531d0a mentions categories only in comments (:172-197); «objectui#2880 S1» is the same citation normalizeChartSchema.test.ts:5 and index.tsx:23 carry; «AGENTS.md #0.1 … second de-facto contract» is that rule's own wording. The pre-existing lead phrase «shorthand for { name }» (the code returns { dataKey: bare }, and normalizeSeries reads raw.dataKey ?? raw.name) is untouched by this round and out of scope. right, closed
4 test docblock rewrite (:34-51) — not in the 欠改 list, reported by the author The old paragraph asserted «does not produce a silently wrong picture», the sentence the PASSed ruling measured false; the file was already open for item 2, and leaving it would make the pin contradict the changeset it pins. Its claims hold: DATA lacks name (:83-86); the code-not-wording reading is what sibling suites pin (AdvancedChartImpl.missingCategoryKey.test.tsx, nullCategoryBucket, unprojectedSeriesDimension, ObjectChart.categoryAxisKeyRender-8269 all query data-chart-error="missing-category-key"); objectui#8168 is ObjectChart.absentCategoryAxisRefusal-8168.test.tsx. right, in scope
5 PR body line 86 — same overstatement, corrected and reported Read back via REST at head c237b09e (body 198 lines): line 86 is the corrected paragraph. A PR-body edit moves no code and no contract; correcting the ruled-false ground where it was repeated is the honest disposition, and reporting it rather than doing it silently is the right form. right, in scope
6 public TS face / accept set unchanged this round by construction of B: the only source blob that moved is comment-identical after stripping; ChartRendererProps, ChartSchema, zod mirror, registry inputs untouched right

Non-regression on the restored, scratch-free tree (git status --short 0 lines, ChartRenderer.tsx blob f2531d0a): pnpm exec vitest run packages/plugin-charts/ from the worktree root → exit 0, 60 files / 541 tests passed (the author's figure, re-derived). eslint on the two changed files → exit 0, 0 errors (8 pre-existing no-explicit-any warnings). CI on this head: Lint, Type Check (which chains tsconfig.test.json), Changeset Declaration / Bump Policy / Fixed Group / Overwrite Report / Claim Re-read, Build & E2E, Test shard 4/4 all success.

② Semver grading vs. the changeset

Unchanged from the PASSed ruling and unchanged by this round: '@object-ui/plugin-charts': minor, frontmatter byte-identical across the two changeset blobs; the body's break is spelled out, which AGENTS.md 版本号策略 mandates over major. Gates run here: check-changeset-presence 0 (5 source files of 1 released package, 1 changeset), check-changeset-no-major 0, check-changeset-fixed 0, check-changeset-overwrite 0 (0 pre-existing changesets modified), check-changeset-claims 0 (report-only; its findings name ObjectChart.tsx, untouched this round). minor is correct and consistent with the changeset. The Migration paragraph that publishes into the CHANGELOG is now true (① item 1).

③ Boundary flags and open_questions

  • One inaccurate claim in the PR body, not in the shipped text: the 欠改 table says the value sentence is «byte-identical». It is not — one that still writes became One that\nstill writes (old blob line 40 vs new 43-44) because it now opens a sentence. The published sentence is the same sentence; noted so nobody re-derives «byte-identical» as a measurement. Not a 欠改.
  • Guard semantics, for precision: hasNoCategoryKey refuses only when no row carries name; a mixed dataset (some rows carrying name) plots. The changeset's «rows carrying no name column» / «rows that DO carry one» describes the two homogeneous cases and is not false for the mixed one (it also «plots silently»). No wording change owed.
  • The silent-name half is pinned nowhere in this PR (the docblock says so: «The cases below pin the refusing half»). It is a pre-existing property of every unbound chart, ⛔ not introduced here, and pinning a wrong picture as expected is not owed by this card.
  • The docblock's «97–168 ms (cold 578 ms)» is a historical measurement stated as one (past tense), offered as the rationale for the form change, not as a live count. In my runs the in-file cold control took 483–496 ms and warm surfaces 40–89 ms — the same shape; the deleted 150 ms window would have been raced by the cold case. No action.
  • Forbidden outcomes — none: no accept-set widening, no declaration, no new key, nothing under packages/types/, no fold into spec(types)!: remove BaseSchema's index signature from the authoring face, declare the riders, pin the compile-fail — executes the #7927 removal ruling (governed: AGENTS.md #0.1) #8347, no rows in undeclared-but-consumed-keys-6150.test.ts (not in the roster).
  • Base-side reds (Doc Snippet Type Check, Bundle Analysis) name no file this PR touches — not weighed. mergeable_state: behind is the base moving, not this diff.
  • Disagreement with the dispatching seat: none this round; its scoping matched what the diff contains.

Not reached: CI Test shards 1–3 still read in_progress at my last read (shard 4 success); the local package run stands in for plugin-charts and their absence does not change the verdict. pnpm --filter @object-ui/plugin-charts type-check not re-run locally (CI Type Check is success on this head; the only non-test source change is comment-only by two firing instruments). The pie-branch value refusal was observed as a named refusal with no surface but its code string was not asserted (console output is silenced under the repo's test setup); the changeset's «plots nothing» holds either way.

Implemented-by: claude/issue-8650-plugin-charts-foreign-dialect
Reviewed-by: session_01L5xpA5q533BgTTNADibEFt

Verdict: PASS

裁定:本轮 348a4bdf..c237b09e 按 blob hash 核实只动了三个文件,承载退役、categories 收拢与六处 cast 删除的两个源码 blob 与已 PASS 头逐字相同,packages/types/ 零命中(对照 5 命中);三项 欠改 全部正确关闭 —— (1) changeset Migration 句经六例复测为真(含刻度读数对照);(2) neverPlots 已删,消融双向证明新 pin 因「拒绝从未出现、图被画出」而红,恢复后拒绝 3–10 ms 内到达;(3) normalizeChartSchema.ts 改动经 removeComments 转译与逐行分类两套仪器、两个会响的对照证明为纯注释,替换文字属实。附带修正的 docblock 与 PR 正文第 86 行同属被裁定为假的同一句,合规且在范围内。minor 不变、与本仓版本策略一致。契约判词不变,PASS。


Generated by Claude Code

os-sam commented Sep 13, 2026

Copy link
Copy Markdown
Collaborator Author

⛔ Correction: a fix for the Doc Snippet Type Check half now EXISTS — objectui#9369. Still not portable.

My standing-down comment 5651795033 said the chain had «⛔ no fix in existence to port». True when written, now false.

objectui#9369 carries Fixes #9308 and Fixes #9346, on the maintainer's 2026-09-13 ruling (verbatim 「同意」, option B), and is not draft. It moves the exact three DataSource fences that fail on this head.

⛔ Why it is still not ported here

  1. The doc fix depends on the code change — the fences move to PredicateScopeProvider, which exists only after objectui#9369's b1/b2 land.
  2. Porting the whole PR is not "the same change" — 35 files, +889/−282, with a declared breaking flip of data.* visibility predicates.
  3. This PR's fence is packages/plugin-charts only.

⇒ disposition unchanged: wait for objectui#9369. ⛔ Still draft, ⛔ still not enqueued.

⚠️ Second blocker independent and untouched: Bundle Analysis's exhausted ui-components row (objectui#9204 / objectui#9316). Both must clear.

Contract state complete: ceiling-tier PASS at c237b09e (record 5652094800), both carriers cleared, --pair 9367 exit 0.


Generated by Claude Code

os-sam commented Sep 13, 2026

Copy link
Copy Markdown
Collaborator Author

CI status — both reds are INHERITED, and one of them is provably stale. ⛔ Not pushing yet.

domain:spec @ objectui seat (session_01L5xpA5q533BgTTNADibEFt), 2026-09-13T09:5xZ.

Doc Snippet Type Check fails on three fences — content/docs/guide/schema-rendering.md:99 and :434, and packages/react/README.md:73 — which are exactly the three PR #9369 named and repaired. #9369 merged 2026-09-13T09:02:22Z (main 85243729) and main is now green on this check (its own run, job 103701523599 at 09:06Z, leaves only Bundle Analysis red). This PR's diff is confined to packages/plugin-charts/** plus a changeset and touches none of those files; its failing run was created 2026-09-13T07:41:04Z, 1h21m before #9369 landed.

Bundle Analysis is main's own standing debt — objectui#9204, dispatched and in flight.

⚠️ This also retires the earlier note on this PR about a +1 doc/skill fence: that reading was corrected once already, and the live failing set is the three inherited fences above and nothing else.

⛔ The re-run was spent on a sibling PR as a probe, and it does not help

rerun_failed_jobs on PR #9349's run 34743258393 produced attempt 2 at 09:42:41Z and failed with the identical three fences ⇒ a pull_request re-run reuses the merge commit recorded at first trigger rather than recomputing it against the current base. The fix reaches a PR only through a new merge ref, i.e. a push. ⇒ re-running here would be a known no-op and is deliberately not done.

The sequencing

check-clause2-carriers.mjs --pair 9367 reads exit 0 with a review of record naming this head. Merging main in now would move the head — stalling that review and owing a re-hang of both carriers plus a fresh review — while leaving Bundle Analysis red anyway.

one base merge after objectui#9204 lands and main is green on both rows. This PR stays watched until then. ⛔ Nothing here is a verdict on its diff.


Generated by Claude Code

@os-sam
os-sam marked this pull request as ready for review September 13, 2026 10:41
@os-sam
os-sam added this pull request to the merge queue Sep 13, 2026
Merged via the queue into main with commit bb383e8 Sep 13, 2026
36 of 38 checks passed
@os-sam
os-sam deleted the claude/issue-8650-plugin-charts-foreign-dialect branch September 13, 2026 11:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

2 participants