Skip to content

Commit 1000cc7

Browse files
fix(spec): a dataset dimension's nullLabel is live; move the objectui pin past its reader (#25437)
<!-- claude-projects-attribution: {"github_login":"os-tesla"} --> _Requested by **Tesla** · [project thread](https://claude.ai/code/project/chan_01AXsQkLFKRdQCqQ3RTr6Jao?thread=cmsg_01AXsQkLFKRdQCqQ3RTr6JaoJ8yb43iqvYRAnady5tqTZG)_ Fixes #25330 Clause-②: no Metadata-protocol: none This PR is landing 3 of 3 for the label half of #25330, following ruling A (6358843349, approved by the maintainer). The earlier landings: - #25402 (merged as `830a63a6`) carries a dataset dimension's `nullLabel` on the answer's column descriptor as `fields[].nullLabel`. It also names System Overview's null user bucket "System". - objectui#13354 (merged as `1d178e06ac5e`) draws a dataset chart's null bucket under that name. This PR moves the console pin past that reader, then flips the liveness row once the reader is at the pin. The seat approved the order as option (a): bump the pin and flip the row in one PR. ## What changes - **The objectui pin.** `.objectui-sha` moves from `5fef032b1ada` to `1d178e06ac5e` by `scripts/bump-objectui.sh`. It brings five objectui commits in. Their six changesets are digested into `.changeset/console-1d178e06ac5e.md` as an `@objectstack/console` patch. - Then `pnpm objectui:build` ran, and `node scripts/gen-sdui-manifest-node.mjs` re-recorded `scripts/sdui-manifest.record.json`. The manifest itself is byte-identical: 107 components. - `pnpm gen:sdui-lockstep` re-recorded `packages/sdui-parser/objectui-lockstep.json` with the objectui checkout parked on the pin. objectui's parser region did not change. - **Liveness.** `liveness/dataset.json` moves `dimensions[].nullLabel` from `planned` to `live`. It was measured at the pin, following the shape of `runAction` (#10068) and `print` (#23710). - **evidence** (`cross-repo`, objectui @1d178e06ac5e): `packages/plugin-dashboard/src/DatasetWidget.tsx#declaredNullCategoryLabel`. It reads the category dimension's `fields[].nullLabel`, and the widget passes it as the chart's `nullCategoryLabel`, ahead of `chart.nullCategory`. - **producer**: `packages/services/service-analytics/src/analytics-service.ts#enrichResultColumns`. It resolves the dimension's `nullLabel` at the request locale and writes it onto the column descriptor, which is the second input the reader depends on. - `authorWarn` and `authorHint` go with the flip, so `os lint` stops telling an author that nothing draws the bucket. The `state-counts/dataset.md` shard is regenerated: 27 live / 1 planned becomes 28 live / 0 planned. - **The dataset form.** The Dimensions repeater offers a Null Label column (`.meta({ title: 'Null Label' })`). - The form ↔ Zod reconciliation ledger had excluded the key with the reason "planned, not yet rendered". The ledger's own rule says such a row "holds only while the verdict does … delete it and decide the offer then". So the row is deleted, and the key is offered beside `label`, which has the same `I18nLabel` type. - The new row label enters the metadata-form catalogs: en is copied from the source, and zh-CN `空值标签`, ja-JP `空値ラベル` and es-ES `Etiqueta de nulos` are authored. That way no locale echoes English, and the dataset panel's zero-echo pin holds. - The two catalog census pins count the new label: 677 → 678 translated leaves and 37 → 38 dataset-form leaves. - **Changeset.** An `@objectstack/spec` patch (`.changeset/25330-null-label-live.md`). `Clause-②: no`: the schema, accept set, served body and error codes are unchanged. Only the ledger verdict, its advisory and a form column for an already-accepted key move. ## Pins and ablation - `metadata-form-zod-reconciliation.test.ts` now requires the form to offer `dimensions.nullLabel`, because no ledger row excuses it any more. - **Ablation** (`scripts/ablation-replace.mjs`, under the verify lock): I replaced the form's `{ field: 'nullLabel', label: 'Null Label' }` with a comment (anchor ×1 → ×0). The ablated blob is exactly `main`'s `c0701a46`. The reconciliation test goes **1 failed / 75 passed**: "dataset.dimensions: accepted by the Zod but unauthorable in the form — offer it, or add a ledger entry: expected [ 'nullLabel' ] to deeply equal []". After restoring, the blob equals HEAD and `git diff HEAD` is empty. - `check:liveness` resolves the new `producer` symbol anchor in this repo and attributes the objectui evidence. `nullLabel` no longer opts into `authorWarn`. ## Verification All at head `78302ab05f`, base `f0fdd45bbc`. - `node scripts/pm/dispatch-gates.mjs --commands`: 106 derived families, all 106 run with exit 0, reconciled with `--ran` (0 UNRUN, 0 NOT MEASURED). Three were red on the first pass and are fixed in the second commit: - `check:liveness`: the count shard was stale. - `check:i18n`: the new form label was missing from the platform-objects bundles. - `check:sdui-lockstep`: the record still named the old pin. - `pnpm --filter @objectstack/platform-objects test`: 93 files, 1341 tests passed. Its `typecheck` exits 0. - `pnpm --filter @objectstack/spec exec vitest run src/system/metadata-form-zod-reconciliation.test.ts src/ui`: 153 files, 5673 tests passed. - `pnpm --filter @objectstack/spec check:generated`: all 14 artifacts up to date. - `node scripts/check-sdui-manifest.mjs`: intact and recorded at the live pin `1d178e06ac5e`. `pnpm check:console-sha`: exit 0. ## Acceptance notes - **Other renderers.** objectui's `DatasetReportRenderer` and `ObjectChart` still draw the null bucket under `chart.nullCategory` only. The flat table draws a null dimension value as `—`. These are recorded in the row's note and are not carried here. - **Pivot.** The objectui reader applies a declared name on a two-dimension pivot only when both dimensions declare the same one, because `buildChartSeries` takes one null label for both arms. This is recorded in the row's evidence. --- 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_016qAuAwFXMw94v5vFqTVcw2 --------- Co-authored-by: Claude <noreply@anthropic.com>
1 parent 2581efb commit 1000cc7

15 files changed

Lines changed: 62 additions & 25 deletions
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
---
2+
'@objectstack/spec': patch
3+
---
4+
5+
fix(spec): a dataset dimension's `nullLabel` is live, so `os lint` stops warning that nothing draws it, and the dataset form offers it
6+
7+
Clause-②: no (a liveness-ledger re-grade plus a form column for a key the schema already accepts: no schema, accept set, served body or error code moves)
8+
Metadata-protocol: none
9+
10+
The console now draws a dataset chart's null bucket under the name its dimension declares: the server carries it on the answer's column descriptor as `fields[].nullLabel` (objectstack#25402), and the dashboard's dataset chart reads it (objectui#13354, at the `.objectui-sha` pin this release builds). So:
11+
12+
- **Liveness:** `liveness/dataset.json` re-grades `dimensions[].nullLabel` from `planned` to `live`, citing the console's reader at the pin and the server's carry as its producer. Its `authorWarn` goes with it, so the advisory lint no longer tells an author who sets `nullLabel` that no renderer draws the bucket under it.
13+
- **Dataset form:** the Dimensions repeater gains a Null Label column, the schema's own `.meta({ title })`. The form had left the key out only while nothing drew it. That reason went with the `planned` verdict, so its row in the form ↔ Zod reconciliation ledger is gone.

‎.changeset/console-1d178e06ac5e.md‎

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
---
2+
"@objectstack/console": patch
3+
---
4+
5+
Console (objectui) refreshed to `1d178e06ac5e`. Frontend changes in this range:
6+
7+
Derived from the changesets objectui declared over the range — 6 releasing of 6 changesets added across 5 non-merge commits.
8+
9+
- **minor** — Setup → Positions now says who holds each position and which permission sets it grants, and a click anywhere on a row opens the item (objectstack#25333). (objectui `a14737b14`)
10+
- **patch** — types: a node derived from an `@objectstack/spec` schema keeps the spec's `credential` registry key (`'value' | 'map'`, objectstack#25036, which marks the webhook's `secret` and `… (objectui `1d178e06a`)
11+
- **patch** — dashboard: a dataset chart draws its null bucket under the name the dataset declares for it (`fields[].nullLabel`, the dimension's `nullLabel` resolved by the server), over the gl… (objectui `1d178e06a`)
12+
- **patch** — Setup's Permission Sets and Positions lists ask before the Active switch turns an item off, and a toast confirms the change either way (objectui#13338). (objectui `fcbf1b280`)
13+
- **patch** — A member who may read none of the objects an app names now lands on one page that says they need access and whom to ask, instead of the app's dashboard drawn as a grid of "You don… (objectui `2c4e5f5af`)
14+
- **patch** — A single-series bar chart draws every bar in its series colour (objectstack#25330). (objectui `56b65c0ce`)
15+
16+
Metadata-protocol: none (the console refresh changes no key, value or type a metadata author writes)
17+
18+
objectui range: `5fef032b1ada...1d178e06ac5e`

‎.objectui-sha‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
5fef032b1ada5b86bad640637e7331e26ee5da6e
1+
1d178e06ac5eda824af06f7d68eaccdcf38dcf63

‎packages/platform-objects/src/apps/translations/en.metadata-forms.generated.ts‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2039,6 +2039,9 @@ export const enMetadataForms: NonNullable<TranslationData['metadataForms']> = {
20392039
"dimensions.dateGranularity": {
20402040
label: "Date Granularity"
20412041
},
2042+
"dimensions.nullLabel": {
2043+
label: "Null Label"
2044+
},
20422045
measures: {
20432046
label: "Measures",
20442047
helpText: "Each: name, aggregate, field (optional for count), and display format/currency"

‎packages/platform-objects/src/apps/translations/es-ES.metadata-forms.generated.ts‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2039,6 +2039,9 @@ export const esESMetadataForms: NonNullable<TranslationData['metadataForms']> =
20392039
"dimensions.dateGranularity": {
20402040
label: "Granularidad de fecha"
20412041
},
2042+
"dimensions.nullLabel": {
2043+
label: "Etiqueta de nulos"
2044+
},
20422045
measures: {
20432046
label: "Medidas",
20442047
helpText: "Cada medida: nombre, agregación, campo (opcional para count) y formato de visualización/moneda"

‎packages/platform-objects/src/apps/translations/ja-JP.metadata-forms.generated.ts‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2039,6 +2039,9 @@ export const jaJPMetadataForms: NonNullable<TranslationData['metadataForms']> =
20392039
"dimensions.dateGranularity": {
20402040
label: "日付の粒度"
20412041
},
2042+
"dimensions.nullLabel": {
2043+
label: "空値ラベル"
2044+
},
20422045
measures: {
20432046
label: "メジャー",
20442047
helpText: "各メジャー:名前、集計関数、フィールド(count の場合は省略可)、表示形式/通貨"

‎packages/platform-objects/src/apps/translations/object-lifecycle-panel-echo-decisions.test.ts‎

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1212,7 +1212,10 @@ describe('#19403 round 10 — the verdicts, on the live bundles', () => {
12121212
// composites spell out their two live sub-rows (`enabled`, `position`;
12131213
// `mode` / `formView` were retired), four new row labels authored in all
12141214
// three locales.
1215-
expect(translated.length, `${locale} positive control`).toBe(677);
1215+
// 678 since #25330: the dataset form's dimensions repeater offers
1216+
// `nullLabel` once its liveness verdict went live — one row label,
1217+
// authored in all three locales.
1218+
expect(translated.length, `${locale} positive control`).toBe(678);
12161219
}
12171220
// ⭐ DARK — the blindness, executable. On a synthetic two-locale catalog the
12181221
// all-three predicate returns 0 while the per-locale one returns 1, so the

‎packages/platform-objects/src/apps/translations/report-form-echo-decisions.test.ts‎

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@
5959
// echoes in two locales TODAY. It is OUT of this population, asserted by
6060
// name — a walk that over-reached into the object form would sweep in 32
6161
// undecided leaves, and the assertion is what notices. `datasetForm` —
62-
// the sibling semantic-layer panel, 37 leaves, 0 echoing — is excluded
62+
// the sibling semantic-layer panel, 38 leaves, 0 echoing — is excluded
6363
// too, and that exclusion is asserted rather than trusted precisely
6464
// because a wrong sweep of it would NOT go red.
6565
// (2) INWARD, AUTHORED. 38 of this population's own 44 leaves come back
@@ -888,7 +888,8 @@ describe('#19403 round 9 — the population, DERIVED from `reportForm`', () => {
888888
// …and `datasetForm`, the sibling semantic-layer panel, is excluded too.
889889
// It is fully authored, so a wrong sweep of it would NOT go red — which is
890890
// exactly why the exclusion is asserted instead of trusted.
891-
expect(DATASET_LEAVES.length).toBe(37);
891+
// 38 since #25330: the dimensions repeater offers `nullLabel`.
892+
expect(DATASET_LEAVES.length).toBe(38);
892893
const datasetEchoes = DATASET_LEAVES.filter((l) =>
893894
TRANSLATED_LOCALES.some(([, forms]) => forms.dataset?.[l.kind === 'section' ? 'sections' : 'fields']?.[l.path]?.[l.prop] === l.en),
894895
);

‎packages/platform-objects/src/apps/translations/zh-CN.metadata-forms.generated.ts‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2039,6 +2039,9 @@ export const zhCNMetadataForms: NonNullable<TranslationData['metadataForms']> =
20392039
"dimensions.dateGranularity": {
20402040
label: "日期粒度"
20412041
},
2042+
"dimensions.nullLabel": {
2043+
label: "空值标签"
2044+
},
20422045
measures: {
20432046
label: "度量",
20442047
helpText: "每个度量:名称、聚合函数、字段(count 时可省略)、显示格式/货币"

‎packages/sdui-parser/objectui-lockstep.json‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@
66
],
77
"objectui": {
88
"repo": "https://github.com/objectstack-ai/objectui.git",
9-
"rev": "5fef032b1ada5b86bad640637e7331e26ee5da6e",
10-
"revDate": "2026-10-22T18:39:55+00:00",
9+
"rev": "1d178e06ac5eda824af06f7d68eaccdcf38dcf63",
10+
"revDate": "2026-10-23T12:16:26+00:00",
1111
"source": "packages/sdui-parser/src",
1212
"files": [
1313
"packages/sdui-parser/src/body-dialect.ts",
@@ -21,7 +21,7 @@
2121
"packages/sdui-parser/src/validate.ts"
2222
]
2323
},
24-
"recordedAgainstPin": "5fef032b1ada5b86bad640637e7331e26ee5da6e",
24+
"recordedAgainstPin": "1d178e06ac5eda824af06f7d68eaccdcf38dcf63",
2525
"grammarRegion": {
2626
"file": "packages/sdui-parser/src/parse.ts",
2727
"delimiter": "/* ---------------------- the JS literal subset (#6614) ---------------------- */",

0 commit comments

Comments
 (0)