This repository was archived by the owner on Oct 26, 2026. It is now read-only.
Repository navigation
Commit 5262f7d
feat(types)!: an authored object-chart takes its props in the properties bag; the flat spelling is refused by name (objectui#11276) (#11328)
Part of #11276
Clause-②: yes (narrowing)
`Clause-②: yes (narrowing)`, copied from the PM claim `5924110462`:
`@object-ui/types`' authoring faces widen (a bag `object-chart` node
that is refused today parses) and narrow (a flat `object-chart` node
that parses today is refused). This is objectui's narrowing-as-`minor`
rule, with a **BREAKING (authoring)** banner in the changeset.
The `object-chart` batch of objectui#11276. It executes triage's routing
call A (`5921136804`) as released by the retriage answer (`5922517855`,
Q2: "the next claim's scope is `object-chart` only"), with the construct
of objectui#10859 batches 4 and 5 (PRs objectui#11291 and
objectui#11309). The card stays open: `object-grid` is the next batch,
and `flex` is with the maintainer as objectui#11300.
## What changed
- `packages/types/src/zod/objectql.zod.ts`: new
`ObjectChartBlockSchema`, the batch 4/5 construct: `BaseSchema` + the
`object-chart` literal + `NODE_ENVELOPE` + `properties` through the
shared `propsBag` helper, beside:
- one `aliasKeyRefusal` per bag member, keyed by the bag's own key set
(read off the bag, not transcribed), so each prop written flat is
refused on both faces with `Did you mean KEY → properties.KEY?` and one
prescription that shows the whole bag document;
- the three list-view spellings objectui#10608 retired (`xAxisField`,
`yAxisFields`, `aggregation`) keep the flat mirror's own retirement
tombstones when written flat (the same objects), so their remedy stays
the spec spelling rather than a pointer at a bag member that is itself
retired;
- `body` / `children`: the flat mirror's objectui#9256 refusals, by
reference;
- the chart-family floor (objectui#10770), read in the bag:
`requireObjectChartFamilyInBag` refuses a node naming neither
`properties.chartType` nor `properties.specType`, at
`properties.chartType`.
- **⛔ No spec row, and none invented.** Installed `@objectstack/spec`
17.5.0's `ComponentPropsMap` has no `object-chart` row, so the spec's
page component takes ANY bag on this type. The bag
(`ObjectChartPropsBag`) is therefore the flat `ObjectChartSchema`
mirror's OWN members by reference: its shape less the node-level keys
(`BaseSchema`'s and `NODE_ENVELOPE`'s, both read off their
declarations), each the same schema object the mirror holds. It is built
from the mirror's shape, not with `.omit()` on the mirror, because zod
refuses `.pick()` / `.omit()` on an object carrying a refinement. The
bag keeps the mirror's posture (`.passthrough()`), so an undeclared bag
key is judged exactly as it was on the flat node: unjudged by the
tolerant face, refused by name by the strict face. The code docblock and
the bag's `.describe()` say this.
- `packages/types/src/zod/public-blocks.zod.ts`: `propsBag` gains an
optional `description` argument for the one bag that is not a spec row,
so the arm does not describe itself as
`ComponentPropsMap['object-chart']`. Every other caller omits it and its
description is byte-identical.
- The arm joins `ObjectQLPublicBlockComponentSchema` (`object-chart` is
in `PUBLIC_BLOCKS`). `ObjectChartSchema` (the flat mirror) leaves
`ObjectQLComponentSchema` (10 to 9 arms), stays exported, and stays
paired with its TypeScript twin in the parity census.
- `packages/types/src/objectql.ts`: the TypeScript `ObjectChartSchema`
is **re-declared, not retired**. Members unchanged; its docblock now
says it is the node as `ObjectChart` reads it after `SchemaRenderer`
hoists `properties`, and as code composes it. The TypeScript union's
docblock names the zod union's new count.
- `packages/types/src/zod/index.zod.ts` (one barrel export) and
`packages/types/src/zod/README.md` (the ObjectQL public-block group
lists the arm, 6).
- New pin
`packages/types/src/__tests__/object-chart-properties-bag-11276.test.ts`
(58 rows plus a type-level block).
- One changeset, `.changeset/11276-object-chart-properties-bag.md`:
`@object-ui/types` minor, BREAKING (authoring) banner. No other released
package's source changes, so there is no second changeset.
**Files beyond the claimed surface, each forced:**
- census rows the new export forces: `zod-mirror-parity.test.ts` (one
`EXCLUSIONS` row; `EXPECTED_MIRROR_PAIRS` untouched),
`objectql-union-arms-7363.test.ts` (9 arms, `object-chart` not among
them), `registered-type-arms-10859-b2.test.ts` (the exact public-block
literal list gains `object-chart`),
`public-block-responsive-styles-10872.test.ts` (`object-chart` gets the
smallest family bag in `RECORD_SOURCE`, because the arm keeps the
floor), `flat-arm-responsive-styles-10872.test.ts` (the batch-9 flat
population is `flex` and `object-grid`; one row pins that the flat
mirror keeps the shared member as the post-hoist reading);
- fixture triage where a face now judges the bag (mirror rows keep the
post-hoist spelling; only door rows move):
`content-channel-e3-residual-9256.test.ts` (`AUTHORED_REQUIRED` gains
the chart), `object-chart-axis-config-10518.test.ts` (5 door rows and
the showcase lit control write the bag),
`object-chart-legacy-axis-keys-retired-10608.test.ts` (the door refuses
the retired key in the bag AND written flat; the remedy rows write the
bag), `object-chart-react-tier-node-10770.test.ts` (the door row reads
the wrapper's props in the bag), `strict-face-read-keys-11070.test.ts`
(the `dataSource` row writes its chart props in the bag; the row's
verdict is unchanged).
## Zone 1, measured before building
1. **The reason holds for this type.** Installed `@objectstack/spec`
17.5.0: `ComponentPropsMap` has no own `object-chart` property
(controls: `object-map` and `object-grid` have one).
`PageComponentSchema` refuses the flat node `{ type: 'object-chart',
chartType, objectName, aggregate }` with `unrecognized_keys` naming the
three ("Unrecognized key(s) on this page component … ADR-0089 D3a") and
accepts the same props in `properties`. Control: a flat `action:button`
`actionType` is refused the same way.
2. **Census, with the stop line.** At base `0c6f9bbd7`, `git grep -l
object-chart` gives 57 non-test files: 16 `CHANGELOG.md` and 16 pending
changesets (records, not producers) and 25 others. Seat 1's census
(`5922247963`) re-verified on this base:
| class | files | action |
|:--|:--|:--|
| authored page-node producers (any spelling) | **none** | nothing to
rewrite |
| runtime composers (build a flat node, render through `SchemaRenderer`,
never meet a zod face) | app-shell `views/ObjectView.tsx` (2 sites),
plugin-view `ObjectView.tsx` (2), plugin-list `ListView.tsx` (2),
plugin-dashboard `DashboardGridLayout.tsx` (1) and
`DashboardRenderer.tsx` (1); the react-page wrapper (`react-page.tsx`, a
comment hit; it composes by tag) | kept flat (they read the TypeScript
twin) |
| the declarations | `objectql.ts`, `objectql.zod.ts`,
`public-blocks.zod.ts` (comment + `propsBag`) | this change |
| names the type, no node shape | `register-plugins.ts`,
`known-schema-types.ts`, core `public-blocks.ts`,
`chart-category-key.ts`, plugin-charts `ObjectChart.tsx` / `index.tsx` /
`normalizeChartSchema.ts`, plugin-dashboard `ObjectMetricWidget.tsx` /
`index.tsx`, sdui-parser `parse.ts`, types `data-display.ts`,
`scripts/regenerate-known-schema-types.mjs`, `ROADMAP.md`,
`content/docs/guide/data-source.md` (a table row) | none |
| governed `skills/**` | `skills/objectui/guides/data-integration.md`,
`skills/objectui/guides/schema-expressions.md`: each names
`object-chart` in a prose list of `useDataScope` callers, no node |
listed, not rewritten (no producer) |
**Stop line: not tripped.** The zod `ObjectChartSchema` object has one
reader in objectui source, the `ObjectQLComponentSchema` union (plus the
barrel re-export); no schema is built from it (unlike `object-view`'s
`table` slot from `ObjectGridSchema`, the shape the `object-grid` batch
meets). Every non-page context that keeps the flat spelling depends on
the TypeScript twin (the composers, `ObjectChartProps.schema`,
`ObjectMetricWidget`'s aggregate type), which is unchanged.
3. **The arm**, as above. The TypeScript twin is re-declared, not
retired; nothing had to retire, so the `needs_decision` stop did not
fire.
4. **Producers:** zero objectui-authored flat `object-chart` page-node
producers to rewrite; zero governed producers (two governed prose hits,
listed above).
## Zone 2, re-measured
1. Held, by symbol: `ObjectChartSchema` is in `objectql.zod.ts`, its
twin in `objectql.ts`, `ObjectMapBlockSchema` (batch 5) in
`objectql.zod.ts`. The new arm sits right after the flat mirror it
reads, which also keeps it out of PR objectui#11312's hunks.
2. Held: 25 non-test files outside the CHANGELOG and changeset records.
3. PR objectui#11312 (objectui#11117) and PR objectui#11320 merged into
`main` at 2026-10-01T04:02Z, after this branch's commits and before this
PR opened. Together with `be5211522`, `main` has moved by three commits
since the base, and the last two touch `objectql.zod.ts`, `objectql.ts`,
`public-blocks.zod.ts` and `zod-mirror-parity.test.ts`. Their hunks are
disjoint from this diff's: GitHub reports the PR mergeable, and the
merge queue re-tests the merged tree.
## Tests (heavy runs through `os-verify-lock.sh`, slot `issue-11276`)
- **Red first** at the arm commit `a13229954` (before triage): `pnpm
exec vitest run packages/types/src/` gave `Tests 29 failed | 7663 passed
(7692)` in 10 files: exactly the census rows and door fixtures listed
above.
- **Green, union at the final head `03b6e0d98`:** `pnpm exec vitest run
packages/types/ packages/cli/` gave `Test Files 330 passed (330)`,
`Tests 8079 passed (8079)`, VERDICT command-exit 0.
- **Consumer sweep at `f1cd6ab70`** (the head before the README +
changeset commit): 234 tracked test files outside `packages/types` and
`packages/cli` that name `object-chart`, `plugin-charts`,
`ObjectChartSchema`, `ObjectChartBlockSchema`, `AnyComponentSchema`,
`StrictAnyComponentSchema`, `safeValidateSchema`,
`ObjectQLComponentSchema`, `ObjectQLPublicBlockComponentSchema`,
`PUBLIC_BLOCKS`, `getPublicConfigs`, `ComponentPropsMap`,
`KNOWN_SCHEMA_TYPES`, `nodeOracles` or the parity / strict-face /
handler-key ledgers, in three chunks: `79 passed / 2499 tests`, `73
passed / 787 tests`, `82 passed / 1576 tests`, each VERDICT 0. The later
commit changes only `README.md` and the changeset; the tests that read
the zod README are in `packages/types` and `scripts/__tests__`, both
re-run after it.
- **`scripts/__tests__/`** (a markdown file changed) at `03b6e0d98`:
`Test Files 177 passed | 2 skipped (179)`, `Tests 5371 passed | 2
skipped (5373)`, VERDICT 0. `node scripts/markdown-test-inputs.mjs
--audit`: "107 candidate test files, all adjudicated; 78 declared
entries, all present".
- **Type-check:** `pnpm --filter @object-ui/types type-check` (`tsc
--noEmit`, examples, `tsconfig.test.json`, which includes
`src/**/*.test.ts`), VERDICT 0. `@object-ui/types` has no workspace
dependency to build first.
- **Runtime ablation** (objectstack `scripts/ablation-replace.mjs`, two
nested WRAP legs plus an EXIT/INT/TERM trap, absolute paths): the flat
arm restored, i.e. `ObjectChartSchema` back into
`ObjectQLComponentSchema` (anchor x1 to x0, blob `ec019f61` to
`0bc58a72`) and `ObjectChartBlockSchema` out of the public-block union
(anchor x1 to x0, blob to `fb03dd31`); on disk, `ObjectChartSchema,` x1
in the ObjectQL union and `ObjectChartBlockSchema,` x0 in the public
one. Over 14 files (the new pin, the 10 triaged and census files, and
three untouched chart and bag pins as controls): `Tests 66 failed | 651
passed (717)`. Red: 43 rows of the new pin and 23 triaged or census rows
(10608 12, 10518 3, 9256 2, 10872-batch-9 2, and one each in 10770,
7363, b2 and 11070), which is exactly the set this diff added or
changed. Green: the untouched pins (`object-chart-undeclared-keys-8885`,
`widget-schema-anchors-7946`, `object-map-properties-bag-10859-b5`), the
census files whose subject is the export itself, and the pin's 15 rows
that do not depend on which arm the union selects (the spec lit
controls, the bag's key set and member identity, its description, and
the refusals the flat mirror shares). Direction red, as expected.
Restored: blob == HEAD `ec019f61`, `git diff HEAD` empty. Vitest imports
the zod sources relatively, so no build sat between the mutation and the
run.
- **Type-level reverse validation** (same tool): the bag's
`.omit(OBJECT_CHART_NODE_LEVEL_KEYS)` widened to also drop `dataset`
made `tsc -p tsconfig.test.json` exit 2 with exactly one error, `TS2344:
Type 'false' does not satisfy the constraint 'true'` on the pin's `keyof
Bag` row. Restored, blob == HEAD.
- **Render identity** (a one-time probe through the real
`SchemaRenderer` and registry, not committed): the bag node `{ type:
'object-chart', properties: { objectName, chartType, aggregate, filter,
title } }` makes the same data-source calls as the flat node with the
same props and draws an identical DOM; control: a bag naming another
object makes different calls. `Tests 1 passed (1)`.
## Gates (exit codes captured before any pipe)
- exit 0: `node scripts/check-changeset-presence.mjs` ("16 source
file(s) of 1 released package(s) changed, and this change declares 1
changeset(s)"), `changeset:check` ("No changeset declares a `major`
bump."), `check:control-bytes` ("OK (scanned 9793 tracked text file(s);
skipped 85 binary)"), `check:new-line-citations` ("VERDICT
new-cross-file-line-citations: 0 new citation(s)"),
`check:handler-key-reads` ("OK 140 arm(s), 212 registration(s) (138
keyed onto an arm), 56 reachable handler read(s), 56 judged"),
`check:spec-symbols`, `check:element-data-source-declaration`,
`check:component-surface-parity`, `check:doc-types`,
`check:prompt-keys`, `check:test-path-roots`,
`check:installed-pin-claims`, `check:vi-mock-specifiers`,
`check:pending-changeset-literals`, `check:changeset-claims`
(report-only), `docs:check-links`, `check:governed-queue-guard`, and
`check-governed-queue-guard.mjs --test` over the 17 changed paths ("NOT
GOVERNED").
- `pnpm exec eslint` on the 15 changed source and test files: 0 errors,
37 warnings, all `no-explicit-any` on lines this diff does not touch.
- **NOT MEASURED** (PREREQUISITE NOT MET: the packages they import are
not built in this worktree, so each refused to run, exit 2 or a
collapsed population): `check:readme-exports`, `check:doc-snippets`,
`check:doc-examples`, `check:skill-examples`,
`check:sdui-registration-pins`. This diff changes no fenced block in any
README, doc or skill. Left to CI, which builds first.
- Not run locally: the repo-wide `pnpm lint` and the full `pnpm test`
farm (CI's).
## Acceptance notes
- **`data` stays a node-level `BaseSchema` key on this arm**, as on
every arm. `ObjectChart` reads `schema.data` (inline rows) and the
registration's `inputs` list `data`, but neither the mirror nor the
TypeScript twin declares it as a chart member, so it is not in the bag:
a flat `data` passes both objectui faces (the spec's page component
refuses it at node level), and `properties.data` passes the tolerant
face unjudged and is refused by the strict face. Whether `data` is a
chart member is a declaration decision this card did not take. Noted,
not filed; no carrier.
- **`dataSource` stays undeclared on `object-chart`**, on the bag arm as
on the flat mirror, as objectui#11070 left it ("refused by name until it
is declared"). The registration is gate-wrapped and reads the binding.
- **The mirror's INTERNAL members ride into the bag with it**
(`xAxisKey`, the `{ dataKey }` series arm, `specType`): the bag is the
mirror's members, so they are judged in the bag exactly as they were
judged flat. No member's verdict changed; only its layer.
- **The same release's pending changesets** `10518`, `10608`, `10770`
and `10872-flat-arm-responsive-styles` describe validator readings on a
flat `object-chart`; this PR's changeset says those readings now happen
in the bag on an authored node and still hold on the flat mirror (the
batch-5 precedent). They are not edited.
- **No render pin is committed**: the renderer half is
`SchemaRenderer`'s generic hoist, already pinned for the earlier bag
arms; the one-time probe above measured it for this type.
## Overlap
PR objectui#11312 (merged first) edited other regions of
`objectql.zod.ts`, `objectql.ts`, `public-blocks.zod.ts` and
`zod-mirror-parity.test.ts`. The hunks are disjoint, and this PR lands
through the merge queue, which tests the merged tree.
Session: `https://claude.ai/code/session_011p7ikEivgXefNDaE5S5Uec` (the
dispatching seat's id; this run is its subagent on branch
`claude/issue-11276-object-chart-properties-bag`).
---
_Generated by [Claude
Code](https://claude.ai/code/session_011p7ikEivgXefNDaE5S5Uec)_
---------
Co-authored-by: Claude <noreply@anthropic.com>1 parent 95bd23c commit 5262f7d
17 files changed
Lines changed: 781 additions & 50 deletions
File tree
- .changeset
- packages/types/src
- __tests__
- zod
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
126 | 126 | | |
127 | 127 | | |
128 | 128 | | |
| 129 | + | |
| 130 | + | |
129 | 131 | | |
130 | 132 | | |
131 | 133 | | |
| |||
134 | 136 | | |
135 | 137 | | |
136 | 138 | | |
137 | | - | |
138 | | - | |
139 | | - | |
140 | | - | |
| 139 | + | |
| 140 | + | |
| 141 | + | |
| 142 | + | |
141 | 143 | | |
142 | 144 | | |
143 | 145 | | |
144 | 146 | | |
| 147 | + | |
145 | 148 | | |
146 | 149 | | |
147 | 150 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
31 | 31 | | |
32 | 32 | | |
33 | 33 | | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
34 | 41 | | |
35 | 42 | | |
36 | 43 | | |
| |||
122 | 129 | | |
123 | 130 | | |
124 | 131 | | |
125 | | - | |
126 | | - | |
127 | | - | |
| 132 | + | |
| 133 | + | |
| 134 | + | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
128 | 138 | | |
129 | 139 | | |
130 | 140 | | |
131 | 141 | | |
132 | | - | |
133 | 142 | | |
134 | 143 | | |
135 | 144 | | |
| |||
161 | 170 | | |
162 | 171 | | |
163 | 172 | | |
164 | | - | |
165 | | - | |
166 | | - | |
167 | | - | |
168 | | - | |
169 | | - | |
170 | | - | |
171 | | - | |
172 | | - | |
173 | 173 | | |
174 | 174 | | |
175 | 175 | | |
| |||
220 | 220 | | |
221 | 221 | | |
222 | 222 | | |
223 | | - | |
| 223 | + | |
224 | 224 | | |
225 | 225 | | |
226 | 226 | | |
227 | 227 | | |
228 | 228 | | |
229 | 229 | | |
| 230 | + | |
| 231 | + | |
| 232 | + | |
| 233 | + | |
| 234 | + | |
| 235 | + | |
| 236 | + | |
230 | 237 | | |
231 | 238 | | |
232 | 239 | | |
233 | 240 | | |
234 | 241 | | |
235 | 242 | | |
236 | 243 | | |
237 | | - | |
| 244 | + | |
238 | 245 | | |
239 | 246 | | |
240 | 247 | | |
| |||
282 | 289 | | |
283 | 290 | | |
284 | 291 | | |
285 | | - | |
| 292 | + | |
286 | 293 | | |
287 | 294 | | |
288 | 295 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
73 | 73 | | |
74 | 74 | | |
75 | 75 | | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
76 | 83 | | |
77 | 84 | | |
78 | 85 | | |
| |||
124 | 131 | | |
125 | 132 | | |
126 | 133 | | |
| 134 | + | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
127 | 140 | | |
128 | 141 | | |
129 | 142 | | |
| |||
200 | 213 | | |
201 | 214 | | |
202 | 215 | | |
203 | | - | |
| 216 | + | |
204 | 217 | | |
205 | 218 | | |
206 | 219 | | |
| |||
220 | 233 | | |
221 | 234 | | |
222 | 235 | | |
223 | | - | |
| 236 | + | |
224 | 237 | | |
225 | 238 | | |
226 | 239 | | |
227 | 240 | | |
228 | 241 | | |
229 | 242 | | |
230 | | - | |
| 243 | + | |
231 | 244 | | |
232 | 245 | | |
233 | 246 | | |
| |||
343 | 356 | | |
344 | 357 | | |
345 | 358 | | |
346 | | - | |
| 359 | + | |
347 | 360 | | |
348 | 361 | | |
349 | 362 | | |
| |||
363 | 376 | | |
364 | 377 | | |
365 | 378 | | |
366 | | - | |
| 379 | + | |
367 | 380 | | |
368 | 381 | | |
369 | 382 | | |
| |||
388 | 401 | | |
389 | 402 | | |
390 | 403 | | |
391 | | - | |
| 404 | + | |
392 | 405 | | |
393 | 406 | | |
394 | 407 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
65 | 65 | | |
66 | 66 | | |
67 | 67 | | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
68 | 75 | | |
69 | 76 | | |
70 | 77 | | |
| |||
102 | 109 | | |
103 | 110 | | |
104 | 111 | | |
105 | | - | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
106 | 120 | | |
107 | 121 | | |
108 | | - | |
| 122 | + | |
109 | 123 | | |
110 | 124 | | |
111 | 125 | | |
| |||
130 | 144 | | |
131 | 145 | | |
132 | 146 | | |
133 | | - | |
| 147 | + | |
134 | 148 | | |
135 | 149 | | |
136 | 150 | | |
137 | 151 | | |
138 | | - | |
| 152 | + | |
139 | 153 | | |
140 | 154 | | |
141 | 155 | | |
| |||
0 commit comments