Skip to content

feat(types)!: declare the spec's axis config on ObjectChartSchema.xAxis / yAxis (objectui#10518) - #10601

Merged
objectstack-fleet[bot] merged 6 commits into
mainfrom
claude/issue-10518-object-chart-axis-config
Sep 25, 2026
Merged

objectstack-fleet[bot] merged 6 commits into
mainfrom
claude/issue-10518-object-chart-axis-config

Conversation

@objectstack-fleet

@objectstack-fleet objectstack-fleet Bot commented Sep 25, 2026 •

Copy link
Copy Markdown
Contributor

Fixes #10518
Clause-②: yes

ObjectChartSchema.xAxis and ObjectChartSchema.yAxis now declare @objectstack/spec's axis config by reference, on both faces. xAxis is ONE ChartAxisSchema object and yAxis is a list of them. This follows ruling 5809510046, branch 2 (declare), which triage 5829725284 reused for this card, and mirrors PR objectui#10511 on ChartSchema. For xAxis it follows the seat decision on the first round's needs_decision (comment 5831464172, option A): the object only, with no string arm and no fold. No renderer changed.

Implemented by the os-dev that seat domain:ui#2 dispatched (claim 5830527047, amended by that decision), session https://claude.ai/code/session_014mXUNuFomfj24w7s1pZzhN. There were five rounds: yAxis, the xAxis patch, then three changeset-prose rounds.

1. Protocol first: the spec declares both keys on this node

Read from the installed @objectstack/spec 17.4.0, which pnpm-lock.yaml pins:

  • In the REACT_BLOCKS entry for the ObjectChart react block, schemaType is 'object-chart', schema is ChartConfigSchema itself (checked by identity), and dataProps includes xAxis and yAxis.
  • ChartConfigSchema.xAxis is ONE ChartAxisSchema with no string arm; a bare string and a list are both refused at xAxis. ChartConfigSchema.yAxis is an ARRAY of them. ChartAxisSchema is a strict object with nine keys, field required, and a .default() on showGridLines and on logarithmic.
  • The metadata tier has no ComponentPropsMap['object-chart'] entry. The spec skips that entry on purpose and says so in component.zod.ts.

So a mirror that declares the spec's shapes is the protocol's own contract. It is not new vocabulary.

2. H1: reach path, measured with the real registry (one-time probe, not committed)

The probe rendered SchemaRenderer, the real registry, ObjectChartBlock, ElementDataSourceGate, ObjectChart, ChartRenderer and normalizeChartSchema. Only AdvancedChartImpl was a double, and it recorded its props. Base was a50600166.

probe node what AdvancedChartImpl received
P1 the showcase producer's node, verbatim (properties bag, dataset-bound) yAxes: [{ field: 'task_count', stepSize: 1 }]
P1 control the same node without yAxis no yAxes
P2 all nine spec keys on one yAxis entry all nine keys on yAxes[0]
P3 all nine spec keys on xAxis all nine keys on xAxis
P4 the showcase renewals-pipeline react shape (objectName + aggregate + xAxis: { field } + yAxis: [{ field, format }]) yAxes: [{ field: 'total', format: '$0,0' }], xAxisKey: 'status'

Render leg, with no leaf double: the showcase node drew its y ticks as 0 1 2 3 4 5 with its yAxis, and as 0 2 4 6 8 without it. The node forwards the axis config, and the renderer acts on it.

3. Per-key liveness read on object-chart carriers, with lit controls

The scanner finds every xAxis / yAxis whose value is an object or a list. It reads the axis-level keys and attributes each hit to its carrier: an enclosing node's type, or the enclosing JSX tag. The file population comes from git ls-tree of the same ref the reads use. Bare-string values were scanned separately.

repo at ref files axis-object hits control xAxisKey: files naming an object-chart carrier hits on an object-chart carrier
objectstack a08e059 9435 58 5 56 14: showcase command-center metadata page yAxis [{ field, stepSize }]; showcase renewals-pipeline react page xAxis { field } and yAxis [{ field, format }]; the rest are docs (react-pages.mdx, validating-metadata.mdx), the objectstack-ui skill and its eval, and lint tests
objectui a50600166 8561 89 141 58 0 authored. The one attributed hit is prose in this node's own docblock. Tests use xAxis { field } in the objectui#8168 render pin. examples/, content/, apps/ and packages/types/examples have 0, and their chartType controls light (2 / 11 / 3 / 1)
hotcrm 4db37cd 849 18 0 0 0 (all 18 hits sit in a dashboard widget chartConfig, a different carrier)
cloud not reachable git ls-remote asks for credentials

Designer inputs for the object-chart registration: objectName, data, filter, aggregate, drillDown. There is no axis input; the aggregate input is the control.

key real producer on an object-chart node
field showcase command-center (metadata, yAxis) and renewals-pipeline (react, xAxis and yAxis)
stepSize showcase command-center (yAxis)
format showcase renewals-pipeline (yAxis)
title, min, max, showGridLines, position, logarithmic no authored document in the three reachable repos

The six unwritten keys are declared as well. The spec declares all nine on this node's react block (section 1). The node's renderer reads all nine (probes P2 and P3). The dispatch fixes the binding as the spec schema by reference, with no hand-written subset. objectui#10511 closed the retire branch on the same grounds.

The non-spec shapes this PR now refuses on an object-chart carrier are a bare-string or list xAxis and a single-object or bare-string yAxis. None appears in any of the three repos. The nearby bare-string hits are all report charts (ReportChartSchema). The one bare-string xAxis written against this type is the objectui#8168 renderer-tolerance fixture (section 4).

4. The change

  • packages/types/src/zod/objectql.zod.ts, xAxis: z.union([stripImportedDefaults(SpecChartAxisSchema), z.never()], { error }). The z.never() arm admits nothing and adds nothing to the inferred type. It exists because zod runs a one-option union as its option, so a single-arm union's error hook never fires. Every refusal is one invalid_union at xAxis, the shape ChartSchema.xAxis already reports. A malformed object gets the axis arm's own issues, with their paths and in the spec's words, including its alias hint. A bare column name, a list or any other non-object gets the remedy xAxis: { field: 'status' }. ⛔ There is no string arm and no fold onto xAxisKey: objectui#7113's alias stays scoped to ChartSchema.
  • The same file, yAxis: z.array(stripImportedDefaults(SpecChartAxisSchema)). A non-list gets a remedy message, and an issue inside an entry keeps its own path and the spec's wording.
  • packages/types/src/objectql.ts: the TS twin, xAxis?: SpecChartAxis and yAxis?: SpecChartAxis[], typed with the spec's ChartAxis. The xAxisKey member doc now points at xAxis. The interface docblock records that neither census pin sees these two keys (see H4).
  • packages/plugin-charts/src/ObjectChart.absentCategoryAxisRefusal-8168.test.tsx: ONE line, the surface extension the seat granted. The leg "a bare string xAxis, the report surface spelling" pins the renderer's tolerance, and normalizeChartSchema is unchanged. Its value now reads 'stage' as unknown as ObjectChartSchema['xAxis'], the cast idiom that file's UNAUTHORABLE helper already applies to aggregate. The leg still pins the renderer, and the type no longer admits the shape. Reverse check: with the cast removed, tsc -p tsconfig.test.json in plugin-charts fails with TS2322 on that line.
  • Boundary ledgers: the entries already cover this crossing (ChartAxisSchema is in IMPORTED since objectui#7690, and objectql.zod.ts#ObjectChartSchema is in SPEC_DERIVED_PAIRS). Their ground comments now name objectui#10518 and both keys, and the pair's comment reads six spec crossings over five spec symbols. Membership is unchanged.
  • Changeset .changeset/10518-object-chart-y-axis-declared.md: @object-ui/types minor, naming every document shape that now refuses on either key, and stating only what holds for every chart type; see section 6. The file name is kept from round one, and the frontmatter is byte-identical (md5 ecedb10c5189b2c8841ea736b67c3cc6 before and after the body edits).

5. Pin, red on the base and green on the head

packages/types/src/__tests__/object-chart-axis-config-10518.test.ts has 39 tests:

  • yAxis, blocks (a) to (e): the spec side read off the installed spec; the key in the mirror's own shape; every spec key accepted and kept; omitted defaults staying omitted (CONTROL: the raw spec schema injects them); the LIT CONTROL, the showcase command-center node flattened the way SchemaRenderer hoists properties; four entry refusals by code + path, each message equal to the spec's own; the refusal at safeValidateSchema, the door objectui validate / objectui check run; a single object or bare name refused with invalid_type; and the TS twin through @ts-expect-error rows plus an Equal type pin.
  • xAxis, blocks (f) to (j): the spec's one-object arm read off the spec, where a string and a list are refused at xAxis; the key in the mirror's own shape; every spec key accepted and kept; omitted defaults staying omitted; the object NOT folded, so no xAxisKey is minted; the LIT CONTROL, the showcase renewals-pipeline axes (xAxis: { field }, yAxis: [{ field, format }], with its objectName + aggregate), which parse on the mirror and through safeValidateSchema; four in-object refusals (min: 'zero', position: 'middle', grid, a missing field), each invalid_union at xAxis carrying the spec's own message; the door; a bare name, a list and a number, each refused naming the { field } remedy (a malformed object is NOT told the remedy); and the TS twin through four @ts-expect-error rows plus an Equal type pin.

Every mutation committed the fix first, restored from HEAD by absolute path under a trap, and proved the restore by blob hash and an empty git diff HEAD. The tests import the mirror from source, so no dist/ is on the path.

  • Round 1, mutation 1 (yAxis only, at 74cf402ed): both source faces reset to the base blobs efe2595f / 2176166f. Observed 8 failed | 11 passed (19), plus TS2344 x1 and TS2578 x4, as predicted.
  • Round 1, mutation 2: only the TS yAxis member deleted. vitest stayed at 19 passed. tsc gave the 5 errors above plus the parity ratchet's TS2322 naming objectql.zod.ts#ObjectChartSchema and yAxis.
  • Round 2, mutation 3 (both keys, at 0b1b1c816): both faces reset to the base blobs; on disk, all four declaration counts went from 1 to 0. Predicted 19 failed / 20 passed, TS2344 x2 and TS2578 x8. Observed 19 failed | 20 passed (39). The 19 are the 8 yAxis refusals and shape pin, plus the xAxis shape pin, four in-object refusals, the door, three remedy refusals, the door for the bare string, and the CONTROL that a malformed object is refused. tsc -p tsconfig.test.json exited 2 with exactly TS2344 x2 and TS2578 x8. Restored: blobs 51ad74bf / 3dcbc78f match HEAD.
  • Round 2, mutation 4: only the TS member xAxis?: SpecChartAxis; deleted. The first attempt was a no-op: a quoting slip left the anchor unmatched, the on-disk count stayed 1, and that reading was voided and rerun. The script now aborts when the mutation does not land. On the rerun the count went from 1 to 0 (blob d80951ba). vitest stayed at 39 passed. tsc exited 2 with TS2344 x1 and TS2578 x4 in the pin, plus the parity ratchet's TS2322 naming objectql.zod.ts#ObjectChartSchema and xAxis. Restored and verified the same way.

6. Gates, at a6e5c6d77 (the merge of main into the branch) unless noted

  • pnpm exec vitest run packages/types/ examples/schema-catalog/test/ packages/plugin-charts/ packages/core/src/validation/__tests__/, plus the three cli validate/check suites and unfulfilled-chart-stubs-8760, from the repo root: 360 files / 8501 tests passed. At 0b1b1c816, before the merge, the same set gave 359 / 8500.
  • Census pins, ledgers and the fixture file, run on their own at 0b1b1c816: object-chart-undeclared-keys-8885, widget-schema-anchors-7946, zod-mirror-parity, imported-defaults-8317 and ObjectChart.absentCategoryAxisRefusal-8168 gave 5 files / 208 tests passed, including "a bare string xAxis, the report surface spelling".
  • pnpm --filter @object-ui/types type-check (tsc, examples, tests): exit 0.
  • Consumer direction, downstream: @object-ui/plugin-charts, the package whose published ObjectChartProps.schema is this type. Its dependency closure was built first (types, core, i18n, react, components, sdui-parser, data-objectstack, react-runtime). The rebuilt dist/objectql.d.ts carries both members. Then pnpm --filter @object-ui/plugin-charts type-check exited 0. The round-1 reverse check still stands: a scratch plugin-charts file typed yAxis: { field: 'n' } got TS2353. No other consumer writes xAxis or yAxis on an ObjectChart-typed value, per a grep of every file that names ObjectChartSchema, ObjectChartProps or the ObjectChart component.
  • node scripts/check-changeset-presence.mjs: 1 changeset for 6 source files in 2 released packages (the second is the plugin-charts test file). check-changeset-no-major and check-changeset-overwrite: green; check-changeset-fixed was green at 0b1b1c816. check:changeset-claims, report-only, was run at 0b1b1c816: the same 38 pending changesets as round 1, none naming the fixture file. The object-chart ones (objectui#8168, [finding] ObjectChartSchema still leaves three keys undeclared that ObjectChart.tsx reads — and ObjectChartBlock, the registry shell wrapping it, is still published as (props: any) #8885, finding(types,plugin-charts): ObjectChartSchema anchors nothing — ObjectChart is published as props: any, and four keys its own producers write are declared on neither copy #7946) were read, and none is falsified. check:pending-changeset-literals: green.
  • check:new-line-citations: VERDICT new-cross-file-line-citations: 0 new citation(s). check:control-bytes and check-type-check-coverage: green. At 0b1b1c816: check:spec-symbols, check:phantom-deps, check:test-path-roots and check:unreferenced-sources green, and check-governed-queue-guard --test over the diff NOT GOVERNED.
  • ESLint over the six touched source and test files (--no-inline-config --format json, at 0b1b1c816): 0 errors. Per rule, base against head on the five edited files is unchanged: no-explicit-any is 34 to 34 in objectql.ts, 1 to 1 in objectql.zod.ts, 2 to 2 in zod-mirror-parity.test.ts, 0 to 0 in imported-defaults-8317.test.ts, and 3 to 3 in the 8168 test. The new pin has 1 warning, from the Equal OF any can-fail control that it copies from object-chart-undeclared-keys-8885.test.ts; warnings are not gated. Each file is in ESLint's own population. eslint.config.js sets no parserOptions.project / projectService, so this diff cannot move another file's verdict.
  • Main and sibling branches: main moved in objectql.ts (objectui#8932's kanban docblock, a distant range, landed as PR objectui#10588), so main was merged in as a merge commit, with no rebase and no force-push. After the merge, git merge-tree --write-tree against the newest origin/main (adeecd666) and against PR objectui#10595's branch (882c5e13e) is clean both times. At that point, main's later commits (through adeecd666) touched none of this diff's files.
  • Rounds 3 and 4, changeset prose only. Round 3 (0e710207d) measured each listed shape through the real object-chart path, whose runtime is byte-identical to base f169a030a. That round also corrected one objectql.zod.ts comment: a list xAxis is not a normalizer tolerance. Contract-review round 2 (record 5832703331) then showed that whether a no-category or no-field shape draws depends on the chart type and on the rows' columns (a name column, the value fallback), extending round 1's finding (record 5832280197) that not every refused shape draws a chart. The changeset therefore names only what holds everywhere.
  • Round 4, at 5367bc102. The lead-in now says that several of the now-refused documents draw a chart today, and that what the rest draw depends on the chart type, on the rows and on the node's other category and series sources. The bullets keep only these equivalences:
    • a malformed min / position, or an undeclared grid / logScale, changes nothing that is drawn;
    • a bare-string xAxis draws what { field } draws;
    • a list, a non-object or an object with no field names no category;
    • a yAxis entry or a single yAxis object with no field adds no series.
      They were measured on the published normalizeChartSchema and by rendering 11 chart types against 2 row sets, one of which carries a name column. The frontmatter md5 is still ecedb10c5189b2c8841ea736b67c3cc6. Gates at 5367bc102: check-changeset-presence ✅, check-changeset-no-major ✅, check:new-line-citations VERDICT … 0 new citation(s), check:control-bytes ✅, and check-changeset-claims report-only exit 0. git merge-tree --write-tree against origin/main e0f820246 is clean.
  • Round 5, at b2936fc66, prose only. Contract-review round 3 found one clause false: the lead-in credited the minor level to what the refused documents draw. The lead-in now gives the reason the version policy reads, which is the narrowed accept set: breaking semantics, which this repo ships as minor. Nothing else changed, and the frontmatter md5 is still ecedb10c5189b2c8841ea736b67c3cc6.

7. H4 and H6

  • H4, census pins: object-chart-undeclared-keys-8885 and widget-schema-anchors-7946 count schema.KEY reads in ObjectChart.tsx. The census regex returns 16 reads for that file, and neither xAxis nor yAxis is among them: the component forwards both by spreading the node. Neither key sat in either ledger, so nothing moved. Both pins pass at the head.
  • H6, docs: content/docs/api/schema-reference.md has no ObjectChartSchema row set, and plugin-charts.mdx has no object-chart section. PR objectui#10571 is on main, but this PR needs neither page, and neither was touched.

Acceptance notes

  • xAxisField / yAxisFields / aggregation are declared on this node and not read there (a one-time probe; seat filing). A static-data object-chart with only xAxisField / yAxisFields reached AdvancedChartImpl with no xAxisKey and no series. An objectName node with xAxisField and no aggregate drew the objectui#8168 refusal (chart-missing-category-axis, role="alert"), and AdvancedChartImpl was never called. The seat filed it as objectui#10608, for its own ruling. Neither key was retired or changed here (H5).
  • The two census pins cannot see a key forwarded by spreading the node. They read schema.KEY only, and AGENTS.md's "a source grep's zero cannot answer this" rule applies. These keys needed the render probe. That is an observation; no card is proposed.
  • The mirror judges the flattened node. A metadata page's properties bag is not a BaseSchema member, so safeValidateSchema on the unhoisted envelope does not reach properties.xAxis / properties.yAxis. The pins judge the hoisted shape and say so.
  • The renewals-pipeline react node as a whole is not this mirror's vocabulary: the react wrapper parks its type as specType, and its series uses the spec's { name } arm. The lit control therefore judges that producer's axis props and binding on a node with chartType. That is outside this card.
  • Context, not a defect: spec main tombstones xAxis / yAxis on the dataset-bound dashboard WIDGET's chartConfig for the next major. Those tombstones are scoped to that carrier, and they say the base ChartConfigSchema that the ObjectChart react block publishes keeps both keys.

Liveness reads, probes and ablations are one-time proofs. Nothing in this PR re-derives them except the pins above.


Generated by Claude Code

….yAxis (objectui#10518)

`ObjectChartSchema.yAxis` is `@objectstack/spec`'s `ChartAxisSchema[]` by
reference on the Zod mirror and `ChartAxis[]` on the TS twin, with the
objectui#8317 import boundary. A single axis object or a bare column name is
refused, as on `ChartSchema.yAxis`. The two boundary ledgers record the new
crossing; the pin is object-chart-axis-config-10518.test.ts.

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

github-actions Bot commented Sep 25, 2026 •

Copy link
Copy Markdown
Contributor

changeset-claim-re-read

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

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

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

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

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

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

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

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

  • names packages/types/src/__tests__/zod-mirror-parity.test.ts → packages/types/src/__tests__/zod-mirror-parity.test.ts — edited by this change

    ⚠️ The JUSTIFICATION for that parity clause was retired (objectui#9743); the clause itself stands and did not move. As first written it credited the zod-mirror-parity ratchet with a zero-drift reading for this pair — but at that time the ratchet measured three directions and was structurally blind to the MIRRORED-but-undeclared one (objectui#9711), so a zero from it recorded that it had not looked in that direction, not that nothing was there. objectui#9725 landed the fourth direction, and it covers this pair BY NAME: packages/types/src/__tests__/zod-mirror-parity.test.ts registers objectql.zod.ts#ObjectGanttSchema in both its mirror map and its declaration map; assertionMirroredUndeclaredMatchesLedger requires every registered pair's mirrored-but-undeclared key set to equal that pair's MirroredUndeclared ledger entry — never for a pair the ledger does not name — and assertionNoVacuousMirroredUndeclaredMeasurement refuses a measurement that has degenerated to any. ⛔ Read this pair's verdict off that reconciliation, which re-derives it on every run, rather than off any figure written here; when this paragraph was authored, on 2026-09-18, it required no MirroredUndeclared entry for the pair.

.changeset/5928-classname-style-props-rename.md

  • names zod-mirror-parity.test.ts → packages/types/src/__tests__/zod-mirror-parity.test.ts — edited by this change

    Where the non-pair is recorded now. zod-mirror-parity.test.ts keys its existing EXCLUSIONS entry — the mechanism that accounts for every exported const with no TypeScript declaration to mirror, each with its stated reason — to ClassNameStylePropsSchema. Named for its own two keys, the const leaves no like-named declaration for a name-derived pairing to reach for.

.changeset/6051-gantt-flat-config-declared-keys.md

  • names packages/types/src/__tests__/zod-mirror-parity.test.ts → packages/types/src/__tests__/zod-mirror-parity.test.ts — edited by this change

    ⚠️ The JUSTIFICATION for that parity clause was retired (objectui#9743) — the same retirement objectui#5903's entry carries, for the same clause and the same reason; the clause itself stands and did not move. As first written it credited the zod-mirror-parity ratchet with a zero-drift reading for this pair, at a time when that ratchet measured three directions and was structurally blind to the MIRRORED-but-undeclared one (objectui#9711), so a zero from it recorded that it had not looked in that direction. objectui#9725 landed the fourth direction, and it covers this pair BY NAME: packages/types/src/__tests__/zod-mirror-parity.test.ts registers objectql.zod.ts#ObjectGanttSchema in both its mirror map and its declaration map; assertionMirroredUndeclaredMatchesLedger reconciles every registered pair's mirrored-but-undeclared key set against that pair's MirroredUndeclared ledger entry — never for a pair the ledger does not name — and assertionNoVacuousMirroredUndeclaredMeasurement refuses a measurement that has degenerated to any. ⛔ Read this pair's verdict off that reconciliation, which re-derives it on every run, rather than off any figure written here; when this paragraph was authored, on 2026-09-18, it required no MirroredUndeclared entry for the pair.

.changeset/6150-undeclared-but-consumed-keys.md

  • names zod-mirror-parity.test.ts → packages/types/src/__tests__/zod-mirror-parity.test.ts — edited by this change

    ⭐ AMENDED, and the amendment ships in this same release. objectui#7804's TreeViewSchema slice gave the key a zod arm after all — a NAMED REFUSAL (handlerKeyRefusal(key, 'runtime-slot', label)), never a shape — because "no mirror entry" is not neutral under BaseSchema.passthrough(): it meant an authored { "type": "tree-view", "onNodeClick": { "action": "toast" } } parsed GREEN, survived the parse, and reached a call site that expects a function. ⇒ the three clauses this bullet used to carry are no longer true of the code shipping beside it. The key is now a MEMBER of TreeViewSchema.shape and an authored value is refused BY NAME at path onNodeClick; it has LEFT zod-mirror-parity.test.ts's RuntimeOnlyDeclared for that file's KnownDrift; and it is no longer "the first pair to sit there without also sitting in UnmirroredDeclared" — draining it emptied that difference, so RuntimeOnlyDeclared is now a SUBSET of UnmirroredDeclared and the union of the two equals UnmirroredDeclared itself. ⛔ objectui#6152's ruling is untouched by any of this: what the key still does not have, and never will, is a z.function() shape — no serialized document could satisfy one.

.changeset/6175-column-state-persistence.md

  • names zod-mirror-parity.test.ts → packages/types/src/__tests__/zod-mirror-parity.test.ts — edited by this change

    Nothing is retired. Both spellings remain declared on DataTableSchema; onColumnReorder stays declared and stays unwired, exactly as the RuntimeOnlyDeclared ledger in zod-mirror-parity.test.ts records it. Which of the two survives is a declared-surface ruling that stays open and is deliberately not settled here.

.changeset/6639-objectgrid-title-mirrored.md

  • names zod-mirror-parity.test.ts → packages/types/src/__tests__/zod-mirror-parity.test.ts — edited by this change

    The gain is the typed refusal: the mirror's .passthrough() base was already admitting any title unexamined, and it now enforces the declared string. zod-mirror-parity.test.ts's UnmirroredDeclared ledger records the key as worked off — the ledger's first shrink by repair (97 + 1 mirrored + 23 reclassified is what the seeded "121" now means).

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

.changeset/7344-handler-string-any-mirrors.md

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

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

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

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

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

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

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

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

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

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

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

.changeset/7654-floating-chatbot-trigger-icon-tombstone.md

  • names zod-mirror-parity.test.ts → packages/types/src/__tests__/zod-mirror-parity.test.ts — edited by this change

    Every other tombstone in this package pairs ?: never with a retirementTombstone() refusal on the Zod twin. There is no twin here to carry one: FloatingChatbotConfig has no Zod mirror at all, and floatingConfig sits in the UnmirroredDeclared ledger (zod-mirror-parity.test.ts, complex.zod.ts#ChatbotSchema). BaseSchema is .passthrough(), so the whole floatingConfig object rides through unvalidated — before this change and after it. Minting a mirror to host a refusal would be the declared-but-UNMIRRORED axis (objectui#6152), a different defect: a key can be mirrored and inert, or unmirrored and live, and fixing one says nothing about the other. This change does not widen into it.

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

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

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

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

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

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

  • names zod-mirror-parity.test.ts → packages/types/src/__tests__/zod-mirror-parity.test.ts — edited by this change

    The pair moves from zod-mirror-parity.test.ts's RuntimeOnlyDeclared to its KnownDrift, which empties the former of the one entry the latter did not also hold — so the two unmirrored ledgers are now in a containment relation, and the cross-ledger figure that recorded their difference states the containment instead.

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

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

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

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

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

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

.changeset/8338-retire-toast-action.md

  • names zod-mirror-parity.test.ts → packages/types/src/__tests__/zod-mirror-parity.test.ts — edited by this change

    The parity ledgers drain with it, every figure re-derived by zod-mirror-parity.test.ts's own AST and mirror instruments rather than stepped by hand: KnownDrift 42 entries / 64 keys → 41 / 63 (the entry's whole content, so the entry went too — the ledger's first loss by RETIRING a key rather than by moving either face toward the other), and WiderThanDeclared 23 / 36 / 47 arms, split 6 / 30 / 0 / 11 → 22 / 35 / 45, split 6 / 29 / 0 / 10. The pair itself stays registered, so EXPECTED_MIRROR_PAIRS does not move.

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

.changeset/8572-chatbot-body-retired.md

  • names zod-mirror-parity.test.ts → packages/types/src/__tests__/zod-mirror-parity.test.ts — edited by this change

    Why this key and not another. It was the ONE place in this vocabulary where body did not mean "what goes inside this component": zod-mirror-parity.test.ts carried the pair under KnownDrift as "two different meanings of one key", and the same collision was the whole reason chatbot was the single arm of the component union whose output was not assignable to SchemaNode. Both ledger rows move with this change, and the two pins that recorded the old state are INVERTED rather than deleted (see below).

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

  • names zod-mirror-parity.test.ts → packages/types/src/__tests__/zod-mirror-parity.test.ts — edited by this change

    ⭐ The declaration alone would not have been enough, and this is the reusable part. A TypeScript declaration does not run at parse time. The hand-written zod mirror is the only face in this repository that can refuse an authored number, so narrowing the declaration without the mirror would have shipped declared !== enforced on a published surface — and zod-mirror-parity.test.ts would have stayed GREEN through it, because that instrument asserts a mirror accepts everything its declaration declares and a mirror left WIDER passes. Both faces moved together for that reason.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

.changeset/object-view-unmirrored-keys-7779.md

  • names zod-mirror-parity.test.ts → packages/types/src/__tests__/zod-mirror-parity.test.ts — edited by this change

    Who is NOT affected: every correctly typed document, and every document that never wrote these keys — absent stays valid on all nine. No renderer changed. The parity ledger (zod-mirror-parity.test.ts) records the move: UnmirroredDeclared 14 entries / 96 keys to 14 / 87, the ObjectViewSchema entry re-derived into the SPEC-DERIVED half because the mirror now references the spec in code.

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

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

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

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

Compared the checked-out tree with 98b1a7cac (merge-base with origin/main): 6 file(s) changed outside .changeset/, read against 1490 pending declaration(s) that publish a body (2074 pending in total). · run

@github-actions

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

Metric Value Budget
Eager closure (gzip, 329 chunks) 3047.3 KB 3104.5 KB
Main entry chunk (gzip) 147.9 KB 350 KB
Entry file index-m6up8lXZ.js —
Status PASS —

The eager closure is every chunk the entry reaches through static imports — what the browser fetches and parses before the app renders. The entry chunk on its own is a small fraction of it.


📦 Bundle Size Report

Package Size Gzipped
app-shell (consoleActionDispatch.js) 0.20KB 0.19KB
app-shell (index.js) 16.68KB 6.20KB
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) 27.95KB 10.04KB
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.52KB 3.45KB
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.13KB 7.95KB
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) 546.37KB 130.65KB
core (index.js) 9.22KB 3.71KB
create-plugin (index.js) 27.94KB 9.51KB
data-objectstack (index.js) 223.91KB 62.28KB
fields (index.js) 259.12KB 65.73KB
i18n (LocalizationContext.js) 1.76KB 0.96KB
i18n (builtinAggregateLabels.js) 0.86KB 0.49KB
i18n (currency.js) 2.59KB 1.22KB
i18n (fallbackInterpolation.js) 6.25KB 2.77KB
i18n (i18n.js) 8.87KB 3.64KB
i18n (index.js) 5.24KB 2.27KB
i18n (pickLocalized.js) 9.86KB 3.95KB
i18n (provider.js) 39.40KB 12.91KB
i18n (useDisplayLocale.js) 3.52KB 1.76KB
i18n (useObjectLabel.js) 34.34KB 9.17KB
i18n (useSafeTranslation.js) 5.60KB 2.33KB
layout (index.js) 39.28KB 11.09KB
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.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.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.01KB 3.93KB
plugin-calendar (index.js) 51.40KB 14.61KB
plugin-charts (index.js) 74.94KB 20.89KB
plugin-chatbot (index.js) 198.36KB 47.20KB
plugin-dashboard (index.js) 133.50KB 35.37KB
plugin-designer (index.js) 216.25KB 44.39KB
plugin-detail (index.js) 232.59KB 61.50KB
plugin-editor (index.js) 2.23KB 1.05KB
plugin-form (index.js) 147.92KB 37.83KB
plugin-gantt (index.js) 169.62KB 41.91KB
plugin-grid (index.js) 215.37KB 58.92KB
plugin-kanban (index.js) 48.26KB 15.04KB
plugin-list (index.js) 114.43KB 28.26KB
plugin-map (index.js) 22.42KB 7.38KB
plugin-markdown (index.js) 13.88KB 4.80KB
plugin-report (index.js) 43.55KB 11.99KB
plugin-timeline (index.js) 30.67KB 8.95KB
plugin-tree (index.js) 10.52KB 3.69KB
plugin-view (index.js) 87.31KB 21.78KB
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) 114.58KB 37.60KB
react (data-invalidation.js) 5.05KB 2.08KB
react (index.js) 4.03KB 1.86KB
react (schema-input.js) 4.25KB 2.04KB
react (spec-input.js) 0.20KB 0.18KB
sdui-parser (body-dialect.js) 4.78KB 2.09KB
sdui-parser (codegen.js) 6.58KB 2.74KB
sdui-parser (dashboard-widget-options.js) 3.08KB 1.30KB
sdui-parser (index.js) 5.78KB 2.56KB
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) 18.27KB 6.20KB
types (ai.js) 4.11KB 2.06KB
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) 5.00KB 2.39KB
types (navigation.js) 0.20KB 0.18KB
types (objectql.js) 0.20KB 0.18KB
types (overlay.js) 0.20KB 0.18KB
types (permissions.js) 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) 17.15KB 6.32KB
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

…ma.xAxis (objectui#10518)

`ObjectChartSchema.xAxis` is ONE `@objectstack/spec` `ChartAxisSchema`
by reference on the Zod mirror and `ChartAxis` on the TS twin, with the
objectui#8317 import boundary. There is no string arm and no fold (seat
decision, option A): a bare column name or a list is refused with the
`xAxis: { field }` remedy, and a malformed object is refused at `xAxis`
with the spec's own diagnostic. The one typed renderer-tolerance fixture
that wrote a bare string takes an explicit cast, and the renderer is
unchanged. The pin, both ledger grounds and the changeset now cover
`xAxis`.

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

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

Metric Value Budget
Eager closure (gzip, 329 chunks) 3047.4 KB 3104.5 KB
Main entry chunk (gzip) 147.9 KB 350 KB
Entry file index-DakaLCUy.js —
Status PASS —

The eager closure is every chunk the entry reaches through static imports — what the browser fetches and parses before the app renders. The entry chunk on its own is a small fraction of it.


📦 Bundle Size Report

Package Size Gzipped
app-shell (consoleActionDispatch.js) 0.20KB 0.19KB
app-shell (index.js) 16.68KB 6.20KB
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) 27.95KB 10.04KB
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.52KB 3.45KB
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.13KB 7.95KB
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) 546.37KB 130.65KB
core (index.js) 9.22KB 3.71KB
create-plugin (index.js) 27.94KB 9.51KB
data-objectstack (index.js) 223.91KB 62.28KB
fields (index.js) 259.41KB 65.82KB
i18n (LocalizationContext.js) 1.76KB 0.96KB
i18n (builtinAggregateLabels.js) 0.86KB 0.49KB
i18n (currency.js) 2.59KB 1.22KB
i18n (fallbackInterpolation.js) 6.25KB 2.77KB
i18n (i18n.js) 8.87KB 3.64KB
i18n (index.js) 5.24KB 2.27KB
i18n (pickLocalized.js) 9.86KB 3.95KB
i18n (provider.js) 39.40KB 12.91KB
i18n (useDisplayLocale.js) 3.52KB 1.76KB
i18n (useObjectLabel.js) 34.34KB 9.17KB
i18n (useSafeTranslation.js) 5.60KB 2.33KB
layout (index.js) 39.28KB 11.09KB
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.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.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.01KB 3.93KB
plugin-calendar (index.js) 51.40KB 14.61KB
plugin-charts (index.js) 74.94KB 20.89KB
plugin-chatbot (index.js) 198.36KB 47.20KB
plugin-dashboard (index.js) 133.50KB 35.37KB
plugin-designer (index.js) 216.25KB 44.39KB
plugin-detail (index.js) 232.60KB 61.49KB
plugin-editor (index.js) 2.23KB 1.05KB
plugin-form (index.js) 147.92KB 37.83KB
plugin-gantt (index.js) 169.62KB 41.91KB
plugin-grid (index.js) 215.37KB 58.92KB
plugin-kanban (index.js) 48.26KB 15.04KB
plugin-list (index.js) 114.43KB 28.26KB
plugin-map (index.js) 22.42KB 7.38KB
plugin-markdown (index.js) 13.88KB 4.80KB
plugin-report (index.js) 43.55KB 11.99KB
plugin-timeline (index.js) 30.67KB 8.95KB
plugin-tree (index.js) 10.52KB 3.69KB
plugin-view (index.js) 87.31KB 21.78KB
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) 114.58KB 37.60KB
react (data-invalidation.js) 5.05KB 2.08KB
react (index.js) 4.03KB 1.86KB
react (schema-input.js) 4.25KB 2.04KB
react (spec-input.js) 0.20KB 0.18KB
sdui-parser (body-dialect.js) 4.78KB 2.09KB
sdui-parser (codegen.js) 6.58KB 2.74KB
sdui-parser (dashboard-widget-options.js) 3.08KB 1.30KB
sdui-parser (index.js) 5.78KB 2.56KB
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) 18.27KB 6.20KB
types (ai.js) 4.11KB 2.06KB
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) 5.00KB 2.39KB
types (navigation.js) 0.20KB 0.18KB
types (objectql.js) 0.20KB 0.18KB
types (overlay.js) 0.20KB 0.18KB
types (permissions.js) 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) 17.15KB 6.32KB
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

Main moved in packages/types/src/objectql.ts (objectui#8932's kanban
docblock edit, a distant range); merged rather than rebased.

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

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

Metric Value Budget
Eager closure (gzip, 329 chunks) 3048.0 KB 3104.5 KB
Main entry chunk (gzip) 147.9 KB 350 KB
Entry file index-C41MGPY1.js —
Status PASS —

The eager closure is every chunk the entry reaches through static imports — what the browser fetches and parses before the app renders. The entry chunk on its own is a small fraction of it.


📦 Bundle Size Report

Package Size Gzipped
app-shell (consoleActionDispatch.js) 0.20KB 0.19KB
app-shell (index.js) 16.68KB 6.20KB
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) 27.95KB 10.04KB
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.52KB 3.45KB
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.13KB 7.95KB
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) 546.37KB 130.65KB
core (index.js) 9.22KB 3.71KB
create-plugin (index.js) 27.94KB 9.51KB
data-objectstack (index.js) 223.91KB 62.28KB
fields (index.js) 259.41KB 65.82KB
i18n (LocalizationContext.js) 1.76KB 0.96KB
i18n (builtinAggregateLabels.js) 0.86KB 0.49KB
i18n (currency.js) 2.59KB 1.22KB
i18n (fallbackInterpolation.js) 6.25KB 2.77KB
i18n (i18n.js) 8.87KB 3.64KB
i18n (index.js) 5.24KB 2.27KB
i18n (pickLocalized.js) 9.86KB 3.95KB
i18n (provider.js) 39.40KB 12.91KB
i18n (useDisplayLocale.js) 3.52KB 1.76KB
i18n (useObjectLabel.js) 34.34KB 9.17KB
i18n (useSafeTranslation.js) 5.60KB 2.33KB
layout (index.js) 39.28KB 11.09KB
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.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.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.01KB 3.93KB
plugin-calendar (index.js) 51.40KB 14.61KB
plugin-charts (index.js) 74.94KB 20.89KB
plugin-chatbot (index.js) 198.36KB 47.20KB
plugin-dashboard (index.js) 133.50KB 35.37KB
plugin-designer (index.js) 216.25KB 44.39KB
plugin-detail (index.js) 232.96KB 61.65KB
plugin-editor (index.js) 2.23KB 1.05KB
plugin-form (index.js) 147.92KB 37.83KB
plugin-gantt (index.js) 169.62KB 41.91KB
plugin-grid (index.js) 215.37KB 58.92KB
plugin-kanban (index.js) 48.26KB 15.04KB
plugin-list (index.js) 114.60KB 28.31KB
plugin-map (index.js) 22.42KB 7.38KB
plugin-markdown (index.js) 13.88KB 4.80KB
plugin-report (index.js) 43.55KB 11.99KB
plugin-timeline (index.js) 30.67KB 8.95KB
plugin-tree (index.js) 10.52KB 3.69KB
plugin-view (index.js) 87.31KB 21.78KB
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) 116.21KB 38.14KB
react (data-invalidation.js) 5.05KB 2.08KB
react (index.js) 4.03KB 1.86KB
react (schema-input.js) 4.25KB 2.04KB
react (spec-input.js) 0.20KB 0.18KB
sdui-parser (body-dialect.js) 4.78KB 2.09KB
sdui-parser (codegen.js) 6.58KB 2.74KB
sdui-parser (dashboard-widget-options.js) 3.08KB 1.30KB
sdui-parser (index.js) 5.78KB 2.56KB
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) 18.27KB 6.20KB
types (ai.js) 4.11KB 2.06KB
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) 5.00KB 2.39KB
types (navigation.js) 0.20KB 0.18KB
types (objectql.js) 0.20KB 0.18KB
types (overlay.js) 0.20KB 0.18KB
types (permissions.js) 2.52KB 1.31KB
types (plugin-scope.js) 0.20KB 0.18KB
types (record-components.js) 0.20KB 0.19KB
types (record-semantics.js) 1.28KB 0.67KB
types (registry.js) 0.20KB 0.18KB
types (reports.js) 0.20KB 0.18KB
types (select-option.js) 0.20KB 0.19KB
types (spec-report.js) 5.05KB 1.93KB
types (spec-ui-namespace.js) 0.20KB 0.19KB
types (strict-authoring-face.js) 17.15KB 6.32KB
types (system-fields.js) 3.33KB 1.54KB
types (theme.js) 6.28KB 2.87KB
types (ui-action.js) 8.11KB 3.32KB
types (views.js) 0.20KB 0.18KB
types (widget.js) 0.20KB 0.18KB

Size Limits

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

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

Contract review

Served-tier: CONTRACT_REVIEW_TIER
Head-sha: a6e5c6d774a1bdccc56a36411b351fde2619ea69

① Derived judgments

  • By reference, strictly: yes. Zod face: xAxis: z.union([stripImportedDefaults(SpecChartAxisSchema), z.never()], { error }), yAxis: z.array(stripImportedDefaults(SpecChartAxisSchema), { error }); TS face: xAxis?: SpecChartAxis, yAxis?: SpecChartAxis[] with ChartAxis as SpecChartAxis from @objectstack/spec/ui. No key list, no subset. The spec's ChartAxis is z.input OF ChartAxisSchema (spec dist/ui/index.d.ts:557), so the two .default() keys are optional on the TS twin, matching the stripped mirror. stripImportedDefaults used exactly as feat(types): declare the spec's axis config object on ChartSchema.xAxis / yAxis (objectui#7690) #10511 (data-display.zod.ts:981,989).
  • xAxis construction, probed on installed zod 4.4.3: one-arm union with an error hook: 0 hook calls, raw invalid_type "expected object, received string". Two-arm [object, z.never()]: hook called once, invalid_union, issue.input set, issue.errors[0] is the axis arm with union-relative paths. Claim true. Types: Equal OF z.input OF M.shape.xAxis, SpecChartAxis | undefined true, Equal OF ..., unknown false, Equal OF ..., any false; yAxis input is SpecChartAxis[] | undefined (tsc exit 0 on a scratch probe). Ratchet compares the real type. Messages dumped from the real mirror: min: 'zero' gives invalid_union@xAxis: ... not a valid @objectstack/spec axis object — xAxis.min: Invalid input: expected number, received string; grid: true carries the spec's Did you mean grid → showGridLines? hint; neither contains the { field remedy. String / list / number / null give the xAxis: { field: 'status' } remedy. Same shape as ChartSchema.xAxis on main (one invalid_union at xAxis; objectChartXAxisError is chartXAxisUnionError minus the string arm). House idiom: the only in-repo remedy on a by-reference object is ObjectGridSchema.exportOptions's z.strictObject(SPEC_SHAPE, { error }) re-wrap, which copies the shape; z.custom().pipe() would degrade z.input to unknown and z.toJSONSchema throws on z.custom (tombstone.zod.ts:158). Nothing simpler was missed. Note: a refine-only failure in the arm bypasses the union hook (probed), moot because the spec's ChartAxisSchema is a plain strict object.
  • Refusals / producers: chartConfigPresentation (core/utils/chart-presentation.ts:415-464) emits no axes, so the dashboard's composed object-chart nodes (DashboardGridLayout.tsx, DashboardRenderer.tsx) carry none; field-less axes from mergeAuthoredPresentation land on a type: 'chart' node (DatasetWidget.tsx:1662); ObjectView.tsx:2543/2574 compose xAxisKey + series only. Bare-string hits in objectui are report-chart (ReportDefaultInspector) or untyped normalizeChartSchema unit inputs. objectstack HEAD 5581d30 / origin/main 949e99b: command-center.page.ts:95 yAxis: [{ field: values[0], stepSize: 1 }], renewals-pipeline.page.ts:166 xAxis={{ field: 'status' }} yAxis={[{ field: 'total', format: '$0,0' }]}; the showcase reports/index.ts:86 bare string is a report chart. Census holds.
  • Fixture line: diff is 1+/1−. Inline as unknown as ObjectChartSchema['xAxis'], the same unknown-to-member cast UNAUTHORABLE applies to aggregate (:110-111), not the helper itself (it is typed to aggregate; one line cannot add a second). Runtime value unchanged; normalizeChartSchema.ts:486 still folds str(xAxisRaw). Reverse check: the uncast shape under Partial OF ObjectChartSchema consumes a @ts-expect-error.
  • Pins: head 39/39. Mutation 3 re-run in a scratch worktree (both faces reset to merge-base blobs dba0fbef/2176166f; the body's efe2595f/51ad74bf are 0b1b1c816's pre-merge blobs, as it says): 19 failed | 20 passed (39), exactly the 19 listed; tsc -p tsconfig.test.json: TS2344 x2, TS2578 x8, all in the pin. Lit controls are the two showcase shapes. Equal rows target SpecChartAxis | undefined / SpecChartAxis[] | undefined with the can-fail control present. Gap, non-blocking: block (d) pins yAxis non-list refusals by code+path only; the remedy text is unpinned.
  • Ledgers: imported-defaults-8317 +3 comment lines, zod-mirror-parity +8/−3 comment lines, membership unchanged; the five ledger/census pins pass at head (5 files / 210 tests).
  • Census blind spot: accurate. Regex at 8885:247 / 7946:326 matches schema.KEY, (schema as T).KEY, schema['KEY']; ObjectChart.tsx:1185-1186 forwards via { ...schema, ... } and has no schema.xAxis / schema.yAxis read.

② Semver level

'@object-ui/types': minor is right under AGENTS.md §9 「版本号策略」: no major in changesets (CI check-changeset-no-major.mjs), breaking semantics go in the body as minor. Clause-②: yes is required (accept set narrows). Frontmatter md5 ecedb10c5189b2c8841ea736b67c3cc6 at 74cf402ed, 0b1b1c816, a6e5c6d77. Body checked sentence by sentence against the installed spec (REACT_BLOCKS entry schema === ChartConfigSchema, dataProps has both keys), objectstack producers, the dumped messages, the type probe and the diff (no renderer file): all true. Soft overclaim: "each of them draws a chart today" for a list xAxis with no other category source (the 8168 refusal draws instead); same wording as #7690's changeset. Of the 29 pending changesets naming object-chart/axes, those with claims about these keys (7690, 8168, 7946, 8885 x2, 10516) are not falsified. Changeset Bump Policy / Declaration / Claim Re-read checks green.

③ Boundary flags

Implemented-by: claude/issue-10518-object-chart-axis-config
Reviewed-by: session_014mXUNuFomfj24w7s1pZzhN

VERDICT: PASS


Generated by Claude Code

…ape draws today (objectui#10518)

The lead-in said every now-refused document draws a chart today. A
per-case render measurement shows that is false for three shapes: an
xAxis object with no field, a list or other non-object xAxis, and a
yAxis entry with no field on a chart whose series come from yAxis alone.
Each can draw a refusal instead. The lead-in now says most of them draw
a chart, and the affected bullets name the exception and what it draws.
The zod comment that called a list xAxis a normalizer tolerance is
corrected the same way. Prose only: the frontmatter is byte-identical.

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

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

Metric Value Budget
Eager closure (gzip, 329 chunks) 3049.8 KB 3104.5 KB
Main entry chunk (gzip) 147.9 KB 350 KB
Entry file index-B2kXUfZN.js —
Status PASS —

The eager closure is every chunk the entry reaches through static imports — what the browser fetches and parses before the app renders. The entry chunk on its own is a small fraction of it.


📦 Bundle Size Report

Package Size Gzipped
app-shell (consoleActionDispatch.js) 0.20KB 0.19KB
app-shell (index.js) 16.57KB 6.15KB
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) 27.95KB 10.04KB
auth (AuthContext.js) 0.31KB 0.24KB
auth (AuthGuard.js) 2.07KB 1.00KB
auth (AuthProvider.js) 40.17KB 10.58KB
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.39KB 1.21KB
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.52KB 3.45KB
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.13KB 7.95KB
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) 546.99KB 130.83KB
core (index.js) 9.22KB 3.71KB
create-plugin (index.js) 27.94KB 9.51KB
data-objectstack (index.js) 223.91KB 62.28KB
fields (index.js) 259.05KB 65.69KB
i18n (LocalizationContext.js) 1.76KB 0.96KB
i18n (builtinAggregateLabels.js) 0.86KB 0.49KB
i18n (currency.js) 2.59KB 1.22KB
i18n (fallbackInterpolation.js) 6.25KB 2.77KB
i18n (i18n.js) 8.87KB 3.64KB
i18n (index.js) 5.24KB 2.27KB
i18n (pickLocalized.js) 9.86KB 3.95KB
i18n (provider.js) 39.40KB 12.91KB
i18n (useDisplayLocale.js) 3.52KB 1.76KB
i18n (useObjectLabel.js) 34.34KB 9.17KB
i18n (useSafeTranslation.js) 5.60KB 2.33KB
layout (index.js) 39.28KB 11.09KB
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.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.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.01KB 3.93KB
plugin-calendar (index.js) 51.40KB 14.61KB
plugin-charts (index.js) 74.94KB 20.89KB
plugin-chatbot (index.js) 198.36KB 47.20KB
plugin-dashboard (index.js) 133.50KB 35.37KB
plugin-designer (index.js) 216.25KB 44.39KB
plugin-detail (index.js) 232.96KB 61.65KB
plugin-editor (index.js) 2.23KB 1.05KB
plugin-form (index.js) 147.92KB 37.83KB
plugin-gantt (index.js) 169.62KB 41.91KB
plugin-grid (index.js) 215.37KB 58.92KB
plugin-kanban (index.js) 48.26KB 15.04KB
plugin-list (index.js) 114.60KB 28.31KB
plugin-map (index.js) 22.42KB 7.38KB
plugin-markdown (index.js) 13.88KB 4.80KB
plugin-report (index.js) 43.55KB 11.99KB
plugin-timeline (index.js) 30.67KB 8.95KB
plugin-tree (index.js) 10.52KB 3.69KB
plugin-view (index.js) 87.84KB 21.96KB
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) 116.21KB 38.14KB
react (data-invalidation.js) 5.05KB 2.08KB
react (index.js) 4.03KB 1.86KB
react (schema-input.js) 4.25KB 2.04KB
react (spec-input.js) 0.20KB 0.18KB
sdui-parser (body-dialect.js) 4.78KB 2.09KB
sdui-parser (codegen.js) 6.58KB 2.74KB
sdui-parser (dashboard-widget-options.js) 3.08KB 1.30KB
sdui-parser (index.js) 5.78KB 2.56KB
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) 18.27KB 6.20KB
types (ai.js) 4.11KB 2.06KB
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) 5.00KB 2.39KB
types (navigation.js) 0.20KB 0.18KB
types (objectql.js) 0.20KB 0.18KB
types (overlay.js) 0.20KB 0.18KB
types (permissions.js) 2.52KB 1.31KB
types (plugin-scope.js) 0.20KB 0.18KB
types (record-components.js) 0.20KB 0.19KB
types (record-semantics.js) 1.28KB 0.67KB
types (registry.js) 0.20KB 0.18KB
types (reports.js) 0.20KB 0.18KB
types (select-option.js) 0.20KB 0.19KB
types (spec-report.js) 5.05KB 1.93KB
types (spec-ui-namespace.js) 0.20KB 0.19KB
types (strict-authoring-face.js) 17.15KB 6.32KB
types (system-fields.js) 3.33KB 1.54KB
types (theme.js) 6.28KB 2.87KB
types (ui-action.js) 8.11KB 3.32KB
types (views.js) 0.20KB 0.18KB
types (widget.js) 0.20KB 0.18KB

Size Limits

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

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

Contract review

Served-tier: CONTRACT_REVIEW_TIER
Head-sha: 0e710207d9a514838dd2ae41e7e573f7e99ca9a1

① Derived judgments

Delta verified. git diff a6e5c6d77 refs/review/pr-10601: 2 files. .changeset/10518-object-chart-y-axis-declared.md +14/−4 (body only); packages/types/src/zod/objectql.zod.ts +8/−6, and every changed line is a // line (0 non-comment lines: grep -vE '^[+-]\s*//' | wc -l → 0). Frontmatter md5 ecedb10c5189b2c8841ea736b67c3cc6 at both a6e5c6d77 and 0e710207d. Pin at head in a scratch worktree (pnpm install --offline, then pnpm exec vitest run packages/types/src/__tests__/object-chart-axis-config-10518.test.ts): 1 file, 39 passed. Runtime byte-identical to base: git diff --stat f169a030a refs/review/pr-10601 -- packages/plugin-charts/src packages/core/src packages/react/src names only the 8168 test file (1 line, the cast).

My own measurement. A 41-case probe rendered the real ObjectChart → ChartRenderer → normalizeChartSchema → AdvancedChartImpl (recharts ResponsiveContainer fixed at 480x320, the package's own idiom), reading chart-missing-category-axis, [data-chart-error] or .recharts-surface plus mark count. All 41 rendered; the probe file was removed and the worktree deleted afterwards.

The four required cases hold: list xAxis object-bound with no aggregate.groupBy → chart-missing-category-axis (8168, role=alert); list xAxis on static rows {stage, amount} → missing-category-key; yAxis: [{ stepSize: 1 }] as the only series source on bar → no-plottable-series; xAxis: { field: 'stage', min: 'zero', position: 'middle' } on static rows → chart (2 marks, ticks won|lost). Each of (a)–(d) has at least one confirming case, and the sufficiency conditions the bullets name are real: xAxisKey (static and object-bound), a dataset dimension, categories: ['value'], series, and dataset-bound with a fieldless yAxis all drew.

The bullets' conditions are too broad in three published sentences, each with a measured counterexample:

  1. Bullet 1, "so the chart draws only when another source names one: an xAxisKey, or the dimension of a dataset-bound chart. Otherwise it draws a refusal instead" (and bullet 2's "only under the same condition … and otherwise the same refusal"). FALSE when the rows carry a name column, the renderer's default category key (AdvancedChartImpl.tsx:2521 and :2749, props.xAxisKey ?? 'name'). Measured on static rows [{ name: 'a', value: 1 }, { name: 'b', value: 2 }]: list xAxis, xAxis: {} and xAxis: 42 each drew 2 marks with ticks a|b and no refusal; an object-bound chart with authored name rows and a list xAxis drew as well. That row shape is the repo's own canonical static fixture (the 8168 pin's "authored data array" case).
  2. Bullet 1, "the renderer's missing-category-key error on any other chart". FALSE for scatter: a list xAxis on static rows with chartType: 'scatter' drew no-plottable-points. hasNoCategoryKey is gated on CATEGORY_AXIS_CHART_TYPES (AdvancedChartImpl.tsx:366-368), which excludes scatter, treemap and sankey.
  3. Bullet 3, "when no entry names a field the chart draws the renderer's no-plottable-series refusal instead". FALSE for pie and donut: chartType: 'pie' and 'donut' with yAxis: [{ stepSize: 1 }], no series, no categories, static rows, each drew 2 sectors. hasNoPlottableSeries fires only for SERIES_ONLY_CHART_TYPES bar / horizontal-bar / line / area / combo (AdvancedChartImpl.tsx:2542-2544, :2623); every other family falls back to series[0]?.dataKey || 'value' (e.g. :1752). Line confirmed refusing; bar confirmed refusing.

Lesser: bullet 4 (single-object or bare-string yAxis) names no exception, but a single object with no field as the only series source on bar drew no-plottable-series, so the lead-in "The exceptions are named in their bullets" is not met there. Nit: bullet 1's "the chart draws today, because the object's field still names the category column" is false for a malformed field value itself (xAxis: { field: 42 } drew missing-category-key); the parenthetical examples scope it, so not blocking alone.

The landing body's round-3 bullets (b) ("Otherwise they draw a refusal … missing-category-key error otherwise") and (d) ("draws the renderer's no-plottable-series refusal when yAxis is the only series source") publish the same two over-broad claims and need the same scoping.

The objectql.zod.ts comment is true. normalizeChartSchema.ts:486 str(schema.xAxisKey) ?? xAxisSpec?.field ?? str(xAxisRaw): a bare string is honoured; a list gives normalizeAxis undefined (isRec at :260, :309) and str([]) undefined, so no category (measured: refusal). yAxis at :489-491 wraps a non-array and accepts normalizeAxis(a) ?? { field: str(a) }, so both yAxis shapes are honoured (single object with a field and bare string both drew).

Observation (e) is real, loud, pre-existing and outside this card; a card is owed. Object-bound + aggregate: { field: 'amount', function: 'sum', groupBy: 'stage' } + series, no xAxisKey, no xAxis → missing-category-key; the control with xAxisKey: 'stage' drew. Mechanism: resolveChartCategoryField (ObjectChart.tsx:128-134) accepts groupBy for the 8168 gate, but finalSchema (:1184-1186) never forwards it as xAxisKey; ChartRenderer.tsx:172 reads schema.xAxisKey ?? spec.xAxisKey (the normalizer reads no aggregate), and AdvancedChartImpl.tsx:2521 defaults to 'name'. Loud: role="status", data-chart-error="missing-category-key", a console.warn (:2761). Pre-existing: runtime byte-identical to base. The card: the 8168 refusal's own remedy list names aggregate.groupBy first as a sufficient binding (OBJECT_BOUND_CHART_CATEGORY_BINDINGS, ObjectChart.tsx:64-68), and a document that follows that remedy alone is refused one layer down; producers are shielded only because every relay floors xAxisKey (8168 pin block 2). Neither the changeset nor the body states (e), so no false prose arises from it; the changeset's missing-category-key arm for object-bound + groupBy + list xAxis matches the measurement.

② Semver level

Unchanged and correct: '@object-ui/types': minor, Clause-②: yes, frontmatter byte-identical. The rationale sentence "documents that validated before now refuse (the accept set narrows), and most of them draw a chart today" reads true: in the probe every malformed-value / undeclared-key xAxis object, bare-string xAxis, malformed / undeclared-key yAxis entry and single-object / bare-string yAxis with a field drew; the refusals are confined to the no-category and no-field shapes. minor stands.

③ Boundary flags

  • CI on 0e710207d, read at about 12:50Z: 43 check runs, 40 success, 3 skipped (dependabot, Test (coverage), Test (coverage shard)), 0 failed; all completed, Spec Main Shape Gate last at 12:49:44Z. No red check.
  • git merge-tree --write-tree refs/review/main refs/review/pr-10601 against current main ac2d6f136 (newer than the body's 402a266c9): tree 59ed693c5, exit 0, no conflict. Main moved objectql.ts / objectql.zod.ts since the merge-base (PR objectui#10595); the merge is clean.
  • Title still "feat(types): declare the spec's axis config list on ObjectChartSchema.yAxis (objectui#10518)", naming yAxis only; the seat retitles at landing. Also: the PR is draft: true on GitHub and its GitHub body is still the round-1 body ("Part of finding(types): ObjectChartSchema (object-chart) carries the same undeclared xAxis / yAxis axis-object passthrough objectui#7690 declared on ChartSchema, and a real producer writes it #10518"); the seat must apply the r3 body and mark it ready before landing.
  • What stops landing: the three over-broad changeset sentences in ① (they publish verbatim to the CHANGELOG) and the matching round-3 bullets (b) and (d) in the landing body. Fix: bullets 1 and 2 add "or rows that carry the renderer's default name column" to the draw condition and scope the missing-category-key arm to the category-axis families (bar, horizontal-bar, line, area, pie, donut, radar, funnel, combo; scatter draws its own no-plottable-points); bullet 3 scope the no-plottable-series refusal to bar, horizontal-bar, line, area and combo with rows present, since pie, donut, radar, funnel, scatter, treemap and sankey fall back to a value column and draw; bullet 4 name the same no-field exception for a single object, or drop the lead-in's "exceptions are named in their bullets".
  • No code line changed, no GitHub write made, /home/user/objectui untouched (HEAD 961ceaa32, clean), scratch worktree removed.

Implemented-by: claude/issue-10518-object-chart-axis-config
Reviewed-by: session_014mXUNuFomfj24w7s1pZzhN

VERDICT: FAIL — three changeset sentences (bullet 1's "draws only when … otherwise a refusal", bullet 1's "missing-category-key on any other chart", bullet 3's unconditional "no-plottable-series refusal") are false for measured shapes (rows carrying name; scatter; pie and donut), and the landing body's round-3 bullets (b) and (d) repeat two of them. Prose-only fix; code, pin, semver, CI and merge are all clean.


Generated by Claude Code

…ow-refused axis shapes (objectui#10518)

Review round 2 showed that the round-3 conditions were too broad. Whether
a no-category or no-field shape draws depends on the chart type and on the
rows: a `name` column, or the `value` fallback. The lead-in now says that
several of the now-refused documents draw a chart today, and that what the
rest draw depends on the chart type, the rows and the node's other
sources. The bullets state only equivalences the renderer guarantees: a
dropped key changes nothing; a bare string reads as `{ field }`; a list,
a non-object or a missing field names no category; a no-field entry adds
no series. Prose only; the frontmatter is byte-identical.

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

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

Metric Value Budget
Eager closure (gzip, 329 chunks) 3050.3 KB 3104.5 KB
Main entry chunk (gzip) 147.9 KB 350 KB
Entry file index-CBoAqwid.js —
Status PASS —

The eager closure is every chunk the entry reaches through static imports — what the browser fetches and parses before the app renders. The entry chunk on its own is a small fraction of it.


📦 Bundle Size Report

Package Size Gzipped
app-shell (consoleActionDispatch.js) 0.20KB 0.19KB
app-shell (index.js) 16.57KB 6.15KB
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) 27.95KB 10.04KB
auth (AuthContext.js) 0.31KB 0.24KB
auth (AuthGuard.js) 2.07KB 1.00KB
auth (AuthProvider.js) 40.17KB 10.58KB
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.39KB 1.21KB
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.52KB 3.45KB
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.13KB 7.95KB
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) 546.99KB 130.83KB
core (index.js) 9.22KB 3.71KB
create-plugin (index.js) 27.94KB 9.51KB
data-objectstack (index.js) 223.91KB 62.28KB
fields (index.js) 260.13KB 65.84KB
i18n (LocalizationContext.js) 1.76KB 0.96KB
i18n (builtinAggregateLabels.js) 0.86KB 0.49KB
i18n (currency.js) 2.59KB 1.22KB
i18n (fallbackInterpolation.js) 6.25KB 2.77KB
i18n (i18n.js) 8.87KB 3.64KB
i18n (index.js) 5.24KB 2.27KB
i18n (pickLocalized.js) 9.86KB 3.95KB
i18n (provider.js) 39.40KB 12.91KB
i18n (useDisplayLocale.js) 3.52KB 1.76KB
i18n (useObjectLabel.js) 34.34KB 9.17KB
i18n (useSafeTranslation.js) 5.60KB 2.33KB
layout (index.js) 39.28KB 11.09KB
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.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.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.01KB 3.93KB
plugin-calendar (index.js) 51.40KB 14.61KB
plugin-charts (index.js) 74.94KB 20.89KB
plugin-chatbot (index.js) 198.36KB 47.20KB
plugin-dashboard (index.js) 133.50KB 35.37KB
plugin-designer (index.js) 216.25KB 44.39KB
plugin-detail (index.js) 232.96KB 61.65KB
plugin-editor (index.js) 2.23KB 1.05KB
plugin-form (index.js) 149.07KB 38.02KB
plugin-gantt (index.js) 169.62KB 41.91KB
plugin-grid (index.js) 215.37KB 58.92KB
plugin-kanban (index.js) 48.26KB 15.04KB
plugin-list (index.js) 114.60KB 28.31KB
plugin-map (index.js) 22.42KB 7.38KB
plugin-markdown (index.js) 13.88KB 4.80KB
plugin-report (index.js) 43.55KB 11.99KB
plugin-timeline (index.js) 30.67KB 8.95KB
plugin-tree (index.js) 10.52KB 3.69KB
plugin-view (index.js) 87.84KB 21.96KB
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) 116.21KB 38.14KB
react (data-invalidation.js) 5.05KB 2.08KB
react (index.js) 4.03KB 1.86KB
react (schema-input.js) 4.25KB 2.04KB
react (spec-input.js) 0.20KB 0.18KB
sdui-parser (body-dialect.js) 4.78KB 2.09KB
sdui-parser (codegen.js) 6.58KB 2.74KB
sdui-parser (dashboard-widget-options.js) 3.08KB 1.30KB
sdui-parser (index.js) 5.78KB 2.56KB
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) 18.27KB 6.20KB
types (ai.js) 4.11KB 2.06KB
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) 5.00KB 2.39KB
types (navigation.js) 0.20KB 0.18KB
types (objectql.js) 0.20KB 0.18KB
types (overlay.js) 0.20KB 0.18KB
types (permissions.js) 2.52KB 1.31KB
types (plugin-scope.js) 0.20KB 0.18KB
types (record-components.js) 0.20KB 0.19KB
types (record-semantics.js) 1.28KB 0.67KB
types (registry.js) 0.20KB 0.18KB
types (reports.js) 0.20KB 0.18KB
types (select-option.js) 0.20KB 0.19KB
types (spec-report.js) 5.05KB 1.93KB
types (spec-ui-namespace.js) 0.20KB 0.19KB
types (strict-authoring-face.js) 17.15KB 6.32KB
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

… (objectui#10518)

The lead-in credited the `minor` level to the refused documents that still
draw a chart. The version policy's reason is the breaking semantics, which
here is the narrowed accept set itself. The lead-in paragraph is replaced
with the seat's exact text and rewrapped to the file's width. The bullets
and the frontmatter are unchanged.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014mXUNuFomfj24w7s1pZzhN
@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

Contract review

Served-tier: CONTRACT_REVIEW_TIER
Head-sha: 5367bc102087a734ecdbb8fe0044bf487ddf8834

① Derived judgments

Delta verified. git diff 0e710207d refs/review/pr-10601 touches ONE file, .changeset/10518-object-chart-y-axis-declared.md (+11/−15). Against merge-base f169a030a the PR changes seven files: the changeset, packages/types/src/objectql.ts, objectql.zod.ts, three test files and the 8168 fixture; normalizeChartSchema.ts, ChartRenderer.tsx, AdvancedChartImpl.tsx, ObjectChart.tsx are byte-identical to refs/review/main. So "No renderer changed" and "The normalizer is unchanged" hold.

Why the equivalences hold for every chart type and row set (source, read-only). ChartRenderer calls normalizeChartSchema(schema, language) once and hands AdvancedChartImpl ONLY the normalized xAxis={props.spec.xAxis} / yAxes={props.spec.yAxes}; there is no ...schema spread, and xAxisKey is schema.xAxisKey ?? spec.xAxisKey. ObjectChart.resolveChartCategoryField reads aggregate.groupBy, else normalizeChartSchema(schema).xAxisKey; ObjectChart.tsx never reads raw schema.xAxis / schema.yAxis (only comments and the resolver's param type name them). AdvancedChartImpl has zero logScale occurrences, every grid hit is a comment, and its axis reads are NormalizedAxis keys only (format, title, showGridLines, position === 'right', logarithmic, min/max/stepSize via domainFor/ticksFor inside numericAxisSpecProps). Two schemas with deep-equal normalizer output therefore draw the same picture regardless of type or rows.

Kept sentences:

  1. "drops a malformed min or position and never reads grid or logScale ... draws exactly what it draws without them" — TRUE. normalizeAxis: min passes num() (finite number only), so 'zero' is dropped; position is kept only when it equals left/right/top/bottom, so 'middle' is dropped, not kept as unknown; grid/logScale are never read (the normalizer reads showGridLines/logarithmic). { field, min: 'zero' }, { field, position: 'middle' }, { field, grid: true } all normalize to the output of { field } (out.xAxis unset because no non-field key survived; xAxisKey = field). No implication about a valid min/position.
  2. "An object with no field names no category of its own" — TRUE. normalizeAxis({}) is {}; xAxisKey = str(schema.xAxisKey) ?? xAxisSpec?.field ?? str(xAxisRaw) gets nothing from it. Not stronger than claimed: { title } without field still renders an x-axis label, which the sentence does not deny.
  3. "A bare string names the category column exactly as { field } does, so it draws what that object draws" — TRUE. 'status': isRec false, str(xAxisRaw) gives 'status'; { field: 'status' }: xAxisSpec.field gives 'status', out.xAxis unset. Both yield exactly { xAxisKey: 'status' }, both below schema.xAxisKey in precedence; resolveChartCategoryField takes the same path, so the objectui#8168 refusal treats them alike (the fixture "a bare string xAxis, the report surface spelling" pins no refusal). No consumer branches on a string xAxis.
  4. "A list or any other non-object names no category, like an object with no field" — TRUE. Array, number, boolean, null all fail isRec and str, so no xAxisKey, same as {}. Only the category claim is made ("any other" reads as other than the bare string just handled, the same phrasing as the bullet's first sentence).
  5. "The renderer ignores what it cannot read and uses the rest of the entry" — TRUE. { field: 'amount', stepSize: 'big', position: 'middle', logScale: true, grid: false } normalizes to { field: 'amount' }; stepSize passes only a finite number greater than zero.
  6. "An entry with no field names no column, so it adds no series" — TRUE and not stronger than that. Series-from-axes runs yAxes.filter((a) => a.field), and only when series/categories yield none. The fieldless entry still lands in yAxes (the .filter drops only undefined), so its title/min/max still shape the axis and a second entry still sets hasDualAxis; the sentence claims only "no series".
  7. "It reads a single object as a one-entry list, so a single object with no field adds no series either" — TRUE: Array.isArray(schema.yAxis) ? schema.yAxis : schema.yAxis !== undefined ? [schema.yAxis] : [], then the same filter. "honours both as a tolerance": a bare string falls to str(a) ? { field: str(a) } and plots.
  8. Unchanged sentences: "still honours a bare string as a tolerance, and that is unchanged" TRUE (str(xAxisRaw) arm, file identical to main); TS paragraph TRUE (the only hunk outside packages/types is the fixture line xAxis: 'stage' as unknown as ObjectChartSchema['xAxis']); "No renderer changed" TRUE.
  9. Lead-in. "Several of them draw a chart today" TRUE (existential: the 8168 fixture's bare-string xAxis with series: [{ dataKey: 'amount' }] draws; { field, grid: true } draws as { field }). "what the rest draw depends on ..." is hedged and consistent with round 2. FALSE: "which is why this ships as minor". AGENTS.md 「版本号策略」, the 推论 bullet: "objectui 自身的破坏性变更也标 minor(在正文里写清 breaking 语义即可)". The policy's input is breaking semantics, and the breaking semantics here are the accept-set narrowing itself: documents that passed safeValidateSchema / objectui validate now fail, whatever they drew. The level would be minor if none of them drew. The clause attributes the level to a fact the policy does not read and contradicts the sentence before it; it publishes verbatim to the CHANGELOG. Exact replacement (keep the existing leading warning glyph, replace the rest of the paragraph):

"Shipped as minor, not patch: documents that validated before now refuse (the accept set narrows), and a narrowed accept set is breaking semantics, which this repo's version policy ships as minor. Several of the refused documents draw a chart today; what the rest draw depends on the chart type, on the rows, and on the node's other category and series sources:"

Landing PR body r4 (changed sentences).

  • Section 4 changeset bullet: accurate once the lead-in is fixed; md5 ecedb10c5189b2c8841ea736b67c3cc6 verified at head over the three frontmatter lines.
  • Section 6 "Rounds 3 and 4" bullet: "Rounds 2 to 4 of the contract review then showed ..." is FALSE. The contract review has rounds 1 (5832280197, found "each of them draws" false), 2 (5832703331, found the chart-type / name column / value fallback dependence) and this round 3, which added nothing on that point; there is no round 4. Replacement: "Contract-review rounds 1 and 2 (records 5832280197 and 5832703331) then showed that whether a no-category or no-field shape draws depends on the chart type and on the rows' columns (a name column, the value fallback)." Line 6 "There were two rounds: yAxis first, then the xAxis patch round" is now stale beside "Rounds 3 and 4"; suggest "There were four rounds: yAxis, the xAxis patch, then two changeset-prose rounds."
  • Section 6 "Round 4" bullet: each of the four equivalences is confirmed at source above; its description of the lead-in stays accurate after the replacement; e0f820246 is an ancestor of current main (dddbc2754), so that merge-tree claim was against a real main commit. The 11-type / 2-row-set probe is the dev's own claim, not re-run and not needed: with one normalization point and no raw reader the equivalences hold by construction.

② Semver level

Unchanged and correct: '@object-ui/types': minor, Clause-②: yes, frontmatter byte-identical (md5 ecedb10c5189b2c8841ea736b67c3cc6). Changeset Bump Policy, Changeset Declaration, Changeset Fixed Group Check, Changeset Claim Re-read, Changeset Overwrite Report are all success on the head. minor is right for the reason the policy gives (breaking narrowing, no major), which is exactly why the body's causal clause must not say otherwise.

③ Boundary flags

  • CI on 5367bc102, last poll about 13:20Z: 42 check runs, 33 completed (30 success, 3 skipped), 9 still in_progress: Test (shard 1/8), 2/8, 3/8, 4/8, 6/8, 7/8, 8/8, Type Check, Spec Main Shape Gate (Test (shard 5/8) is success). No red check, so no log line to name; landing waits on those nine.
  • git merge-tree --write-tree refs/review/main refs/review/pr-10601 against main dddbc2754: clean, tree c4e86ebd6, exit 0. PR mergeable_state is behind; the queue rebuilds on main.
  • PR is draft: true; the live title and body are still round 1 ("declare the spec's axis config list on ObjectChartSchema.yAxis", "Part of finding(types): ObjectChartSchema (object-chart) carries the same undeclared xAxis / yAxis axis-object passthrough objectui#7690 declared on ChartSchema, and a real producer writes it #10518", "xAxis on this node is NOT declared here"), contradicting the head. The seat applies the r4 body and a new title at landing; the r4 body needs the "Rounds 2 to 4" sentence fixed first.
  • Blocking: the changeset lead-in's causal clause (①.9) needs one commit on the branch. Nothing else in the delta blocks.
  • No worktree created, no writes to the checkout, no GitHub writes.

Implemented-by: claude/issue-10518-object-chart-axis-config
Reviewed-by: session_014mXUNuFomfj24w7s1pZzhN

VERDICT: FAIL

The one branch-side defect is the lead-in clause "which is why this ships as minor", which misattributes the bump to what the refused documents draw rather than to the accept-set narrowing the version policy actually reads; the exact replacement paragraph is given in ①.9 and is a one-line commit. Seat-side, replace the r4 body's "Rounds 2 to 4 of the contract review" sentence as given before applying it. Everything else in the changeset body is confirmed true at source for every chart type and row set.


Generated by Claude Code

@github-actions

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

Metric Value Budget
Eager closure (gzip, 329 chunks) 3050.9 KB 3104.5 KB
Main entry chunk (gzip) 147.9 KB 350 KB
Entry file index-DaGLNCB-.js —
Status PASS —

The eager closure is every chunk the entry reaches through static imports — what the browser fetches and parses before the app renders. The entry chunk on its own is a small fraction of it.


📦 Bundle Size Report

Package Size Gzipped
app-shell (consoleActionDispatch.js) 0.20KB 0.19KB
app-shell (index.js) 16.57KB 6.15KB
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) 27.95KB 10.04KB
auth (AuthContext.js) 0.31KB 0.24KB
auth (AuthGuard.js) 2.07KB 1.00KB
auth (AuthProvider.js) 40.17KB 10.58KB
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.39KB 1.21KB
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.52KB 3.45KB
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.13KB 7.95KB
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) 546.99KB 130.83KB
core (index.js) 9.22KB 3.71KB
create-plugin (index.js) 27.94KB 9.51KB
data-objectstack (index.js) 223.91KB 62.28KB
fields (index.js) 260.06KB 65.86KB
i18n (LocalizationContext.js) 1.76KB 0.96KB
i18n (builtinAggregateLabels.js) 0.86KB 0.49KB
i18n (currency.js) 2.59KB 1.22KB
i18n (fallbackInterpolation.js) 6.25KB 2.77KB
i18n (i18n.js) 8.87KB 3.64KB
i18n (index.js) 5.24KB 2.27KB
i18n (pickLocalized.js) 9.86KB 3.95KB
i18n (provider.js) 39.40KB 12.91KB
i18n (useDisplayLocale.js) 3.52KB 1.76KB
i18n (useObjectLabel.js) 34.34KB 9.17KB
i18n (useSafeTranslation.js) 5.60KB 2.33KB
layout (index.js) 39.28KB 11.09KB
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.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.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.01KB 3.93KB
plugin-calendar (index.js) 51.40KB 14.61KB
plugin-charts (index.js) 74.94KB 20.89KB
plugin-chatbot (index.js) 198.36KB 47.20KB
plugin-dashboard (index.js) 133.54KB 35.39KB
plugin-designer (index.js) 216.25KB 44.39KB
plugin-detail (index.js) 232.96KB 61.65KB
plugin-editor (index.js) 2.23KB 1.05KB
plugin-form (index.js) 151.18KB 38.74KB
plugin-gantt (index.js) 169.62KB 41.91KB
plugin-grid (index.js) 215.37KB 58.92KB
plugin-kanban (index.js) 48.26KB 15.04KB
plugin-list (index.js) 114.44KB 28.25KB
plugin-map (index.js) 22.42KB 7.38KB
plugin-markdown (index.js) 13.88KB 4.80KB
plugin-report (index.js) 43.55KB 11.99KB
plugin-timeline (index.js) 30.67KB 8.95KB
plugin-tree (index.js) 10.52KB 3.69KB
plugin-view (index.js) 87.84KB 21.96KB
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) 116.21KB 38.14KB
react (data-invalidation.js) 5.05KB 2.08KB
react (index.js) 4.03KB 1.86KB
react (schema-input.js) 4.25KB 2.04KB
react (spec-input.js) 0.20KB 0.18KB
sdui-parser (body-dialect.js) 4.78KB 2.09KB
sdui-parser (codegen.js) 6.58KB 2.74KB
sdui-parser (dashboard-widget-options.js) 3.08KB 1.30KB
sdui-parser (index.js) 5.78KB 2.56KB
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) 18.27KB 6.20KB
types (ai.js) 4.11KB 2.06KB
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) 5.00KB 2.39KB
types (navigation.js) 0.20KB 0.18KB
types (objectql.js) 0.20KB 0.18KB
types (overlay.js) 0.20KB 0.18KB
types (permissions.js) 2.52KB 1.31KB
types (plugin-scope.js) 0.20KB 0.18KB
types (record-components.js) 0.20KB 0.19KB
types (record-semantics.js) 1.28KB 0.67KB
types (registry.js) 0.20KB 0.18KB
types (reports.js) 0.20KB 0.18KB
types (select-option.js) 0.20KB 0.19KB
types (spec-report.js) 5.05KB 1.93KB
types (spec-ui-namespace.js) 0.20KB 0.19KB
types (strict-authoring-face.js) 17.15KB 6.32KB
types (system-fields.js) 3.33KB 1.54KB
types (theme.js) 6.28KB 2.87KB
types (ui-action.js) 8.11KB 3.32KB
types (views.js) 0.20KB 0.18KB
types (widget.js) 0.20KB 0.18KB

Size Limits

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

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

Contract review

Served-tier: CONTRACT_REVIEW_TIER
Head-sha: b2936fc6693bad6bed722e0f0f47e8fe2b3eb6b3

① Derived judgments

  • Diff 5367bc102..b2936fc66: one file, one hunk, .changeset/10518-object-chart-y-axis-declared.md lines 23 to 26 (the lead-in paragraph), +3/-2. Bullets, closing paragraphs and frontmatter untouched. Frontmatter (lines 1 to 3, both --- inclusive) md5 ecedb10c5189b2c8841ea736b67c3cc6, identical at both heads.
  • The lead-in, unwrapped, is byte-equal to the round-3 replacement text with the leading ⚠️ kept (cmp of the two strings: identical).
  • True against policy: AGENTS.md §9 「版本号策略」 at refs/review/main (98b1a7cac), line 271: changesets never declare major; "objectui 自身的破坏性变更也标 minor(在正文里写清 breaking 语义即可)". A narrowed accept set is breaking semantics, the file states them in its body as the policy asks, and the frontmatter reads '@object-ui/types': minor.
  • Consistent with the bullets: bullets 1, 2 (bare string) and 4 describe refused documents that draw today ("draws exactly what it draws without them", "draws what that object draws", normalizer honours both); the list / non-object / no-field cases say only "names no category" / "adds no series", which is exactly what "depends on the chart type, on the rows, and on the node's other category and series sources" leaves open. No bullet restates the retracted "which is why this ships as minor" clause.
  • Body r4 to r5: exactly three changed lines (6, 89, 96); nothing else moved.
    • Line 6, "five rounds": the branch holds 6 commits over main, 5 non-merge: 74cf402ed (yAxis), 0b1b1c816 (xAxis), then 0e710207d, 5367bc102, b2936fc66 (three docs(changeset) commits). Matches section 5 (rounds 1, 2) and section 6 (rounds 3, 4, 5). True.
    • Line 89: the record ids map to rounds 1 and 2 as the background gives them (5832280197, 5832703331). What those records showed is outside the supplied inputs; see ③.
    • Line 96, Round 5 bullet: "one clause false" matches round 3; "credited the minor level to what the refused documents draw" is a fair paraphrase of the removed "Several of them draw a chart today, which is why this ships as minor"; the stated new reason is the new text and the policy; "nothing else changed" and the md5 match the diff. True.
  • Staleness sweep after round 5: section 4's changeset bullet (line 63) still describes the file (every refusing shape named, only what holds everywhere, frontmatter md5). Section 6's Round 4 bullet (line 90) says the lead-in "now says" several refused documents draw today and the rest depend on chart type, rows and other sources: that sentence survives verbatim in the head lead-in, so the bullet is still accurate and asserts nothing about the retracted clause. The merge-tree claims on lines 88 and 95 are SHA-scoped history, not claims about today.

② Semver level

minor on @object-ui/types, as the frontmatter declares and the new lead-in justifies: accept-set narrowing is breaking, and this repo ships breaking as minor (AGENTS.md line 271). Changeset Bump Policy, Changeset Declaration and Changeset Fixed Group Check are green on the head.

③ Boundary flags

  • Line 89's attribution to round 1 is unverified, not confirmed. The background says round 1 PASSed the whole change and only rounds 2 and 3 failed prose, and the records are not among my inputs. If record 5832280197 does not itself make the chart-type / rows point, use: "Contract-review round 2 (record 5832703331) then showed that whether a no-category or no-field shape draws depends on the chart type and on the rows' columns (a name column, the value fallback)." The "then" after "Round 3 (0e710207d)" also implies both records postdate that commit; the seat holds the timestamps.
  • The Round 5 bullet names no head SHA and no gates, unlike the Round 3 and 4 bullets. Optional: "Round 5, at b2936fc66, prose only."
  • Line 63 says "before and after the body edit" (singular); there have been three body edits and the md5 holds across all of them. Optional: "the body edits".
  • The PR title on GitHub is still round 1's ("... axis config list on ObjectChartSchema.yAxis ..."), while the r5 body says "Fixes finding(types): ObjectChartSchema (object-chart) carries the same undeclared xAxis / yAxis axis-object passthrough objectui#7690 declared on ChartSchema, and a real producer writes it #10518" and covers both keys. The title is outside this review's inputs; noted for the seat.
  • CI on b2936fc6: 42 check runs, 0 failed. 26 success (all five changeset guards, Control Byte Scan, Line Citation Gate, Governed Surface Queue Guard, Build & E2E, Test (dist pins), Build Docs, Bundle Analysis among them), 13 in progress (Test shards 1 to 8, Type Check, Lint, Spec Main Shape Gate, Doc Snippet Type Check, README Export Check), 3 skipped (Test (coverage), the coverage shard, dependabot). No red check.
  • git merge-tree --write-tree refs/review/main refs/review/pr-10601 with main at 98b1a7cac: clean, tree 652c7732e, exit 0. GitHub reports mergeable_state: behind and draft: true; the queue rebuilds on main.

Implemented-by: claude/issue-10518-object-chart-axis-config
Reviewed-by: session_014mXUNuFomfj24w7s1pZzhN

VERDICT: PASS


Generated by Claude Code

@objectstack-fleet objectstack-fleet Bot changed the title feat(types): declare the spec's axis config list on ObjectChartSchema.yAxis (objectui#10518) feat(types)!: declare the spec's axis config on ObjectChartSchema.xAxis / yAxis (objectui#10518) Sep 25, 2026
@objectstack-fleet
objectstack-fleet Bot marked this pull request as ready for review September 25, 2026 13:34
@objectstack-fleet
objectstack-fleet Bot added this pull request to the merge queue Sep 25, 2026
Merged via the queue into main with commit fb13e85 Sep 25, 2026
45 checks passed
@objectstack-fleet
objectstack-fleet Bot deleted the claude/issue-10518-object-chart-axis-config branch September 25, 2026 13:50
akarma-synetal pushed a commit to akarma-synetal/objectui that referenced this pull request Sep 28, 2026
…ies type and names chartType (objectui#10584) (objectstack-ai#10768)

Fixes objectstack-ai#10584
Clause-②: no. The accept set does not move; this is a `.describe` and
docblock wording fix. `yes` would be owed only if a named producer
turned the card to widening, and then the dev stops and reports.

## What changed

- `packages/types/src/zod/objectql.zod.ts`, the `series` member of
`ObjectChartSchema`: the `.describe()` no longer calls the element "the
arm ChartRendererProps declares". It now says the copy is that `{
dataKey }` arm minus the arm's per-series `type`, which this copy does
not declare, and that this copy's per-series family override is
`chartType` (`bar` | `line` | `area`). A short comment above the member
points at the TS twin for the ground.
- `packages/types/src/objectql.ts`, the `series` member docblock: "this
copy has not taken up" (which read as a lag) now says the omission is
deliberate. Taking `type` up widens a published accept set and waits for
a named producer that writes it on an `object-chart` node. The docblock
also states what a `type` written anyway meets on each face (measured
below).
- `.changeset/10584-object-chart-series-describe.md`: `@object-ui/types`
`patch`, since the `.describe()` string is published text.

Both edits stay inside the `ObjectChartSchema` block, which is the file
surface the claim names. No member, type or schema node changes.

## Premise check on `origin/main` at `0896838deb`

- **H1 holds.** The zod `.describe()` said "the arm ChartRendererProps
declares", while both arms of `ChartRendererProps.schema.series` carry
`type?: string` (objectui#8086). The TS docblock already named the
omission ("every member of it except `type` ... this copy has not taken
up"). It now says the omission is deliberate.
- **H2 holds.** PR objectstack-ai#10734 (objectui#10608) and PR objectstack-ai#10601
(objectui#10518) are both on `main`, so this card's serial predecessors
on the block have landed. The text was re-read on `main`; the card's
line numbers were not used.
- **H3: no pin.** `git grep` for the old describe text
("ChartRendererProps declares", "plotted series in the renderer", "has
not taken up") matches only the two source files. No test, generated
artifact or doc asserts the string, and no describe-verdict pin
(`INTERNAL` / `AUTHORABLE` prefix) reads it.

## Stop condition: producer census for a per-series `type` on
`object-chart`

No producer found, so the work did not stop. Each reading has a control
that hits:

- **objectui (in-repo):** every `type: 'object-chart'` literal outside
tests is in one of the relays: app-shell `ObjectView`, plugin-view
`ObjectView`, plugin-list `ListView`, plugin-dashboard
`DashboardRenderer` and `DashboardGridLayout`. Each writes `series` as
`{ dataKey, label }`, and none writes `type`. app-shell forwards
`viewDef.chart.series` verbatim, but the spec's `ListChartConfigSchema`
is a `strictObject` with no `series` member, so no conforming stored
view carries one. `chartConfigPresentation` emits no `series`. The only
`{ dataKey, type }` literals are in `plugin-charts` tests of the `chart`
renderer.
- **objectstack showcase (at `16c5a33`):** `command-center.page.ts`
writes `object-chart` nodes with no `series`.
`renewals-pipeline.page.ts` writes `series={[{ name: 'total', label:
'Invoice value' }]}` on the ObjectChart react block: the `{ name }` arm,
with no `type`.
- **hotcrm (shallow clone at `2f7b232`):** zero `object-chart` /
`ObjectChart` hits, and zero `series` in the 15 files under
`src/**/dashboards` and `src/**/reports`. Control: 34 chart `type:`
literals across those files (five dashboards and two reports).

## What each face does with a per-series `type` (measured, unchanged by
this PR)

Measured on the rebuilt `dist` at HEAD `5dc9a71e02`, with the same
readings on the base build:

- **zod mirror:** `ObjectChartSchema.safeParse` of `series: [{ dataKey:
'margin', type: 'line' }]` gives `success: true`, and the parsed series
is `[{"dataKey":"margin"}]` (the plain `z.object` element strips
`type`). `{ dataKey, chartType: 'line' }` keeps `chartType`. `{ label }`
alone is still `invalid_type` at `series.0.dataKey`. The base build
gives the same result for each.
- **TS face:** `tsc --strict` on a literal typed `ObjectChartSchema`
gives `TS2353` ("'type' does not exist in type ...") for `{ dataKey,
type }` and compiles `{ dataKey, chartType }`.
- **`dist` diff, base vs head:** the non-comment lines of
`objectql.d.ts` are byte-identical. `zod/objectql.zod.d.ts` and
`zod/index.zod.d.ts` differ only in union-member emission order on
members this PR does not touch (`"json" | "csv" | "xlsx"` versus `"json"
| "xlsx" | "csv"`, `position` and `operator` unions).
`zod/objectql.zod.js` differs only in the comment and the describe
string.

## Verification (all on HEAD `5dc9a71e02`, working tree clean)

- `pnpm --filter @object-ui/types build`: `VERDICT command-exit 0`. The
dependency closure `@object-ui/types^...` has no build script, so it is
empty.
- `pnpm --filter @object-ui/types type-check`: `VERDICT command-exit 0`
(the script name is echoed as `type-check`).
- `pnpm exec vitest run --maxWorkers=2 packages/types/`: `Test Files 245
passed (245)`, `Tests 5327 passed (5327)`, exit 0.
- `pnpm exec vitest run --maxWorkers=2 packages/plugin-charts/`: `Test
Files 82 passed (82)`, `Tests 964 passed (964)`, exit 0. Direction: the
downstream consumer of `@object-ui/types` named in the dispatch, run to
confirm no fixture reads the describe string.
- Out-of-package tests that parse `objectql.ts` / `objectql.zod.ts` from
disk (app-shell `relayRungCensus-7559`, `chartConfigForward-7891`;
plugin-grid, plugin-kanban, plugin-tree and react census pins; and eight
`scripts/__tests__` suites): `Test Files 15 passed (15)`, `Tests 602
passed (602)`, exit 0.
- ESLint `--no-inline-config --format json` on the two touched sources:
exit 0, 2 files linted, 0 errors, and 35 `no-explicit-any` warnings,
none on an edited line. Type-aware linting is not enabled
(`eslint.config.js` has no `parserOptions.project` / `projectService`),
so this diff cannot move a verdict on any untouched file.
- `node scripts/check-changeset-presence.mjs` 0 · `node
scripts/check-changeset-no-major.mjs` 0 · `pnpm
check:new-line-citations` 0 (`VERDICT new-cross-file-line-citations: 0
new citation(s)`) · `pnpm check:control-bytes` 0 · `pnpm
check:spec-symbols` 0 · `pnpm check:test-path-roots` 0 · `pnpm
check:changeset-claims` 0 (report-only). The pending objectui#8086
changeset's sentence "that copy of the internal arm does not carry
`type`, and its type is unchanged" is still true.
- `pnpm check:component-surface-parity` 0 ·
`check:designer-field-key-parity` 0 · `check:doc-types` 0 ·
`check:installed-pin-claims` 0 · `check:handler-key-reads` 0 ·
`check:action-forward-parity` 0.
- `node scripts/check-governed-queue-guard.mjs --test` on the three
paths: `NOT GOVERNED`.
- **NOT MEASURED: `pnpm check:doc-examples`**, exit 2, prerequisite not
met. It needs the dist of about 30 workspace packages, and that full
build is CI's. This diff adds no `@example` block or fence (zero added
lines match), so the gate's population is unchanged.
- **NOT RUN: Spec Main Shape Gate.** The touched member is not
spec-derived: the `series` element is a local copy of
`ChartRendererProps`' arm and binds no `@objectstack/spec` symbol. The
emitted `objectql.d.ts` is non-comment byte-identical, so compiling
against any spec cannot move.

## Acceptance notes

- **Kept verbatim: the `INTERNAL (relay-composed)` prefix.** It is
objectui#7946's ruled verdict. The census above measured a channel it
does not name: the ObjectChart react block. The spec's `react-blocks`
entry has `schemaType: 'object-chart'` and `schema: ChartConfigSchema`,
and it lists `series` in `dataProps`. `ChartSeriesSchema` is the `{ name
}` arm and carries the per-series `type`. The showcase's
`renewals-pipeline` page writes `series={[{ name, label }]}` through
that block onto an `object-chart` node, and the published zod face
refuses that node (`invalid_value` at `chartType`, `invalid_type` at
`series.0.dataKey`). That belongs to the same family as objectui#10518 /
objectui#10608 (the `object-chart` copy against the spec's ChartConfig
contract), and it is reported to the seat rather than acted on here. It
does not change this card's answer. On this node the spec's per-series
`type` rides the `{ name }` arm, and the spec refuses `dataKey` by name,
so a `{ dataKey, type }` entry is not spec-authorable on `object-chart`
either.
- The describe names `chartType` because it is this copy's declared
per-series override. It is not a new authoring recommendation: the
member stays `INTERNAL`.
- No pin was added. The dispatch owed one only if the wording was
already pinned, and it was not.

Refs: objectui#8086 · objectui#7946 · PR objectstack-ai#10554

---
_Generated by [Claude
Code](https://claude.ai/code/session_014fWVhLzhxR8qrFsJ5o8TYW)_

Co-authored-by: Claude <noreply@anthropic.com>
akarma-synetal pushed a commit to akarma-synetal/objectui that referenced this pull request Sep 28, 2026
…i#10793, objectstack-ai#10802 and objectstack-ai#10821 made false (objectui#10877) (objectstack-ai#10891)

Fixes objectstack-ai#10877
Clause-②: no. It is release-text hygiene, and no published type or
behaviour moves.

## What this does

Eight pending changesets each state a contract fact that a later PR in
this same unreleased batch made false: PR objectstack-ai#10793 (objectui#7924,
`densityMode` retired), PR objectstack-ai#10821 (objectui#7928,
`ObjectViewSchema.listViews` mirrored by reference, a named view's
`options` bag refused whole) and PR objectstack-ai#10802 (objectui#10770,
`ObjectChartSchema.series` became two arms). A pending changeset
publishes verbatim into the CHANGELOG at the next release, and the
release PR objectui#5400 is still open. So each false sentence now has a
dated supersession note beside it.

The note form is copied from the landed precedents, PR objectstack-ai#10533 (the
`6235-mergedsort-wrap.md` note) and PR objectstack-ai#10828 (objectui#10801): a bold
headline naming the date and the card whose change supersedes the
sentence, then what holds now, then the superseding entry by file and
PR, then "the text above is kept as the reading of this change".

- Zero lines deleted: `git diff --numstat` against the merge-base
`9f0c84a448` is 168 insertions, 0 deletions, over 8 files. The first
round added 10 notes in 6 files. Patch round 1 added 4 notes in 2 files
(below). Patch round 2 edited the 7779 note and added none, so there are
14 notes.
- The frontmatter is byte-identical in all nine entries the claim and
its addendum `5862987983` name. The md5 of the frontmatter block is
equal at the merge-base `9f0c84a448` and the head `50deccd71a` for each:
7924-retire `ecedb10c`, 8355 `8f322642`, 10321 `564c93d5`, 10584
`84f96a9a`, 8365 `379475b3`, 9242 `acef2a2c`, 8086 `e927372d`, 7779
`ecedb10c`, 7946 `2ffd8635`.
- The seventh entry, `8086-chart-series-type-arm.md`, is untouched
(whole-file md5 `7ea6b544` at base and head). Every sentence in it
measured STILL-TRUE (see the lit control below).
- No new changeset: the diff is `.changeset/` only, and
`check-changeset-presence` says none is owed.

| Entry | FALSE-NOW sentences, quoted | Superseding entry (PR) | Notes |
| --- | --- | --- | --- |
| `7924-named-list-view-retire.md` | "`NamedListView` (one entry of
`ObjectViewSchema.listViews`)"; "Two bucket-③ members are NOT retired"
and "They stay declared as they were." |
`7928-listviews-by-reference-fold.md` (objectstack-ai#10821);
`7924-density-mode-through-fold.md` (objectstack-ai#10793) | 2 |
| `8355-retire-calendar-date-aliases.md` | "it now names the key and the
remedy on all five authoring surfaces", for "a named view's two nestings
under `listViews`"; "plus a `.check()` on `ObjectViewSchema` for a named
view's two nestings"; "`ObjectViewSchema.listViews` stays UNMIRRORED"
and the rest of that paragraph; "`timeline.dateField` stays a live,
accepted alias", on a named view; "the structural guard that `listViews`
stays out of the object's `shape`" |
`7928-listviews-by-reference-fold.md` (objectstack-ai#10821) | 3 |
| `10321-named-view-kanban-groupby-refused.md` |
"`ObjectViewSchema.listViews` is unmirrored"; "and in its legacy
`options.kanban` bag" with the issue path under `options.kanban`;
"reports one issue per written key, naming the key and the replacement";
"Not changed, deliberately: `listViews` stays unmirrored" and the rest
of that paragraph | `7928-listviews-by-reference-fold.md` (objectstack-ai#10821) | 2 |
| `10584-object-chart-series-describe.md` | "It now says the copy is
that `{ dataKey }` arm minus its per-series `type`, and that the
per-series family override on an `object-chart` node is `chartType`";
"taking `type` up would widen a published accept set" |
`10770-object-chart-react-tier-node.md` (objectstack-ai#10802) | 1 |
| `8365-stray-kanban-groupby-refused.md` | "objectui#10321 gives that
route its own door, which refuses the key in either nesting with the
same message" | `7928-listviews-by-reference-fold.md` (objectstack-ai#10821) | 1 |
| `9242-stray-kanban-groupby-lane-second-route.md` | "which refuses the
key in either nesting with the same message"; "(a named view's `kanban`
is typed as the `list-view`'s), but not the key inside the untyped
`options.kanban` bag on either" | `7928-listviews-by-reference-fold.md`
(objectstack-ai#10821) | 1 |
| `object-view-unmirrored-keys-7779.md` (patch round 1) | the table's
"still unmirrored"; "`listViews` stays unmirrored, on the ruling's own
fallback clause."; "The declaration's value is the local
`NamedListView`"; the 21-read / 43-unread figures; "The key therefore
stays in the parity ledger … until the maintainer decides its value
type" | `7928-listviews-by-reference-fold.md` (objectstack-ai#10821) | 1 |
| `objectchart-schema-anchor-7946.md` (patch round 1) | the `series`
half of "value types taken from their READ sites (`ChartRendererProps`
for `xAxisKey` / `series`)" and of "two are INTERNAL, relay-composed
(`xAxisKey`, `series` …)"; "`series` entries must be `dataKey`-shaped.";
"`aggregate` is the exception, and only because the spec's own object is
strict." | `10770-object-chart-react-tier-node.md` (objectstack-ai#10802) | 3 |

**Placement.** Each note sits directly after the paragraph that holds
the false sentence. Where two false paragraphs are adjacent, one note
covers both: the first 10321 note, the 10584 note and the last 8355
note. The 8355 note after the UNMIRRORED paragraph also covers the
matching clause in the `@object-ui/types` bullet above it, because both
describe the same named-view check. No note cites a line address; source
facts are cited by symbol and test name, and `check:new-line-citations`
reads 0 new citations.

## Measured, not inherited (one-time probes, not committed)

The probes ran the worktree sources at base `b2683a2c0e`, with
`@objectstack/spec` 17.4.0 resolved from `packages/types`. The zod face
ran through `tsx`, and the TS face through `tsc --noEmit` against
`packages/types/src/index.ts`. Each probe sits beside a control that
differs only by the key. A named view is `listViews.v` with `columns`
set.

Zod face (`ObjectViewSchema.safeParse`; `safeValidateSchema` gives the
same issues on the two `kanban` rows):

| Probe | Result |
| --- | --- |
| control `kanban: { groupByField, columns }` | parses |
| `kanban.groupBy` | two issues: `unrecognized_keys` at
`listViews.v.kanban` naming `groupBy`, and `custom` at
`listViews.v.kanban.groupBy` |
| `options: { kanban: { groupBy } }` | one issue: `unrecognized_keys` at
`listViews.v` naming `options`; nothing at the `options.kanban.groupBy`
path |
| `calendar.dateField` | `unrecognized_keys` at `listViews.v.calendar`,
and `custom` at `listViews.v.calendar.dateField` |
| `options: { calendar: { dateField } }` | one issue: `options` refused
|
| `timeline.dateField` | `unrecognized_keys` at `listViews.v.timeline`;
control `timeline: { startDateField, titleField }` parses |
| each of the 16 retired `NamedListView` spellings, and `densityMode` |
`unrecognized_keys` at `listViews.v` naming the key (17 of 17); control
`userActions: { search: false }` parses |
| `listViews` in `ObjectViewSchema.shape` | present |
| list-view route: `kanban.groupBy`, `options.kanban.groupBy`,
`calendar.dateField`, `options.calendar.dateField`, `timeline.dateField`
| `invalid_type`, `custom`, `invalid_type`, `custom`, parses: unchanged
|

TS face (`tsc`):

| Probe | Result |
| --- | --- |
| named view `kanban.groupBy` in an `ObjectViewSchema` literal | TS2353,
excess property on the spec's kanban block |
| named view `options` | TS2353, `options` does not exist |
| named view canonical control | compiles |
| `list-view` `kanban.groupBy` | TS2322 (`never`): unchanged |
| `list-view` `options.kanban.groupBy` | compiles: unchanged |
| a `NamedListView` value as a `listViews` entry | TS2322, not
assignable |
| `NamedListView` with `densityMode`; with `allowExport` | TS2322;
compiles |

Chart series (`ObjectChartSchema.safeParse`): `{ name, type: 'line' }`
parses with `type` kept; `{ dataKey, type: 'line' }` parses with `type`
stripped; `{ name, chartType }` is refused (`invalid_union`). The series
`.describe()` string now names both arms.

The runtime fold was read, not probed: `normalizeListViewSchema` still
folds `densityMode` and the eight `show*` flags, and `ListView` still
merges `options.kanban` under `kanban`.

## Lit control: STILL-TRUE, left byte-identical

- `8086-chart-series-type-arm.md`, the whole entry. PR objectstack-ai#10802 changed no
`plugin-charts` source (its one file there is a test).
`ChartRendererProps.schema.series` still declares `type?: string` on
both arms. The `ObjectChartSchema.series` docblock still says the copy
of the internal arm omits `type`, and that internal arm's type is the
same literal as before PR objectstack-ai#10802.
- 8365, "takes the identical message through a check on that untyped
bag", and the distinguishing `options.kanban` fixture. Both are the
`list-view` route, measured unchanged.
- 9242, "a `list-view` document carrying the key, under `kanban` or
under the legacy `options.kanban` bag, is refused by
`safeValidateSchema`". Measured unchanged.
- 8355, the `@object-ui/types` bullet's "on the legacy
`options.calendar` nesting (a check, since an open record declares no
member". This is the list-view surface, measured unchanged.
- 7924-retire, "`densityMode` is folded onto `rowHeight` by
`normalizeListViewSchema`" and "Only the authoring face changes". The
fold still does both.
- 10584, "Wording only. The accepted shape does not move on either
face". This is a statement about that change's own delta, and it is
still true of that change.
- 7779 (patch round 1): `viewTabBar` retired; the eight keys enforced;
"64 declared top-level members"; the spec record requires `columns` and
refuses `options`, tuple filters and `default`; "not papered over with
`z.any()`"; "absent stays valid on all nine"; the ledger move 14/96 →
14/87 (that change's own delta). Each measured true at `0ea55c3701`.
- 7946 (patch round 1): the `xAxisKey` half of the INTERNAL sentence
(its `.describe()` still says all five producers compute it); `type:
'object-chart'` required; `chartType` must be the declared union;
`normalizeChartSchema` translates the `{ name }` arm; `aggregate`
`function` / `groupBy` required with unknown members refused; a
misspelled key on the node itself is not refused; `filter` keeps both
arms. Each measured true at `0ea55c3701`.

## Gates (re-taken at head `50deccd71a`; hand-derived from
`package.json` and `.github/workflows/`; each exit captured by
redirect-then-status)

| Command | Verdict line | Exit |
| --- | --- | --- |
| `pnpm check:pending-changeset-literals` | ✅ No test source names a
pending changeset. | 0 |
| `node scripts/check-changeset-claims.mjs` | ✅ No pending changeset
names a file this change touches. (Self-contradiction reading: every
declared package across the 8 bodies is not negated.) | 0 |
| `node scripts/check-changeset-presence.mjs` | ✅ No source or published
contract of a released package changed in this range, so no changeset is
owed. | 0 |
| `node scripts/check-changeset-no-major.mjs` | ✅ No changeset declares
a `major` bump. | 0 |
| `node scripts/check-changeset-overwrite.mjs` | report-only: this
change touches 8 changesets it did not add. The declared packages are
identical at base and head for all 8, which is the prose-correction
case. | 0 |
| `node scripts/check-changeset-fixed.mjs` | ✅ All workspace packages
are in the changeset fixed group. | 0 |
| `pnpm check:new-line-citations` | VERDICT
new-cross-file-line-citations: 0 new citation(s) | 0 |
| `pnpm check:control-bytes` | ✅ check-control-bytes: OK | 0 |
| `pnpm check:spec-symbols` | ✅ spec member citations: nothing cites a
key its spec symbol does not declare. | 0 |
| `pnpm check:test-path-roots` | ✅ check-test-path-roots: OK | 0 |
| `node scripts/check-installed-spec-pin-claims.mjs` | OK (it excludes
`.changeset/`, so it was run for completeness only) | 0 |
| `node scripts/check-governed-queue-guard.mjs --test` (the 8 paths) | ✅
NOT GOVERNED | 0 |

Tests, from the repo root under the shared verify lock: every
`scripts/__tests__` file that names `.changeset` (derived with `git grep
-l`: 24 test files, plus one fixture that is not a test), and the five
`@object-ui/types` pins that re-derive what the notes state
(`calendar-date-alias-refusal-8355`,
`named-view-kanban-stray-group-by-10321`,
`object-view-listviews-by-reference-7928`,
`object-chart-react-tier-node-10770`,
`object-view-unmirrored-keys-7779`). Result at `f5e0123f4b`: **Test
Files 29 passed (29), Tests 1193 passed (1193)**, lock `VERDICT
command-exit 0`. Re-taken at `0ea55c3701` with the 24
`scripts/__tests__` files and the four pins the new notes rest on
(`object-view-unmirrored-keys-7779`,
`object-chart-react-tier-node-10770`,
`object-view-listviews-by-reference-7928`, `zod-mirror-parity`): **Test
Files 28 passed (28), Tests 1200 passed (1200)**, lock `VERDICT
command-exit 0`. Re-taken at `50deccd71a` (patch round 2): the 24
`scripts/__tests__` files plus `object-view-unmirrored-keys-7779` gave
**25 files / 1146 tests**, and the four other pins
(`calendar-date-alias-refusal-8355`,
`named-view-kanban-stray-group-by-10321`,
`object-view-listviews-by-reference-7928`,
`object-chart-react-tier-node-10770`) gave **4 files / 48 tests**. Both
runs gave lock `VERDICT command-exit 0`.

Not applicable, with the reason:
- `@object-ui/types` type-check, package vitest runs and consumer
sweeps: the diff touches no package source, only `.changeset/`.
- The Spec Main Shape Gate: no touched type.
- ESLint `--no-inline-config` on the touched files: `eslint.config.js`
has no configuration that matches `.md`. All 8 files report "File
ignored because no matching configuration was supplied", so it judged
nothing (NOT MEASURED).

## Acceptance notes

- **Residue in the same family: closed by patch round 1.** The first
round stopped on two files outside the claimed surface,
`object-view-unmirrored-keys-7779.md` and
`objectchart-schema-anchor-7946.md`. Each is named by a superseding PR
itself. The seat extended the file surface (addendum `5862987983`,
option A), and patch round 1 (`80ee15eecb`) added one note to 7779 and
three to 7946, in the same form and measured the same way. `Fixes
objectstack-ai#10877` stays.
- **For the at-tier review.** The last 7946 note also names two changes
outside the three PRs: `drillDown` (objectui#8885, PR objectstack-ai#8895) and `xAxis`
/ `yAxis` (objectui#10518, PR objectstack-ai#10601). Both landed after the 7946 entry,
and both also make its "`aggregate` is the exception" sentence false.
That sentence of the note can be dropped if the review holds it out of
scope; the rest of the note stands without it.
- Not measured: the wider pending population that names `listViews` /
`NamedListView` or `ObjectChartSchema`. Only the entries the superseding
PRs name were read.
- **Source prose. These are observations and were not filed; carrier:
none.**
- The `ObjectChartSchema.series` TS docblock
(`packages/types/src/objectql.ts`) says "A `type` written on this arm
anyway is an excess property on a literal typed by this interface."
Since PR objectstack-ai#10802 that is false. `{ dataKey: 'amount', type: 'line' }`
compiles in an `ObjectChartSchema` literal, because the union's `{ name
}` arm declares `type` (tsc probe above). The zod mirror still strips
it.
- The zod docblock headed "WHERE THIS ARM IS INSTALLED — TWO ROUTES, TWO
NESTINGS EACH, ONE STRING" (`packages/types/src/zod/objectql.zod.ts`)
still says a named view's `listViews` "is unmirrored", and it still
names a `custom` issue under `options.kanban` on that route. The
docblocks of `checkNamedViewKanbanStrayGroupBy` and
`namedViewKindRefusals` are current.
- **A dispatch premise, corrected.** "Each one already states in its own
body that it supersedes the older entry" holds for
`7924-density-mode-through-fold.md` and
`7928-listviews-by-reference-fold.md`.
`10770-object-chart-react-tier-node.md` names no superseded entry. The
supersession is stated in PR objectstack-ai#10802's body ("Superseded pending
changesets"), which names the objectui#10584, objectui#7946-anchor and
objectui#8086 entries.
- **`main` merged, twice.** `origin/main` `4f38f39286` was merged as
`0ea55c3701`: the two merged commits touch none of the probed sources,
and the probes re-ran byte-identical. `origin/main` `9f0c84a448` was
merged as `bade176fff` (patch round 2), which carries `35d68c4c` (PR
objectstack-ai#10884, objectui#10758). That merge moved probed sources
(`objectql.zod.ts`, `objectql.ts`, `ChartRenderer.tsx`); the probes
re-ran at `50deccd71a`, byte-identical to round 1's head outputs.
Neither merge used a rebase or a force-push.
- **Patch round 2 (at-tier record `5864532186`, FAIL on one note).** The
7779 note said the renderer reads 20 members and leaves 44 unread. That
was true at `4f38f39286`, but PR objectstack-ai#10884 re-took the census to 43 / 21 on
`main`. Per the seat's decision (REWORK `5864543090`), the note now
states no figure. It says the split is no longer the 21 / 43 the entry
counted, names both changes that moved it (objectui#7928 and
objectui#10758), and cites the census pin in
`object-view-unmirrored-keys-7779.test.ts`, which re-derives the figures
on every run (`43 read + 21 unread = 64` at the head). No other note
moved.
- **The headline card.** Each note's headline names the card whose
change supersedes the sentence, as the PR objectstack-ai#10533 notes did. PR objectstack-ai#10828's
notes named their own card instead, because the cause there was a spec
release that has no pending entry.
- **Commit trailers are model-free** (`Co-Authored-By: Claude`), per the
dispatch. The harness offered a trailer that carries a model name, and
it was not used.

Implemented by a `domain:spec#1` dispatch (dev subagent). Session:
`https://claude.ai/code/session_014fWVhLzhxR8qrFsJ5o8TYW`.

---
_Generated by [Claude
Code](https://claude.ai/code/session_014fWVhLzhxR8qrFsJ5o8TYW)_

---------

Co-authored-by: Claude <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

2 participants