@object-ui/plugin-charts 17.6.0 → 18.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,3259 @@
1
1
  # @object-ui/plugin-charts
2
2
 
3
+ ## 18.0.0
4
+
5
+ ### Dependency floors
6
+
7
+ Computed from `.objectstack-sha` `06cab4849a8a`: the earliest published `@objectstack/spec` that contains it is `18.0.0`.
8
+
9
+ - `@objectstack/spec` (`devDependencies`): `^18.0.0-next.1` → `^18.0.0`
10
+
11
+ ### Major Changes
12
+
13
+ - 6f3299f: objectui moves to major 18, following `@objectstack/*` from 17 to 18 (objectui#12334). objectui's major is not a count of its own breaking changes: it tracks the major of the `@objectstack/spec` its packages depend on, so that the same major means compatible across the two projects. These packages already declare `@objectstack/*` on the 18 line (objectui#12030), so every package in the fixed release group crosses to 18 together. It is the one `major` that rule admits: objectui's own breaking changes ship as `minor`, described in their entries.
14
+
15
+ The 18 line is released from Changesets pre mode on the `next` tag (`.changeset/pre.json`), as `@objectstack/*` 18 is: these releases are `18.0.0-next.N` on the npm `next` dist-tag, and they do not move `latest`. The first `18.0.0` on `latest` comes when `@objectstack` 18 is generally available and this repository leaves pre mode.
16
+
17
+ What a consumer must do to take it is in the `@objectstack/*` 18 entry of this release (objectui#12030): move its own `@objectstack/*` packages to the 18 line at the same time.
18
+
19
+ ### Minor Changes
20
+
21
+ - fd060f0: The `object-chart` and `view:chart` registrations no longer declare `objectName`
22
+ required, so the page compile accepts a node whose `dataSource` binding names the
23
+ object, and a chart that names its object in neither place shows a hint instead
24
+ of an empty frame (objectui#11605).
25
+
26
+ `object-chart` has no spec row. The binding doc says a node bound by
27
+ `dataSource.object` needs no `objectName` of its own, and the renderer agrees:
28
+ `dataSource.object` lands on `objectName` before the chart reads the node. The
29
+ registrations still declared `required: true`, and the page compile reads them,
30
+ so a bound chart with no `objectName` of its own was refused with
31
+ `missing-required-prop` and the save failed.
32
+
33
+ **Clause-②: yes (widening)** — an `object-chart` (or `view:chart`) node that
34
+ names its object through `dataSource.object` and sets no `objectName` now
35
+ compiles and saves. A node that names its object in neither place also compiles
36
+ now, and the chart shows "No object named: set objectName or dataSource.object."
37
+ where it used to draw an empty frame with no message. A chart with inline
38
+ `data`, a `dataset` or a `bind` path shows no hint and renders as before. The
39
+ published `objectName` inputs now carry a description that says the binding can
40
+ supply them.
41
+ - 96fcf30: **Clause-②: yes (an export widens, and an accept set narrows)**
42
+
43
+ A chart's value axis over a count now draws whole-number ticks (objectui#11681). Dashboard charts over a `count` measure ("Tasks by Status", "Projects by Health", "Invoices by Month") used to read 0.5, 0.8, 1.5 or 2.3 on their value axis. The dataset answer states each measure column's aggregate (`fields[].aggregate`, from `@objectstack/spec` 18). The chart now carries it to the axis, and an axis whose series all plot `count` or `count_distinct` sets `allowDecimals: false`. Any other measure on the axis keeps the previous ticks, so a sum over currency keeps its decimals. Every cartesian value axis is covered, including the horizontal-bar value axis that runs across the plot. Each side of a dual-axis chart decides for itself.
44
+
45
+ - `@object-ui/core` (widens): `buildChartSeries` copies a result field's `aggregate` onto the series it derives. `ChartResultField` and `ChartSeriesBinding` gain an optional `aggregate`. `INTEGER_AGGREGATES` and `isIntegerAggregate` are new exports.
46
+ - `@object-ui/plugin-dashboard`: the dataset widget keeps the aggregate on the series it builds. That includes the comparison overlay and the series a dimensionless chart transposes, which states an aggregate only when every measure shares it.
47
+ - `@object-ui/plugin-charts` (widens): the `dataKey` arm of `ChartRendererProps.schema.series` and `NormalizedSeries` (carried by the exported `NormalizedChartSchema`) gain an optional `aggregate`, read by `normalizeSeries`. The accept set only widens: nothing that compiled before is refused. The member is renderer-internal.
48
+ - `@object-ui/types` (narrows): `aggregate` on a chart series is refused by name. FROM: `ChartDataSeriesSchema` (and so `ChartSchema.series[]`) accepted `{ name, aggregate: 'count' }` and stripped the key. TO: it refuses that series with an `invalid_type` issue at `aggregate`, and `ChartDataSeries.aggregate` is typed `?: never`. The key is internal: declare the aggregate on the dataset measure instead.
49
+
50
+ ### Patch Changes
51
+
52
+ - 82500a7: Rotated x-axis labels fit inside the chart, and the dashboard inspector's Layout fields are readable (objectui#11796).
53
+
54
+ - **Rotated category labels are no longer cut off.** When a bar, line or area chart turns its x-axis labels to fit them, each label hangs its start away from the plot. The axis used to reserve a fixed 60px for them, which counted the text width alone, so the longest labels ran past it and the chart cut off their first letters ("acklog" for Backlog, "ogress" for In Progress on a dashboard bar chart). The axis now reserves the room its longest drawn label needs at the rotation angle: more for long labels, less for short ones, with a wide glyph (Chinese, Japanese, Korean) counted a full em. Every rotated label is now shortened with an ellipsis past 12 characters, also on axes with more than five categories, where a long label used to be clipped mid-word instead. The full name stays on the bar's tooltip. Charts whose labels do not rotate keep the axis height they had.
55
+ - **The dashboard inspector stacks its fields.** Studio's dashboard inspector is a narrow side panel, and the dashboard form's Layout section put Columns, Gap and Refresh Interval Seconds in three columns there: a two-digit value showed one digit and the labels wrapped onto several lines. The inspector now renders every section of the form in one column, in the declared field order. Other forms keep the column layout their sections declare.
56
+
57
+ Nothing is added to either package entry: no export, prop, type member or language-pack key.
58
+ - d03b022: `ObjectChart` decides its missing-category-axis refusal before it fetches, so a chart that refuses reads nothing (objectui#12061).
59
+
60
+ The refusal (`chart-missing-category-axis`, objectui#8168) is drawn when an object-bound chart declares no category by any spelling (`aggregate.groupBy`, `xAxisKey`, `xAxis.field`). It was a render-time return only: the fetch ran anyway, issuing the object's `find` with no `$top` (or `aggregate` with no `groupBy`), and the rows were then discarded. Since objectui#6152 round 15, every chart list view that names no `dataset` composes that node, so each render of such a view paid for the read.
61
+
62
+ Now the refusal and the fetch read one value. A refused chart issues no `find`, no `aggregate` and no comparison query, and a data-invalidation event for its object does not start one. The refusal's code, `role="alert"` and wording are unchanged, and it is still the first paint, with no loading skeleton before it. A chart with a category fetches exactly as before. A chart that is refused at mount and later given a category (for example, a spec `xAxis` added in a designer preview) fetches at that point.
63
+ - 1e6d83b: Data-bound blocks title their "data source could not be resolved" panel in the page's language (objectui#12920, the family of objectui#12910). The panel shows when a block's `dataSource.view` names a view its object does not have. Each block's title now reads `@object-ui/i18n` through `useObjectTranslation`, with the `en` pack's value as the inline default, so a page with no `I18nProvider` draws the same English it drew before.
64
+
65
+ - **Plugin blocks.** `object-calendar`, `object-chart`, `object-metric`, `object-pivot`, `detail-view`, `record:related_list`, `object-form`, `embeddable-form`, `object-master-detail-form`, `record:line_items`, `object-gantt`, `object-grid`, `object-kanban`, `list-view`, `object-map` and `object-timeline` read one `element.KIND.sourceUnresolved` key per block kind. `object-metric` reads `element.number.sourceUnresolved`, the key `element:number` already reads for the same sentence. The three forms share `element.form.sourceUnresolved`. `record:related_list`'s panel for a failed `parentDataSource` read reads `element.relatedList.parentUnreadable` ("This related list’s parent record could not be read").
66
+ - **`@object-ui/react` panel defaults.** `ElementDataSourceErrorPanel` with no `title` reads `element.component.sourceUnresolved`, and `NoDataSourcePanel` with no `title` reads `element.component.noDataSource`. A passed `title` still wins, an empty string included. Props and markup do not change.
67
+
68
+ Clause-②: yes
69
+
70
+ The new keys in `@object-ui/i18n` widen its exported `TranslationKeys`. No prop, input or export of these packages changes.
71
+ - 988aa9f: Charts and dataset widgets read their object's metadata through the data source, so the widgets of one dashboard ask for one object's metadata once (objectui#13039).
72
+
73
+ The chart's category colours and dimension labels come from the bound object's field options. It read them with its own request to `/api/v1/meta/object/NAME`, outside the data source's metadata cache, so every chart over one object sent one more request for the same document. The chart now reads it through the data source's `getObjectSchema` when one is in scope: the read that its own group-by labels, the metric tile and the data table already use, and that the ObjectStack adapter joins while it is in flight. With no data source, or one that cannot answer `getObjectSchema`, the chart reads the document directly as before.
74
+
75
+ The dataset label hook in `@object-ui/react` (`useDatasetDimensionMeta`, behind `useDatasetDimensionLabels`) made the same per-widget request, one for every non-metric dataset widget on a dashboard and for the dataset report block. It now reads through the `SchemaRendererProvider`'s data source in the same way when that source answers `getObjectSchema`, and reads the document directly otherwise.
76
+
77
+ Colours, labels and dotted dimension paths resolve as they did. Nothing is added to the package entry.
78
+ - 5115c1f: Advanced chart axis tick labels now use the theme's muted foreground instead of recharts' default `#666`, so they stay readable on dark cards (objectui#13129). Every axis the advanced chart draws, cartesian and polar, shares one tick style.
79
+ - 9a4ddb2: A category x axis rotates its labels, and cuts them at 12 characters, only when the measured band cannot hold them (objectui#13241). A full-width bar chart now draws a name such as "Needs Analysis" whole and horizontal instead of "Needs Analy…"; a narrow widget whose labels do not fit keeps rotating and cutting them, with the full name on the bar's tooltip. Until the chart's width is measured, the length rule applies as before.
80
+ - 0253416: feat(plugin-list)!: a chart list view binds only an ADR-0021 `dataset`; the legacy inline chart axes and their `name` / `value` floors are retired on every route (objectui#6152, round 15)
81
+
82
+ Clause-②: no
83
+
84
+ **Changed (breaking for a stored chart view that names no `dataset`).** Every door refuses the
85
+ pre-ADR-0021 chart axes on a list view: `@objectstack/spec`'s chart block is a strict object of
86
+ `chartType`, `dataset`, `dimensions` and `values`, and `@object-ui/types`, `objectui validate` and the
87
+ platform's view write door judge by it, top-level and in the `options` bag. The renderers kept
88
+ reading the axes, so a chart view stored before the doors closed still drew an inline aggregate, and
89
+ a chart view that declared nothing was drawn from the invented fields `name` and `value`. They no
90
+ longer do, on every route that did: `ListView`'s chart branch and its capability gate, the object
91
+ page's chart view (`@object-ui/app-shell`) and `ObjectView`'s own views (`@object-ui/plugin-view`).
92
+
93
+ | stored chart block (either nesting) | what renders now | write instead |
94
+ | :--- | :--- | :--- |
95
+ | `xAxisField` / `categoryField`, `yAxisFields` / `valueField`, `aggregation` (and, on the object page, `series` and `filter` on the block) | the chart's refusal: "Chart category axis required", in place of the chart; a view of another type no longer offers Chart in its view switcher | `chart: { dataset, values, dimensions }`, naming an ADR-0021 dataset of the object |
96
+ | no binding at all on a view whose `viewType` is `chart` | the same refusal, where a chart grouped by `name` and counting `value` used to draw | the same dataset block |
97
+
98
+ A dataset-bound chart renders as before. The refusal is `ObjectChart`'s own screen for an object-bound
99
+ chart that names no category axis (objectui#8168); its remedy names that component's keys, not the
100
+ list view's dataset block.
101
+
102
+ **Not measured: production.** The census before this change (objectui#6152 round 13) found no writer
103
+ and no stored row carrying these axes in any repository corpus a seat can reach, with positive
104
+ controls; this repository's create-view dialog writes the dataset block. Stored view and page
105
+ metadata in deployments was not measured. A row that carries the axes renders the refusal until it is
106
+ re-saved with a dataset block.
107
+
108
+ - `@object-ui/plugin-view`: an `ObjectView` kanban view no longer reads `kanban.conditionalFormatting`.
109
+ The list view's kanban block does not declare it, and every door that judges the block refuses it
110
+ by name; the view's own `conditionalFormatting` is the one place it is read. The development-only
111
+ flat-key warning no longer names `dateField`, `groupBy`, `groupField`, `imageField` or
112
+ `subtitleField`, which it told an author to move into a block that refuses them.
113
+ - `@object-ui/app-shell`: the object page's development-only flat-key warning no longer names the
114
+ twelve keys every per-kind block refuses (among them `groupField`, `imageField`, `cardFields`,
115
+ `xAxisField`, `yAxisFields`, `aggregation` and `series`).
116
+ - `@object-ui/plugin-charts`, `@object-ui/types`: comments only, where they said the list-view relays
117
+ still read the legacy axes.
118
+ - Updated dependencies [18d7b48]
119
+ - Updated dependencies [172acc3]
120
+ - Updated dependencies [f0496bd]
121
+ - Updated dependencies [c4c506b]
122
+ - Updated dependencies [9db9ff3]
123
+ - Updated dependencies [c096f03]
124
+ - Updated dependencies [d92b2a1]
125
+ - Updated dependencies [92f4e2b]
126
+ - Updated dependencies [b10c68e]
127
+ - Updated dependencies [bdc9049]
128
+ - Updated dependencies [e8c0b96]
129
+ - Updated dependencies [b92329c]
130
+ - Updated dependencies [2e818d0]
131
+ - Updated dependencies [fd060f0]
132
+ - Updated dependencies [fd060f0]
133
+ - Updated dependencies [8b14aec]
134
+ - Updated dependencies [2abec3a]
135
+ - Updated dependencies [9dfaca6]
136
+ - Updated dependencies [c000398]
137
+ - Updated dependencies [73b5d77]
138
+ - Updated dependencies [7b17705]
139
+ - Updated dependencies [fc3c2cc]
140
+ - Updated dependencies [f9f4a62]
141
+ - Updated dependencies [848ba0e]
142
+ - Updated dependencies [57d82cb]
143
+ - Updated dependencies [de96f3d]
144
+ - Updated dependencies [9ca3cac]
145
+ - Updated dependencies [c910630]
146
+ - Updated dependencies [ce464d9]
147
+ - Updated dependencies [e6dcd85]
148
+ - Updated dependencies [96fcf30]
149
+ - Updated dependencies [7a2c60b]
150
+ - Updated dependencies [834c559]
151
+ - Updated dependencies [22b503c]
152
+ - Updated dependencies [9fc68aa]
153
+ - Updated dependencies [d50f724]
154
+ - Updated dependencies [17acfbb]
155
+ - Updated dependencies [6be0f7a]
156
+ - Updated dependencies [89cc738]
157
+ - Updated dependencies [c0862c1]
158
+ - Updated dependencies [c0862c1]
159
+ - Updated dependencies [c0862c1]
160
+ - Updated dependencies [c0862c1]
161
+ - Updated dependencies [c0862c1]
162
+ - Updated dependencies [c0862c1]
163
+ - Updated dependencies [ded4494]
164
+ - Updated dependencies [d172f63]
165
+ - Updated dependencies [4c0de52]
166
+ - Updated dependencies [a80fef7]
167
+ - Updated dependencies [3bf8894]
168
+ - Updated dependencies [e06365c]
169
+ - Updated dependencies [1e1f09e]
170
+ - Updated dependencies [455c646]
171
+ - Updated dependencies [f34e877]
172
+ - Updated dependencies [f34e877]
173
+ - Updated dependencies [9844bbf]
174
+ - Updated dependencies [cef0eee]
175
+ - Updated dependencies [7ebff39]
176
+ - Updated dependencies [054fd84]
177
+ - Updated dependencies [5275d1f]
178
+ - Updated dependencies [7241a81]
179
+ - Updated dependencies [74add0c]
180
+ - Updated dependencies [aaba865]
181
+ - Updated dependencies [f1781be]
182
+ - Updated dependencies [fbad078]
183
+ - Updated dependencies [45d5853]
184
+ - Updated dependencies [4f4fc03]
185
+ - Updated dependencies [2312bd9]
186
+ - Updated dependencies [6d5eb34]
187
+ - Updated dependencies [c5406c2]
188
+ - Updated dependencies [c5406c2]
189
+ - Updated dependencies [d99b731]
190
+ - Updated dependencies [2571a3e]
191
+ - Updated dependencies [2a48bd4]
192
+ - Updated dependencies [8a55f0c]
193
+ - Updated dependencies [c7b30bd]
194
+ - Updated dependencies [20c6d35]
195
+ - Updated dependencies [417e245]
196
+ - Updated dependencies [69bca0a]
197
+ - Updated dependencies [023f00d]
198
+ - Updated dependencies [158c75d]
199
+ - Updated dependencies [7525045]
200
+ - Updated dependencies [5af42db]
201
+ - Updated dependencies [ce991bd]
202
+ - Updated dependencies [3c0f806]
203
+ - Updated dependencies [1071393]
204
+ - Updated dependencies [5f75cfa]
205
+ - Updated dependencies [6757a93]
206
+ - Updated dependencies [b7cd5c8]
207
+ - Updated dependencies [5330038]
208
+ - Updated dependencies [c9fc10b]
209
+ - Updated dependencies [dc6d28e]
210
+ - Updated dependencies [c0c2f79]
211
+ - Updated dependencies [0665c3b]
212
+ - Updated dependencies [d2500d8]
213
+ - Updated dependencies [e723f58]
214
+ - Updated dependencies [82bb1d5]
215
+ - Updated dependencies [f3d5408]
216
+ - Updated dependencies [b231607]
217
+ - Updated dependencies [b231607]
218
+ - Updated dependencies [466a219]
219
+ - Updated dependencies [6fb281d]
220
+ - Updated dependencies [54159d3]
221
+ - Updated dependencies [fa778e6]
222
+ - Updated dependencies [334f0cf]
223
+ - Updated dependencies [c08c933]
224
+ - Updated dependencies [92f979d]
225
+ - Updated dependencies [c4dd707]
226
+ - Updated dependencies [c4dd707]
227
+ - Updated dependencies [7578323]
228
+ - Updated dependencies [38bb373]
229
+ - Updated dependencies [923504f]
230
+ - Updated dependencies [5c2982a]
231
+ - Updated dependencies [97e7d4e]
232
+ - Updated dependencies [10aba37]
233
+ - Updated dependencies [5d3f437]
234
+ - Updated dependencies [51c661e]
235
+ - Updated dependencies [7af0ab3]
236
+ - Updated dependencies [b434f5f]
237
+ - Updated dependencies [9f282ef]
238
+ - Updated dependencies [fd4872f]
239
+ - Updated dependencies [f0532d8]
240
+ - Updated dependencies [cea429b]
241
+ - Updated dependencies [3092aca]
242
+ - Updated dependencies [82e5f53]
243
+ - Updated dependencies [d81e460]
244
+ - Updated dependencies [8106db1]
245
+ - Updated dependencies [068a540]
246
+ - Updated dependencies [ca45c6d]
247
+ - Updated dependencies [093d55b]
248
+ - Updated dependencies [b64fda3]
249
+ - Updated dependencies [a8051d6]
250
+ - Updated dependencies [72594f2]
251
+ - Updated dependencies [524136e]
252
+ - Updated dependencies [2b06a91]
253
+ - Updated dependencies [6f3299f]
254
+ - Updated dependencies [065a1cf]
255
+ - Updated dependencies [f2b17c6]
256
+ - Updated dependencies [52d6194]
257
+ - Updated dependencies [23bf859]
258
+ - Updated dependencies [1c72d77]
259
+ - Updated dependencies [2b4d3f1]
260
+ - Updated dependencies [d75f212]
261
+ - Updated dependencies [37db09f]
262
+ - Updated dependencies [ff9df88]
263
+ - Updated dependencies [70e843f]
264
+ - Updated dependencies [caac3b2]
265
+ - Updated dependencies [a2225f9]
266
+ - Updated dependencies [5c4deb5]
267
+ - Updated dependencies [a8e5b73]
268
+ - Updated dependencies [d9d9d98]
269
+ - Updated dependencies [c950345]
270
+ - Updated dependencies [21f9577]
271
+ - Updated dependencies [044f231]
272
+ - Updated dependencies [f8267df]
273
+ - Updated dependencies [9b82ced]
274
+ - Updated dependencies [3821a3a]
275
+ - Updated dependencies [3eb3ec1]
276
+ - Updated dependencies [92c2a69]
277
+ - Updated dependencies [646caea]
278
+ - Updated dependencies [1ffd6a2]
279
+ - Updated dependencies [5f8ecf6]
280
+ - Updated dependencies [8ed7e5a]
281
+ - Updated dependencies [6c4d00d]
282
+ - Updated dependencies [db8ce2f]
283
+ - Updated dependencies [726d8c9]
284
+ - Updated dependencies [f0e760a]
285
+ - Updated dependencies [a5bb7ac]
286
+ - Updated dependencies [f78efdd]
287
+ - Updated dependencies [8a8bcf3]
288
+ - Updated dependencies [f74638c]
289
+ - Updated dependencies [ef71a09]
290
+ - Updated dependencies [8614705]
291
+ - Updated dependencies [619e3f7]
292
+ - Updated dependencies [ca7a4c3]
293
+ - Updated dependencies [c9e6742]
294
+ - Updated dependencies [f62b6ff]
295
+ - Updated dependencies [608033b]
296
+ - Updated dependencies [611566b]
297
+ - Updated dependencies [efa9cb4]
298
+ - Updated dependencies [d66d7e8]
299
+ - Updated dependencies [15d8ca6]
300
+ - Updated dependencies [378896d]
301
+ - Updated dependencies [9d857c9]
302
+ - Updated dependencies [670ea10]
303
+ - Updated dependencies [ff215d9]
304
+ - Updated dependencies [71243db]
305
+ - Updated dependencies [a8add5c]
306
+ - Updated dependencies [33ee9de]
307
+ - Updated dependencies [4839f5c]
308
+ - Updated dependencies [a23e804]
309
+ - Updated dependencies [c7462e7]
310
+ - Updated dependencies [36e2f7b]
311
+ - Updated dependencies [ac59073]
312
+ - Updated dependencies [44cb469]
313
+ - Updated dependencies [e058d76]
314
+ - Updated dependencies [c999d4c]
315
+ - Updated dependencies [8df2608]
316
+ - Updated dependencies [5483297]
317
+ - Updated dependencies [ed43c79]
318
+ - Updated dependencies [260ef71]
319
+ - Updated dependencies [655e897]
320
+ - Updated dependencies [655e897]
321
+ - Updated dependencies [8d80845]
322
+ - Updated dependencies [69a408f]
323
+ - Updated dependencies [d2b21a1]
324
+ - Updated dependencies [5ff64ef]
325
+ - Updated dependencies [64acb7e]
326
+ - Updated dependencies [4ff5b6b]
327
+ - Updated dependencies [473e5a0]
328
+ - Updated dependencies [b279016]
329
+ - Updated dependencies [bb6c38c]
330
+ - Updated dependencies [26323c4]
331
+ - Updated dependencies [9753811]
332
+ - Updated dependencies [2727527]
333
+ - Updated dependencies [3da39ae]
334
+ - Updated dependencies [bc281f4]
335
+ - Updated dependencies [d637be3]
336
+ - Updated dependencies [2cfdc99]
337
+ - Updated dependencies [2cfdc99]
338
+ - Updated dependencies [1e6d83b]
339
+ - Updated dependencies [1e6d83b]
340
+ - Updated dependencies [6058bf8]
341
+ - Updated dependencies [c219165]
342
+ - Updated dependencies [a7ae252]
343
+ - Updated dependencies [fb501bc]
344
+ - Updated dependencies [30083da]
345
+ - Updated dependencies [7f9cc37]
346
+ - Updated dependencies [025130c]
347
+ - Updated dependencies [76f91f8]
348
+ - Updated dependencies [ea34d9b]
349
+ - Updated dependencies [8aa8e3e]
350
+ - Updated dependencies [024b7b6]
351
+ - Updated dependencies [cb80001]
352
+ - Updated dependencies [909c64e]
353
+ - Updated dependencies [9e7e1a5]
354
+ - Updated dependencies [2493e85]
355
+ - Updated dependencies [d0b9648]
356
+ - Updated dependencies [46dbf32]
357
+ - Updated dependencies [a928aaa]
358
+ - Updated dependencies [47508f3]
359
+ - Updated dependencies [61ed5ad]
360
+ - Updated dependencies [1b94d50]
361
+ - Updated dependencies [6f877f1]
362
+ - Updated dependencies [988aa9f]
363
+ - Updated dependencies [1ce0711]
364
+ - Updated dependencies [fb85637]
365
+ - Updated dependencies [9f1dd79]
366
+ - Updated dependencies [df71568]
367
+ - Updated dependencies [d11174a]
368
+ - Updated dependencies [2d8a8b7]
369
+ - Updated dependencies [cbac9d7]
370
+ - Updated dependencies [9eb1479]
371
+ - Updated dependencies [74e37aa]
372
+ - Updated dependencies [961b69f]
373
+ - Updated dependencies [52907d7]
374
+ - Updated dependencies [f466b0a]
375
+ - Updated dependencies [673a71c]
376
+ - Updated dependencies [616df65]
377
+ - Updated dependencies [58798ec]
378
+ - Updated dependencies [8803ca5]
379
+ - Updated dependencies [e70c21d]
380
+ - Updated dependencies [4b92c5a]
381
+ - Updated dependencies [06be396]
382
+ - Updated dependencies [3650d94]
383
+ - Updated dependencies [7c05f21]
384
+ - Updated dependencies [8cd4db4]
385
+ - Updated dependencies [daeb77f]
386
+ - Updated dependencies [eb4552e]
387
+ - Updated dependencies [3c3115e]
388
+ - Updated dependencies [55e90fd]
389
+ - Updated dependencies [9b75509]
390
+ - Updated dependencies [b13ea3c]
391
+ - Updated dependencies [d7e9e9a]
392
+ - Updated dependencies [cf62edf]
393
+ - Updated dependencies [0253416]
394
+ - Updated dependencies [5d77c09]
395
+ - Updated dependencies [3fd8625]
396
+ - Updated dependencies [1473757]
397
+ - Updated dependencies [d73d987]
398
+ - Updated dependencies [12ff256]
399
+ - Updated dependencies [26b0bd2]
400
+ - Updated dependencies [26b0bd2]
401
+ - Updated dependencies [d328698]
402
+ - Updated dependencies [d328698]
403
+ - Updated dependencies [b4e0787]
404
+ - Updated dependencies [088e0f7]
405
+ - Updated dependencies [78b07f4]
406
+ - Updated dependencies [f962cdc]
407
+ - Updated dependencies [b403bb3]
408
+ - Updated dependencies [8a25fee]
409
+ - Updated dependencies [4016370]
410
+ - Updated dependencies [12dc7b4]
411
+ - @object-ui/types@18.0.0
412
+ - @object-ui/components@18.0.0
413
+ - @object-ui/core@18.0.0
414
+ - @object-ui/i18n@18.0.0
415
+ - @object-ui/react@18.0.0
416
+
417
+ ## 17.7.0
418
+
419
+ ### Minor Changes
420
+
421
+ - ad1785c: refactor(plugin-charts)!: retire the `pie-chart`, `donut-chart` and `radar-chart` node type keys; the families are `chart` + `chartType` (objectui#10859, batch 8 phase 2c)
422
+
423
+ **BREAKING (authoring):** the plugin no longer registers `pie-chart`, `donut-chart` or `radar-chart` (and with them `plugin-charts:pie-chart`, `plugin-charts:donut-chart` and `plugin-charts:radar-chart`), and their `CHART_TYPE_KEYWORD_FAMILIES` rows are gone. `objectui validate` already refused each at `type`. Their one producer, this package's `examples/chart-examples.ts`, now authors `{ type: 'chart', chartType: … }`, which `objectui validate` accepts on both faces. A node still authored with one of the three types now renders the "Unknown component type" panel.
424
+
425
+ Migration:
426
+
427
+ - `{ "type": "pie-chart", … }` → `{ "type": "chart", "chartType": "pie", … }`, with the same keys;
428
+ - `{ "type": "donut-chart", … }` → `{ "type": "chart", "chartType": "donut", … }`, with the same keys;
429
+ - `{ "type": "radar-chart", … }` → `{ "type": "chart", "chartType": "radar", … }`, with the same keys.
430
+
431
+ A legacy report section whose `chart.type` says one of the three now reaches the generic `chart` renderer with no family derived from that type; give it the matching `chartType`. `chart:bar` is the one family keyword this package still registers.
432
+
433
+ **Clause-②: yes** — registrations leave the runtime (narrowing), released as `minor` with this banner.
434
+ - 37140f4: refactor(plugin-charts)!: retire the `scatter-chart` node type key; scatter is `chart` + `chartType: 'scatter'` (objectui#10859, batch 8 phase 2b)
435
+
436
+ **BREAKING (authoring):** the plugin no longer registers `scatter-chart` (and with it `plugin-charts:scatter-chart`), a second key on the generic `ChartRenderer` whose family came from its `CHART_TYPE_KEYWORD_FAMILIES` row. That row is gone too. `objectui validate` refused a `scatter-chart` node at `type`, and nothing in this repository, its examples or objectstack authored it. A node authored `type: "scatter-chart"` now renders the "Unknown component type" panel.
437
+
438
+ Migration:
439
+
440
+ - `{ "type": "scatter-chart", … }` → `{ "type": "chart", "chartType": "scatter", … }`, with the same keys.
441
+
442
+ A legacy report section whose `chart.type` says `scatter-chart` now reaches the generic `chart` renderer with no family derived from that type; give it `chartType: "scatter"`.
443
+
444
+ `pie-chart`, `donut-chart` and `radar-chart` were ruled the same way but stay registered: this package's `examples/chart-examples.ts` still authors them, so they wait on their own decision.
445
+
446
+ **Clause-②: yes** — a registration leaves the runtime (narrowing), released as `minor` with this banner.
447
+
448
+ ⚠️ **Dated note, 2026-10-02 — the three chart aliases are retired too — objectui#10859.**
449
+ The decision this entry said `pie-chart`, `donut-chart` and `radar-chart` wait on is made (the seat's fork ruling on objectui#10859): later in this same release, phase 2c moved `examples/chart-examples.ts` to `{ type: 'chart', chartType: 'pie' | 'donut' | 'radar' }` and then unregistered all three keys, with their `plugin-charts:` twins and `CHART_TYPE_KEYWORD_FAMILIES` rows. The rest of this entry is kept as the reading of this change.
450
+ - 19f484f: `FormulaFieldMetadata` declares `@objectstack/spec`'s `expression` in place of `formula`, and three readers of a lookup's display pointer read the spec's `displayField` alone (objectui#11070, round 6). Both retired spellings go at once, with no alias.
451
+
452
+ - **Types.** `FormulaFieldMetadata.formula` is removed. `FormulaFieldMetadata.expression` is `FieldSchema`'s `expression` by reference: a CEL source string, or the spec's `{ dialect, source, … }` envelope. Nothing in ObjectUI read the removed member through the type. `FieldSchema` refuses `formula` by name on every field type, with a rename hint to `expression`.
453
+ - **Form payloads.** `sanitizeFormData` (`@object-ui/plugin-form`) no longer treats a `formula` key as a "computed" flag. Every `type: 'formula'` field is still dropped from the payload by its type, as before. Only a field of some other type that carries `formula` changes: its value is now sent like any writable field's. The spec refuses such a definition at publish, so a served one cannot carry it.
454
+ - **Display pointer.** `deriveColumns` and `hydrateColumns` (`@object-ui/plugin-form`, the master-detail grid columns), `ObjectChart`'s group-by labels (`@object-ui/plugin-charts`) and the action-param resolver (`@object-ui/app-shell`) read `displayField`, then `reference_field`. None of them reads `display_field` any more.
455
+ - **A fix for spec-spelled lookups in master-detail grids.** `deriveColumns` and `hydrateColumns` read `display_field || reference_field` before, with no `displayField` leg. A lookup that declared only `displayField`, which is the spec's spelling, got no display pointer on its grid column. It now gets one.
456
+
457
+ A definition served through `ObjectStackAdapter.getObjectSchema` or `MetadataProvider` loses nothing: the ingestion pass (objectui#7650) stamps a stored `display_field` onto `displayField` before any of these readers sees it. Measured with a lookup carrying `display_field: 'title'` served through `ObjectStackAdapter.getObjectSchema`: the master-detail column (`deriveColumns` and `hydrateColumns`), the chart's axis label and the action param all resolve the `title` column before and after this change.
458
+
459
+ ## ⚠️ BREAKING, priced as minor under the fixed group's version policy
460
+
461
+ TypeScript that writes `formula` on a `FormulaFieldMetadata` no longer compiles (an excess-property error naming the key). Rename it to `expression` and write the formula in CEL against the record, for example `record.quantity * record.unit_price`.
462
+
463
+ At runtime, a lookup whose display pointer is spelled only `display_field` loses it wherever the ingestion pass does not run first. Measured before and after this change, on a lookup with `display_field: 'title'` handed to the readers directly:
464
+
465
+ - **`deriveColumns` / `hydrateColumns` with a `childSchema` that did not come through the ingestion pass** (an external caller, or a master-detail form whose `DataSource` is not `ObjectStackAdapter`): the column's `displayField` was `title`. It is now absent.
466
+ - **`ObjectChart` on a `DataSource` other than `ObjectStackAdapter`**, grouped by that lookup: the axis label came from the `title` column. It now comes from the `name` column, the generic fallback.
467
+ - **The action-param resolver, when a host passes its own unfolded `objects`** (for example through `RecordDetailView`'s `objects` prop): the lookup param's `displayField` was `title`. It is now absent.
468
+
469
+ The same lookups spelled `displayField` resolve the `title` column in all three after this change. Before it, the chart and the action param already did, and the master-detail columns did not (the fix above).
470
+
471
+ **Fix:** spell the pointer `displayField`, or serve the definition through `ObjectStackAdapter`.
472
+ - 06634af: fix(plugin-charts): an `object-chart` whose `specType` is a single-value or tabular spec family draws its routed form, not a silent bar chart; the renderer has no default family (objectui#11520)
473
+
474
+ **What an accepted document draws changes.** `specType` is the react tier's chart family: the react-page wrapper parks `<ObjectChart type="gauge">` there, because `type` is the node's discriminator. Both faces declare it as the spec's whole `ChartTypeSchema`, so an `object-chart` with `specType` set to `gauge`, `solid-gauge`, `metric`, `kpi`, `bullet`, `table` or `pivot` parsed on both faces, and drew a **bar chart**, with no note. The same families on `chartType` already drew the forms below.
475
+
476
+ - **`gauge`, `solid-gauge`, `metric`, `kpi`, `bullet` on `specType`** now draw the number card: one row's number, the form the same family draws on `chartType`.
477
+ - **`table`, `pivot` on `specType`** now draw the tabular notice, which names the data-table and pivot components.
478
+ - **An off-spec `specType`** (both faces refuse it) draws the unknown-type notice, which names the value.
479
+ - **A chart that names no family at all** (both faces refuse it: `object-chart` needs `chartType` or `specType`, and `chart` needs `chartType`) draws a notice reading "This chart names no chart type — nothing was drawn." It used to draw a bar chart. A caller that means a bar names `bar`.
480
+
481
+ Every family this block draws as a chart draws exactly what it drew before, on both keys.
482
+
483
+ How: `normalizeChartSchema` used to keep only the families this package draws as a chart, and `AdvancedChartImpl` drew a missing family as `'bar'`. The normalizer now hands the named family on as named, so `specType` reaches the same family dispatch `chartType` reaches, and the `'bar'` default is removed (with its four copies in the refusal guards).
484
+
485
+ ⚠️ **Type.** `NormalizedChartSchema['chartType']`, exported from this package, widens from the thirteen drawn families to the declared chart families (`DeclaredChartFamily` in the emitted declarations; not a new entry export): `object-chart`'s `chartType` union together with its `specType` (the spec's `ChartType`), both read off `ObjectChartSchema` in `@object-ui/types` by reference. It is now the family the schema names, drawn or not, and a misspelled family still fails to compile. Shipped as `minor`, not `major` (objectui never declares `major`); a consumer that reads it exhaustively needs a branch for each single-value and tabular family, which this package draws no chart of.
486
+ - 045d20b: Relationship-target readers resolve a lookup's target from `reference` alone,
487
+ dropping the `reference_to` fallback arm (objectui#6837, half 2).
488
+
489
+ Maintainer ruling, 2026-08-31, 原文照录: 「objectui不是前端的项目吗?后端的元数据只要
490
+ 对,前端按协议执行就行了呀」. Protocol normalization belongs on the SERVER; the front
491
+ end just executes the protocol. objectstack#13847 landed the server half — a
492
+ `field-reference-to-alias` conversion rewrites stored `reference_to` to
493
+ `reference` on the serve path and in `os migrate meta`.
494
+
495
+ `reference` is the only target spelling `@objectstack/spec`'s `FieldSchema`
496
+ declares. Measured on the installed 17.2.0: it refuses `reference_to`,
497
+ `referenceTo` and `target` with `unrecognized_keys`, each carrying its own
498
+ "Did you mean -> `reference`?" rename, while a nonsense key gets the same
499
+ refusal with NO rename hint and `reference` parses clean.
500
+
501
+ ## ⚠️ BREAKING for a hand-written schema that spells `reference_to` — read this
502
+
503
+ **This is a behaviour change for BYO consumers, and it is being stated rather
504
+ than shipped silently.** ObjectUI is usable without an ObjectStack backend
505
+ (`examples/byo-backend-console`), and a hand-written TypeScript schema passes
506
+ through no zod door, so nothing rejects the legacy spelling at authoring time.
507
+
508
+ **The break surface is narrower than "all BYO consumers", and this is the
509
+ measurement rather than a blanket claim.** Two ingestion choke points stamp both
510
+ snake_case keys from whichever spelling arrived — `MetadataProvider`'s type
511
+ cache for metadata type `object`, and `ObjectStackAdapter.getObjectSchema`. Any
512
+ def that passed either one already carries `reference` and is **completely
513
+ unaffected**. What is affected is exactly:
514
+
515
+ - **A `DataSource` implementation other than `ObjectStackAdapter`.**
516
+ `getObjectSchema` is a required member of the published `DataSource`
517
+ interface, and the readers call it on the generic `dataSource` (through
518
+ `useSettledSchema` and directly), so a host adapter's object schema reaches
519
+ them raw. Every in-repo example of one is on this path:
520
+ `ApiDataSource`, `ValueDataSource`, `packages/types/examples/rest-data-source.ts`,
521
+ `examples/byo-backend-console/src/mockDataSource.ts`,
522
+ `packages/runner/src/lib/mockDataSource.ts`,
523
+ `apps/site/app/components/galleryDataSource.ts`,
524
+ `apps/console/src/sdui-workbench-preview.tsx`,
525
+ `packages/plugin-grid/demo/bulk-actions.tsx`.
526
+
527
+ **Measured on this tree, none of those eight emits a relationship target at all** —
528
+ `reference_to` and `reference` are both zero in each, and
529
+ `examples/byo-backend-console` carries no lookup or master_detail field
530
+ anywhere (its only `reference` hits are a vite triple-slash directive and a
531
+ tsconfig `references` array). The single in-repo producer that WAS on this
532
+ surface, `packages/plugin-gantt/demo/main.tsx`, is fixed here at the producer.
533
+
534
+ ⇒ **If you author object metadata by hand and spell a lookup's target
535
+ `reference_to`, rename that key to `reference`.** Symptom if you do not: the
536
+ target silently fails to resolve, and the affected surface degrades rather than
537
+ erroring — a related list is not derived, a gantt quick filter falls back to the
538
+ distinct values in the loaded rows instead of the referenced object's full
539
+ domain, a tree stops auto-detecting its parent pointer, a lookup cell shows a
540
+ raw id, a chart's group-by labels stay unresolved.
541
+
542
+ The ingestion choke point now emits a **dev-mode warning** when a def arrives
543
+ carrying only `reference_to` or `referenceTo` and no `reference`. It names the
544
+ object, the field and the offending key, and points at this ruling. Stamping is
545
+ deliberately unchanged, so nothing that worked stops working. It is memoised
546
+ once per **(object name, field name, spelling, target value)** — every segment
547
+ of that key is pinned, in both directions, in
548
+ `reference-keys.legacyWarning-6837.test.ts`.
549
+
550
+ ⛔ **This warning does NOT cover the break described above, and it is worth being
551
+ exact about that rather than letting it read as mitigation.** It lives in
552
+ `normalizeFieldReferenceKeys`, reachable only through
553
+ `normalizeSchemaReferenceKeys`, which has exactly two production call sites —
554
+ `MetadataProvider` (metadata type `object`) and
555
+ `ObjectStackAdapter.getObjectSchema`. Both of those also STAMP the def, so the
556
+ warning fires precisely where the def still resolves and nothing is broken. A
557
+ hand-written schema served through any OTHER `DataSource` — the break surface —
558
+ reaches a reader raw: it never passes through this code and produces **no
559
+ warning at all**. On that path the failure is exactly as silent as before.
560
+ A reader-side or shared-resolver diagnostic, which would cover it, remains open
561
+ on objectui#6837.
562
+
563
+ ⚠️ **Dated note, 2026-09-29 — the call-site count above has since moved —
564
+ objectui#7650.** "exactly two production call sites" above held when this change landed
565
+ (`045d20ba8`). Later in this same release objectui#7650 (PR objectui#8868) added a call
566
+ on `MetadataProvider`'s by-name object-schema serve path. Re-measured for objectui#10979
567
+ on `main` at `2eaf5be27`, `normalizeSchemaReferenceKeys` had three production call sites:
568
+ two in `MetadataProvider`, on its list path and on its by-name path, and one in
569
+ `ObjectStackAdapter.getObjectSchema`.
570
+ `.changeset/7650-metadata-item-reference-canonicalisation.md` (PR objectui#8868) states
571
+ what ships; the text above is kept as the reading of this change.
572
+
573
+ ## What did NOT change
574
+
575
+ **Every key these readers EMIT is byte-identical**, and that was verified
576
+ mechanically over the whole diff rather than asserted. Eleven of the sixteen
577
+ sites write a target onto a bag whose own contract spells it `reference_to` (or
578
+ camelCase `referenceTo`): the six whose read and write share a line —
579
+ `RecordDetailDrawer`, `RelatedList`, `buildDefaultPageSchema`, `ListView`,
580
+ `FilterConditionField`, `resolveActionParams` — plus five more that read on one
581
+ line and emit on another, and so are just as much emitters: `RecordDetailView`,
582
+ `RecordMetaFooter`, `ObjectGallery`, `fieldEnrichment` (all `reference_to`) and
583
+ `UserFilters` (`referenceTo`). Only the right-hand read narrowed anywhere; the
584
+ emitted key is what its target contract declares, and renaming it would be a
585
+ separate change.
586
+
587
+ **Three readers were deliberately left alone.** `LookupCellRenderer`
588
+ (`fields/src/index.tsx`), `LookupField` and `UserField` read `FieldMetadata` —
589
+ ObjectUI's OWN contract, whose `LookupFieldMetadata` declares `reference_to` and
590
+ never declares `reference`. They are fed by the emitters above and by published
591
+ example schemas (`examples/schema-catalog/src/schemas/fields-lookup/*.json`), so
592
+ narrowing them would break in-repo producers, and `plugin-grid`'s
593
+ `relationalMetaCopySet.derivation.test.ts` re-derives its read set from exactly
594
+ those three sources — where `reference_to` is recorded with verdict
595
+ `adapter-stamped`. `DetailViewFieldSchema` is likewise untouched.
596
+
597
+ ⚠️ **Dated note, 2026-09-30 — the stamp, the three readers and the emitted key have since moved — objectui#11070.** Later in this same release objectui#11070 (round 4) retired `reference_to` inside ObjectUI as well. `normalizeFieldReferenceKeys` now FOLDS a legacy `reference_to` / `referenceTo` onto `reference` and no longer stamps `reference_to`, so "Stamping is deliberately unchanged" and "stamp both snake_case keys" above no longer describe what ships. `LookupCellRenderer`, `LookupField` and `UserField` read `reference` only; `LookupFieldMetadata`, `MasterDetailFieldMetadata` and `DetailViewField` (with `DetailViewFieldSchema`) declare `reference`; and the emitters listed under "What did NOT change" write `reference`. A hand-written schema served through a `DataSource` other than `ObjectStackAdapter` that spells only `reference_to` therefore also loses the lookup picker's target and the read cell's name. `.changeset/11070-reference-to-round4.md` states what ships; the text above is kept as the reading of this change.
598
+ - 0349555: A sankey with no positive flow says so, instead of rendering an empty div
599
+ (objectui#7140).
600
+
601
+ `AdvancedChartImpl`'s sankey arm keeps only strictly positive measures, so a
602
+ chart handed **real rows** whose measure is all `0`, all `null`, all negative,
603
+ or unparseable built no links and returned a bare `<div>`. Measured in Chromium
604
+ against a populated control: the control drew 1 `<svg>` / 7 `<path>` /
605
+ 26 descendants; each of those four tiles rendered `descendantCount: 1`,
606
+ `svgCount: 0`, `textContent: ''`, and their screenshots hashed identical to one
607
+ another. No marks, no text, no `role` — a tile indistinguishable from a widget
608
+ that had crashed, which is the one distinction the file's other refusals exist
609
+ to make.
610
+
611
+ It now renders through the `ChartRefusal` shell those refusals already use —
612
+ same box, same `role="status"`, and a new `data-chart-error="no-positive-flow"`
613
+ — reading *"This chart has no flow to draw: no row's `<measure>` is above
614
+ zero."*
615
+
616
+ Two boundaries are deliberate and pinned:
617
+
618
+ - **No rows at all is untouched.** That is the empty-result question, answered
619
+ upstream in `ObjectChart` where the query outcome is known; a sentence about
620
+ what the rows contain would be false about a dataset with no rows in it.
621
+ - **One positive row among zeros still draws.** The refusal fires on an empty
622
+ link set, never on a thin one.
623
+
624
+ One code and one sentence for three causes (a genuinely all-zero flow, values a
625
+ flow cannot represent because they are negative, and measures `Number(…) || 0`
626
+ folds to zero): naming any single cause would be false for the other two, so
627
+ the copy names the predicate the filter actually applies, which is true for all
628
+ three. No recovery is promised. Every other chart family is byte-identical —
629
+ eight of the twelve tiles in the browser sweep hashed unchanged.
630
+ - 0dc2c93: `compareTo` on a `scatter` chart is no longer supported — scatter joins pie / donut /
631
+ funnel on the list of chart families that ignore it (objectui#7402, maintainer ruling
632
+ 2026-09-03).
633
+
634
+ **This removes a published capability, deliberately.** Until now a `chartType: 'scatter'`
635
+ chart (and the dashboard widget types `scatter` and `bubble`, which both render as one)
636
+ with `compareTo` set synthesised a muted "previous period" overlay series. It drew the
637
+ wrong picture: a scatter binds ONE measure, and the renderer reads y through the single
638
+ `YAxis dataKey={series[0].dataKey}`, so the overlay was plotted on the PRIMARY series' y
639
+ — "previous period" painted exactly on top of "current" (objectui#7194).
640
+
641
+ Enforce-or-remove: rather than keep drawing that, the capability is removed until it can
642
+ be drawn honestly. Drawing a real second measure on a scatter needs the multi-measure
643
+ projection recorded as option A of objectui#7194, which is not built (zero authored
644
+ callers). **If and when that projection lands, `compareTo` on a scatter returns with
645
+ it** — it is the same missing mechanism, one payment.
646
+
647
+ What changes for authors:
648
+
649
+ - A `compareTo` on a scatter is now IGNORED rather than drawn. The primary series still
650
+ renders exactly as before — nothing refuses, nothing goes blank, and no comparison
651
+ query is issued on the inline chart path.
652
+ - No `<measure>__comparison` (inline chart) / `<measure>__compare` (dashboard) series is
653
+ appended for a scatter, so a compare-to scatter document also never reaches the
654
+ two-or-more-series scatter refusal being added under objectui#7194.
655
+ - Charts that keep the overlay: line, area, bar, horizontal-bar, combo. Charts that
656
+ ignore `compareTo`: pie, donut, funnel and — as of this change — scatter (and the
657
+ `bubble` widget type that renders as a scatter).
658
+
659
+ Reachability at the time of the change: **0** authored scatter/bubble instances in-repo
660
+ across both spellings (control `"type": "bar"` fires at 5 example files); incidence in
661
+ deployed tenant metadata is not measurable from this repo.
662
+ - 01c27c4: Fix: a chart series' `type` override (`ChartDataSeries.type`, objectui#6121) is now
663
+ honoured when the series array is written in the internal `dataKey` binding, not only
664
+ the `name` binding — the same sentence #2945 shipped for the other
665
+ dialect.
666
+
667
+ `ChartRenderer`'s `isInternalShaped` fast path (introduced by #2945 to fix a different
668
+ bug — a `name`-shaped `series` shadowing the normalized `dataKey`-shaped one) took the
669
+ raw authored array untouched whenever every entry already carried `dataKey`, bypassing
670
+ `normalizeSeries` — the only place `type` is translated to the renderer-internal
671
+ `chartType`. So an author who wrote `series: [{ dataKey: 'revenue' }, { dataKey:
672
+ 'margin', type: 'line' }]` — both keys independently valid on `ChartDataSeriesSchema` —
673
+ got neither the override nor a combo chart, silently.
674
+
675
+ `ChartRenderer` now always takes the series array through the one normalization layer
676
+ (objectui#2880 S1) instead of special-casing the `dataKey` shape around it.
677
+
678
+ **Breaking on unmodified documents, deliberately — this changes rendered output.** A
679
+ chart authored with a `dataKey`-shaped series carrying a `type` override used to render
680
+ one family for every series; it now renders the mix the author actually described (the
681
+ card's own regression case: two bars become one bar and one line).
682
+
683
+ **Two more effects on the delivered key set for a `dataKey`-shaped series array**,
684
+ undisclosed until now — `normalizeSeries` is a no-op on a well-formed entry, but these
685
+ two cases were never well-formed under the old fast path either:
686
+
687
+ - An i18n `label` written as a `{ en, zh-CN, … }` record on a `dataKey`-shaped entry was
688
+ previously forwarded as that raw object; it is now resolved to a plain string (the
689
+ first string-valued limb), matching what a `name`-shaped series already got from
690
+ `normalizeChartSchema`.
691
+ - A `dataKey`-shaped entry whose `dataKey` does not resolve to a non-empty string (and
692
+ has no `name` to fall back to) was previously forwarded as-is; it is now dropped from
693
+ the delivered series array, matching what a `name`-shaped series with no usable key
694
+ already got.
695
+
696
+ No existing well-formed internal caller (`DashboardRenderer`, `ObjectView`, the dataset
697
+ path) changes behaviour — every series entry those callers construct already carries a
698
+ non-empty string `dataKey` and a string `label`.
699
+ - 967e5d8: Chart `series[].opacity` and `series[].dashArray` are honoured on every series,
700
+ not only on a `variant: 'comparison'` one (objectui#7698).
701
+
702
+ `@objectstack/spec` declares `ChartSeries.opacity` ("Override series opacity")
703
+ and `ChartSeries.dashArray` ("Override stroke dash pattern") as unconditional
704
+ per-series overrides, and `normalizeSeries` read both off every series. The
705
+ renderer then honoured them on a comparison overlay only, so an author who
706
+ wrote `{ name: 'cost', opacity: 0.6 }` or `{ name: 'cost', dashArray: '4 4' }`
707
+ on a primary series got a mark drawn exactly as if the key were absent. Fixed
708
+ in the renderer rather than by narrowing the published declaration to match:
709
+ the spec is the contract of record, and a renderer's partial implementation
710
+ does not get to dictate it (AGENTS.md #0.1).
711
+
712
+ **Two gaps, not one.** The `variant` guard was the visible half — `comparisonStyle`
713
+ returned `null` for any other variant. The second half only showed on
714
+ `dashArray`: that helper already returned an AUTHORED dash for every family
715
+ (the `??` takes the left side whatever the kind), and the **Bar and Scatter
716
+ marks** then passed `fillOpacity` only, dropping `strokeDasharray` and
717
+ `strokeOpacity` on the floor — so an authored dash was lost on those two
718
+ families even on a comparison series. A fix aimed at the guard alone would have
719
+ left that untouched. `comparisonStyle` is now `seriesStyle`, and the Bar and
720
+ Scatter marks pass all three channels.
721
+
722
+ **Comparison series are unaffected.** The authored branch already won over the
723
+ muted defaults, and those defaults stay gated on `variant: 'comparison'`: a
724
+ comparison series carrying neither key keeps its lower opacity and its `'4 4'`
725
+ line/area dash exactly as before. The two stroke defaults no mark ever consumed
726
+ (bar and scatter — neither is stroked by this renderer) are now spelled
727
+ `undefined`, so opening `strokeOpacity` on those marks does not hand them a
728
+ default they never had.
729
+
730
+ Only a stroked mark can show a dash, so on a `bar` or `scatter` mark an
731
+ authored `dashArray` reaches the mark and paints nothing — the mark's geometry,
732
+ not a condition on the key. The `ChartDataSeries` mirror docs and the
733
+ plugin-charts reference, which stated the comparison-only condition as an
734
+ interim measure, are corrected in the same change.
735
+ - edea22a: **BREAKING** — `SchemaRendererProvider`'s `dataSource` prop, and the context
736
+ type every `useSchemaContext()` consumer reads back, are the published
737
+ `DataSource` contract instead of `any`.
738
+
739
+ **FROM** `dataSource={anything}` **TO** `dataSource={adapter}` — a `DataSource`
740
+ from `@object-ui/types`, or `null` / `undefined` when the host has no adapter
741
+ bound.
742
+
743
+ ```ts
744
+ // before — compiled, and failed at runtime on the first find()
745
+ <SchemaRendererProvider dataSource={'not-an-adapter'}>
746
+ // before — compiled, and no reader can do anything with it
747
+ <SchemaRendererProvider dataSource={{}}>
748
+ // after
749
+ <SchemaRendererProvider dataSource={adapter}> // a DataSource
750
+ <SchemaRendererProvider dataSource={undefined}> // "I have no adapter"
751
+ ```
752
+
753
+ Both sites are typed `DataSource | null | undefined` — the spelling
754
+ `useSettledSchema` in this same package already used. The two absences are part
755
+ of the contract, not a weakening of it: a Studio preview, a `kind:'react'` page
756
+ rendered before the host's adapter connects, and a widget probe driving
757
+ `apiFetch` alone all render with nothing bound, and every reader in the tree
758
+ already guards for it. What the union refuses is everything that is not an
759
+ adapter: a string, an empty object, a plain data bag, a partial adapter missing
760
+ a required member.
761
+
762
+ The measured cost, both halves, because the two `any`s have different blast
763
+ radii (measured separately on `origin/main`, whole-repo type-check over the 33
764
+ packages that depend on `@object-ui/react`):
765
+
766
+ - the **context type** — the `any` that reaches every `useSchemaContext()`
767
+ reader — reds **7 diagnostics at 7 sites in 4 packages**, all of them
768
+ production code or a mocked module factory.
769
+ - the **provider prop** — the injection points — reds **52 diagnostics at 27
770
+ sites in 11 packages**, all but one of them test doubles.
771
+
772
+ That ordering is the reverse of the prediction on the card: the context `any`
773
+ was expected to be the expensive one because it infects the whole tree, and it
774
+ is the cheap one, because every reader in the tree already guarded and none of
775
+ them ever reached past `find` / `getObjectSchema`. The prop is the expensive
776
+ one, because the injection points are overwhelmingly test doubles that were
777
+ never complete adapters. The full accounting is on objectui#7912.
778
+
779
+ Two runtime behaviours change, both in the "no adapter" direction and both
780
+ strictly closer to what the surrounding code already intended:
781
+
782
+ - `@object-ui/components`' `kind:'react'` page passed an empty object as its
783
+ "no adapter yet" stand-in. An empty object is TRUTHY, so it walked past every
784
+ `if (!dataSource)` guard written to catch exactly that state and failed later,
785
+ at the call. It now passes the absent adapter itself, so the guard fires where
786
+ it was meant to. The module-constant identity that stand-in existed for is
787
+ preserved: `null` is a primitive, so the provider's memo is unaffected.
788
+ - `@object-ui/plugin-calendar`, `@object-ui/plugin-gantt` and
789
+ `@object-ui/plugin-kanban` collapse a `null` adapter from the context to
790
+ `undefined` before handing it to their widget, whose prop declares the single
791
+ spelling `dataSource?: DataSource`.
792
+
793
+ Nothing else moves at runtime: no value flowing through this key changes, and
794
+ no data path is touched. A TypeScript consumer outside this repo that handed
795
+ this prop something other than an adapter now gets a compile error naming the
796
+ key (TS2322 / TS2739 / TS2740), which is why the FROM/TO is spelled out above.
797
+
798
+ Five `as any` reads of this context in `@object-ui/fields` are gone — they were
799
+ redundant the moment the seam became honest — and `LookupField`'s local
800
+ re-declaration of the imported context as a `Context` of `any`, which laundered
801
+ its `dataSource` read while looking typed, is gone with them. Both directions of
802
+ the contract are pinned against the real compiler in
803
+ `SchemaRendererContext.dataSourceType.pin.test.ts`, and the card's planted
804
+ documentation probe (a bare string in `packages/react/README.md`'s provider
805
+ example) now fails `pnpm check:doc-snippets`, where it used to exit 0 with zero
806
+ diagnostics.
807
+
808
+ objectui#7912.
809
+ - aa6be30: `ChartRendererProps.schema.series`: the `dataKey` arm now declares `type?: string`, the
810
+ per-series family override the `name` arm already declares, with the same member type
811
+ (objectui#8086). The TypeScript face now states what `ChartDataSeriesSchema` (where
812
+ `dataKey` and `name` are each independently optional beside `type`) and the renderer
813
+ (every entry goes through `normalizeSeries`, `01c27c431`) accept. No other arm changes:
814
+ `chartType` stays on the `dataKey` arm alone, and wins when an entry writes both.
815
+
816
+ The accept set only widens. A value typed as the `dataKey` arm may now carry `type`, and
817
+ an entry narrowed with `'dataKey' in entry` may read it; nothing that compiled before is
818
+ refused. `ChartRendererProps` is not re-exported by name from the package entry: it
819
+ reaches consumers as the props type of the exported `ChartRenderer` component. An object
820
+ literal written against the whole `series` union was already accepted before this
821
+ change, because `type` is known to the `name` arm; the gap was at the arm.
822
+
823
+ The `ObjectChartSchema.series` docblock in `@object-ui/types` is restated to match: that
824
+ copy of the internal arm does not carry `type`, and its type is unchanged.
825
+ - 0758bd8: `ObjectChart` refuses an object-bound chart that declares no category axis (objectui#8168).
826
+
827
+ An object-bound chart that named no field to group by used to be composed anyway.
828
+ `runAggregate` passed `schema.aggregate` to `ds.aggregate(objectName, { field,
829
+ function, groupBy, filter })` with no guard on `groupBy`, and the `ds.find` leg
830
+ handed the same bag to `aggregateRecords`, which buckets every record on
831
+ `record[groupBy] ?? 'Unknown'`. So one path asked a driver to group by `undefined`
832
+ and the other collapsed the whole object into a single `'Unknown'` bar — and which
833
+ of those a reader saw was decided by the data source, not by the renderer. The only
834
+ loud states this component had were a fetch `error` (`chart-error`) and a generic
835
+ "No data yet"; neither is a statement about an absent binding.
836
+
837
+ `ObjectCalendar`, `ObjectGantt` and `ObjectTimeline` each already refuse a view that
838
+ declares no axis. This is the fourth, following `ObjectTimeline`'s shape
839
+ (objectui#7459): a `role="alert"` box, `data-testid="chart-missing-category-axis"`,
840
+ naming the bindings the author can declare — `aggregate.groupBy`, `xAxisKey`,
841
+ `xAxis.field` — rendered from the resolver's own vocabulary so the message cannot
842
+ drift from what the resolver reads.
843
+
844
+ **Breaking, deliberately — and this repo ships breaking as `minor`.** A chart that
845
+ previously rendered an `'Unknown'`-bucketed bar (or whatever the driver did with
846
+ `groupBy: undefined`) now renders the refusal instead. That is the intent: the
847
+ picture it drew was not a picture of the data.
848
+
849
+ It keys on the CATEGORY alone. A measure may legitimately be absent — `count` takes
850
+ no field — so refusing on an absent measure would refuse `count` grouped by a
851
+ declared category, a chart that renders correctly. Four shapes are deliberately
852
+ untouched: an ADR-0021 `dataset` chart (which may declare no dimension), a chart
853
+ carrying authored `data` or a `bind` scope (no field name is read to fetch those
854
+ rows), a spec-shape `xAxis: { field }` with no `xAxisKey` (resolved through
855
+ `normalizeChartSchema`, this package's one translation of the author-facing shape),
856
+ and every schema the five in-repo producers compose today — all five floor their own
857
+ category, so none of them can reach the refusal.
858
+
859
+ This does **not** retire the six `'name'` / `'value'` floors at the three relay faces;
860
+ that is the remainder of objectui#7547 and is mechanical only once this screen exists.
861
+
862
+ New key `chart.unconfigured.noCategoryAxis` in all ten locale packs.
863
+ - 0a174f3: fix(plugin-dashboard,core,plugin-charts): route a structured `aggregate.groupBy` on `object-metric` to the spec-shape wire
864
+
865
+ An authored `aggregate.groupBy` is a union — a bare field name, or the
866
+ structured date-bucketing node `{ field, dateGranularity?, alias? }` — and the
867
+ two need different queries. The spec-shape
868
+ `{ groupBy: GroupByNode[], aggregations, where }` reaches `engine.aggregate` and
869
+ runs the server-side date-bucket engine; the legacy
870
+ `{ field, function, groupBy, filter }` query reaches the cube/analytics wire,
871
+ whose `dimensions` the contract declares as an array of dimension NAMES and
872
+ which does not honour `dateGranularity` at all.
873
+
874
+ `ObjectChart.runAggregate` has routed between the two since objectui#7946.
875
+ `ObjectMetricWidget.computeOne` had no such branch: it forwarded the authored
876
+ value straight through, so a metric widget carrying a structured node posted
877
+ `dimensions: [{ field: 'closed_at', dateGranularity: 'month' }]` — an object
878
+ where a name is declared. Nothing refused it and nothing reported it, so the
879
+ author asked for one question and the platform answered another (objectui#8613).
880
+
881
+ - The routing test and the payload are now one function,
882
+ `objectAggregateSpecQuery` (with `isStructuredGroupBy`) in `@object-ui/core`.
883
+ `ObjectChart.runAggregate` and `ObjectMetricWidget.computeOne` both call it,
884
+ so the two renderers cannot post different wires for one authored shape. The
885
+ measure alias is `chartMeasureKey`'s answer, i.e. what the chart's own
886
+ `aggregateValueKey` already delegated to — the chart's posted payload is
887
+ unchanged.
888
+ - `ObjectMetricWidgetProps.aggregate.groupBy` said `string`. That was a claim
889
+ about the author which nothing upstream backed: the value crosses two `any`
890
+ seams on the way in, so the declaration refused the node at neither compile
891
+ time nor runtime. It is now the contract's union, taken by reference through
892
+ `ObjectChartSchema['aggregate']`.
893
+
894
+ Unchanged, and pinned as controls: a plain string `groupBy` and an absent one
895
+ (floored at the single `'_all'` bucket) still take the legacy query byte for
896
+ byte, and an ARRAY `groupBy` still travels there too — it is not this union's
897
+ object arm, and it must keep reaching the producer-side refusal `503cd8b89`
898
+ landed in the adapter.
899
+ - bb383e8: Retire the "Tremor/simple format" adapter in `ChartRenderer` — the `index`,
900
+ `category` and `value` reads (objectui#8650, triage ruling `5619609278` on
901
+ AGENTS.md #0.1: route to the producer, ⛔ not a declaration).
902
+
903
+ **Breaking, deliberately, for three keys — and NOT for the fourth.** The card
904
+ filed four undeclared reads as one group. A cast-aware read census plus a
905
+ TypeScript-checker declaredness reading measured them apart, and they do not
906
+ share one verdict:
907
+
908
+ - `index` / `category` (they aliased the category axis) and `value` (it became
909
+ a single series) are **retired**. They are declared on no published face —
910
+ not `ChartSchema`, not its zod mirror, not `ChartRendererProps.schema` — are
911
+ advertised by no registry `inputs`, and are taught by no doc, guide or skill.
912
+ A structural producer census over `packages/`, `apps/`, `examples/`,
913
+ `content/docs/` and the skills corpus (5695 files, 74 chart nodes) found
914
+ **zero** nodes writing `category` or `value` and **one** writing `index` —
915
+ this repo's own test for the adapter. The zero is read against controls that
916
+ fire in the same population (`xAxisKey` 41 nodes, `series` 44, `chartType`
917
+ 40, `data` 52) and a nonsense key that returns 0.
918
+ - `categories` is **not retired and is unaffected**. It is a declared member of
919
+ the published `ChartSchema` and of its zod mirror, is documented in the
920
+ schema reference as an alternative series list, and was ruled live by
921
+ the maintainer ruling of 2026-08-31. `normalizeChartSchema` — the single translation point
922
+ (objectui#2880 S1) — already consumed it, so `ChartRenderer`'s own branch was
923
+ a second, un-normalized read that no well-formed chart could reach. Removing
924
+ it changes nothing for a well-formed chart and removes two wrong answers for
925
+ a malformed one: `categories: 'revenue'` reached `.map` on a string and threw
926
+ during render, and a `categories` whose entries the normalizer rejects
927
+ produced a `[{ dataKey: '' }]` series.
928
+
929
+ **Migration.** Write the canonical spellings, which every producer in the
930
+ measured corpora already writes: `xAxisKey` (or the spec's `xAxis: { field }`)
931
+ for the category axis, and `series` (or `categories`) for the plotted columns.
932
+ A chart that still writes `index` / `category` binds no category axis, so
933
+ `AdvancedChartImpl` falls back to its default category key, `name`. What that
934
+ degrades to depends on the rows, and only one half of it is a refusal: rows
935
+ carrying no `name` column hit its existing on-screen `missing-category-key`
936
+ refusal, while rows that DO carry one plot silently against `name` instead of
937
+ the column the author named — a wrong picture rather than a refusal. One that
938
+ still writes `value` plots nothing.
939
+
940
+ Also deletes six `(schema as any)` casts that the published declarations had
941
+ already made unnecessary — `colors`, `categoryColors` and `categoryOrder` on
942
+ `ChartRenderer`, and `colors`, `compareTo` and `series` on `ObjectChart` (the
943
+ objectui#8327 bucket-(b) class: declared, then read through a needless cast).
944
+ No behaviour changes with them; `ObjectChart.tsx` now has no `(schema as any)`
945
+ read left at all.
946
+ - 47ba790: **BREAKING** — `ObjectChartBlock`, the registry shell exported beside `ObjectChart`, declares its props instead of taking `(props: any)` (objectui#8885).
947
+
948
+ **Clause-②: yes** — a published component signature narrows. `@object-ui/plugin-charts` 17.6.0 publishes `ObjectChartBlock: (props: any) => React.JSX.Element`. It is now `(props: Omit<ObjectChartProps, 'schema'> & { schema: BaseSchema }) => React.JSX.Element`. No export is added, removed or renamed, and no runtime behaviour changes.
949
+
950
+ **FROM** any props bag **TO** `ObjectChart`'s own props, with `schema` as the raw node:
951
+
952
+ ```tsx
953
+ // before: all of these compiled
954
+ <ObjectChartBlock schema={node} dataSorce={adapter} /> // misspelled prop, silently dropped
955
+ <ObjectChartBlock schema="object-chart" /> // a string, not a node
956
+ <ObjectChartBlock schema={{ objectName: 'deal' }} /> // a node with no `type`
957
+ // after: pass a node (`BaseSchema`: at least `type`) and only ObjectChart's props
958
+ <ObjectChartBlock schema={{ type: 'object-chart', objectName: 'deal', chartType: 'bar' }} dataSource={adapter} />
959
+ ```
960
+
961
+ `schema` is `BaseSchema`, the node `SchemaRenderer` hands every registered renderer, and not `ObjectChartSchema`. The shell receives the node BEFORE `ElementDataSourceGate` maps its `dataSource` binding, so a node that carries only `{ type, dataSource: { object, view } }` is legal input. So is a node typed `chart`, the alias this same shell is registered under. The other props (`dataSource`, `onSegmentClick`) are `ObjectChartProps`' own, so a misspelled prop name is now an excess-property error.
962
+
963
+ Migration: a direct caller that passed extra props through the shell must pass only `schema`, `dataSource` and `onSegmentClick`, and a node without `type` must add one. Nodes rendered through the registry (`SchemaRenderer`) are unaffected: the registry resolves renderers as `any`, and the type annotations and the single hand-off cast erase at build.
964
+ - 1b969ae: A scatter's two numeric axes now honour the spec `ChartAxis` every other chart
965
+ family already honours, instead of dropping it.
966
+
967
+ `min` / `max` / `stepSize` / `logarithmic` / `title` / `format` written on a
968
+ chart's `xAxis` or `yAxis` were accepted by the schema and resolved by
969
+ `normalizeChartSchema`, and then the scatter branch — alone among the families —
970
+ never handed them to its axes. An author who pinned `min: 0` to stop a
971
+ truncated-baseline reading got the truncated baseline back; a `logarithmic` axis
972
+ rendered linear; explicit `stepSize` ticks and an axis `title` never appeared.
973
+ Nothing refused and nothing looked broken: the chart drew confidently, at a scale
974
+ the author had overridden.
975
+
976
+ **This is a user-visible render change.** A scatter that already declared any of
977
+ those keys will now draw at the domain, tick spacing, scale and labelling it
978
+ asked for rather than at recharts' auto-fitted ones. A scatter that declares no
979
+ axis config renders exactly as before — the derivation contributes no prop when
980
+ there is no axis to derive from.
981
+
982
+ Both axes are covered, not just the y the report named: scatter is this
983
+ renderer's only family whose x is a numeric MEASURE rather than a category band,
984
+ so it is the only one where these keys mean anything on x, and it was dropping
985
+ them there too.
986
+
987
+ The repair composes with the scatter edge margin rather than shadowing it. That
988
+ margin is spent as recharts' axis `padding`, which insets the pixel range and
989
+ leaves the domain alone, so an authored domain and the margin are now live at
990
+ once — the domain is the author's, and no extreme mark is half-painted outside
991
+ the plot box. A pin holds that pair together.
992
+
993
+ No new key, no new exported symbol: the derivation the other families use is now
994
+ shared by both orientations, and the scatter axes spread it.
995
+ - 3f983f4: A chart heading now follows the VIEWER's language instead of the author's key order
996
+ (objectui#8943).
997
+
998
+ `@objectstack/spec` types `ChartConfigSchema.title` as `I18nLabel` — a plain string OR
999
+ an inline locale map — so `{ "title": { "zh-CN": "定价", "en": "Pricing" } }` is authored
1000
+ surface, not an accident. `normalizeChartSchema`'s module-local `label()` resolved the
1001
+ map arm with `Object.values(v).find(isString)`: **the first string in key order**. It
1002
+ never read the active language, never preferred `default` or `en`, and had no diagnostic
1003
+ — the chart rendered confidently in whichever language the author happened to type first.
1004
+ Reordering the JSON, with no other change, showed the same viewer a different language.
1005
+
1006
+ `label()` now delegates to `pickLocalized` (`@object-ui/i18n`), this repository's one
1007
+ answer for that union: exact tag -> base language -> a region-qualified sibling ->
1008
+ `default` -> `en` -> first value, pinned as the twin of the backend's `resolveI18nLabel`.
1009
+ The drill-drawer heading in the same component already routed through it, so `ObjectChart`
1010
+ had two answers for one union on one node; it now has one.
1011
+
1012
+ Every `I18nLabel` slot this module resolves is covered, not only the heading: `title`,
1013
+ `subtitle`, `description`, an axis `title` (`normalizeAxis`) and a series `label`
1014
+ (`normalizeSeries`).
1015
+
1016
+ - `normalizeChartSchema(schema, language?)` takes an OPTIONAL second argument — the
1017
+ viewer's active language. Every existing call compiles and every non-label key is
1018
+ byte-for-byte unchanged. `ChartRenderer` reads it from `useObjectTranslation()` and
1019
+ passes it down, which is what closes the defect on the rendered path.
1020
+ - Omitting it is not neutral: `pickLocalized` reads an absent language as `en`, so a
1021
+ locale map resolves through `default` -> `en` -> first value. That is deterministic
1022
+ rather than key-order-dependent, and it is the right answer only for a caller with no
1023
+ viewer. A caller that reads a heading off the result should pass one.
1024
+ - The admission test did not widen. Only a string or an inline locale map is accepted;
1025
+ a number or boolean `title` is still refused rather than stringified, because
1026
+ broadening what the renderer accepts belongs in the spec and not in a renderer-side
1027
+ coercion (AGENTS.md #0.1).
1028
+ - 14582b8: feat(types,plugin-charts): anchor `ObjectChart`'s props to `ObjectChartSchema` and declare the four keys its producers write
1029
+
1030
+ `ObjectChart` was published as `(props: any)`, so `ObjectChartSchema` anchored
1031
+ nothing: every `schema={{ … }}` literal handed to the component was type-checked
1032
+ against nothing at all. Four keys its producers write and its renderer reads —
1033
+ `xAxisKey`, `series`, `aggregate`, `filter` — were declared on neither published
1034
+ copy of the shape, and rode `BaseSchema`'s index signature / `.passthrough()`
1035
+ unvalidated. That is the mechanism that let objectui#7891's undeclared `config`
1036
+ rung survive from the day it was written.
1037
+
1038
+ Maintainer ruling 2026-09-09 (option A), applying objectui#6576's gallery
1039
+ treatment to the chart:
1040
+
1041
+ - `ObjectChartProps.schema` is `ObjectChartSchema`; the published `.d.ts` no
1042
+ longer says `props: any`. `ObjectChartProps` is exported.
1043
+ - The four keys are declared on BOTH copies, with value types taken from their
1044
+ READ sites (`ChartRendererProps` for `xAxisKey` / `series`, `ObjectChart.tsx`
1045
+ for `filter`) rather than copied from any producer's literal — except where
1046
+ `@objectstack/spec` already owns the shape, which is `aggregate`: that one is
1047
+ declared BY REFERENCE as `ChartAggregate` / `ChartAggregateSchema`, so the
1048
+ authoring door here and at the react-page publish gate are one shape and
1049
+ cannot drift into two dialects.
1050
+ - `colors` converges: the zod mirror has declared it since objectui#3913 and the
1051
+ TS interface did not, a drift no ratchet could see because a mirror-only key
1052
+ is in neither of the parity guard's two difference ledgers.
1053
+
1054
+ Two of the four are AUTHORABLE (`aggregate`, `filter` — the spec names this
1055
+ component's own props as their carrier and parses `aggregate` at the react-page
1056
+ publish gate) and two are INTERNAL, relay-composed (`xAxisKey`, `series` — every
1057
+ producer computes them and the spec's author-facing vocabulary refuses the
1058
+ internal spellings by name). The internal pair is declared anyway, because it was
1059
+ already passing through unvalidated: declaring buys the value check without
1060
+ minting authorable vocabulary, and each description says which it is.
1061
+
1062
+ ⚠️ **Dated note, 2026-09-28 — `series` has since gained an AUTHOR arm — objectui#10770.**
1063
+ Later in this same release each `ObjectChartSchema.series` entry became ONE of two arms,
1064
+ on both faces: the spec's `ChartSeriesSchema` (TS: `ChartSeries`), by reference, which is
1065
+ AUTHORABLE (the react tier's `ObjectChart` block publishes it as its `series` prop, and the
1066
+ react-page wrapper forwards the authored array onto the node), or the unchanged INTERNAL
1067
+ `{ dataKey }` arm, still typed from `ChartRendererProps`. So "two are INTERNAL,
1068
+ relay-composed (`xAxisKey`, `series` …)" now holds for `xAxisKey` and for the
1069
+ `{ dataKey }` arm only, and "except where `@objectstack/spec` already owns the shape,
1070
+ which is `aggregate`" now takes in the `{ name }` arm of `series` too. The `series`
1071
+ description names both arms. `.changeset/10770-object-chart-react-tier-node.md` (PR
1072
+ objectui#10802) states what ships; the text above is kept as the reading of this change.
1073
+
1074
+ `filter` keeps BOTH arms (a `FilterArray` or the ObjectQL `$filter` object), and
1075
+ narrowing to one is a decision LOCAL TO THIS NODE rather than a fleet-wide one:
1076
+ the six sibling `object-*` widgets that declare `filter` are already array-only,
1077
+ so there is no cross-widget convention to renegotiate. What blocks the narrowing
1078
+ is this component's own drill-down spread, which mis-composes the array arm into
1079
+ index keys; that is named as the successor on the member's docblock.
1080
+
1081
+ BEHAVIOUR, from what the anchor made visible: `ObjectChart` resolved the
1082
+ group-by column twice and only one site normalised the structured
1083
+ `groupBy: { field, dateGranularity }` node. The other used the raw union as a row
1084
+ index, a field name and a drill-filter key, so a date-bucketed chart lost its
1085
+ option-colour resolution, its label→raw reverse map and its drill filter to a
1086
+ lookup on the node's stringification. Both sites now share one normalisation, and
1087
+ the behaviour is pinned at runtime by
1088
+ `plugin-charts/src/__tests__/ObjectChart.structuredGroupBy-7946.test.tsx` (drill
1089
+ filter keyed by the projected column, alias and field arms, and the label→raw
1090
+ recovery) — a compile-time pin cannot see a wrong runtime value flowing from a
1091
+ correctly-typed read.
1092
+
1093
+ The drill drawer's heading fallback now resolves `schema.title` through
1094
+ `pickLocalized` (`@object-ui/i18n`) instead of using it as a bare string. The
1095
+ spec types that slot as `I18nLabel` — a plain string or an inline locale map —
1096
+ and the map arm used to reach the heading as an object.
1097
+
1098
+ ## Migration — what a TS consumer of `<ObjectChart schema={…}>` must change
1099
+
1100
+ The headline is that a wrong VALUE TYPE is now a compile error, but three
1101
+ NARROWINGS bite first, and they are what the eight edited test files in this
1102
+ change had to absorb:
1103
+
1104
+ - **`type: 'object-chart'` is now required on the literal.** A minimal
1105
+ `schema={{ objectName: 'account', chartType: 'bar' }}` no longer compiles.
1106
+ - **`chartType` must be the declared union.** A literal written inline is fine;
1107
+ one hoisted into a non-`const` object widens to `string` and is refused. Use
1108
+ `as const` (or annotate the holder as `ObjectChartSchema`).
1109
+ - **`series` entries must be `dataKey`-shaped.** The renderer's internal arm is
1110
+ `{ dataKey, … }`; the spec's author-facing `{ name, … }` arm is a different
1111
+ shape, translated by `normalizeChartSchema` one layer down.
1112
+
1113
+ ⚠️ **Dated note, 2026-09-28 — a `{ name }`-shaped `series` entry is now accepted —
1114
+ objectui#10770.** Later in this same release `ObjectChartSchema.series` took the spec's
1115
+ `ChartSeriesSchema` (TS: `ChartSeries`), by reference, as a second arm beside the
1116
+ `{ dataKey }` one, on both faces. So "`series` entries must be `dataKey`-shaped" no
1117
+ longer holds, and that narrowing no longer bites:
1118
+ `series: [{ name: 'total', label: 'Invoice value' }]` compiles and parses. An entry with
1119
+ neither `name` nor `dataKey` is still refused, and `normalizeChartSchema` is still the one
1120
+ translation between the arms.
1121
+ What bites instead is reading: an element of `ObjectChartSchema['series']` is a union, so
1122
+ a consumer narrows it (for example with `'dataKey' in entry`) before it reads `.dataKey`.
1123
+ `.changeset/10770-object-chart-react-tier-node.md` (PR objectui#10802) states what ships;
1124
+ the text above is kept as the reading of this change.
1125
+
1126
+ And, from the by-reference `aggregate`:
1127
+
1128
+ - **`aggregate.function` and `aggregate.groupBy` are REQUIRED**, `aggregate.field`
1129
+ stays optional (only `count` counts rows rather than a column), the structured
1130
+ `groupBy` node must name its `field`, and unknown members are REFUSED by name
1131
+ rather than dropped. `aggregate: {}` and `{ field: 'amount' }` used to compile
1132
+ and no longer do. This is `ChartAggregateSchema`'s accept set, which the publish
1133
+ gate has always enforced on authored `<ObjectChart aggregate={…}>` literals —
1134
+ so a document that compiles today is one the platform already accepted.
1135
+
1136
+ The RENDERER still accepts more than this and still draws its named refusal
1137
+ screen for an aggregate that declares no category axis (objectui#8168): untyped
1138
+ producers forward `aggregate` as `any`, so out-of-contract documents keep
1139
+ arriving at runtime. Narrowing the declaration is about what an author may
1140
+ WRITE, not about what the renderer will tolerate.
1141
+
1142
+ ⚠️ Anchoring does not buy rejection of a MISSPELLED key on the node itself:
1143
+ `BaseSchema` carries `[key: string]: any` (objectui#5155), the same ceiling
1144
+ objectui#6576 accepted. `aggregate` is the exception, and only because the spec's
1145
+ own object is strict.
1146
+
1147
+ ⚠️ **Dated note, 2026-09-28 — `aggregate` is no longer the only strict member —
1148
+ objectui#10770.** Later in this same release a `series` entry on the `{ name }` arm became
1149
+ the spec's closed `ChartSeriesSchema`, by reference, so on the zod face a misspelled key
1150
+ in one is refused, while one in a `{ dataKey }` entry is still stripped. So "`aggregate`
1151
+ is the exception" no longer holds alone. Other changes in this release did the same for
1152
+ `drillDown` (objectui#8885) and for `xAxis` / `yAxis` (objectui#10518), each a strict spec
1153
+ object by reference. A misspelled key on the node itself still passes, as above.
1154
+ `.changeset/10770-object-chart-react-tier-node.md` (PR objectui#10802) states what ships;
1155
+ the text above is kept as the reading of this change.
1156
+ - 6f017e9: Dashboard chart widgets no longer render as a blank area when their height class
1157
+ resolves to `auto`.
1158
+
1159
+ `ChartContainer`'s min-size fallback was applied only to the wrapper `div`.
1160
+ Recharts measures its own `width:100%;height:100%` size-detector element, and a
1161
+ percentage height never resolves against an ancestor's `min-height`, so the
1162
+ wrapper obediently grew to 280px while the measured element stayed at 0 — and
1163
+ Recharts renders no children at all for a non-positive box. The result was a
1164
+ widget card with its title over an empty chart area: no marks, no refusal, no
1165
+ empty state, and permanent, because a box that never changes fires no resize.
1166
+ The floor is now applied to the measured element as well, under the same
1167
+ condition, so an author's explicit height still wins.
1168
+
1169
+ ### Patch Changes
1170
+
1171
+ - a9f34df: fix(plugin-charts): the legend swatch carries its series colour as a custom property
1172
+
1173
+ `ChartLegendContent` painted each swatch with an inline `backgroundColor`, the
1174
+ colour-bearing property AGENTS.md's styling carve-out names as forbidden. The
1175
+ swatch now publishes the author-declared colour as `--color-bg` and a static
1176
+ `bg-(--color-bg)` utility consumes it, the same shape the tooltip indicator in
1177
+ the same file already uses, so the theme keeps control of the rule. The
1178
+ rendered colour is unchanged.
1179
+ - 3759c56: Gantt, chart and grid views refresh in place after a write instead of being rebuilt (objectui#10035).
1180
+
1181
+ `ObjectGrid`, `ObjectGantt` and `ObjectChart` query for themselves and read no refresh input, so both object-view layers could show them a write only by remounting them — which lost a gantt's scroll, collapsed groups and zoom, a chart's open drill-down, and a grid's selection, column state and in-progress edit. Each now refetches when the data-invalidation bus (`notifyDataChanged` / `useDataInvalidation` from `@object-ui/react`) reports a change to the object it reads:
1182
+
1183
+ - `@object-ui/plugin-grid`: `ObjectGrid` re-reads its rows into the same table.
1184
+ - `@object-ui/plugin-gantt`: `ObjectGantt` re-reads silently and keeps the chart mounted, as its toolbar refresh does.
1185
+ - `@object-ui/plugin-charts`: `ObjectChart` re-runs its query on both binding shapes — an object-bound aggregate follows its `objectName`, a dataset-bound chart follows the dataset's base object as the `queryDataset` answer names it.
1186
+ - `@object-ui/plugin-view`: the object view keys every view on its identity alone, and declares on the bus its own saves and deletes and each `onMutation` write it hears.
1187
+ - `@object-ui/app-shell`: the object page keys its list and its chart view on identity alone, and declares on the bus the changes it learns of without a data-source write — server actions, flows, imports, realtime events and an explicit refresh.
1188
+
1189
+ Rows a host hands these components (`data`, `bind`, inline values) are still the host's to refresh; only the components' own queries follow the bus.
1190
+ - bff63cc: A cartesian chart whose series are bound to a column no row carries now says so, naming the
1191
+ column, instead of drawing an empty frame (objectui#10396). The tile renders the existing
1192
+ `data-chart-error` placeholder with the new code `missing-series-key` and a sentence worded after
1193
+ `missing-category-key`: "This chart cannot plot its series: no row has a `KEY` field." Several
1194
+ missing keys are joined with "or". A console warning names the missing keys and the keys the rows
1195
+ do carry, as the category refusal's warning does.
1196
+
1197
+ The shape is objectui#8266's: a fieldless count projects its value as `count`, and a series bound to
1198
+ `value` over those rows drew the category ticks and zero marks, silently. What now refuses, each of
1199
+ which drew zero marks before: a bar / column / horizontal-bar / line / area / combo chart with rows,
1200
+ when not one row carries ANY bound series key. That holds whatever else the chart declares: a
1201
+ stack, a declared `min` / `max` or `stepSize`, or a second axis.
1202
+
1203
+ What keeps drawing, unchanged: a chart where even one row carries the key; a chart where one bound
1204
+ key is carried and another is not (the carried series draws); and a dotted key such as `a.b`,
1205
+ which the chart resolves into nested rows. A dotted key is never judged missing, so a chart that
1206
+ binds one stays silent even when it resolves nothing. A column no row carries beside a key that is
1207
+ carried but has no numeric value (for example an all-boolean series) also stays silent, as before.
1208
+
1209
+ Precedence: `missing-category-key` wins when the category key is missing too, and
1210
+ `no-plottable-series` still owns a chart with no series at all. A key that IS carried but holds no
1211
+ numeric value on any row keeps `no-numeric-value` (objectui#7195). Scatter, pie, donut, funnel,
1212
+ treemap and radar never receive this code.
1213
+ - a506001: A chart's `xAxis` object is no longer dropped when it carries `min`, `max`, `stepSize`,
1214
+ `logarithmic` or `position` without also carrying `title`, `format` or `showGridLines`
1215
+ (objectui#10516).
1216
+
1217
+ `normalizeChartSchema` kept the x-axis object only when one of those three hand-named keys
1218
+ was present. Any other axis lost everything but its `field`, so a scatter authored with
1219
+ `xAxis: { field: 'progress', min: 0, max: 200, stepSize: 50 }` drew the auto-fitted x
1220
+ domain and ticks instead of the ones it declared, and nothing refused. The object is now
1221
+ kept whenever it carries any key of the spec's `ChartAxisSchema` other than `field`. The
1222
+ key set is the one the normalizer reads, not a second hand-written list.
1223
+
1224
+ **User-visible render change.** A scatter whose `xAxis` declares `min` / `max` /
1225
+ `stepSize` / `logarithmic` with no title, format or grid flag now draws the x scale it asked
1226
+ for. That completes objectui#9675's x-axis repair for axes written that way. An `xAxis`
1227
+ carrying only `field` renders as before.
1228
+
1229
+ `position` on `xAxis` now survives normalization too, but at this change no renderer reads
1230
+ it: the x axis draws along the bottom whatever it says.
1231
+
1232
+ ⚠️ **Dated note, 2026-09-25 — the renderer now reads `xAxis.position` — objectui#10587.**
1233
+ Later in this same release the x axis takes the side `position` names where that axis can
1234
+ run along it, and a side it cannot take draws the default side with a note naming the key.
1235
+ The sentence above is kept as the reading of this change; the objectui#10587 entry states
1236
+ what ships.
1237
+ - 9fbbb17: BREAKING (`@object-ui/components`): `RefreshIndicator`'s `ariaLabel` prop is now required and has no default. It used to default to the English literal "Refreshing", so the progress bar on every view that passed no name was announced in English to screen-reader users in every locale (objectui#10580). A `RefreshIndicator` rendered without `ariaLabel` now fails to type-check.
1238
+
1239
+ (The bump is `minor` by this repo's release model: objectui's major follows the `@objectstack` family major, and its own breaking changes ship as `minor` with the breaking semantics stated here.)
1240
+
1241
+ Migration: pass the bar's accessible name from your own translation layer, for example `ariaLabel={t('grid.refreshing')}`. The component renders the string you pass as the bar's `aria-label` and does not translate it.
1242
+
1243
+ `ObjectGrid`, `ListView`, `ObjectChart` and `ObjectDataTable` now name their refresh bar in the active locale. The grid and the list read the `grid.refreshing` and `list.refreshing` keys their pull-to-refresh text already uses. The chart reads `chart.refreshing` and the dashboard data table reads `dashboard.refreshing`, both with no English literal behind them, so a host that renders either one with no i18next instance at all gets the key itself as the bar's name.
1244
+
1245
+ `@object-ui/i18n`: new keys `chart.refreshing` and `dashboard.refreshing` in every built-in locale pack.
1246
+ - 33b324c: A chart's `xAxis.position` now places the x axis, and a side that axis cannot take is
1247
+ refused with a note that names the key (objectui#10587).
1248
+
1249
+ `position` is declared on `@objectstack/spec`'s `ChartAxisSchema`, which `xAxis` takes by
1250
+ reference, and since objectui#10516 the normalizer keeps it on the x-axis object. No axis
1251
+ read it, so `xAxis: { field: 'month', position: 'top' }` validated and still drew the axis
1252
+ along the bottom.
1253
+
1254
+ - **bar, line, area and scatter** (and a combo derived from its series' families): the x
1255
+ axis runs across the plot. `top` draws it along the top; `bottom` draws it along the
1256
+ bottom, the default.
1257
+ - **horizontal-bar**: the `xAxis` object configures the category axis, which runs down the
1258
+ plot there (its `format` already applied to that axis). `left` or `right` puts the
1259
+ category axis on that side; the default stays the left.
1260
+ - **A side the axis cannot take** (`left` / `right` across the plot, `top` / `bottom` on
1261
+ horizontal-bar) draws the axis at its default side, and the chart shows a note under the
1262
+ plot (`data-chart-note="x-axis-position"`) naming `xAxis.position`, the value, and the
1263
+ side the axis was drawn on. The value still validates: `ChartAxisSchema` is shared by the
1264
+ x and y axes, and this change does not narrow it.
1265
+
1266
+ A top axis also mirrors its title and its rotated tick labels, so both stay on the far side
1267
+ of the axis from the plot.
1268
+
1269
+ **User-visible render change** only for a chart whose `xAxis` declares `position`. The
1270
+ bottom / no-position controls in `ChartRenderer.xAxisPosition-10587.test.tsx` pin that a
1271
+ chart declaring none still draws its x axis along the bottom with no note.
1272
+ - a95ec20: An object-bound `object-chart` that names its category with `aggregate.groupBy` alone now draws that
1273
+ category, instead of being refused with `missing-category-key` (objectui#10634).
1274
+
1275
+ A node with `objectName`, `aggregate: { field: 'amount', function: 'sum', groupBy: 'stage' }` and
1276
+ `series`, and no `xAxisKey` or `xAxis`, passed `ObjectChart`'s absent-category screen (objectui#8168),
1277
+ whose remedy lists `aggregate.groupBy` first. The schema `ObjectChart` then handed to `ChartRenderer`
1278
+ carried no category key, so the chart floored it on `'name'`, found no `name` column in the grouped
1279
+ rows, and refused. The author had followed the refusal's own remedy and was refused again, over a key
1280
+ they never wrote.
1281
+
1282
+ `ObjectChart` now forwards the category when the author named it only through `groupBy`. The key it
1283
+ forwards is the column the aggregate projects its group under, per the contract's result-column
1284
+ convention (`chartAggregateResultKeys` in `@objectstack/spec/ui`): the `groupBy` string, or
1285
+ `alias ?? field` for the structured `{ field, dateGranularity?, alias? }` node. This is the same
1286
+ column the dashboard relays already bind (objectui#8269). An `alias` therefore binds the aliased
1287
+ column the rows carry, not the underlying field.
1288
+
1289
+ What does not change:
1290
+
1291
+ - An authored category axis always wins. The forward fills an absent slot only, and asks this
1292
+ package's own axis resolution whether one is authored: `xAxisKey`, a spec-shape `xAxis: { field }`,
1293
+ or a bare string `xAxis`. It never writes over any of them.
1294
+ - Charts that draw authored rows (`data`, or a `bind` scope) are unchanged, with or without
1295
+ `objectName`. Their rows never went through the aggregate, so `groupBy` says nothing about their
1296
+ columns.
1297
+ - Dataset-bound charts (ADR-0021) are unchanged. They take their category from their dimensions.
1298
+ - The absent-category refusal fires on exactly the same nodes as before.
1299
+ - 4df0f3d: A chart's `yAxis[].position` now places each value axis, and `horizontal-bar` lays out and
1300
+ binds its axes (objectui#10654, the y-side twin of objectui#10587; objectui#10655 folded in).
1301
+
1302
+ `position` is declared on `@objectstack/spec`'s `ChartAxisSchema`, which each `yAxis` entry
1303
+ takes, and the normalizer keeps it. No axis was placed by it: it only chose which entry
1304
+ configured the right-hand axis a combo always draws (and the value format of a right-bound
1305
+ series), and how the normalizer bound the series it derives from the entries. So a lone
1306
+ `position: 'right'` entry drew its axis on the left, `top` / `bottom` passed in silence, a second
1307
+ entry was always the right-hand axis, and with no `series` a first entry at `right` took both
1308
+ derived series to the right-hand axis.
1309
+
1310
+ - **Where each entry is drawn.** `placeYAxes` (in `normalizeChartSchema`) is the one place a y
1311
+ side is resolved; the normalizer binds each series it derives from the entries with the same
1312
+ call, so a derived series plots against its own entry's axis.
1313
+ - bar (`column`), line, area, combo and scatter: `left` / `right`. Scatter draws one y axis,
1314
+ the first entry's.
1315
+ - horizontal-bar: the value axes run across the plot, so `bottom` / `top`; a series'
1316
+ `yAxis: 'left'` binds the bottom axis and `'right'` the top one.
1317
+ - A lone entry's axis is drawn on the side it names. With two entries each is drawn on the
1318
+ side it names, and an entry that names no side takes the side the other left free.
1319
+ - **Both entries naming the same side:** the first keeps it and the second is drawn on the
1320
+ other side, with a note naming `yAxis[1].position`. `yAxis[0]` is already the primary axis
1321
+ (its `showGridLines` governs the horizontal grid), and declaration order is the one
1322
+ tie-break an author can read off the metadata.
1323
+ - A side a value axis cannot take is refused: the entry is placed as if it named none, and
1324
+ the chart shows a note under the plot (`data-chart-note="y-axis-position"`) naming
1325
+ `yAxis[N].position`, the value and the side the axis was drawn on. `ChartAxisSchema` is
1326
+ shared by both axes and is not narrowed.
1327
+ - **horizontal-bar.** Two entries draw two value axes, along the bottom and the top, and the
1328
+ bars bind to them; they were bound to `yAxisId`s the branch never rendered, and bars were
1329
+ dropped. `xAxis.title` is drawn on the category axis, and the `yAxis` title is laid out for an
1330
+ axis running across the plot, under it at the bottom and over it at the top.
1331
+ - **Grid and annotations** bind to the rendered left value axis whenever the value axes carry
1332
+ ids (a combo always; bar, line, area and horizontal-bar with two entries). They were bound to
1333
+ an axis id those charts do not render: a two-entry chart's horizontal grid lost its per-tick
1334
+ lines and its `axis: 'x'` annotations, a combo with fewer than two entries drew no annotation,
1335
+ and a two-entry horizontal-bar dropped its `axis: 'y'` annotations.
1336
+ - **A right-hand value axis** lays its title out on the far side of its tick labels, the left
1337
+ layout mirrored, as a top x axis mirrors the bottom one.
1338
+
1339
+ **User-visible render change** for a chart whose `yAxis` entries declare `position`, a
1340
+ horizontal-bar with an axis title or two `yAxis` entries, the grid and annotations of two-entry
1341
+ and combo charts, and the title of every right-hand value axis.
1342
+ `ChartRenderer.yAxisPosition-10654.test.tsx` pins each row against its `bar` control.
1343
+ - daf1405: A chart's `yAxis` entry after the second now carries a note naming it, instead of going unused
1344
+ in silence (objectui#10691).
1345
+
1346
+ `@objectstack/spec` declares `ChartConfig.yAxis` as an uncapped list, so a third entry
1347
+ validates; a bar (`column`), line, area, combo or `horizontal-bar` chart draws at most two value
1348
+ axes, one per slot. Such an entry drew no axis and no note, while its `title`, `format`, `min`
1349
+ and `max` went unused and a series derived from it plotted against the right-hand axis.
1350
+
1351
+ - **The note.** Every entry after the second gets a `p role="note"
1352
+ data-chart-note="y-axis-undrawn"` under the plot, in the `ChartFootnote` channel the
1353
+ `x-axis-position` / `y-axis-position` notes use. It names `yAxis[N]` and, when the chart
1354
+ declares neither `series` nor `categories`, the axis its `field` is plotted against: the one
1355
+ in the right-hand slot (the top one on `horizontal-bar`), and the entry drawn there.
1356
+ - **One answer.** `placeYAxes` lists the entries it draws on no axis (`undrawn`), with the slot
1357
+ a series derived from one binds to. The normalizer binds that series from the list, and the
1358
+ renderer writes the note from it. The binding itself is unchanged: the right-hand slot, as
1359
+ before.
1360
+ - **Not narrowed.** The accepted count does not move, and the chart is not refused: the spec
1361
+ owns the `yAxis` face.
1362
+
1363
+ A chart with two entries or fewer, a `scatter` chart (it draws one y axis), and a family that
1364
+ draws no value axis render as before.
1365
+ - 1fc77fd: A `scatter` chart's `yAxis` entry after the first now carries a note naming it, instead of
1366
+ going unused in silence (objectui#10721).
1367
+
1368
+ `@objectstack/spec` declares `ChartConfig.yAxis` as an uncapped list, so a second entry
1369
+ validates; a `scatter` chart draws one value axis, the first entry's. objectui#10691 gave the
1370
+ bar (`column`), line, area, combo and `horizontal-bar` charts a note for each entry after the
1371
+ second, and left `scatter` as it was: with `series` authored, a second or later entry drew no
1372
+ axis and no note, and its `title`, `format`, `min` and `max` went unused.
1373
+
1374
+ - **The note.** Every entry after the first gets a `p role="note"
1375
+ data-chart-note="y-axis-undrawn"` under the plot, in the `ChartFootnote` channel
1376
+ objectui#10691's note uses. It names `yAxis[N]` and the one axis the chart draws, `yAxis[0]`.
1377
+ It says nothing about a series derived from the entry: with neither `series` nor
1378
+ `categories`, two entries that carry a `field` are refused as before
1379
+ (`data-chart-error="scatter-multi-series"`).
1380
+ - **One answer.** The scatter slice moved into `placeYAxes`, which now takes the chart family,
1381
+ so the renderer and the normalizer place the same entries. A series the normalizer derives
1382
+ from an entry after the first now binds to the slot the one axis is drawn in, where it used to
1383
+ bind as if the chart drew two axes. A scatter reads no series binding and measures its one
1384
+ series against that axis, so what it draws does not move.
1385
+ - **Not narrowed.** The accepted count does not move, and the chart is not refused: the spec
1386
+ owns the `yAxis` face.
1387
+
1388
+ A `scatter` chart with one entry, and every other family, render as before.
1389
+ - 256b4c9: A filter refused as malformed (`INVALID_FILTER`) no longer throws out of render or out of a click
1390
+ handler at the sites that merge filters there. That holds whether this layer's filter converter
1391
+ refused it or, at the drill seam, the spec's own `parseFilterAST`. Each site now surfaces the
1392
+ refusal the way its siblings already do (objectui#10789). The filter stays **refused**: nothing
1393
+ that was refused is accepted, and no site falls back to "no filter".
1394
+
1395
+ - **`ElementDataSourceGate` / `useElementDataSource`** (`@object-ui/react`): the gate's merge of
1396
+ the component's `filter` with the composed binding, and the merge of a saved view's filter
1397
+ with the binding's own, lowered through the throwing converter inside render. A refused
1398
+ filter from either now makes the binding `missing` with a new optional `filterRefusal` on the
1399
+ result (`error` carries its message). The gate then draws, in place of the block, the
1400
+ malformed-filter notice the wrapped blocks draw: `view.malformedFilter`, naming the refused
1401
+ operator or field. `element:record_picker`, which reads the same hook, shows its
1402
+ configuration-error panel with the refusal.
1403
+ - **`PeoplePicker` / `RecordPickerDialog`** (`@object-ui/fields`): the recents merge and the
1404
+ dialog's `mergedFilter` lower through `toFilterNodeSafely`; a refusal is shown in the picker's
1405
+ existing error state and no query runs without the filter.
1406
+ - **Drill-downs** (`ObjectChart`, `ObjectPivotTable`, `DatasetWidget`, `DatasetReportRenderer`):
1407
+ a widget or report filter refused at the drill seam made the drill click throw. The converter
1408
+ refuses some (a spec `$not`, say). The spec's `parseFilterAST` refuses others, such as a scalar
1409
+ on a list operator in either dialect: `[['stage', 'in', 'won']]` or `{ stage: { $in: 'won' } }`.
1410
+ The drill is now not opened or emitted (never with the scope dropped), and the refusal is logged
1411
+ with `console.warn`, naming the operator. `composeDrillFilter` (`@object-ui/core`) now throws
1412
+ one refusal type: the spec's `INVALID_FILTER` error is re-raised as a `FilterOperatorError` with
1413
+ its message and the same `INVALID_FILTER` / 400 envelope, and any other error passes through
1414
+ unchanged.
1415
+ - **`ListView` export** (`@object-ui/plugin-list`): the server export builds its filter inside
1416
+ its `try`, so a refusal is named in the export menu instead of escaping the click.
1417
+ - **`convertFiltersToAST`** (`@object-ui/core`): an `$or` member that is the TRUE identity no
1418
+ longer stops the members after it from being read. `{ $or: [{}, { a: {} }] }` is now refused
1419
+ like `{ $or: [{ a: {} }, {}] }` already was, instead of answering TRUE (every row); a TRUE
1420
+ disjunct beside members that lower still absorbs its `$or`.
1421
+ - eb97ce6: fix(plugin-timeline,plugin-charts,i18n): a stored date-only day reads as that day in every viewer zone on the timeline, on a chart's date axis and in the published date helpers (objectui#10866, slice 2)
1422
+
1423
+ These readers parsed a `YYYY-MM-DD` value with the engine's own `Date` parse, which reads it as UTC midnight, so every viewer west of UTC saw the day before. Each now reads the value through `toDisplayDate` from `@object-ui/core`, which rebuilds a date-only value at local midnight of the day it names. A value with a time part keeps its instant.
1424
+
1425
+ - **Timeline.** The object timeline's date bucket, its sort and the item date the renderer prints read the value that way. West of UTC an item due today no longer sits under "Overdue", one due tomorrow no longer sits under "Today", and the `short` and `long` item faces print the stored day. The `iso` face prints a date-only value's day from local getters, and an instant's UTC day as before. A day its month does not have, such as `2026-02-30`, is no longer rolled into March: the item sits under "No date", sorts with the dateless items, and its `short` and `long` faces are the ones an unparsable value already had. An unparsable value now sorts with the dateless items too, and the `iso` face prints such a value as written where it used to throw. The gantt variant's axis headers, extent and bar positions are not changed here, so west of UTC its bar tooltip, which prints through the same item-date function, now names the stored day while the axis above it still reads the day before, until a later slice of objectui#10866.
1426
+ - **Charts.** A date-only category on the x axis reads `Sep 1` for `2026-09-01`, and `Sep 2026` on a month-grained axis, in every zone. When the display locale is a tag `Intl` refuses, the tick still prints the stored day: it reads the local-midnight value with local getters, because its `toISOString()` would name the day before east of UTC. An instant's fallback keeps its UTC day. A date-only category naming a day its month does not have falls back to the raw category, the face any other non-date category gets, instead of the rolled day.
1427
+ - **i18n helpers.** `formatDate`, `formatDateTime`, `formatRelativeTime` and `formatDateSpec` read a date-only string as the day it names: `formatDateTime` shows midnight of that day, and `formatRelativeTime` counts to the start of it. `formatDateSpec` applies its `timeZone` to an instant only, and formats a date-only value in the local zone, where the shared step's local midnight reads back as its day; a `timeZone` west of UTC no longer turns `2026-09-01` into August 31st for every viewer. All four return a day its month does not have as the raw string. `formatRelativeTime` now returns an unparsable value as its string, the face the other three already gave one, where it used to throw a `RangeError`.
1428
+ - 6837bfa: fix(plugin-charts): an `object-chart` whose family is on `specType` gets `compareTo` exactly as the same family on `chartType` does, so a `specType: scatter` chart with `compareTo` draws instead of refusing, and `specType: pie` makes no comparison fetch (objectui#11530)
1429
+
1430
+ `ObjectChart` decides two things with `chartTypeIgnoresCompareTo` from `@object-ui/core`: whether to run the comparison query, and whether to add the `__comparison` overlay series. Both read only `chartType`. A family on `specType` (the react tier's channel, which objectui#11520 routes) was invisible to them. So a family that ignores `compareTo` (`pie`, `donut`, `funnel` and `scatter` at this release) still fetched the comparison window and still got the overlay:
1431
+
1432
+ - **`specType: scatter` with `compareTo`** made 2 aggregate calls and rendered the refusal "A scatter plots one measure. Keep exactly one series: amount, amount__comparison" (with the document's own measure). It now makes 1 call and draws the scatter.
1433
+ - **`specType: pie`, `donut` or `funnel` with `compareTo`** made a comparison call whose rows the chart never drew. It now makes 1 call. The picture is unchanged.
1434
+
1435
+ Both decisions now read the family the chart draws, which is the value `normalizeChartSchema` hands `ChartRenderer`: `chartType`, else `specType`. The family list stays the one in `chartTypeIgnoresCompareTo`. The object fetch also re-runs when that family changes, where it used to re-run on a `chartType` change only.
1436
+
1437
+ No other document changes: a family on `chartType` and every family that keeps `compareTo` (on either key) fetch and draw as before.
1438
+ - f82f857: fix(charts): a cartesian chart that declares no series at all now says so instead of drawing an empty frame (objectui#4695)
1439
+
1440
+ A `bar` / `horizontal-bar` / `line` / `area` / `combo` (and `column`) chart handed
1441
+ data rows but no series binding — no `series`, no `categories`, no y-axis `field`,
1442
+ so `series` reaches the renderer as `undefined` — drew axes, grid, tooltip and
1443
+ legend around zero marks and said nothing. It now renders the same placeholder
1444
+ objectui#4683 introduced for a computed-but-empty series list
1445
+ (`data-chart-error="no-plottable-series"`, `role="status"`), with its own sentence:
1446
+ "none was declared" rather than "no measure or group reached" the axis, and a
1447
+ console warning that lists the row keys a series could name.
1448
+
1449
+ Unchanged: a chart with no rows; pie, donut, funnel, radar and scatter charts,
1450
+ which fall back to a `value` column and keep drawing; and every chart that
1451
+ declares its series.
1452
+ - 39f4309: Published typings from every `vite-plugin-dts` package now carry an explicit extension on
1453
+ every relative specifier, and a type error in the declaration build now fails the build
1454
+ instead of being printed and ignored (objectui#5439, objectui#5483).
1455
+
1456
+ **Consumers on `moduleResolution: nodenext` or `node16` may see NEW type errors, and that
1457
+ is the fix working.** These packages re-export mostly through NAMED re-exports —
1458
+ `export { useObjectChat } from './useObjectChat'`. TypeScript could not follow the
1459
+ extensionless hop, but it still DECLARED the name, so the symbol resolved to a silent
1460
+ `any`. Nothing errored; consumers simply got no types. With the extension emitted, the
1461
+ symbol carries its real type, and any call site that was relying on the `any` now type
1462
+ checks for the first time. This is the mode that produced the 21 residual `TS7006` on
1463
+ `@object-ui/app-shell` reported against objectui#5365 — a type hole that opened quietly,
1464
+ unlike objectui#5365's own `export * from './ui'` packages where the same defect surfaced
1465
+ immediately as `TS2305: has no exported member`.
1466
+
1467
+ 410 extensionless relative specifiers across 19 packages were emitted before this change;
1468
+ the count is now 0 in all 22 packages that build typings through `vite-plugin-dts`.
1469
+ `@object-ui/fields` was already clean — its sources write explicit `.js` specifiers — and
1470
+ is wired so it stays that way.
1471
+
1472
+ The second half changes no emitted output today: 22/22 packages built green unmodified, so
1473
+ making the declaration step's exit code honest turns nothing red. It changes what a FUTURE
1474
+ regression does — print and exit 0, versus fail the build.
1475
+ - 3beef6d: The spec's `dataSource` element binding is now DECLARED by the blocks that read
1476
+ it, so the html tier stops reporting the one working saved-view spelling as
1477
+ `unknown-prop` (objectui#6678).
1478
+
1479
+ `PageComponentSchema.dataSource` — `{ object, view, filter, sort, limit }` — is
1480
+ the one spelling that resolves a saved view for an object-bound block. It works,
1481
+ and it drew the identical `unknown-prop` warning as the two spellings that do
1482
+ nothing (`viewName`, `view`), because `validateTree` looks a prop up in the
1483
+ block's declared `inputs` and no registration declared this key. On the tier
1484
+ built to accept AI-authored pages, where the diagnostic IS the contract, the
1485
+ only signal pointed away from the key that works.
1486
+
1487
+ Adopting the maintainer ruling of 2026-08-29 — option B **in the injection
1488
+ form**:
1489
+
1490
+ - `ELEMENT_DATA_SOURCE_INPUT` is the single declaration, in `@object-ui/core`
1491
+ beside the binding's own semantics; `Registry.register` emits it for any
1492
+ registration whose renderer passed through the new `elementDataSourceBlock()`
1493
+ seam. One mechanism, one copy — not a hand-kept declaration per block, which is
1494
+ the shape that drifts and that a new block forgets. The seam lives in
1495
+ `@object-ui/core` and is re-exported by `@object-ui/react` beside
1496
+ `ElementDataSourceGate` for discoverability; call sites take the core import,
1497
+ because a registration runs at module scope and this repo's suites partially
1498
+ mock `@object-ui/react`.
1499
+ - Seventeen renderers, in thirteen files across twelve packages, reach the seam
1500
+ and now publish the key to the save gate, the parser whitelist, the generated
1501
+ JSX authoring types and the block list. The card named nine blocks; the tree
1502
+ also has `plugin-grid`, `plugin-timeline`, two further `plugin-form` blocks and
1503
+ `element:record_picker` — nothing was hand-listed, so the mechanism covered
1504
+ them. `element:record_picker` consumes the gate's HOOK and status panels rather
1505
+ than the wrapper tag (its object lives under `properties`), and was found by a
1506
+ render probe rather than by reading sources.
1507
+ - `dataSource` on a block that does NOT read it (`flex`, `card`) still reports
1508
+ `unknown-prop`. Adding the key to `sdui-parser`'s `BASE_PROPS` was refused for
1509
+ exactly this reason — that set mirrors `BaseSchema`, and silencing the key
1510
+ everywhere would make the diagnostic lie in the other direction.
1511
+ - New `check:element-data-source-declaration` fails any source that consumes the
1512
+ gate without reaching the seam, so a block added tomorrow cannot forget.
1513
+
1514
+ Behaviour of the binding itself is unchanged — this is a declaration, not a
1515
+ resolution change. The saved view still resolves its columns, and an
1516
+ unresolvable `view` still fails loudly rather than widening to the object's full
1517
+ scope.
1518
+
1519
+ The spec/registry parity gates (repo-wide and the `record:related_list` per-block
1520
+ pin) now derive their accepted set from the WHOLE node contract rather than from
1521
+ `ComponentPropsMap[type]` alone. `PageComponentSchema` accepts and keeps
1522
+ `dataSource` on a page-component node — it is a node-level key, a sibling of
1523
+ `type` and `className`, not a per-block prop — so the gates' previous complaint
1524
+ was measurably wrong. Derived from the spec, not exempted, and both still
1525
+ discriminate against an invented key.
1526
+ - 40c4711: A sankey that drew only SOME of its rows now says how many (objectui#7148).
1527
+
1528
+ The sankey arm keeps strictly positive measures
1529
+ (`data.filter((r) => (Number(r?.[dataKey]) || 0) > 0)`), so a mixed dataset
1530
+ drew a normal, healthy, confident chart of a fraction of itself and nothing
1531
+ anywhere recorded that the other rows existed. Measured in Chromium across 27
1532
+ tiles: `[{New business: 40}, {Refunds: -25}, {Chargebacks: -12}]` rendered
1533
+ `svg: 1`, `path: 3`, 18 descendants, no `role`, no text, and — against a live
1534
+ console control that did fire on the same instrument — zero console output.
1535
+ Its screenshot hashed byte-identical to five other datasets, one of which
1536
+ genuinely had a single row. Six datasets, one image: a reader had no bit of
1537
+ information separating a complete flow from a third of one.
1538
+
1539
+ The discard itself stands — a flow has no negative width, so it is the only
1540
+ thing that arm can do with those rows. What is added is a footnote under the
1541
+ plot naming the ratio and the predicate the filter applies:
1542
+
1543
+ > Showing 1 of 3 rows — 2 rows have no `amount` above zero, which a flow
1544
+ > cannot draw.
1545
+
1546
+ It names the predicate rather than a cause because `Number(…) || 0` folds
1547
+ negatives, zeros, `null`, unparseable strings and a missing key into one
1548
+ discard, and all five were measured reaching this branch beside a survivor;
1549
+ naming any one of them is a sentence that is false for the other four.
1550
+
1551
+ A complete flow is byte-for-byte unchanged and gains no wrapper element, and a
1552
+ drawable sankey is never replaced by prose: the `no-positive-flow` refusal
1553
+ still owns the case where NOTHING survives the filter, and the "one positive
1554
+ among zeros still draws" boundary still draws — that fixture is itself a
1555
+ thinned dataset, so it now draws *and* says so.
1556
+ - e8c553b: A scatter handed more than one series now refuses instead of drawing a false picture.
1557
+
1558
+ Scatter binds one measure: `series[0].dataKey` is the y axis, and every series was
1559
+ handed the same rows through that one axis. A second series therefore added a
1560
+ colour and a legend entry and nothing else — measured, two series over two rows
1561
+ painted four symbols at two positions, each drawn twice, and the second measure's
1562
+ values appeared nowhere on the plot. The data was valid and the picture was
1563
+ confidently wrong, which no existing refusal could see.
1564
+
1565
+ A `chartType: 'scatter'` with two or more `series` now renders the renderer's
1566
+ refusal shell under `data-chart-error="scatter-multi-series"`, stating that a
1567
+ scatter plots one measure, naming the fix (keep exactly one series) and listing
1568
+ the series keys it was handed. A single-series scatter is unchanged.
1569
+
1570
+ This refusal counts authored `series` only. `compareTo` on scatter is out of
1571
+ its scope: objectui#7402 ruled (b) that scatter joins pie / donut / funnel in
1572
+ excluding `compareTo` — `supportsCompareTo` and the dashboard widget path stop
1573
+ synthesising a comparison series for it, so no `…__comparison` overlay is ever
1574
+ built for a scatter and this guard is never reached by a compare-to document.
1575
+ That exclusion ships as a separate change; until it lands, a `compareTo`
1576
+ document still reaches the renderer as two series and refuses here today.
1577
+
1578
+ No multi-measure projection is built (maintainer ruling, 2026-09-02): nothing
1579
+ in-repo authors a two-series scatter, so that capability waits for a real caller.
1580
+ The refusal copy is `chart.scatterOneMeasure` in all ten locale packs.
1581
+ - 3632060: A cartesian chart whose numeric axis has rows but nothing to build a scale from now says so
1582
+ instead of drawing an empty frame (objectui#7195). The tile renders the existing
1583
+ `data-chart-error` placeholder with the new code `no-numeric-value` and a sentence naming the
1584
+ bound key and the row count: "none of the N rows has a numeric value for KEY".
1585
+
1586
+ The answer is keyed on the whole dataset, not on the value's type. A boolean beside one real
1587
+ number still draws (Recharts builds the scale from the number and places the booleans on it), so
1588
+ that mixed chart keeps drawing with no note. What now refuses, each of which drew zero marks
1589
+ before:
1590
+
1591
+ - scatter, when every row's x (or y, or both) is a boolean, or a boolean mixed only with values
1592
+ that cannot be placed. That last shape used to carry a footnote implying one point was drawn;
1593
+ - bar / column / horizontal-bar / line / area / combo with no stacked bar or area series, when
1594
+ no row gives any bound series a value the axis can scale: every value boolean, `null` or an
1595
+ unparseable string. A line's `stack` has no effect in the renderer, so a "stacked" line is
1596
+ judged the same way.
1597
+
1598
+ A chart with ANY stacked bar or stacked area series is never refused, whatever its values: the
1599
+ stack gives its axis a scale on its own, and every series on that axis is placed on it (an
1600
+ all-boolean series beside a stacked all-`null` one draws). Some of those charts draw nothing
1601
+ (a stacked all-`null` bar, a stacked area of unparseable strings); they stay silent, exactly as
1602
+ before, rather than risk a sentence over marks that are on screen.
1603
+
1604
+ What keeps drawing, unchanged: numeric strings, `Number` objects, `Date` values, range values
1605
+ (an array read by its first two elements, both numbers, so `[1, 3]` and `[1, 2, 3]` alike: range
1606
+ bars and range areas), every chart with a STACKED bar or area series (the stack paints booleans
1607
+ as numbers, and unparseable strings, `NaN`, objects and arrays as full-height bars), a series that
1608
+ is all boolean beside a numeric one, a dual-axis chart with one live axis, and any axis whose
1609
+ spec declares both a numeric `min` and a numeric `max` (the chart builds that scale from the spec
1610
+ and places booleans on it), and any axis whose spec declares a `stepSize` (with one declared
1611
+ bound, the chart's tick builder reads booleans as 0 and 1 and supplies the other end; a `stepSize`
1612
+ alone is left silent too, erring toward silence). A `min` or `max` alone, `logarithmic` alone
1613
+ or an annotation does not build a scale, so those tiles are still refused. `''` counts as a value at zero: a line, area or scatter draws it, and a bar,
1614
+ horizontal-bar or combo paints the same zero-height picture as all-zero data, silently, exactly
1615
+ as before. A bound series key that is not a plain property of any row (a dotted path such as
1616
+ `a.b`, which Recharts resolves into nested rows, or a column no row carries) keeps the chart
1617
+ silent: the refusal fires only when every bound key is read from the rows directly. Rows with no placeable pair still get scatter's
1618
+ `no-plottable-points`, a multi-series scatter still gets `scatter-multi-series`, and
1619
+ `missing-category-key` / `no-plottable-series` still take precedence over this one.
1620
+
1621
+ ⚠️ **Dated note, 2026-09-27 — a column no row carries is now refused when every bound key is one — objectui#10396.** Later in this same release, a bar / column / horizontal-bar / line / area / combo chart whose every bound series key names a column no row carries renders its own refusal, `missing-series-key` ("no row has a `KEY` field"), instead of staying silent. A dotted path, and a column no row carries beside a key the rows do carry, still keep the chart silent. The rest of this entry is kept as the reading of this change; the objectui#10396 entry states what that shape now renders.
1622
+ - bb459ea: Name the scatter legend's series, so its swatch stops reading as a stray data point
1623
+ (objectui#7248).
1624
+
1625
+ The Chart Gallery scatter ("Estimate vs Progress") appeared to draw a seventh point
1626
+ below the x-axis, outside the plot area. It was not a point. `ChartLegendContent`
1627
+ resolves a label as `config[nameKey || item.dataKey || 'value']`, and a `<Scatter>`
1628
+ carries **no `dataKey`** — scatter's keys live on the XAxis/YAxis, not on the mark — so
1629
+ the key collapsed to the literal string `'value'`, missed a config keyed by measure
1630
+ name, and the legend entry rendered its colour swatch with no text beside it. An 8x8
1631
+ square in `--chart-1`, the same colour as the marks, sitting under the x-axis.
1632
+
1633
+ Measured on the running showcase in real Chromium: the swatch sat at cy 341 against a
1634
+ plot area ending at cy 295, on a y scale of 4.835 px per unit — y = -9.5, at x ≈ 45.
1635
+ That is the "x≈40, y≈-10" the report described, to the pixel, and all six real marks
1636
+ were inside the plot area at every viewport width swept from 1440 down to 480.
1637
+
1638
+ **The y domain was not the defect and is unchanged.** Clamping it — the fix the report
1639
+ asked for — would have created the bug it described: mixed-sign and all-negative
1640
+ fixtures are pinned here drawing every mark, because recharts already extends the
1641
+ domain to cover negative values.
1642
+
1643
+ Two changes. The scatter now passes `nameKey` so its legend resolves the measure's
1644
+ label, and `ChartLegendContent` falls back to the series `name` recharts itself put on
1645
+ the legend item when the config lookup misses. The second closes the class rather than
1646
+ this one instance: the swatch renders unconditionally, so a config miss must never
1647
+ leave it anonymous. Charts whose config already resolves are unaffected — only a
1648
+ currently-empty label changes.
1649
+ - 47547d0: Localize the server's built-in aggregate measure titles on dataset charts
1650
+ (objectui#7258 — consumer half of the objectstack#14492 contract; maintainer
1651
+ ruling B, 2026-09-02).
1652
+
1653
+ A dataset-bound chart's aggregate axis / legend title read the analytics
1654
+ service's hard-coded English `Count` on a zh console whose category labels were
1655
+ already Chinese. The renderer was passing `fields[].label` through verbatim —
1656
+ correctly, for an author-declared measure (objectui#4106) — and had no way to
1657
+ tell the server's built-in default apart from an author's label.
1658
+
1659
+ The wire now can: `AnalyticsResult.fields[]` gains an OPTIONAL structural
1660
+ discriminator, `builtinAggregate?: 'count' | 'sum' | 'avg' | 'min' | 'max' |
1661
+ 'count_distinct'`, populated only on the server-side built-in defaults
1662
+ (objectstack#14492). This change is the consumer side of that contract:
1663
+
1664
+ - `@object-ui/core`: `buildChartSeries` now accepts `ChartMeasureField[]` —
1665
+ `ChartResultField` plus the optional `builtinAggregate` carrier
1666
+ (`BuiltinAggregateCarrier`), declared beside the renderer shape rather than
1667
+ on it because the spec this release is built against does not carry the key
1668
+ yet; new `BUILTIN_AGGREGATES` / `BuiltinAggregate` / `isBuiltinAggregate` /
1669
+ `resolveMeasureLabel`; `ChartSeriesOptions.builtinAggregateLabels` carries
1670
+ the locale strings in (core stays React-free and i18n-free — the same
1671
+ division as `nullCategoryLabel`). A field carrying a recognised
1672
+ discriminator resolves through that map; every other field keeps its wire
1673
+ `label` verbatim — never by matching the label's text or the field's name
1674
+ (the rejected option A).
1675
+ - `@object-ui/i18n`: `builtinAggregateLabels(tt)` resolves the six strings
1676
+ through the existing `report.aggregate.*` keys (zh already carried 计数 /
1677
+ 求和 / 平均 / …; all ten packs are pinned to cover the vocabulary).
1678
+ - `plugin-charts` (`ObjectChart`), `plugin-dashboard` (`DatasetWidget`),
1679
+ `plugin-report` (`DatasetReportRenderer`): pass the resolved map to
1680
+ `buildChartSeries`.
1681
+
1682
+ Before: 合作中 / 已流失 / 潜在 under an axis titled `Count`. After: the same
1683
+ chart titled `计数`; an `en` session still reads `Count`; an author-labelled
1684
+ measure (`Tasks`) and a measure literally named `count` without the
1685
+ discriminator are byte-for-byte unchanged. Until the upstream field is
1686
+ populated the wire carries no discriminator and every chart renders exactly as
1687
+ before.
1688
+ - acb5797: Fix categorical (bar/line/area/combo) x-axis labels still being dropped above
1689
+ 5 buckets (objectui#7386, follow-up to objectui#7247).
1690
+
1691
+ `xAxisCommonProps` charged every band axis above `X_AXIS_ALL_LABELS_MAX_BUCKETS`
1692
+ a `minTickGap` of 48px (32px mobile) — a time-series budget that recharts adds
1693
+ **on top of** its own measured-overlap check, not instead of it. A 7-status
1694
+ pipeline at a 290px widget (≈33px/band) dropped 4 of its 7 names even though
1695
+ nothing was actually wide enough to collide.
1696
+
1697
+ `minTickGap` is now `0` for that branch: recharts' own measured-width overlap
1698
+ avoidance (`interval: 'preserveStartEnd'`, unchanged) is the only thing
1699
+ governing tick density above the bound, same as it already was for every tick
1700
+ it kept. Verified in real Chromium — this repo's DOM test environment reports
1701
+ zero text metrics, so it cannot exercise this change at all: at 7 and 8
1702
+ buckets and realistic widget widths, every label now draws with zero measured
1703
+ overlap (checked against each rotated label's true rotated rectangle, not an
1704
+ axis-aligned box); a 180-point daily series at 800px still thinned sensibly
1705
+ (11 ticks, zero overlap) — the "hundreds of points" case objectui#7247 guarded
1706
+ against stays protected by the same measured-overlap check, just without the
1707
+ removed extra margin.
1708
+
1709
+ Not changed: `X_AXIS_ALL_LABELS_MAX_BUCKETS` / the ≤5-bucket "draw everything"
1710
+ branch (objectui#7247, out of this issue's scope); the scatter chart's own
1711
+ `minTickGap` (its x axis is `type="number"`, a genuinely continuous measure,
1712
+ not a categorical band — a different axis with a different, still-correct,
1713
+ constant); and recharts' angled-tick collision model, which stays on its more
1714
+ conservative projected-bounding-box approximation rather than the true
1715
+ parallel-line perpendicular-separation constraint — a deliberate,
1716
+ documented-in-code choice, not an oversight, given this change's scale (a
1717
+ handful of buckets, not a rewrite of recharts' geometry).
1718
+ - e859ad0: Reserve a margin at both ends of a scatter's numeric axes, so an extreme mark is drawn
1719
+ wholly inside the plot area (objectui#7396).
1720
+
1721
+ Both scatter axes are numeric and carry no explicit domain, so recharts fits the domain
1722
+ to `[dataMin, dataMax]` and maps it across the whole plot box. A row at either extreme
1723
+ is therefore **centred on the boundary**, and since a mark has a radius, about half of
1724
+ each extreme symbol paints outside the plot area — the half-dots hugging both edges of
1725
+ the Chart Gallery scatter.
1726
+
1727
+ Measured on that scatter ("Estimate vs Progress") in real Chromium — viewport 1440,
1728
+ widget svg 510x350, plot area x 53..505 / y 5..296:
1729
+
1730
+ - before: marks at cx 53, 256.4, 301.6, 414.6, 459.8, 505 with the y-max row at cy 5,
1731
+ radius 4.514px. The first and last sit exactly on the x boundary and the y-max one on
1732
+ the top boundary, each overhanging its edge by a full radius.
1733
+ - after: cx 65, 257.6, 300.4, 407.4, 450.2, 493 with the y-max row at cy 17. The worst
1734
+ case now clears its nearest edge by 7.486px, on both axes.
1735
+
1736
+ The card reported the x axis; the y axis clipped the same way and is fixed with it.
1737
+
1738
+ **The domain is not touched.** The margin is reserved as recharts' axis `padding`, which
1739
+ insets the pixel range the scale maps into and leaves the domain alone, so every tick
1740
+ **value** is unchanged — the axes still read 0/25/50/75/100 and 0/15/30/45/60 — and only
1741
+ the mapping moves. Padding the domain instead would invent unround tick endpoints, and it
1742
+ would write the same recharts prop a spec-declared `min`/`max` needs (objectui#9675), where
1743
+ whichever landed second would shadow the other.
1744
+
1745
+ The margin is sized to the largest radius the scatter's declared symbol-area envelope
1746
+ admits, not to the radius drawn today, so neither a change in recharts' own default mark
1747
+ size nor a future variable-size mark can reopen it.
1748
+
1749
+ Every scatter's marks shift inward by that margin; nothing else about the chart changes.
1750
+ - ed4a2f1: fix(plugin-charts): `pie-chart`, `donut-chart`, `radar-chart` and `scatter-chart` render as the family they name
1751
+
1752
+ A schema written as `type: 'pie-chart'` (or `plugin-charts:pie-chart`, and likewise donut / radar / scatter) drew a **bar chart**. The four registrations declared their family as `defaultProps: { chartType: … }`, and nothing on the SDUI path has ever read a registration's `defaultProps` — so `ChartRenderer` resolved no family and `AdvancedChartImpl` fell to its `'bar'` default. Valid data, a confidently wrong picture, and no `data-chart-error` that could fire.
1753
+
1754
+ `ChartRenderer` now derives the family from the schema's own `type`, through `normalizeChartSchema` — the package's single translation point, so the exported `normalizeChartSchema` answers what the runtime actually draws. An explicit `chartType` still wins, so `plugin-charts:chart` with `chartType: 'scatter'` is unchanged.
1755
+
1756
+ The five inert `defaultProps: { chartType: … }` are removed with it rather than left beside a mechanism that works. Registration `defaultProps` remains unread on the SDUI path repo-wide; activating it generally is a separate, wider change and is not this one.
1757
+
1758
+ ⚠️ `scatter-chart` now genuinely reaches the scatter arm, so a two-series `scatter-chart` now renders the `scatter-multi-series` refusal it was always supposed to.
1759
+
1760
+ ⚠️ **Dated note, 2026-10-02 — `scatter-chart` is retired — objectui#10859.**
1761
+ Later in this same release objectui#10859 batch 8 (phase 2b) unregistered `scatter-chart` and
1762
+ `plugin-charts:scatter-chart`, and its `CHART_TYPE_KEYWORD_FAMILIES` row went with it; the scatter
1763
+ family is authored as `{ type: 'chart', chartType: 'scatter' }`. `pie-chart`, `donut-chart` and
1764
+ `radar-chart` stay registered. The rest of this entry is kept as the reading of this change.
1765
+
1766
+ ⚠️ **Dated note, 2026-10-02 — `pie-chart`, `donut-chart` and `radar-chart` are retired too — objectui#10859.**
1767
+ Later in this same release objectui#10859 batch 8 (phase 2c) unregistered the three keys, with their
1768
+ `plugin-charts:` twins and `CHART_TYPE_KEYWORD_FAMILIES` rows, after moving `examples/chart-examples.ts`
1769
+ to `{ type: 'chart', chartType: 'pie' | 'donut' | 'radar' }`. `chart:bar` is the one family keyword left.
1770
+ The rest of this entry is kept as the reading of this change.
1771
+ - ff79d38: Read the spec-declared lookup spellings in two readers that could not see them at all
1772
+ (objectui#7435).
1773
+
1774
+ `ObjectChart`'s group-by label chain and `resolveActionParams`' picker group both read the
1775
+ object-schema field def in `snake_case` only. That def is what `getObjectSchema` /
1776
+ `useMetadata()` serve, and it carries the spelling `@objectstack/spec`'s `FieldSchema`
1777
+ declares — so `displayField`, `descriptionField` and `lookupFilters` were dropped on the
1778
+ floor. The chart fell through to the generic `name` heuristic and drew a label the author
1779
+ had explicitly overridden; an action param rendered its picker with defaults. Nothing
1780
+ warned, because the readers were simply reading keys that were not there.
1781
+
1782
+ Each of the three keys now has its declared spelling ranked FIRST, with the existing
1783
+ `snake_case` legs kept behind it in their existing order — the shape objectui#7155
1784
+ established. Measured on the pin this tree resolves, `@objectstack/spec@17.4.0`:
1785
+ `FieldSchema.safeParse` over a minimal lookup def accepts all three camelCase keys and
1786
+ refuses every snake twin with `unrecognized_keys`, with the minimal def accepted and a
1787
+ nonsense key refused as controls in the same run.
1788
+
1789
+ The legacy legs are kept rather than retired. A per-site producer sweep found no in-repo
1790
+ producer of any of the three snake spellings and zero key-position occurrences in the
1791
+ producer repo (control lit), but two producers lie outside what that sweep measures: a
1792
+ document stored before the key was tightened, since the serve path runs no parse, and a
1793
+ host `DataSource` that never passes through the adapter's key canonicalisation. Dropping a
1794
+ leg would be a silent regression for already-authored data.
1795
+
1796
+ Two keys deliberately gain nothing. `idField` has no `FieldSchema` spelling in either
1797
+ casing, and `titleFormat` is an object-level key whose canonical target is deprecated in
1798
+ favour of `nameField`; reading either camelCase spelling would fossilise a key no contract
1799
+ declares, so both keep their existing snake-only reads and their absence is now pinned.
1800
+ - c6198c2: **Breaking for authored metadata:** `ComponentInput.label`, `ComponentInput.defaultValue` and
1801
+ `ComponentInput.advanced` are RETIRED on both faces (objectui#7493 item ① and objectui#7781;
1802
+ maintainer ruling A of 2026-09-06, immediate, no deprecation window; ADR-0049 enforce-or-remove).
1803
+ They are the three keys the manifest serializer does not forward, and nothing read them on any
1804
+ publication or consumption path.
1805
+
1806
+ No manifest ever published them, so no consumer could ever have read them. `sdui-parser`'s
1807
+ serializer (`packages/sdui-parser/src/index.ts`) forwards exactly seven keys per input — `name`,
1808
+ `type`, `of`, `required`, `enum`, `binding`, `description` — so a value authored under any of the three
1809
+ never reached `sdui.manifest.json`, the generated JSX `.d.ts`, or a diagnostic; its boundary type
1810
+ has no slot for them; the registry's data-source seam reads `name` only; and neither the designer
1811
+ nor the app-shell inspectors consult registry `inputs` at all. A structural census over every
1812
+ `inputs:` array in the repository (re-measured on this change's merge-base, `name` 951 and `type`
1813
+ 951 as the controls) counted the writes: `label` 908, `defaultValue` 245, `advanced` 9 — written on
1814
+ nearly every registration, read by nothing.
1815
+
1816
+ FROM → TO, per key — all three **TOMBSTONED, not removed**, because the route was measured on
1817
+ the built face before it was chosen: `ComponentInputSchema` is a non-strict `z.object`, and an
1818
+ undeclared key parses GREEN and is silently STRIPPED, so a deletion would have swallowed 1,162
1819
+ authored values in silence. The tombstone is what makes the refusal loud and by name.
1820
+
1821
+ - `label?: string` → `label?: never` on the interface, `retirementTombstone()` on the Zod mirror.
1822
+ Migration: delete the key. An input is identified by its `name` on every path that reaches it;
1823
+ nothing ever rendered a label for it.
1824
+ - `defaultValue?: any` → `defaultValue?: never` / `retirementTombstone()`. Migration: delete the
1825
+ key. The renderer's own fallback read IS the default; tell the author about it in `description`,
1826
+ which IS published. (Tightening the type to `unknown` was ruled out: it closes no error class,
1827
+ since nothing reads the value.)
1828
+ - `advanced?: boolean` → `advanced?: never` / `retirementTombstone()`. Migration: delete the key.
1829
+ No designer surface ever hid an "advanced" input; there is nothing to write instead.
1830
+
1831
+ The retirement kit: `?: never` on `ComponentInput` (`packages/types/src/base.ts`), so authoring one
1832
+ is a `tsc` error at the registration site; `retirementTombstone()` on `ComponentInputSchema`
1833
+ (`packages/types/src/zod/base.zod.ts`), so an authored value is REFUSED at parse time with
1834
+ `code: 'invalid_type'`, the key named in the issue `path`, and the migration note as the message
1835
+ (one string, both channels). Pinned in
1836
+ `packages/types/src/__tests__/component-input-retired-keys-7493.test.ts`, which also holds a
1837
+ tree-scoped absence census over every `inputs:` array under `packages/**` and `apps/**`.
1838
+
1839
+ Accept-set change, stated plainly for reviewers: a document that sets any of the three keys on a
1840
+ `ComponentInput` used to parse GREEN (the value was then dropped by the serializer) and now parses
1841
+ RED. Every in-repo authoring site — 1,199 keys across 110 registration files, the three standalone
1842
+ `ComponentInput[]` arrays and the two named input arrays `tsc` found included — is deleted in the same change, as the ruling's split rule
1843
+ requires; the `WidgetRegistry` seam no longer copies the widget-manifest values onto the synthesized
1844
+ `ComponentInput` (they fed nothing), and the data-source declaration `ELEMENT_DATA_SOURCE_INPUT`
1845
+ drops its `label`. The patch entries on the other packages record exactly that: their registrations
1846
+ stop authoring inert keys, with no runtime or published-manifest change.
1847
+
1848
+ The nine test files that read `defaultValue` off a registration were re-pinned against the
1849
+ renderer's ACTUAL default (its own fallback read, or the `defaultProps` it ships) instead of the
1850
+ declaration that went away; two assertions that only restated the shadow default were dropped with
1851
+ the reason on the line.
1852
+
1853
+ The in-repo zero is what was measured. Whether anything OUTSIDE this repository writes these keys
1854
+ is not measurable from here (the objectui#5674 limit); converting such a write from a silent drop
1855
+ into a named refusal is exactly what the tombstones buy. `WidgetInput`'s own `label` /
1856
+ `defaultValue` / `advanced` (the widget-manifest face) stay declared and writable — nothing has
1857
+ ruled on that face; that it now has no reader either is recorded as objectui#7911.
1858
+ - 1fbf63f: Honour a radar series' declared presentation keys (objectui#8157).
1859
+
1860
+ On `chartType: 'radar'` the mark rendered a bare `fillOpacity={0.6}` and read nothing
1861
+ off the series, so three things `@objectstack/spec` declares for every `ChartSeries`
1862
+ were inert at once — `opacity` and `dashArray` (both read by `normalizeSeries` and then
1863
+ discarded) and the whole `variant: 'comparison'` treatment, which is declared and
1864
+ documented with no family restriction. A radar series carrying any of the three drew
1865
+ identically to one carrying none, while every cartesian mark in the same file resolved
1866
+ its presentation through the shared `seriesStyle` helper.
1867
+
1868
+ The radar arm now calls that helper like the cartesian arms do:
1869
+
1870
+ - an authored `opacity` sets both the polygon's fill and its stroke opacity;
1871
+ - an authored `dashArray` dashes the polygon outline — radar is a stroked mark, so
1872
+ unlike a bar or a scatter this is a family where a dash actually paints;
1873
+ - `variant: 'comparison'` mutes a radar overlay, taking the `area` family's defaults
1874
+ (radar being the other mark this renderer both strokes and fills) rather than any
1875
+ newly invented numbers.
1876
+
1877
+ **The default face does not move.** `0.6` was a default as much as a bug — a radar fill
1878
+ needs some opacity or an overlay is unreadable — so the literal became the fallback
1879
+ (`fillOpacity={pres.fillOpacity ?? 0.6}`) instead of being deleted. A radar series that
1880
+ declares none of the three keys paints exactly what it painted before: `fill-opacity`
1881
+ `0.6`, no stroke fade, no dash. Already-drawn radar charts that author nothing are
1882
+ untouched; only a chart that authors one of the keys changes, which is the repair.
1883
+
1884
+ No cartesian arm changed. The helper gained `'radar'` in its `kind` union and an
1885
+ `areaLike` binding that is exactly `kind === 'area'` for every cartesian kind.
1886
+ - fc32921: Fix a dashboard chart widget with a FIELDLESS `count` aggregate plotting nothing
1887
+ (objectui#8266).
1888
+
1889
+ A widget bound to an object with `aggregate: { function: 'count', groupBy: 'status' }`
1890
+ and no `field` — the normal way to author "how many records per status" — rendered an
1891
+ empty chart. No error, no empty state: a plot frame with the category ticks drawn and
1892
+ not one mark in it, which reads exactly like "this object has no rows yet".
1893
+
1894
+ **Cause.** The two dashboard relays (`DashboardGridLayout`, `DashboardRenderer`) each
1895
+ built the series binding as `aggregate?.field || (options.yField || 'value')`, which for
1896
+ a fieldless count resolves to `'value'`. The rows an object-bound fieldless count
1897
+ returns are keyed `'count'` — the alias the engine projects `COUNT(*)` under, pinned
1898
+ since framework#3701. A `dataKey` naming a column no row carries plots nothing, and
1899
+ neither of the renderer's two guards fires on it: the rows DO carry the category key,
1900
+ and the series array is not empty.
1901
+
1902
+ **Fix.** `chartMeasureKey` is a new `@object-ui/core` export delegating to
1903
+ `chartAggregateValueKey` in `@objectstack/spec/ui` — the contract's own derivation of
1904
+ "the value column an object-bound aggregate produces". Both relays now consult it, and
1905
+ the row-projection side (`aggregateValueKey` in `@object-ui/plugin-charts`) is routed
1906
+ through the same function, so the two halves of the question cannot drift again.
1907
+
1908
+ **What moves on screen.** A chart that was blank now draws. Charts that already drew are
1909
+ unaffected: a field-bearing aggregate resolves to its raw field under both the old and
1910
+ the new reading, and a chart with no `aggregate` at all keeps the author's `yField`.
1911
+ One authored key changes meaning: a `yField` written on an object-bound chart that
1912
+ ALSO declares an aggregate no longer wins over the aggregate's own column — it named a
1913
+ record column that a grouped aggregate never returns, so it plotted nothing before.
1914
+
1915
+ **Not fixed here, and out of scope.** The same widget with no `options.xField` is
1916
+ refused by the category-axis guard naming `name`, a key the author never wrote (they
1917
+ wrote `aggregate.groupBy`). That is the category half of the same relay gap and is
1918
+ filed separately.
1919
+ - 8f9d87a: Fix a dashboard chart widget that declares its category as `aggregate.groupBy` being
1920
+ refused for lacking a `name` column (objectui#8269).
1921
+
1922
+ A widget bound to an object with `aggregate: { function: 'count', groupBy: 'status' }`
1923
+ and no `options.xField` rendered a refusal instead of a chart:
1924
+
1925
+ > This chart cannot plot its category axis: no row has a `name` field.
1926
+
1927
+ The author wrote `groupBy: 'status'`. Nothing on screen said `groupBy` was the key that
1928
+ had been ignored, and `name` appeared nowhere in their metadata — so the diagnostic sent
1929
+ them to debug the wrong layer.
1930
+
1931
+ **Cause.** The two dashboard relays (`DashboardGridLayout`, `DashboardRenderer`) each
1932
+ floored the category binding on a literal — `options.xField || 'name'` — and handed it to
1933
+ the `object-chart` node without ever consulting the aggregate that decides it. An
1934
+ object-bound aggregate returns one row per group keyed by the raw `groupBy` field, so no
1935
+ row carried `name` and the category-axis guard (framework#4033) fired correctly on a
1936
+ binding that was already wrong when it arrived.
1937
+
1938
+ **Fix.** `chartCategoryKey` is a new `@object-ui/core` export delegating to
1939
+ `chartAggregateCategoryKey` in `@objectstack/spec/ui` — the contract's own derivation of
1940
+ "the category column an object-bound aggregate produces", and the published sibling of the
1941
+ `chartAggregateValueKey` that objectui#8266 adopted for the measure axis. Both relays now
1942
+ consult it for the object-provider branch.
1943
+
1944
+ **What moves on screen.** A widget that rendered a refusal now draws. Measured through
1945
+ `ChartRenderer` at 480x320 over the rows a fieldless count returns
1946
+ (`[{status:'open',count:2},{status:'paid',count:5}]`): the composed binding went from
1947
+ `xAxisKey: 'name'` — a `missing-category-key` refusal, 0 marks — to `xAxisKey: 'status'`,
1948
+ 1 series and 2 marks with the category ticks drawn.
1949
+
1950
+ **Unaffected.** A chart with no `aggregate` at all keeps the author's `xField` (its rows
1951
+ are raw records, so that key is the right one), an UNGROUPED aggregate keeps it too (it
1952
+ returns a single row with no category column), and the authored-literal-rows branch — the
1953
+ `chart` node composed after the object-provider check fails — keeps its floor unchanged.
1954
+ One authored key changes meaning, exactly as objectui#8266's `yField` did: an `xField`
1955
+ written on an object-bound chart that ALSO declares a `groupBy` no longer wins over the
1956
+ aggregate's own column — it named a record column a grouped aggregate never returns, so it
1957
+ produced the same refusal before.
1958
+ - 681d3f1: Compose an `ObjectChart` drill-down filter instead of spreading it, so the widget's own
1959
+ filter survives into the drilled query for BOTH arms of `ObjectChartSchema.filter`
1960
+ (objectui#8944).
1961
+
1962
+ **The defect.** `ObjectChartSchema.filter` admits a spec `FilterArray`
1963
+ (`[['region','=','emea']]`) and the ObjectQL `$filter` object (`{ region: 'emea' }`),
1964
+ and both are read — both travel verbatim to `ds.aggregate` / `ds.find`. The drill seam
1965
+ composed them by spreading the widget's filter into an object literal, which is correct
1966
+ for the object arm and silent nonsense for the array arm: spreading an array yields
1967
+ index keys, so an authored `FilterArray` drilled as
1968
+ `{ '0': ['region','=','emea'], stage: 'won' }` — the widget's conditions replaced by a
1969
+ key the query layer ignores. Nothing errored; the drawer opened and looked right.
1970
+
1971
+ **Direction of the failure.** The widget's filter is what narrows. Dropping it made the
1972
+ drilled list a **superset** — it showed records the chart itself was scoped to exclude.
1973
+ Not a security boundary, but the worse direction for a silent bug.
1974
+
1975
+ **The composition rule, named rather than picked.** `widget.filter ∧ drill.filter`. The
1976
+ two are independent filter sources and a drill must satisfy both: the click context only
1977
+ says which bucket of the widget's scope was asked for, so it may narrow that scope and
1978
+ never widen it. This is not a new rule — it is the contract `mergeFilterNodes` already
1979
+ states ("combine filter sources under a single `and`, each as its OWN child"), the sink
1980
+ every other multi-source filter in this repo goes through. A new
1981
+ `composeDrillFilter` helper in `@object-ui/core` applies it at the drill seam and
1982
+ documents it, then lowers the result back to the `FilterCondition` object dialect with
1983
+ `parseFilterAST` — the spec's single lowering sink — because that is the dialect both
1984
+ drill sinks take.
1985
+
1986
+ **Compatibility.** A lone surviving source lowers back to exactly the flat object the
1987
+ spread produced, so a chart with no filter of its own drills byte-identically to before.
1988
+ Only a genuinely composed pair gains the `$and`.
1989
+
1990
+ `serializeDrillFilterParams` (the drill "Open in list" / `target: 'navigate'` URL writer)
1991
+ learns to flatten that `$and` into the flat `filter[...]` params its own read side already
1992
+ ANDs back together. Without that it took the `String(value)` path — `$and` holds an array —
1993
+ and emitted `filter[$and]=[object Object],[object Object]` while both real conditions
1994
+ vanished, which is the outcome that function's contract says it never produces.
1995
+ - 6223a9d: fix(plugin-charts): a scatter chart's grid now honours the spec axis `showGridLines`
1996
+
1997
+ The scatter branch drew its grid from a hard-coded `vertical={false}` instead
1998
+ of the grid config every other cartesian family derives from the spec axes, so
1999
+ `showGridLines` declared on either scatter axis was accepted and then dropped.
2000
+ It now uses that same derivation: `yAxis.showGridLines: false` removes the
2001
+ horizontal lines and `xAxis.showGridLines: true` adds vertical ones.
2002
+
2003
+ A scatter whose axes declare no `showGridLines` renders exactly as before
2004
+ (horizontal lines only).
2005
+ - a78cd37: Dates and numbers across the console and the plugins format in the session's
2006
+ display locale instead of the machine's (objectui#9909).
2007
+
2008
+ Every one of these faces handed `Intl` — directly, or through a formatter called
2009
+ without one — either no locale tag or an explicit `undefined`, which is not "the
2010
+ user's locale": it is the locale of the machine the browser runs on, which is
2011
+ neither of this repository's two locale channels.
2012
+ A German or Spanish session therefore read, beside a translated label, a date or
2013
+ an amount grouped and decimal-marked the machine's way — and an amount with
2014
+ inverted separators does not read as unformatted, it reads as a different
2015
+ number. They now go through `useDisplayLocale()` (tenant regional default, then
2016
+ the active UI language, then `'en'`), and a plain helper takes that tag from its
2017
+ caller. The surfaces:
2018
+
2019
+ - **`@object-ui/fields`** — `GridField`'s numeric and currency cells (list mode
2020
+ and computed columns) and both total cells. The same cell helper's date branch
2021
+ already used the display locale, so a single grid row read two conventions at
2022
+ once.
2023
+ - **`@object-ui/plugin-charts`** — ISO-date x-axis ticks, compact y-axis ticks,
2024
+ the single-value face, spec `format` strings and the tooltip value.
2025
+ - **`@object-ui/app-shell`** — the organization invitations, members and
2026
+ accept-invitation dates; marketplace version dates; the AI conversation row's
2027
+ older-than-a-week date and its tooltip; the build-debug token count; the
2028
+ record approvals timeline; and the metadata-admin audit, history, external
2029
+ datasource snapshot, schema-browser row estimate, flow-run start and job
2030
+ next-fire faces. The audit, history and flow-run panels format these in the
2031
+ DISPLAY locale, not in the `locale` prop they take for their UI strings
2032
+ (`AuditPanel` defaults that prop to `'en-US'`; `HistoryPanel` and
2033
+ `FlowRunsPanel` leave it optional).
2034
+ - **`@object-ui/console`** — the approvals inbox's timestamp tooltips, amounts
2035
+ and payload summary; the audit log's timestamp column; the flow runs table and
2036
+ its run detail.
2037
+ - **`@object-ui/components`** — the export dialog's record counts and the debug
2038
+ panel's event times.
2039
+ - **`@object-ui/plugin-form`** — the analytics submission count, the
2040
+ master-detail subtotal / tax / total stack and the edit-conflict dialog's
2041
+ "their save" time.
2042
+ - **`@object-ui/plugin-chatbot`** — the approvals inbox's past-30-days date and
2043
+ the times stamped on local-mode chat messages (the user's and the
2044
+ auto-response).
2045
+ - **`@object-ui/plugin-dashboard`** — the record-count badge, and the currency
2046
+ and date-format branches of `renderFieldValue`, which was handed the display
2047
+ locale and spent it only on its percent branch.
2048
+ - **`@object-ui/plugin-grid`** — the record-detail panel's inferred currency
2049
+ value and the mobile card's amount line, siblings of date cells already on the
2050
+ display locale.
2051
+ - **`@object-ui/plugin-designer`** — `VersionHistory`'s version times.
2052
+
2053
+ A host that mounts one of the components that newly read the display locale with
2054
+ NO `I18nProvider` now gets react-i18next's once-per-module `NO_I18NEXT_INSTANCE`
2055
+ notice in the console on the first such mount; the faces still render, in the
2056
+ channel's `'en'` last resort, and mounting an `I18nProvider` (as the console
2057
+ does) avoids the notice.
2058
+
2059
+ **Additive API** (nothing that compiled before stops compiling):
2060
+
2061
+ - `@object-ui/types`: `ValidationContext` gains an optional `locale`. At this
2062
+ change, the `@object-ui/core` validation engine prints the `date_min` /
2063
+ `date_max` bound in it; omitted, `Intl` follows the runtime default, as
2064
+ `formatDisplayNumber` already declares for a caller with no locale in hand.
2065
+
2066
+ ⚠️ **Dated note, 2026-09-25 — that engine (`ValidationEngine`) is removed from
2067
+ `@object-ui/core` by a later change; `ValidationContext.locale` stays declared in
2068
+ `@object-ui/types`, and at that change nothing in `@object-ui/core` reads it —
2069
+ objectui#7659.**
2070
+
2071
+ ⚠️ **Dated note, 2026-09-27 — `ValidationContext` itself is removed from
2072
+ `@object-ui/types` by a later change, with the rest of the Phase 3.5
2073
+ validation types it belonged to, so the `locale` member this entry adds no
2074
+ longer exists — objectui#10719.**
2075
+ - `@object-ui/plugin-report`: `exportReport`, `exportAsHTML` and `exportAsPDF`
2076
+ take a trailing optional `locale` for the exported file's "Generated:" time,
2077
+ and `LiveExportOptions` gains an optional `locale` that `exportWithLiveData`
2078
+ forwards. Omitted, the time uses the display channel's own last resort
2079
+ (`'en'`), never the machine's locale. `ReportViewer` passes the session's
2080
+ display locale. The locale is deliberately NOT a `ReportExportConfig` member:
2081
+ that type is authored report metadata, and a display locale belongs to the
2082
+ session.
2083
+
2084
+ **One census, repository-wide.** `plugin-detail`'s machine-locale census pin
2085
+ (objectui#9786) is now a single test, `machineLocaleCensus-9909.test.ts` in
2086
+ `@object-ui/i18n`, covering every workspace package whose manifest depends on
2087
+ `@object-ui/i18n`. It refuses any call site that passes nothing, `undefined`,
2088
+ the `'default'` pseudo-tag (a subtag no locale data answers, so `Intl` resolves
2089
+ it to the machine's locale) or a hard-coded tag, unless the site is declared
2090
+ with its reason — for example the `catch` fallback for a tag `Intl` itself
2091
+ rejected, or an ISO formatter feeding `<input type="date">`. Each declared site
2092
+ is counted exactly, so deleting one without its entry is refused too. The
2093
+ per-package pin it replaces is deleted. The runtime tripwire that observes the
2094
+ argument each locale-taking call (`Intl` constructors, `Date` and `Number`
2095
+ `toLocale*`) actually receives moved into the private `@object-ui/test-support`
2096
+ package, and every surface above is pinned with it: the same data under two
2097
+ declared locales must render differently, NO locale-taking call may receive the
2098
+ machine's locale (nothing, `undefined` or `'default'`), and the surface's own
2099
+ calls must receive the declared tag. A call carrying another declared tag, such
2100
+ as the `'en'` of the session's UI language, is tolerated by design: only the
2101
+ machine's locale is the defect.
2102
+ - 894d103: `ObjectChart`'s wrapper div now carries `h-full`, keeping the height chain intact from a dashboard grid cell's declared height down to the element Recharts measures. Previously the chain died at the plain auto-height wrapper: `height: 100%` on the chart container computed to `auto`, Recharts measured a permanent zero, and only the `CHART_MIN_HEIGHT` floor (`6f017e99c`) kept dashboard charts visible — at a fixed floor height instead of filling the cell (#5451). Under auto-height parents `h-full` resolves to `auto`, so non-dashboard hosts are unchanged.
2103
+ - 5eddeeb: Pie, donut, funnel and treemap now say when rows carry no magnitude they can draw.
2104
+
2105
+ These four families size a mark BY its measure, so a row whose value is zero,
2106
+ negative, `null` or unparseable stays in the data and is given no area. Measured
2107
+ in Chromium across 74 tiles: an all-zero pie put ZERO non-white pixels on the
2108
+ page while its DOM carried 31 descendants and a real `svg`; a treemap handed
2109
+ `40 / null`, `40 / 0` or `40 / -25 / -12` rendered one full-bleed leaf that was
2110
+ byte-identical to a genuinely one-row treemap; and a funnel handed `40` beside a
2111
+ `null` drew no segments at all and labelled the tile with the row that had no
2112
+ value.
2113
+
2114
+ When no row can be sized, these charts now render the file's refusal shell
2115
+ (`no-positive-magnitude`) instead of a blank tile. When only some rows can be
2116
+ sized, the chart still draws and carries a note counting the ones it could not.
2117
+ All-positive charts, charts handed no rows at all, bar charts, and both sankey
2118
+ answers are unchanged.
2119
+ - cef27e2: The value-fallback label prettifier `humanizeLabel` has one implementation instead of two byte-identical copies.
2120
+
2121
+ `humanizeLabel` turns a stored value into a display string when nothing else
2122
+ resolves it — an option with no declared label, an object name, a chart axis
2123
+ member. It existed twice, byte for byte: once in `@object-ui/fields` (read by
2124
+ `plugin-grid`, `plugin-gantt`, `plugin-detail` and by that package's own
2125
+ renderers) and once as a deliberate local copy in `plugin-charts`'
2126
+ `ObjectChart.tsx`, whose comment said it was there "to avoid a dependency on
2127
+ `@object-ui/fields`".
2128
+
2129
+ Two copies of one convention is a live hazard rather than tidiness: one
2130
+ dashboard can hold a chart and a grid over the same stored value, so a change
2131
+ landing on one copy alone would put that value on screen under two spellings at
2132
+ once. The single implementation now lives in `@object-ui/core` — the shared
2133
+ ancestor both packages already depend on, so the dependency the copy existed to
2134
+ avoid is still avoided and no new edge is created, and core takes no React
2135
+ (objectui#4389: core-canonical logic, plugins consume). Both former sites
2136
+ re-export it, so `import { humanizeLabel } from '@object-ui/fields'` keeps
2137
+ working unchanged.
2138
+
2139
+ **Nothing rendered changes.** The surviving implementation is byte-identical to
2140
+ both deleted copies, and each former call site is pinned by identity against the
2141
+ core function — not by a copied output table that someone would have to remember
2142
+ to edit in two places.
2143
+
2144
+ The core module also writes down, for the first time, why this convention stays
2145
+ distinct from `humanizeFieldKey` (the KEY fallback, in `@object-ui/plugin-dashboard`),
2146
+ which additionally splits camelCase:
2147
+
2148
+ ```
2149
+ input humanizeFieldKey humanizeLabel
2150
+ needs_analysis Needs Analysis Needs Analysis
2151
+ NeedsAnalysis Needs Analysis NeedsAnalysis <- differ
2152
+ unitPrice Unit Price UnitPrice <- differ
2153
+ BestCase Best Case BestCase <- differ
2154
+ lost-to-competitor Lost-To-Competitor Lost To Competitor <- differ
2155
+ ```
2156
+
2157
+ A field KEY is authored in the codebase and carries a machine spelling, so
2158
+ splitting camelCase recovers words its author meant. A stored VALUE is arbitrary
2159
+ tenant data, where a mid-token capital is not reliably a word boundary and
2160
+ splitting it rewrites what the tenant wrote (`McDonald` to `Mc Donald`). The two
2161
+ conventions also do not nest — on the last row each leaves alone the separator
2162
+ the other rewrites. Whether they should ever converge is a separate decision
2163
+ that would move rendered output in four packages at once; it is deliberately not
2164
+ made here.
2165
+ - d6fe1e1: Draw every categorical x-axis label on short axes
2166
+
2167
+ A vertical bar chart in a dashboard-width widget dropped most of its x-axis
2168
+ labels — three bars drew one label, five bars drew two — leaving the bars
2169
+ unnamed, with no legend to fall back on because a single-series bar chart has
2170
+ none.
2171
+
2172
+ The x axis applied one tick policy to time and category alike (`preserveStartEnd`
2173
+ with a 48px `minTickGap`), which is right for hundreds of dates and wrong for a
2174
+ band axis, where a dropped tick is an identity the reader cannot recover rather
2175
+ than a sample they can interpolate. It was also keyed to the viewport rather
2176
+ than the widget, so a 200px chart inside an 800px console was treated as a wide
2177
+ one.
2178
+
2179
+ Bar, column, line, area and combo charts now draw every label on a categorical
2180
+ x axis of five buckets or fewer — rotating, and ellipsising an over-long name
2181
+ rather than clipping it. Longer axes keep the existing measured thinning, and
2182
+ horizontal bars are unchanged.
2183
+ - fb336df: Move `lucide-react` from `^1.31.0` to `^1.43.0` in every package that declares it, and
2184
+ repair what the jump breaks, so icons resolved from a STRING keep drawing a glyph.
2185
+
2186
+ Measured once against the installed 1.43.0 artifact when this change was made; nothing in
2187
+ the repository re-derives these readings. Across the jump lucide removes no runtime export,
2188
+ no public type name and no `lucide-react/dynamic.mjs` name, and every name this repository
2189
+ imports from `lucide-react` resolves. Exactly one key leaves the runtime `icons` record:
2190
+ `Trash2`, retired in favour of `trash`.
2191
+
2192
+ What a user sees change:
2193
+
2194
+ - Icons the lazy icon seam draws (`resolveIcon`, objectui#9251) get their path data again.
2195
+ lucide 1.43.0 icon modules export their path data inside `__iconData` and no longer
2196
+ export `__iconNode`; the seam now reads both. Reading only `__iconNode` against 1.43.0
2197
+ leaves every such glyph an empty box, with nothing thrown or logged.
2198
+ - `DetailView`'s delete action and three schema-catalog examples spell their icon
2199
+ `trash`, not `trash-2`, so they keep resolving. The glyph is unchanged: 1.43.0's `trash`
2200
+ path data is byte-identical to the `trash-2` path data of 1.31.0 and 1.35.0. Anything
2201
+ that already authored `trash` now draws that same artwork, because lucide moved it under
2202
+ the `trash` name; a few other glyphs were also redrawn upstream.
2203
+ - Icons imported as COMPONENTS carry lucide 1.43.0's own classes: one class per declared
2204
+ alias (a spinner renders `class="lucide lucide-loader-circle lucide-loader-2 ..."`), and
2205
+ no longer the class lucide used to derive from the PascalCase key where that differs
2206
+ (`ArrowDown01` no longer carries `lucide-arrow-down01`). The canonical
2207
+ `lucide-<icon name>` class is still there, so a `.lucide-loader-circle` selector still
2208
+ matches.
2209
+ - Icons resolved from a STRING through the seam keep the classes they had: `lucide`, the
2210
+ canonical `lucide-<icon name>` class and the key-derived class. They do not carry
2211
+ lucide's per-alias classes. That is a maintainer ruling (objectui#8941, option C): the
2212
+ alias list lives only inside each lazily loaded icon module, and it was not moved into
2213
+ the eager name list. A selector that targets an alias class matches a component-imported
2214
+ icon and not a string-resolved one. This also dates the example in the objectui#9251
2215
+ entry: `trash-2` no longer resolves as a string, so no seam-drawn glyph carries
2216
+ `lucide-trash2 lucide-trash-2`; a digit-bearing name that still resolves, such as
2217
+ `arrow-down-0-1`, carries `lucide-arrow-down01 lucide-arrow-down-0-1`.
2218
+ - 6c5ee71: `ObjectChart` now depends on the `fieldOptionLabel` resolver directly instead of
2219
+ holding it behind a ref, so a chart re-resolves its groupBy option labels when
2220
+ the resolver genuinely changes (objectui#5587).
2221
+
2222
+ The ref existed for a reason that no longer holds. `useSafeFieldLabel()` returned
2223
+ a fresh object on every render outside an i18next provider, so a direct
2224
+ dependency made `fetchData`'s `useCallback` identity fresh on every render, and
2225
+ the effect that depends on `fetchData` refetched on every render — an unbounded
2226
+ loop. `ObjectChart` worked around that locally with `fieldOptionLabelRef` plus a
2227
+ `useEffect` keeping it current. `useObjectLabel`'s memo now holds with or without
2228
+ an i18next instance bound (objectui#5564), so the resolver's identity is stable
2229
+ on both paths and the indirection buys nothing.
2230
+
2231
+ It did cost something, and that is the user-visible half: a ref-hidden dependency
2232
+ meant `fetchData` did NOT re-run when the resolver changed. A chart mounted
2233
+ before its `I18nProvider`, or rendered across a language switch, kept serving
2234
+ groupBy labels resolved by the old resolver until some unrelated dependency
2235
+ (object name, filter, aggregate) happened to move. It now refetches once on that
2236
+ transition and shows labels in the active language.
2237
+
2238
+ Pinned by `ObjectChart.fieldOptionLabelRefetch.test.tsx`, which counts fetches
2239
+ across forced re-renders both outside and inside a provider. Reverting
2240
+ `useObjectLabel.ts` to its pre-objectui#5564 state turns the no-provider case red
2241
+ (2 fetches instead of 1, alongside React's "Maximum update depth exceeded"), so
2242
+ the removal is pinned to the fix that unlocked it rather than to a comment.
2243
+ - 93bbc20: Scatter now says when it cannot place a row, instead of drawing an empty axis.
2244
+
2245
+ Scatter is the only two-measure positional chart in the renderer: `xAxisKey` feeds
2246
+ a numeric X axis and `series[0]` a numeric Y axis, so a point exists only when
2247
+ both are numbers. Measured in real Chromium, rows it could not place produced a
2248
+ tile byte-identical to a scatter handed no rows at all, and six different
2249
+ authoring failures shared one image. A chart with one placeable row among three
2250
+ was 99.75% pixel-identical to a genuinely one-row scatter.
2251
+
2252
+ Handed rows it cannot place any of, a scatter now renders the file's refusal
2253
+ shell under `data-chart-error="no-plottable-points"`, naming both keys. When some
2254
+ rows place and some do not it draws as before with a `data-chart-note="unplotted-points"`
2255
+ footnote carrying the count. Charts whose rows all place are byte-identical to
2256
+ before, and no wrapper element is added to them.
2257
+
2258
+ The predicate is positional, not magnitude-based: zero and negative coordinates
2259
+ are ordinary scatter data and keep drawing.
2260
+ - dd35800: `ObjectChart` now renders a self-describing empty state when its query succeeds
2261
+ and returns no rows, instead of falling through to a bare chart frame.
2262
+
2263
+ The frame was measured in a browser rather than assumed: recharts derives its
2264
+ ticks from the data, so with an empty result the bar and line families emit two
2265
+ hairline axis rules and no `text` nodes at all, and pie/donut emit nothing —
2266
+ there are no labelled axes to tell the reader what would have been plotted.
2267
+ Beside the component's own red "Failed to load chart data" box, a blank tile
2268
+ gives the reader nothing to distinguish a young chart from a broken one.
2269
+
2270
+ The copy is the one `plugin-dashboard` already shows on the dataset-bound path
2271
+ ("No data yet" / the load succeeded / the source name), so the same chart over
2272
+ the same empty result no longer reads two different ways depending on which
2273
+ widget drew it. Charts with inline authored data are unchanged — they ran no
2274
+ query to report on.
2275
+ - Updated dependencies [7b10bef]
2276
+ - Updated dependencies [97abedc]
2277
+ - Updated dependencies [b46c58f]
2278
+ - Updated dependencies [a507334]
2279
+ - Updated dependencies [ad694ac]
2280
+ - Updated dependencies [6f96fca]
2281
+ - Updated dependencies [afb2284]
2282
+ - Updated dependencies [3ac2de8]
2283
+ - Updated dependencies [0aacecc]
2284
+ - Updated dependencies [63f4f92]
2285
+ - Updated dependencies [777fca2]
2286
+ - Updated dependencies [c131d9e]
2287
+ - Updated dependencies [5f00ff4]
2288
+ - Updated dependencies [c9e073a]
2289
+ - Updated dependencies [7b395d8]
2290
+ - Updated dependencies [0879812]
2291
+ - Updated dependencies [8cedb0d]
2292
+ - Updated dependencies [162621b]
2293
+ - Updated dependencies [4c6f549]
2294
+ - Updated dependencies [6cc910b]
2295
+ - Updated dependencies [061f5e8]
2296
+ - Updated dependencies [2dd4d3f]
2297
+ - Updated dependencies [e686f4d]
2298
+ - Updated dependencies [4ab4f1b]
2299
+ - Updated dependencies [b57107d]
2300
+ - Updated dependencies [e3ea4f9]
2301
+ - Updated dependencies [bb5d4ee]
2302
+ - Updated dependencies [dc666f7]
2303
+ - Updated dependencies [3335767]
2304
+ - Updated dependencies [8b1f066]
2305
+ - Updated dependencies [af243c1]
2306
+ - Updated dependencies [cff4b77]
2307
+ - Updated dependencies [961ceaa]
2308
+ - Updated dependencies [f3f4e4c]
2309
+ - Updated dependencies [a05c350]
2310
+ - Updated dependencies [1dbb993]
2311
+ - Updated dependencies [2b5f509]
2312
+ - Updated dependencies [808f339]
2313
+ - Updated dependencies [6cf5999]
2314
+ - Updated dependencies [274e14a]
2315
+ - Updated dependencies [8c10f4f]
2316
+ - Updated dependencies [90dac98]
2317
+ - Updated dependencies [6096f20]
2318
+ - Updated dependencies [544aca2]
2319
+ - Updated dependencies [ea02938]
2320
+ - Updated dependencies [a14fb23]
2321
+ - Updated dependencies [ae98f1d]
2322
+ - Updated dependencies [f98eddf]
2323
+ - Updated dependencies [ce6bd99]
2324
+ - Updated dependencies [a5b08c9]
2325
+ - Updated dependencies [86982ac]
2326
+ - Updated dependencies [cdefa2a]
2327
+ - Updated dependencies [0961d5e]
2328
+ - Updated dependencies [6276478]
2329
+ - Updated dependencies [5e67837]
2330
+ - Updated dependencies [ff14e29]
2331
+ - Updated dependencies [9b28151]
2332
+ - Updated dependencies [64563a9]
2333
+ - Updated dependencies [1a5003f]
2334
+ - Updated dependencies [09ab32b]
2335
+ - Updated dependencies [8acc51b]
2336
+ - Updated dependencies [ea9d17f]
2337
+ - Updated dependencies [45362a3]
2338
+ - Updated dependencies [2a943bf]
2339
+ - Updated dependencies [93a689d]
2340
+ - Updated dependencies [4357a27]
2341
+ - Updated dependencies [e5f4343]
2342
+ - Updated dependencies [3261e64]
2343
+ - Updated dependencies [f5178a2]
2344
+ - Updated dependencies [2ad3671]
2345
+ - Updated dependencies [8740e86]
2346
+ - Updated dependencies [d22b37b]
2347
+ - Updated dependencies [1daf477]
2348
+ - Updated dependencies [3d614ea]
2349
+ - Updated dependencies [6c2f3c5]
2350
+ - Updated dependencies [fb13e85]
2351
+ - Updated dependencies [c2d8659]
2352
+ - Updated dependencies [e0f8202]
2353
+ - Updated dependencies [ac2d6f1]
2354
+ - Updated dependencies [9fbbb17]
2355
+ - Updated dependencies [c3a26cc]
2356
+ - Updated dependencies [a66e58e]
2357
+ - Updated dependencies [d89492c]
2358
+ - Updated dependencies [9a5f998]
2359
+ - Updated dependencies [9327397]
2360
+ - Updated dependencies [17cc3a3]
2361
+ - Updated dependencies [02e6d36]
2362
+ - Updated dependencies [4758b33]
2363
+ - Updated dependencies [4758b33]
2364
+ - Updated dependencies [f905090]
2365
+ - Updated dependencies [9c78ebe]
2366
+ - Updated dependencies [9c78ebe]
2367
+ - Updated dependencies [12809a5]
2368
+ - Updated dependencies [7afc81d]
2369
+ - Updated dependencies [f9c06ef]
2370
+ - Updated dependencies [5ad3b88]
2371
+ - Updated dependencies [f9d772b]
2372
+ - Updated dependencies [97b6c21]
2373
+ - Updated dependencies [26ca2ad]
2374
+ - Updated dependencies [41ae65b]
2375
+ - Updated dependencies [baac95a]
2376
+ - Updated dependencies [13220af]
2377
+ - Updated dependencies [29b45f6]
2378
+ - Updated dependencies [39b8d51]
2379
+ - Updated dependencies [17b323e]
2380
+ - Updated dependencies [b956e69]
2381
+ - Updated dependencies [33e58d8]
2382
+ - Updated dependencies [256b4c9]
2383
+ - Updated dependencies [c5ec15c]
2384
+ - Updated dependencies [fec3b1a]
2385
+ - Updated dependencies [b8e0941]
2386
+ - Updated dependencies [0c50f18]
2387
+ - Updated dependencies [1dae95a]
2388
+ - Updated dependencies [e32dae1]
2389
+ - Updated dependencies [30b11ad]
2390
+ - Updated dependencies [4aebea0]
2391
+ - Updated dependencies [f976774]
2392
+ - Updated dependencies [3d6badf]
2393
+ - Updated dependencies [25cb364]
2394
+ - Updated dependencies [a60539b]
2395
+ - Updated dependencies [de1b879]
2396
+ - Updated dependencies [c6678b1]
2397
+ - Updated dependencies [0638322]
2398
+ - Updated dependencies [e3782d2]
2399
+ - Updated dependencies [db0beb2]
2400
+ - Updated dependencies [997ce38]
2401
+ - Updated dependencies [ae0b9d3]
2402
+ - Updated dependencies [ad1785c]
2403
+ - Updated dependencies [3b469c8]
2404
+ - Updated dependencies [990a2d6]
2405
+ - Updated dependencies [1c84036]
2406
+ - Updated dependencies [1c84036]
2407
+ - Updated dependencies [6650259]
2408
+ - Updated dependencies [4f8b7f8]
2409
+ - Updated dependencies [9e6619f]
2410
+ - Updated dependencies [f6ae5e2]
2411
+ - Updated dependencies [eb97ce6]
2412
+ - Updated dependencies [7343376]
2413
+ - Updated dependencies [b2683a2]
2414
+ - Updated dependencies [dded788]
2415
+ - Updated dependencies [b45d463]
2416
+ - Updated dependencies [54a7830]
2417
+ - Updated dependencies [f3135a4]
2418
+ - Updated dependencies [b5696d3]
2419
+ - Updated dependencies [3f9d926]
2420
+ - Updated dependencies [e978ed5]
2421
+ - Updated dependencies [6a7f24e]
2422
+ - Updated dependencies [b3c96d6]
2423
+ - Updated dependencies [8d0ca91]
2424
+ - Updated dependencies [c30c8dd]
2425
+ - Updated dependencies [244d516]
2426
+ - Updated dependencies [deca847]
2427
+ - Updated dependencies [ac15833]
2428
+ - Updated dependencies [ac15833]
2429
+ - Updated dependencies [e2dffc9]
2430
+ - Updated dependencies [328abeb]
2431
+ - Updated dependencies [dd0d78f]
2432
+ - Updated dependencies [24d3e65]
2433
+ - Updated dependencies [95a7c8d]
2434
+ - Updated dependencies [e227156]
2435
+ - Updated dependencies [cc4e476]
2436
+ - Updated dependencies [92970c4]
2437
+ - Updated dependencies [d570eaa]
2438
+ - Updated dependencies [4b742f4]
2439
+ - Updated dependencies [42687ba]
2440
+ - Updated dependencies [6cd8f66]
2441
+ - Updated dependencies [24a0f14]
2442
+ - Updated dependencies [797a30f]
2443
+ - Updated dependencies [b4075c0]
2444
+ - Updated dependencies [9b85600]
2445
+ - Updated dependencies [e327c89]
2446
+ - Updated dependencies [2eaf5be]
2447
+ - Updated dependencies [bf7ab35]
2448
+ - Updated dependencies [99878d8]
2449
+ - Updated dependencies [3c13675]
2450
+ - Updated dependencies [63ab761]
2451
+ - Updated dependencies [0eb9f36]
2452
+ - Updated dependencies [ae582b7]
2453
+ - Updated dependencies [51c2949]
2454
+ - Updated dependencies [a4b017e]
2455
+ - Updated dependencies [8732846]
2456
+ - Updated dependencies [559a2e2]
2457
+ - Updated dependencies [db11afd]
2458
+ - Updated dependencies [154075a]
2459
+ - Updated dependencies [582edef]
2460
+ - Updated dependencies [19f484f]
2461
+ - Updated dependencies [0a78a20]
2462
+ - Updated dependencies [615346d]
2463
+ - Updated dependencies [75dcc81]
2464
+ - Updated dependencies [55a12a8]
2465
+ - Updated dependencies [edfcf5a]
2466
+ - Updated dependencies [0a3e540]
2467
+ - Updated dependencies [c021b35]
2468
+ - Updated dependencies [f61dab1]
2469
+ - Updated dependencies [b0a05dd]
2470
+ - Updated dependencies [dd5ff19]
2471
+ - Updated dependencies [54997ff]
2472
+ - Updated dependencies [81f8498]
2473
+ - Updated dependencies [a782fa7]
2474
+ - Updated dependencies [1d6a23d]
2475
+ - Updated dependencies [0645133]
2476
+ - Updated dependencies [76e9df0]
2477
+ - Updated dependencies [0ecaa7d]
2478
+ - Updated dependencies [b24f93a]
2479
+ - Updated dependencies [6158e4c]
2480
+ - Updated dependencies [cff8641]
2481
+ - Updated dependencies [c27b575]
2482
+ - Updated dependencies [84b275c]
2483
+ - Updated dependencies [0e6e76b]
2484
+ - Updated dependencies [bf43afa]
2485
+ - Updated dependencies [385ebc5]
2486
+ - Updated dependencies [858eafb]
2487
+ - Updated dependencies [a8c5509]
2488
+ - Updated dependencies [c2a8d23]
2489
+ - Updated dependencies [0ffc423]
2490
+ - Updated dependencies [3cc4fe5]
2491
+ - Updated dependencies [cd5b19a]
2492
+ - Updated dependencies [cd5b19a]
2493
+ - Updated dependencies [17dc167]
2494
+ - Updated dependencies [20d23be]
2495
+ - Updated dependencies [20d23be]
2496
+ - Updated dependencies [2e3da72]
2497
+ - Updated dependencies [1263e40]
2498
+ - Updated dependencies [e6bc087]
2499
+ - Updated dependencies [9419df1]
2500
+ - Updated dependencies [8bab157]
2501
+ - Updated dependencies [a7557a7]
2502
+ - Updated dependencies [7d074ba]
2503
+ - Updated dependencies [6158e4c]
2504
+ - Updated dependencies [6158e4c]
2505
+ - Updated dependencies [52aad5c]
2506
+ - Updated dependencies [18d1a0a]
2507
+ - Updated dependencies [7fed09d]
2508
+ - Updated dependencies [58da8ae]
2509
+ - Updated dependencies [a8b9889]
2510
+ - Updated dependencies [138ad45]
2511
+ - Updated dependencies [138ad45]
2512
+ - Updated dependencies [5262f7d]
2513
+ - Updated dependencies [6aa029b]
2514
+ - Updated dependencies [2124d04]
2515
+ - Updated dependencies [be52115]
2516
+ - Updated dependencies [770cc5b]
2517
+ - Updated dependencies [1a88ce2]
2518
+ - Updated dependencies [a1a44d6]
2519
+ - Updated dependencies [e0a9c67]
2520
+ - Updated dependencies [5638529]
2521
+ - Updated dependencies [5638529]
2522
+ - Updated dependencies [d0fba91]
2523
+ - Updated dependencies [c476be0]
2524
+ - Updated dependencies [c82ff39]
2525
+ - Updated dependencies [6c3da53]
2526
+ - Updated dependencies [31987bd]
2527
+ - Updated dependencies [3c3ce15]
2528
+ - Updated dependencies [063119f]
2529
+ - Updated dependencies [e100589]
2530
+ - Updated dependencies [304f611]
2531
+ - Updated dependencies [e46ee77]
2532
+ - Updated dependencies [f9c8c4e]
2533
+ - Updated dependencies [6e9c8d2]
2534
+ - Updated dependencies [9547063]
2535
+ - Updated dependencies [3f6efd6]
2536
+ - Updated dependencies [55d18c6]
2537
+ - Updated dependencies [c4ab6d0]
2538
+ - Updated dependencies [0e9058b]
2539
+ - Updated dependencies [c4ab6d0]
2540
+ - Updated dependencies [5988b6b]
2541
+ - Updated dependencies [6158e4c]
2542
+ - Updated dependencies [00ccdf7]
2543
+ - Updated dependencies [9d9ed54]
2544
+ - Updated dependencies [4a1adb7]
2545
+ - Updated dependencies [4a1adb7]
2546
+ - Updated dependencies [50c73fe]
2547
+ - Updated dependencies [ca3de72]
2548
+ - Updated dependencies [83e3f83]
2549
+ - Updated dependencies [401611b]
2550
+ - Updated dependencies [2c0ddf2]
2551
+ - Updated dependencies [4abc0aa]
2552
+ - Updated dependencies [f560ded]
2553
+ - Updated dependencies [2b188fa]
2554
+ - Updated dependencies [b654d4e]
2555
+ - Updated dependencies [f68e0a0]
2556
+ - Updated dependencies [aea682a]
2557
+ - Updated dependencies [fcdc8ec]
2558
+ - Updated dependencies [2d576e4]
2559
+ - Updated dependencies [8366acc]
2560
+ - Updated dependencies [95e58a3]
2561
+ - Updated dependencies [9d7419b]
2562
+ - Updated dependencies [fc7db05]
2563
+ - Updated dependencies [9ed8d0f]
2564
+ - Updated dependencies [c73cdb5]
2565
+ - Updated dependencies [6f5719e]
2566
+ - Updated dependencies [d0097af]
2567
+ - Updated dependencies [432882b]
2568
+ - Updated dependencies [64dae8e]
2569
+ - Updated dependencies [b06e374]
2570
+ - Updated dependencies [06a8af5]
2571
+ - Updated dependencies [6a91586]
2572
+ - Updated dependencies [a04d7c6]
2573
+ - Updated dependencies [5ccc500]
2574
+ - Updated dependencies [f3c2bb0]
2575
+ - Updated dependencies [978507b]
2576
+ - Updated dependencies [778138e]
2577
+ - Updated dependencies [9801765]
2578
+ - Updated dependencies [9cebfca]
2579
+ - Updated dependencies [460575f]
2580
+ - Updated dependencies [d796c8d]
2581
+ - Updated dependencies [594704f]
2582
+ - Updated dependencies [d3995fe]
2583
+ - Updated dependencies [1b1d772]
2584
+ - Updated dependencies [d88e20f]
2585
+ - Updated dependencies [2d7304d]
2586
+ - Updated dependencies [636b236]
2587
+ - Updated dependencies [4172589]
2588
+ - Updated dependencies [d6d8fb9]
2589
+ - Updated dependencies [64d624d]
2590
+ - Updated dependencies [053fdc8]
2591
+ - Updated dependencies [41b7ce3]
2592
+ - Updated dependencies [ae476b8]
2593
+ - Updated dependencies [39f4309]
2594
+ - Updated dependencies [95bad12]
2595
+ - Updated dependencies [d2fb6ef]
2596
+ - Updated dependencies [7cd3987]
2597
+ - Updated dependencies [ee3b878]
2598
+ - Updated dependencies [e304a4e]
2599
+ - Updated dependencies [fda49e5]
2600
+ - Updated dependencies [490d9a9]
2601
+ - Updated dependencies [fc62bb4]
2602
+ - Updated dependencies [41df893]
2603
+ - Updated dependencies [0cba1b7]
2604
+ - Updated dependencies [00f3eb5]
2605
+ - Updated dependencies [1ec291c]
2606
+ - Updated dependencies [453dbaa]
2607
+ - Updated dependencies [95f8704]
2608
+ - Updated dependencies [f8cdbf2]
2609
+ - Updated dependencies [69a2163]
2610
+ - Updated dependencies [24e027e]
2611
+ - Updated dependencies [2c3cd1b]
2612
+ - Updated dependencies [e176053]
2613
+ - Updated dependencies [e30ed15]
2614
+ - Updated dependencies [90665e0]
2615
+ - Updated dependencies [8d3a529]
2616
+ - Updated dependencies [5ac2e2c]
2617
+ - Updated dependencies [194fae1]
2618
+ - Updated dependencies [7e19d03]
2619
+ - Updated dependencies [b08b7eb]
2620
+ - Updated dependencies [1e946c9]
2621
+ - Updated dependencies [546ddf7]
2622
+ - Updated dependencies [864154e]
2623
+ - Updated dependencies [b023625]
2624
+ - Updated dependencies [75bd83d]
2625
+ - Updated dependencies [44d075b]
2626
+ - Updated dependencies [40c479a]
2627
+ - Updated dependencies [971d387]
2628
+ - Updated dependencies [ee851c3]
2629
+ - Updated dependencies [6414dfd]
2630
+ - Updated dependencies [a8d5c71]
2631
+ - Updated dependencies [905b21f]
2632
+ - Updated dependencies [88e9109]
2633
+ - Updated dependencies [2c45966]
2634
+ - Updated dependencies [db3a600]
2635
+ - Updated dependencies [3a3db76]
2636
+ - Updated dependencies [0d723a3]
2637
+ - Updated dependencies [0c95d3d]
2638
+ - Updated dependencies [3e4fa2c]
2639
+ - Updated dependencies [b5b928a]
2640
+ - Updated dependencies [6fd2cf7]
2641
+ - Updated dependencies [5fa06c4]
2642
+ - Updated dependencies [52a43de]
2643
+ - Updated dependencies [195052f]
2644
+ - Updated dependencies [e4559d1]
2645
+ - Updated dependencies [2c71482]
2646
+ - Updated dependencies [129bcc5]
2647
+ - Updated dependencies [a26b9e4]
2648
+ - Updated dependencies [5ef9c4f]
2649
+ - Updated dependencies [46f0bb4]
2650
+ - Updated dependencies [06b82b8]
2651
+ - Updated dependencies [8ec11e1]
2652
+ - Updated dependencies [6f81384]
2653
+ - Updated dependencies [22ba927]
2654
+ - Updated dependencies [f8c70f4]
2655
+ - Updated dependencies [5d3a2d1]
2656
+ - Updated dependencies [8f1d995]
2657
+ - Updated dependencies [b362c1b]
2658
+ - Updated dependencies [f9c34df]
2659
+ - Updated dependencies [dddb942]
2660
+ - Updated dependencies [00c665e]
2661
+ - Updated dependencies [29754cf]
2662
+ - Updated dependencies [d7de534]
2663
+ - Updated dependencies [3c2b6f7]
2664
+ - Updated dependencies [6e88630]
2665
+ - Updated dependencies [b84dc18]
2666
+ - Updated dependencies [ac8abb0]
2667
+ - Updated dependencies [9d86e1d]
2668
+ - Updated dependencies [3a5817f]
2669
+ - Updated dependencies [99a3c2d]
2670
+ - Updated dependencies [5961030]
2671
+ - Updated dependencies [f24de8b]
2672
+ - Updated dependencies [c8ea8af]
2673
+ - Updated dependencies [9602dc8]
2674
+ - Updated dependencies [3190414]
2675
+ - Updated dependencies [4e480f5]
2676
+ - Updated dependencies [38a123c]
2677
+ - Updated dependencies [299102e]
2678
+ - Updated dependencies [30c73cd]
2679
+ - Updated dependencies [830ed58]
2680
+ - Updated dependencies [d7acad6]
2681
+ - Updated dependencies [45a9aeb]
2682
+ - Updated dependencies [713db46]
2683
+ - Updated dependencies [c71e14d]
2684
+ - Updated dependencies [bf3a03c]
2685
+ - Updated dependencies [cb55718]
2686
+ - Updated dependencies [748494b]
2687
+ - Updated dependencies [5967be0]
2688
+ - Updated dependencies [831be72]
2689
+ - Updated dependencies [29cb85b]
2690
+ - Updated dependencies [3e028c8]
2691
+ - Updated dependencies [d0889e2]
2692
+ - Updated dependencies [ce503e5]
2693
+ - Updated dependencies [f20dcf0]
2694
+ - Updated dependencies [12402a9]
2695
+ - Updated dependencies [aff3d7a]
2696
+ - Updated dependencies [4ca30d0]
2697
+ - Updated dependencies [7a5da14]
2698
+ - Updated dependencies [fff9645]
2699
+ - Updated dependencies [9c3b7ce]
2700
+ - Updated dependencies [2c1c967]
2701
+ - Updated dependencies [9486ac6]
2702
+ - Updated dependencies [9486ac6]
2703
+ - Updated dependencies [4d5f9b4]
2704
+ - Updated dependencies [d6ceb8d]
2705
+ - Updated dependencies [dc4365c]
2706
+ - Updated dependencies [e321d52]
2707
+ - Updated dependencies [969ba84]
2708
+ - Updated dependencies [4c68077]
2709
+ - Updated dependencies [7977ff9]
2710
+ - Updated dependencies [3beef6d]
2711
+ - Updated dependencies [06b8c42]
2712
+ - Updated dependencies [46b9bc9]
2713
+ - Updated dependencies [b97790a]
2714
+ - Updated dependencies [dbd5194]
2715
+ - Updated dependencies [7c9b044]
2716
+ - Updated dependencies [d47de51]
2717
+ - Updated dependencies [3fe6463]
2718
+ - Updated dependencies [b392674]
2719
+ - Updated dependencies [4f3a1e2]
2720
+ - Updated dependencies [31ab372]
2721
+ - Updated dependencies [846889b]
2722
+ - Updated dependencies [2acd8e1]
2723
+ - Updated dependencies [26896c6]
2724
+ - Updated dependencies [67fc3b0]
2725
+ - Updated dependencies [33a3b3c]
2726
+ - Updated dependencies [b87f15b]
2727
+ - Updated dependencies [045d20b]
2728
+ - Updated dependencies [a2d2515]
2729
+ - Updated dependencies [c18d099]
2730
+ - Updated dependencies [adb2a86]
2731
+ - Updated dependencies [03380aa]
2732
+ - Updated dependencies [4562ea5]
2733
+ - Updated dependencies [3619792]
2734
+ - Updated dependencies [3561bd2]
2735
+ - Updated dependencies [bf97b98]
2736
+ - Updated dependencies [320374d]
2737
+ - Updated dependencies [b0d308d]
2738
+ - Updated dependencies [40f34b4]
2739
+ - Updated dependencies [8063bcb]
2740
+ - Updated dependencies [b74a859]
2741
+ - Updated dependencies [d4493fd]
2742
+ - Updated dependencies [240b80f]
2743
+ - Updated dependencies [77cb489]
2744
+ - Updated dependencies [bfaa158]
2745
+ - Updated dependencies [777e5c6]
2746
+ - Updated dependencies [0c386dd]
2747
+ - Updated dependencies [9e37d9b]
2748
+ - Updated dependencies [5ad86dd]
2749
+ - Updated dependencies [16a725f]
2750
+ - Updated dependencies [4dfdcc3]
2751
+ - Updated dependencies [6a449fc]
2752
+ - Updated dependencies [446d93d]
2753
+ - Updated dependencies [ecd9cb2]
2754
+ - Updated dependencies [98d4108]
2755
+ - Updated dependencies [0e3b3be]
2756
+ - Updated dependencies [a29ae2d]
2757
+ - Updated dependencies [220c18d]
2758
+ - Updated dependencies [00d3f09]
2759
+ - Updated dependencies [4388f71]
2760
+ - Updated dependencies [0b1ac58]
2761
+ - Updated dependencies [c93b4d5]
2762
+ - Updated dependencies [c1fe272]
2763
+ - Updated dependencies [3cab570]
2764
+ - Updated dependencies [8ad218d]
2765
+ - Updated dependencies [3e41187]
2766
+ - Updated dependencies [5f78953]
2767
+ - Updated dependencies [639114c]
2768
+ - Updated dependencies [639114c]
2769
+ - Updated dependencies [1490691]
2770
+ - Updated dependencies [1f31d3a]
2771
+ - Updated dependencies [d1842ab]
2772
+ - Updated dependencies [78ca238]
2773
+ - Updated dependencies [d8ec8d6]
2774
+ - Updated dependencies [351eb31]
2775
+ - Updated dependencies [866cd1d]
2776
+ - Updated dependencies [20c04b2]
2777
+ - Updated dependencies [01c9023]
2778
+ - Updated dependencies [48c19bd]
2779
+ - Updated dependencies [a6d8b8d]
2780
+ - Updated dependencies [4b5bb95]
2781
+ - Updated dependencies [b652514]
2782
+ - Updated dependencies [adbda1b]
2783
+ - Updated dependencies [adbda1b]
2784
+ - Updated dependencies [8952395]
2785
+ - Updated dependencies [e2b3826]
2786
+ - Updated dependencies [0348bc9]
2787
+ - Updated dependencies [e8c553b]
2788
+ - Updated dependencies [2e32ed4]
2789
+ - Updated dependencies [3ed3eec]
2790
+ - Updated dependencies [7c3df8f]
2791
+ - Updated dependencies [a4514e8]
2792
+ - Updated dependencies [db3896c]
2793
+ - Updated dependencies [b9f5ff1]
2794
+ - Updated dependencies [e75f4c9]
2795
+ - Updated dependencies [19f1639]
2796
+ - Updated dependencies [4704aa4]
2797
+ - Updated dependencies [47547d0]
2798
+ - Updated dependencies [1bee5d0]
2799
+ - Updated dependencies [858cd72]
2800
+ - Updated dependencies [cfc9b6d]
2801
+ - Updated dependencies [554f2b6]
2802
+ - Updated dependencies [72f55c9]
2803
+ - Updated dependencies [26e06d7]
2804
+ - Updated dependencies [669d71b]
2805
+ - Updated dependencies [ed27d7c]
2806
+ - Updated dependencies [52c8cf7]
2807
+ - Updated dependencies [2ceb43a]
2808
+ - Updated dependencies [7cdd2b9]
2809
+ - Updated dependencies [52c8cf7]
2810
+ - Updated dependencies [3399704]
2811
+ - Updated dependencies [71a4a53]
2812
+ - Updated dependencies [7bf244b]
2813
+ - Updated dependencies [f0bb9fa]
2814
+ - Updated dependencies [81a2eb1]
2815
+ - Updated dependencies [caa0cd3]
2816
+ - Updated dependencies [caa0cd3]
2817
+ - Updated dependencies [20cb8db]
2818
+ - Updated dependencies [25c7d58]
2819
+ - Updated dependencies [00d2fa6]
2820
+ - Updated dependencies [77b2a18]
2821
+ - Updated dependencies [c6198c2]
2822
+ - Updated dependencies [721d1e0]
2823
+ - Updated dependencies [c2f0f48]
2824
+ - Updated dependencies [1237ae4]
2825
+ - Updated dependencies [2f61238]
2826
+ - Updated dependencies [51eb515]
2827
+ - Updated dependencies [c354ce5]
2828
+ - Updated dependencies [8fe8e5c]
2829
+ - Updated dependencies [feac439]
2830
+ - Updated dependencies [9ae871d]
2831
+ - Updated dependencies [efbd566]
2832
+ - Updated dependencies [2a5bf45]
2833
+ - Updated dependencies [9587fc9]
2834
+ - Updated dependencies [e62c44e]
2835
+ - Updated dependencies [daf9d57]
2836
+ - Updated dependencies [23b9958]
2837
+ - Updated dependencies [c15d7ec]
2838
+ - Updated dependencies [5d0876c]
2839
+ - Updated dependencies [f7ace0a]
2840
+ - Updated dependencies [b041b9c]
2841
+ - Updated dependencies [ce2aaef]
2842
+ - Updated dependencies [544ecba]
2843
+ - Updated dependencies [2ce2612]
2844
+ - Updated dependencies [bc640ec]
2845
+ - Updated dependencies [1e215c4]
2846
+ - Updated dependencies [da6e191]
2847
+ - Updated dependencies [3e377c9]
2848
+ - Updated dependencies [a3eb5d0]
2849
+ - Updated dependencies [4ce14f1]
2850
+ - Updated dependencies [aef97e5]
2851
+ - Updated dependencies [2af1fa7]
2852
+ - Updated dependencies [c14d3a0]
2853
+ - Updated dependencies [a137d0c]
2854
+ - Updated dependencies [caf477f]
2855
+ - Updated dependencies [f6375da]
2856
+ - Updated dependencies [967e5d8]
2857
+ - Updated dependencies [c907a9c]
2858
+ - Updated dependencies [a4611b3]
2859
+ - Updated dependencies [20316ba]
2860
+ - Updated dependencies [d3499b3]
2861
+ - Updated dependencies [91f9276]
2862
+ - Updated dependencies [309c75e]
2863
+ - Updated dependencies [c9f9bae]
2864
+ - Updated dependencies [18897a4]
2865
+ - Updated dependencies [8b7ea39]
2866
+ - Updated dependencies [a915064]
2867
+ - Updated dependencies [dcbf0b2]
2868
+ - Updated dependencies [52cac38]
2869
+ - Updated dependencies [93fea2e]
2870
+ - Updated dependencies [1422a92]
2871
+ - Updated dependencies [d05fe17]
2872
+ - Updated dependencies [a480f79]
2873
+ - Updated dependencies [f08d1a8]
2874
+ - Updated dependencies [64a252d]
2875
+ - Updated dependencies [786bc91]
2876
+ - Updated dependencies [75fca96]
2877
+ - Updated dependencies [7ca6ddd]
2878
+ - Updated dependencies [f1cd290]
2879
+ - Updated dependencies [5a41ce7]
2880
+ - Updated dependencies [8d50bc2]
2881
+ - Updated dependencies [604476d]
2882
+ - Updated dependencies [d1bebb0]
2883
+ - Updated dependencies [95bf128]
2884
+ - Updated dependencies [335abea]
2885
+ - Updated dependencies [edea22a]
2886
+ - Updated dependencies [0f5cadf]
2887
+ - Updated dependencies [4f9f1ee]
2888
+ - Updated dependencies [66e8b2a]
2889
+ - Updated dependencies [aa083cd]
2890
+ - Updated dependencies [12b5992]
2891
+ - Updated dependencies [b93e245]
2892
+ - Updated dependencies [c842594]
2893
+ - Updated dependencies [290de37]
2894
+ - Updated dependencies [e1c27e4]
2895
+ - Updated dependencies [8c8da45]
2896
+ - Updated dependencies [8cd8eb5]
2897
+ - Updated dependencies [cf1d29e]
2898
+ - Updated dependencies [1bd79c8]
2899
+ - Updated dependencies [af9e957]
2900
+ - Updated dependencies [b1030c7]
2901
+ - Updated dependencies [c974edf]
2902
+ - Updated dependencies [ad852b6]
2903
+ - Updated dependencies [6778809]
2904
+ - Updated dependencies [7fb22a1]
2905
+ - Updated dependencies [ad66d79]
2906
+ - Updated dependencies [0758bd8]
2907
+ - Updated dependencies [ee4d19f]
2908
+ - Updated dependencies [496d31d]
2909
+ - Updated dependencies [0ea7054]
2910
+ - Updated dependencies [9a853f2]
2911
+ - Updated dependencies [cb847fd]
2912
+ - Updated dependencies [ee70287]
2913
+ - Updated dependencies [3e98e13]
2914
+ - Updated dependencies [a695f50]
2915
+ - Updated dependencies [fc32921]
2916
+ - Updated dependencies [4eaa835]
2917
+ - Updated dependencies [8f9d87a]
2918
+ - Updated dependencies [b1777ae]
2919
+ - Updated dependencies [24845c4]
2920
+ - Updated dependencies [6f864cf]
2921
+ - Updated dependencies [24d1edd]
2922
+ - Updated dependencies [645087c]
2923
+ - Updated dependencies [33f4a19]
2924
+ - Updated dependencies [6e9a3d4]
2925
+ - Updated dependencies [4a292d2]
2926
+ - Updated dependencies [5323168]
2927
+ - Updated dependencies [841dd2b]
2928
+ - Updated dependencies [3014fc0]
2929
+ - Updated dependencies [dacb402]
2930
+ - Updated dependencies [846cec0]
2931
+ - Updated dependencies [91facae]
2932
+ - Updated dependencies [b38014e]
2933
+ - Updated dependencies [474797d]
2934
+ - Updated dependencies [704e695]
2935
+ - Updated dependencies [a407bd6]
2936
+ - Updated dependencies [317dbce]
2937
+ - Updated dependencies [309728c]
2938
+ - Updated dependencies [aa08d7e]
2939
+ - Updated dependencies [3a43a15]
2940
+ - Updated dependencies [868e825]
2941
+ - Updated dependencies [f76f436]
2942
+ - Updated dependencies [ce45a03]
2943
+ - Updated dependencies [421544b]
2944
+ - Updated dependencies [fb01022]
2945
+ - Updated dependencies [e9d9212]
2946
+ - Updated dependencies [ecfb693]
2947
+ - Updated dependencies [abc1b18]
2948
+ - Updated dependencies [81a51db]
2949
+ - Updated dependencies [67749c7]
2950
+ - Updated dependencies [507b61b]
2951
+ - Updated dependencies [512c84b]
2952
+ - Updated dependencies [c300267]
2953
+ - Updated dependencies [fb3a101]
2954
+ - Updated dependencies [d4733f2]
2955
+ - Updated dependencies [7c9145f]
2956
+ - Updated dependencies [1570eac]
2957
+ - Updated dependencies [f391ede]
2958
+ - Updated dependencies [f5cfbbd]
2959
+ - Updated dependencies [f5cfbbd]
2960
+ - Updated dependencies [8b532cb]
2961
+ - Updated dependencies [64c3cdd]
2962
+ - Updated dependencies [4d65991]
2963
+ - Updated dependencies [c42554e]
2964
+ - Updated dependencies [555b4ec]
2965
+ - Updated dependencies [1ccfc23]
2966
+ - Updated dependencies [542718f]
2967
+ - Updated dependencies [7f27bc5]
2968
+ - Updated dependencies [0a174f3]
2969
+ - Updated dependencies [676f677]
2970
+ - Updated dependencies [f95b140]
2971
+ - Updated dependencies [541ce4e]
2972
+ - Updated dependencies [6479086]
2973
+ - Updated dependencies [d79f525]
2974
+ - Updated dependencies [d1865d2]
2975
+ - Updated dependencies [55ba3ff]
2976
+ - Updated dependencies [f1190b0]
2977
+ - Updated dependencies [561abef]
2978
+ - Updated dependencies [ef52001]
2979
+ - Updated dependencies [6a4680b]
2980
+ - Updated dependencies [c3a4273]
2981
+ - Updated dependencies [abf710d]
2982
+ - Updated dependencies [093af32]
2983
+ - Updated dependencies [1bd1be7]
2984
+ - Updated dependencies [d234fa9]
2985
+ - Updated dependencies [adf5812]
2986
+ - Updated dependencies [e36acd4]
2987
+ - Updated dependencies [5058336]
2988
+ - Updated dependencies [2f6b2bf]
2989
+ - Updated dependencies [2028b31]
2990
+ - Updated dependencies [63601ab]
2991
+ - Updated dependencies [c372b29]
2992
+ - Updated dependencies [152f0a7]
2993
+ - Updated dependencies [8693b85]
2994
+ - Updated dependencies [e82dad1]
2995
+ - Updated dependencies [58b7b3d]
2996
+ - Updated dependencies [84defab]
2997
+ - Updated dependencies [681d3f1]
2998
+ - Updated dependencies [969d4f2]
2999
+ - Updated dependencies [f3bc481]
3000
+ - Updated dependencies [b79aac2]
3001
+ - Updated dependencies [93fc0e7]
3002
+ - Updated dependencies [a4b723f]
3003
+ - Updated dependencies [2b10ca0]
3004
+ - Updated dependencies [7db4a81]
3005
+ - Updated dependencies [19a0b0e]
3006
+ - Updated dependencies [526fc11]
3007
+ - Updated dependencies [f8e3e9a]
3008
+ - Updated dependencies [b9d47ec]
3009
+ - Updated dependencies [3b6bc69]
3010
+ - Updated dependencies [6214db6]
3011
+ - Updated dependencies [6732df4]
3012
+ - Updated dependencies [fe9e0d0]
3013
+ - Updated dependencies [63fb72c]
3014
+ - Updated dependencies [804831c]
3015
+ - Updated dependencies [279e48e]
3016
+ - Updated dependencies [8700d6d]
3017
+ - Updated dependencies [8db2a0f]
3018
+ - Updated dependencies [689953a]
3019
+ - Updated dependencies [30443fb]
3020
+ - Updated dependencies [8d3dbb2]
3021
+ - Updated dependencies [efc1c9c]
3022
+ - Updated dependencies [da45e6b]
3023
+ - Updated dependencies [7533465]
3024
+ - Updated dependencies [835f0f3]
3025
+ - Updated dependencies [a9d97be]
3026
+ - Updated dependencies [ed35b44]
3027
+ - Updated dependencies [9ba7e9c]
3028
+ - Updated dependencies [729e851]
3029
+ - Updated dependencies [96919a4]
3030
+ - Updated dependencies [345e24a]
3031
+ - Updated dependencies [20b507a]
3032
+ - Updated dependencies [2e471dc]
3033
+ - Updated dependencies [6748587]
3034
+ - Updated dependencies [be50942]
3035
+ - Updated dependencies [775e079]
3036
+ - Updated dependencies [7e8b3c0]
3037
+ - Updated dependencies [53374dc]
3038
+ - Updated dependencies [f6fb83f]
3039
+ - Updated dependencies [2049b03]
3040
+ - Updated dependencies [2bf34f7]
3041
+ - Updated dependencies [15b33ae]
3042
+ - Updated dependencies [7cbc724]
3043
+ - Updated dependencies [7098eed]
3044
+ - Updated dependencies [3df7c5c]
3045
+ - Updated dependencies [fb91ac9]
3046
+ - Updated dependencies [fb91ac9]
3047
+ - Updated dependencies [641fb55]
3048
+ - Updated dependencies [8524372]
3049
+ - Updated dependencies [7cbefa5]
3050
+ - Updated dependencies [72d6587]
3051
+ - Updated dependencies [a272a4f]
3052
+ - Updated dependencies [55f39ee]
3053
+ - Updated dependencies [0ce32d5]
3054
+ - Updated dependencies [0970a0e]
3055
+ - Updated dependencies [e427e9c]
3056
+ - Updated dependencies [bbc9dc3]
3057
+ - Updated dependencies [02f1813]
3058
+ - Updated dependencies [1ef89c0]
3059
+ - Updated dependencies [ba0b61a]
3060
+ - Updated dependencies [ba0b61a]
3061
+ - Updated dependencies [ac716ff]
3062
+ - Updated dependencies [f0f3cd5]
3063
+ - Updated dependencies [ab856ed]
3064
+ - Updated dependencies [20f3e65]
3065
+ - Updated dependencies [bbba098]
3066
+ - Updated dependencies [87af769]
3067
+ - Updated dependencies [3be720e]
3068
+ - Updated dependencies [43c0d17]
3069
+ - Updated dependencies [c3df43a]
3070
+ - Updated dependencies [d16d0e9]
3071
+ - Updated dependencies [bbe57fd]
3072
+ - Updated dependencies [272a530]
3073
+ - Updated dependencies [1779e8d]
3074
+ - Updated dependencies [f7fcc2c]
3075
+ - Updated dependencies [f0f4d6c]
3076
+ - Updated dependencies [4128188]
3077
+ - Updated dependencies [b253c4e]
3078
+ - Updated dependencies [78a9c67]
3079
+ - Updated dependencies [4a7ef0d]
3080
+ - Updated dependencies [4598f6d]
3081
+ - Updated dependencies [dea17b4]
3082
+ - Updated dependencies [89bb77a]
3083
+ - Updated dependencies [06611e4]
3084
+ - Updated dependencies [44152c4]
3085
+ - Updated dependencies [3939545]
3086
+ - Updated dependencies [66abbde]
3087
+ - Updated dependencies [dc3893d]
3088
+ - Updated dependencies [1bbaa16]
3089
+ - Updated dependencies [6ee259a]
3090
+ - Updated dependencies [7649f43]
3091
+ - Updated dependencies [e708426]
3092
+ - Updated dependencies [3b6d53b]
3093
+ - Updated dependencies [276d174]
3094
+ - Updated dependencies [2982ed9]
3095
+ - Updated dependencies [a8198de]
3096
+ - Updated dependencies [0c789a4]
3097
+ - Updated dependencies [05a49f2]
3098
+ - Updated dependencies [b234a84]
3099
+ - Updated dependencies [a78cd37]
3100
+ - Updated dependencies [5ea623e]
3101
+ - Updated dependencies [5eabe86]
3102
+ - Updated dependencies [ca5d671]
3103
+ - Updated dependencies [32bf2d6]
3104
+ - Updated dependencies [ff0c384]
3105
+ - Updated dependencies [af4fb29]
3106
+ - Updated dependencies [c698a81]
3107
+ - Updated dependencies [ff5ef1c]
3108
+ - Updated dependencies [befd40c]
3109
+ - Updated dependencies [9a97800]
3110
+ - Updated dependencies [6bca0e4]
3111
+ - Updated dependencies [81c0bc4]
3112
+ - Updated dependencies [3c76801]
3113
+ - Updated dependencies [60500cb]
3114
+ - Updated dependencies [2fcefb9]
3115
+ - Updated dependencies [77f846a]
3116
+ - Updated dependencies [bc5870c]
3117
+ - Updated dependencies [b55a346]
3118
+ - Updated dependencies [065bba7]
3119
+ - Updated dependencies [f760064]
3120
+ - Updated dependencies [dd19463]
3121
+ - Updated dependencies [6791717]
3122
+ - Updated dependencies [8ea3bee]
3123
+ - Updated dependencies [100547e]
3124
+ - Updated dependencies [3a58149]
3125
+ - Updated dependencies [6d1c155]
3126
+ - Updated dependencies [d7573b3]
3127
+ - Updated dependencies [bf3edfe]
3128
+ - Updated dependencies [2c8474c]
3129
+ - Updated dependencies [6ce89da]
3130
+ - Updated dependencies [0e05aac]
3131
+ - Updated dependencies [ae61ad4]
3132
+ - Updated dependencies [5aed9e4]
3133
+ - Updated dependencies [83c77dc]
3134
+ - Updated dependencies [18a8e7d]
3135
+ - Updated dependencies [e7957ab]
3136
+ - Updated dependencies [f7e34ca]
3137
+ - Updated dependencies [e719ebd]
3138
+ - Updated dependencies [516583b]
3139
+ - Updated dependencies [f9e4f91]
3140
+ - Updated dependencies [6ef48b1]
3141
+ - Updated dependencies [fa429cf]
3142
+ - Updated dependencies [ed8df3e]
3143
+ - Updated dependencies [fe76ece]
3144
+ - Updated dependencies [8b446f5]
3145
+ - Updated dependencies [8e74b27]
3146
+ - Updated dependencies [7102b20]
3147
+ - Updated dependencies [8ebd57f]
3148
+ - Updated dependencies [617707a]
3149
+ - Updated dependencies [c40f3b8]
3150
+ - Updated dependencies [58770f3]
3151
+ - Updated dependencies [aefe428]
3152
+ - Updated dependencies [485f096]
3153
+ - Updated dependencies [7357447]
3154
+ - Updated dependencies [199d31b]
3155
+ - Updated dependencies [b655a9d]
3156
+ - Updated dependencies [3e01cb5]
3157
+ - Updated dependencies [7138bc1]
3158
+ - Updated dependencies [cef27e2]
3159
+ - Updated dependencies [4e8622b]
3160
+ - Updated dependencies [dffd752]
3161
+ - Updated dependencies [06973aa]
3162
+ - Updated dependencies [50798f3]
3163
+ - Updated dependencies [6a576c9]
3164
+ - Updated dependencies [105f3c5]
3165
+ - Updated dependencies [3ccd9e8]
3166
+ - Updated dependencies [689b979]
3167
+ - Updated dependencies [c70f865]
3168
+ - Updated dependencies [e546222]
3169
+ - Updated dependencies [fd13f52]
3170
+ - Updated dependencies [d7bd274]
3171
+ - Updated dependencies [98c3a74]
3172
+ - Updated dependencies [fffa30d]
3173
+ - Updated dependencies [ebce5a3]
3174
+ - Updated dependencies [fb336df]
3175
+ - Updated dependencies [9d9040d]
3176
+ - Updated dependencies [20e317c]
3177
+ - Updated dependencies [0fce2ef]
3178
+ - Updated dependencies [42df928]
3179
+ - Updated dependencies [0e2ddd4]
3180
+ - Updated dependencies [b7479ab]
3181
+ - Updated dependencies [9850c6e]
3182
+ - Updated dependencies [de570cc]
3183
+ - Updated dependencies [b2ea297]
3184
+ - Updated dependencies [5b5a5c3]
3185
+ - Updated dependencies [14582b8]
3186
+ - Updated dependencies [51e144e]
3187
+ - Updated dependencies [19cbf10]
3188
+ - Updated dependencies [ab92940]
3189
+ - Updated dependencies [a691c0b]
3190
+ - Updated dependencies [0b1326d]
3191
+ - Updated dependencies [1e66879]
3192
+ - Updated dependencies [c5200f0]
3193
+ - Updated dependencies [af3861f]
3194
+ - Updated dependencies [515f171]
3195
+ - Updated dependencies [1f4e029]
3196
+ - Updated dependencies [4f14ad7]
3197
+ - Updated dependencies [258d264]
3198
+ - Updated dependencies [cac64b3]
3199
+ - Updated dependencies [8033ad1]
3200
+ - Updated dependencies [fa140b8]
3201
+ - Updated dependencies [71cba28]
3202
+ - Updated dependencies [190fbd0]
3203
+ - Updated dependencies [c00bf28]
3204
+ - Updated dependencies [93127bd]
3205
+ - Updated dependencies [f2158ec]
3206
+ - Updated dependencies [759606e]
3207
+ - Updated dependencies [fd8dace]
3208
+ - Updated dependencies [72ffc34]
3209
+ - Updated dependencies [a51fa0c]
3210
+ - Updated dependencies [51f3d8d]
3211
+ - Updated dependencies [bf28341]
3212
+ - Updated dependencies [78cbdb5]
3213
+ - Updated dependencies [b7543a9]
3214
+ - Updated dependencies [6c6cee7]
3215
+ - Updated dependencies [42887e0]
3216
+ - Updated dependencies [83fe6e7]
3217
+ - Updated dependencies [d1ab06f]
3218
+ - Updated dependencies [38a9568]
3219
+ - Updated dependencies [f90b8fb]
3220
+ - Updated dependencies [91783c4]
3221
+ - Updated dependencies [982885d]
3222
+ - Updated dependencies [dba7d84]
3223
+ - Updated dependencies [ca39427]
3224
+ - Updated dependencies [bd09957]
3225
+ - Updated dependencies [5a07e67]
3226
+ - Updated dependencies [2d36552]
3227
+ - Updated dependencies [45d8288]
3228
+ - Updated dependencies [b2437a7]
3229
+ - Updated dependencies [f157423]
3230
+ - Updated dependencies [7a90afd]
3231
+ - Updated dependencies [eddc1dd]
3232
+ - Updated dependencies [490f482]
3233
+ - Updated dependencies [27308c5]
3234
+ - Updated dependencies [8689166]
3235
+ - Updated dependencies [c9327c9]
3236
+ - Updated dependencies [920165d]
3237
+ - Updated dependencies [9101be5]
3238
+ - Updated dependencies [f53a8d0]
3239
+ - Updated dependencies [968dc1e]
3240
+ - Updated dependencies [57f9b07]
3241
+ - Updated dependencies [3c73d99]
3242
+ - Updated dependencies [d91aed9]
3243
+ - Updated dependencies [ed71d9e]
3244
+ - Updated dependencies [7776fc2]
3245
+ - Updated dependencies [e76634c]
3246
+ - Updated dependencies [c86185e]
3247
+ - Updated dependencies [fb96ecb]
3248
+ - Updated dependencies [1170ed1]
3249
+ - Updated dependencies [92814db]
3250
+ - Updated dependencies [4d73b07]
3251
+ - @object-ui/react@17.7.0
3252
+ - @object-ui/core@17.7.0
3253
+ - @object-ui/types@17.7.0
3254
+ - @object-ui/i18n@17.7.0
3255
+ - @object-ui/components@17.7.0
3256
+
3
3257
  ## 17.6.0
4
3258
 
5
3259
  ### Minor Changes