diff --git a/.changeset/console-89cad75d5570.md b/.changeset/console-89cad75d5570.md new file mode 100644 index 00000000000..e3527c0e273 --- /dev/null +++ b/.changeset/console-89cad75d5570.md @@ -0,0 +1,122 @@ +--- +"@objectstack/console": minor +--- + +Console (objectui) refreshed to `89cad75d5570`. Frontend changes in this range: + +Derived from the changesets objectui declared over the range — 74 releasing of 88 changesets added across 64 non-merge commits; omitted: 14 release-nothing changesets, 6 commits carrying no changeset (they ship no package code). + +- **minor** — **BREAKING** — chore(console)!: drop the lazy `tree` registration stub (objectui#10859, batch 8) (objectui `990a2d616`) +- **minor** — **BREAKING** — chore(cli)!: the generated known-types list drops the thirty node type keys objectui#10859 batch 8 retired (objectui `990a2d616`) +- **minor** — **BREAKING** — chore(core)!: the record-source `data` arm table drops `tree` and `view:tree` (objectui#10859, batch 8) (objectui `990a2d616`) +- **minor** — **BREAKING** — refactor(fields)!: the 28 field widgets that still registered a bare node-type fallback register `field:` only (objectui#10859, batch 8) (objectui `990a2d616`) +- **minor** — **BREAKING** — refactor(plugin-tree)!: retire the bare `tree` node type key; `object-tree` is the one spelling (objectui#10859, batch 8) (objectui `990a2d616`) +- **minor** — **BREAKING** — refactor(plugin-view)!: retire the bare `view` node type key; `object-view` is the one spelling (objectui#10859, batch 8) (objectui `990a2d616`) +- **minor** — Three more reader sites stop riding `BaseSchema`'s index signature (objectui#11355 round 2, part of the preparation for objectui#8347's removal of that signature). None changes ru… (objectui `31987bd50`) +- **minor** — **BREAKING** — feat(types): the six `@object-ui/plugin-designer` node types validate; `ProcessDesignerSchema.variables` and `ReportDesignerSchema.parameters` leave the TypeScript face (objectui#… (objectui `063832222`) +- **minor** — **BREAKING** — BREAKING (`@object-ui/core`): `mergeAuthoredPresentation` and `axisPresentation` are no longer exported (objectui#11372). (objectui `f9c8c4e45`) +- **minor** — **BREAKING** — A `page` node refuses `maxWidth` and `padding` by name, and the layout guide teaches the controls that work: `pageType` for the page's width, a `container` for a narrower column o… (objectui `a1a44d621`) +- **minor** — `object-timeline` and `view:timeline` publish the ten `@objectstack/spec` 17.5.0 row keys their renderer honours, and `objectName` is no longer required (objectui#11168 slice 5, u… (objectui `6cd5ae3ea`) +- **minor** — The console build now writes `dist/sdui.manifest.json`, the SDUI component manifest of the Console it built (objectui#11403). (objectui `f88a900e7`) +- **minor** — A bind-only `list` is accepted: `ListSchema.items` is optional on both faces, and the zod face requires at least one of `bind` / `items` (objectui#11405). (objectui `9547063da`) +- **minor** — **BREAKING** — feat(core): the `flex()` builder emits its props in the `properties` bag (objectui#11276) (objectui `138ad4554`) +- **minor** — **BREAKING** — feat(types): an authored `flex` takes its props in the spec's `properties` bag; the flat spelling is refused by name (objectui#11276) (objectui `138ad4554`) +- **minor** — **BREAKING** — feat(types): an authored `object-grid` takes its props in the spec's `properties` bag; the flat spelling is refused by name (objectui#11276) (objectui `6aa029b63`) +- **minor** — **BREAKING** — objectui's app document refuses `mobileNavMode` by name, the answer the platform already gives (objectui#11363). (objectui `e100589f3`) +- **minor** — fix: the widget width / height editors write a whole four-number `layout` (objectui#11388) (objectui `6e9c8d27e`) +- **minor** — **BREAKING** — A gate that is declared but cannot be evaluated is a fault, not "no gate" (objectui#11358) (objectui `063119f2b`) +- **minor** — A public block's prop written directly on the node, instead of inside its `properties` bag, is refused by name on both faces, with a message naming `properties.KEY` (objectui#1087… (objectui `b5696d344`) +- **minor** — Five label positions that `@objectstack/spec` types as `I18nLabel` now accept the per-locale map in `@object-ui/types` too, where they were typed `string` (objectui#10993, batch 4… (objectui `b4075c088`) +- **minor** — feat(plugin-gantt): `object-gantt` publishes the eleven `@objectstack/spec` row keys its renderer honours (objectui#11168 slice 4) (objectui `8673402a3`) +- **minor** — The strict authoring face accepts the `layout` that the editable dashboard grid's Save Layout writes onto a `metric-card` in a dashboard's widget slot (objectui#11070, round 11).… (objectui `0a78a20c8`) +- **minor** — The spec's page blocks, the `element:text_input` / `element:record_picker` rows and a stored page document under its page kind have a TypeScript authoring type, and `SchemaRendere… (objectui `304f61137`) +- **minor** — Small reader sites stop riding `BaseSchema`'s index signature (objectui#11355, part of the preparation for objectui#8347's removal of that signature). Each key was measured on its… (objectui `3c3ce15a7`) +- **minor** — Declare `pageSize` on `ObjectDataTableSchema`, on both faces (objectui#11348). (objectui `6c3da53ae`) +- **minor** — A form field of `type: 'grid'` declares the grid widget's field-level keys (objectui#11070, round 10). (objectui `edfcf5a5e`) +- **minor** — The grid field's `sort_field` is declared, and a master-detail detail's sort field is derived only (objectui#11070, round 9). (objectui `0a3e5409f`) +- **minor** — `formatMetadataError` and `formatMetadataIssue` are exported from `@object-ui/data-objectstack`: the one reader of a failed metadata save (objectui#11302). (objectui `d89329033`) +- **minor** — `object-map` publishes the three keys its `@objectstack/spec` 17.5.0 row declares and its registration left out: `mapStyle`, `navigation` and `enableClustering` (objectui#11168 sl… (objectui `20d23befe`) +- **minor** — `object-tree` publishes the keys its `@objectstack/spec` 17.5.0 row declares and its renderer honours (objectui#11168 slice 3, objectui#11111 decision 3 = B). Each key was measure… (objectui `20d23befe`) +- **minor** — `ObjectTreeSchema` mirrors the `object-tree` row of `@objectstack/spec` 17.5.0 (objectui#11168 slice 3). The change applies to both faces, TypeScript and zod. (objectui `20d23befe`) +- **minor** — `UIActionSchema.size` takes the `action:button` row's vocabulary by reference (objectui#11168 slice 3). Before this, the type was `'sm' | 'md' | 'lg'`. That made `size: 'default'`… (objectui `20d23befe`) +- **minor** — Eight renderers stop riding `BaseSchema`'s index signature for node keys their types did not declare (objectui#11347, the `@object-ui/components` preparation for objectui#8347's r… (objectui `c82ff391f`) +- **minor** — **BREAKING (rendering):** a dataset-bound dashboard widget no longer reads `chartConfig.series`, `chartConfig.xAxis` or `chartConfig.yAxis` (objectui#11315). (objectui `1a88ce22f`) +- **minor** — **BREAKING (authoring, TypeScript only):** on a dashboard widget, `chartConfig.type`, `chartConfig.xAxis`, `chartConfig.yAxis` and `chartConfig.series` are now compile errors, the… (objectui `1a88ce22f`) +- **minor** — The grid field reads each field-level key under the one spelling `GridFieldMetadata` declares (objectui#11070, round 8). (objectui `55a12a8e1`) +- **minor** — A region-tagged language code reaches the built-in catalogue of its base language (objectui#11326) (objectui `d0fba91aa`) +- **minor** — The grid field's `columns` is `@objectstack/spec`'s inline grid column list, by reference, and `object-chart` declares the per-element `dataSource` binding like the other gate-wra… (objectui `75dcc81c3`) +- **minor** — A custom page publishes the console's record navigator to the blocks placed on it (objectui#11293). (objectui `2124d0411`) +- **minor** — A standalone `object-calendar` honours `navigation: { mode: 'page' }`, and a `navigation` block written without `mode`, by opening the record page (objectui#11293). (objectui `2124d0411`) +- **minor** — A standalone `object-kanban` honours `navigation: { mode: 'page' }`, and a `navigation` block written without `mode`, by opening the record page (objectui#11293). (objectui `2124d0411`) +- **minor** — `useNavigationOverlay` hands an authored `page` click with no `onNavigate` to the record navigator the host publishes (objectui#11293). (objectui `2124d0411`) +- **patch** — fix(fields): a read-only number field shows its value the way its table cell does (objectui#11431) (objectui `52c95a166`) +- **patch** — fix(i18n): every count plural family carries every plural form its language uses (objectui#11432) (objectui `55d18c649`) +- **patch** — fix(plugin-dashboard): a dimensioned `pie` / `donut` / `funnel` / `treemap` / `sankey` widget with several measures now says which measures it drops (objectui#11417) (objectui `175df47ef`) +- **patch** — `AiUsageIndicator` renders the reset line for the rolling 5-hour pace window, `resetKind: 'fiveHour'` (objectui#11415, consumer of cloud#2059 / cloud#2574). (objectui `c681b9ff2`) +- **patch** — The `object-calendar` / `calendar` `navigation` input description said `openNewTab: true` "outranks the mode". That does not hold for `none`: `useNavigationOverlay` checks `mode =… (objectui `6cd5ae3ea`) +- **patch** — The `object-kanban` `navigation` input description said `openNewTab: true` "outranks the mode". That does not hold for `none`: `useNavigationOverlay` checks `mode === 'none'` befo… (objectui `6cd5ae3ea`) +- **patch** — fix(plugin-dashboard): a dimensionless `column` / `horizontal-bar` draws every measure; the dropped-measure warning speaks whenever the widget's own branch leaves a declared measu… (objectui `db0e9d3a0`) +- **patch** — fix(plugin-designer): the dashboard editor's type picker no longer turns a multi-measure widget into a type the widget door refuses (objectui#8894) (objectui `db0e9d3a0`) +- **patch** — A host feed slot written on a `record:activity` or `record:history` node is refused by name: `items` and `entries`, and the `loading` flag paired with each (objectui#11321). (objectui `e0a9c6760`) +- **patch** — fix(plugin-gantt): a number row in the gantt tooltip shows the field's declared decimals, and none when it declares none (objectui `c1763e50c`) +- **patch** — fix(fields): the number cell ignores a malformed `scale` instead of flooring it or crashing (objectui `c1763e50c`) +- **patch** — The dataset designer no longer writes `field: ''` for a row whose Field box is blank (objectui#11402). (objectui `0858267e4`) +- **patch** — fix(layout): the mobile tab bar draws its tabs in the sidebar's order, and shows an entry's badge (objectui `7728c67c8`) +- **patch** — docs(plugin-grid): authored `object-grid` examples write their props in the `properties` bag (objectui#11276) (objectui `6aa029b63`) +- **patch** — fix(app-shell): a refused metadata save shows the server's message and field path on every transport (objectui `d59f11c0d`) +- **patch** — fix(layout): the mobile tab bar draws only the entries its sidebar draws (objectui `5ad9f5dc8`) +- **patch** — fix(app-shell): a published html page that gains a plugin component can be published again from the Studio (objectui `3ae919307`) +- **patch** — fix(app-shell): a datasource created as External or Validate only, or switched to either from Managed, now saves without a credential (objectui#11368) (objectui `8001068b9`) +- **patch** — The Studio surfaces import `formatMetadataError` from `@object-ui/data-objectstack`, where the reader now lives (objectui#11302). What they show is unchanged; the publish-failure… (objectui `d89329033`) +- **patch** — `MetadataFieldsPage` shows the per-field prescription when the spec refuses a save, not only the refusal headline (objectui#11302). (objectui `d89329033`) +- **patch** — `object-map` reads `mapStyle` before `map.style`, as `@objectstack/spec`'s `object-map` row says in `mapStyle`'s own description ("Read before `map.style`"). This is objectui#1116… (objectui `20d23befe`) +- **patch** — The page-block inspector labelled the `object-form` `columns` field "Columns (grid layout)" in English and 「列数(网格布局)」 in Chinese. That pointed at the `grid` form layout, which obj… (objectui `20d23befe`) +- **patch** — The `object-timeline` / `view:timeline` `navigation` input description had three wording errors, and all three are corrected (objectui#11168 slice 3, from the contract record on o… (objectui `20d23befe`) +- **patch** — The README's "View tabs" section listed `form.layout` as `vertical | horizontal | inline | grid`. It now lists `vertical | horizontal`, the two values the form layout keeps after… (objectui `20d23befe`) +- **patch** — fix(plugin-gantt): a percent row in the gantt tooltip shows the field's declared decimals (objectui `b149617e6`) +- **patch** — fix(plugin-dashboard): the `object-metric` tile shows a percent or number aggregate at the field's declared width (objectui `b149617e6`) +- **patch** — fix(plugin-grid): the mobile card's percent value shows the field's declared decimals (objectui `b149617e6`) +- **patch** — fix(layout): the mobile tab bar opens the same page as the sidebar (objectui#11211) (objectui `c18a0754b`) +- **patch** — A bulk action whose `visible` is blank now shows on the grid's selection bar and runs over every selected record, as it already does on the row menu and the toolbars of the same g… (objectui `5638529e6`) +- **patch** — Docblock only: `BulkActionDef.visible` now says what the grid's selection bar does with an `ast`-only envelope (objectui#11322). (objectui `5638529e6`) +- **patch** — Docblock only, no behavior change: `partitionRowsByPredicate` now names its callers and says who decides "is a gate declared?" (objectui#11322). (objectui `5638529e6`) + +⚠️ 16 of these carry a breaking change: 16 by the author's own breaking annotation in the changeset body — objectui declares no `major` inside a launch window (`scripts/check-changeset-no-major.mjs`). Each is marked **BREAKING** in the list above — read them before compiling the release record. + +**In this console build, declared nowhere** — objectui merged 6 commits in this range with no `.changeset/*.md`. The code is inside the pin above and ships here, but nothing upstream declared them, so they appear in no objectui CHANGELOG and in no entry above. Listed by subject rather than counted, because a count cannot tell a dependency bump from a form-behaviour change (objectstack#6174); the upstream gate that would prevent this is objectui#3387. + +- _(no changeset)_ docs(fields): the number page and catalog teach `scale` for the decimal width (objectui#11413) (#11429) (objectui `01f99e31e`) +- _(no changeset)_ docs(fields): the percent page and catalog teach `scale` for the decimal width (objectui#11255) (#11411) (objectui `549aaa831`) +- _(no changeset)_ docs(skills): the page-builder guide authors object-grid and object-gantt in the properties bag (objectui#10859; objectui#11276 rider) (#11404) (objectui `64c173d70`) +- _(no changeset)_ docs(skills): the mobile guide teaches mobileNavMode where it is read, not on the app schema (objectui#11363) (#11397) (objectui `abca9867e`) +- _(no changeset)_ fix(site): move next 16.3.3 to 16.3.6 for GHSA-vcvr-r3jv-pc5j (critical) (#11361) (objectui `ad58cc159`) +- _(no changeset)_ docs(guide): slotted-pages header example keeps only PageHeaderProps keys; pin it (objectui#11165) (#11339) (objectui `743181a48`) + + + +objectui range: `31971ff1e28f...89cad75d5570` diff --git a/.changeset/objectui-pin-citations-89cad75d5570.md b/.changeset/objectui-pin-citations-89cad75d5570.md new file mode 100644 index 00000000000..84955df50f2 --- /dev/null +++ b/.changeset/objectui-pin-citations-89cad75d5570.md @@ -0,0 +1,9 @@ +--- +'@objectstack/spec': patch +--- + +The spec's objectui citations, and the shipped description text that names the `.objectui-sha` pin (the `FormField.span` describe and six migration-entry descriptions), are re-measured against the new console pin, objectui `89cad75d5570`. + +Clause-②: no + +Several records were corrected rather than moved, because objectui changed what they describe on this hop: `object-map` now reads `mapStyle` ahead of `map.style` on the declared-block path as well (objectui#11168 slice 3), so the `getMapConfig` return quote is rewritten; `object-tree`'s `navigation` read and `@object-ui/types`' `ObjectTreeSchema` mirror now carry the spec row's keys with no cast, and objectui's record-source table no longer lists the retired bare `tree` / `view:tree` keys (objectui#10859 batch 8); `object-map`, `object-gantt` and `object-timeline` publish the further keys their rows declare (objectui#11168 slices 3–5). Two stale `object-timeline` anchors (`filter` and `variant`) that were already one line off at the previous pin are corrected. No key, default, enum member or export moves. diff --git a/.objectui-sha b/.objectui-sha index a3d306939c4..e8693cff406 100644 --- a/.objectui-sha +++ b/.objectui-sha @@ -1 +1 @@ -31971ff1e28f89cfc45f0c19bc5b05e443f28b79 +89cad75d55702cc4f267bead5bf267de575d5842 diff --git a/content/docs/references/ui/view.mdx b/content/docs/references/ui/view.mdx index a1e4db974f3..4b7be09c7aa 100644 --- a/content/docs/references/ui/view.mdx +++ b/content/docs/references/ui/view.mdx @@ -213,7 +213,7 @@ Column footer summary configuration | **required** | `boolean` | optional | Required override | | **hidden** | `boolean` | optional | Hidden override | | **colSpan** | `integer` | optional | Absolute column span (1-4). The renderer clamps it to the form grid's current column count, so the cell starts at a real column boundary at every surface width and never overflows (`colSpan: 4` in a 3-column grid renders as 3); a `colSpan` within the column count renders as authored, and `colSpan: 1` emits no span class at all. | -| **span** | `Enum<'auto' \| 'full'>` | optional (default: `"auto"`) | Relative field width. 'auto' (default — omit it): the renderer sizes the field from its widget type × the current column count — at the pin this repo builds against (`.objectui-sha` = `31971ff1e28f`), only textarea, markdown, html, richtext and repeater resolve to the full column count (repeater reaches it through the wide `field:grid` widget it maps to). 'full': resolves to the form grid's full column count. How far down the container-query tiers that span is emitted is the renderer's, not this key's: at that same pin the renderer emits one clamped col-span class per multi-column tier (`@md:col-span-2 @2xl:col-span-3` for a 3-column grid), so the field takes the whole row at every multi-column tier, not just the widest. | +| **span** | `Enum<'auto' \| 'full'>` | optional (default: `"auto"`) | Relative field width. 'auto' (default — omit it): the renderer sizes the field from its widget type × the current column count — at the pin this repo builds against (`.objectui-sha` = `89cad75d5570`), only textarea, markdown, html, richtext and repeater resolve to the full column count (repeater reaches it through the wide `field:grid` widget it maps to). 'full': resolves to the form grid's full column count. How far down the container-query tiers that span is emitted is the renderer's, not this key's: at that same pin the renderer emits one clamped col-span class per multi-column tier (`@md:col-span-2 @2xl:col-span-3` for a 3-column grid), so the field takes the whole row at every multi-column tier, not just the widest. | | **widget** | `string` | optional | Custom widget/component name (overrides type-based inference) | | **language** | `string` | optional | Code editor language (for type=code) | | **keyField** | `{ field?: string; label?: string \| Record; placeholder?: string \| Record; helpText?: string \| Record; … }` | optional | Key column config for record-typed fields | @@ -343,7 +343,7 @@ Form-view select option — the object-field option shape minus the per-option ` | **required** | `boolean` | optional | Required override | | **hidden** | `boolean` | optional | Hidden override | | **colSpan** | `integer` | optional | Absolute column span (1-4). The renderer clamps it to the form grid's current column count, so the cell starts at a real column boundary at every surface width and never overflows (`colSpan: 4` in a 3-column grid renders as 3); a `colSpan` within the column count renders as authored, and `colSpan: 1` emits no span class at all. | -| **span** | `Enum<'auto' \| 'full'>` | optional (default: `"auto"`) | Relative field width. 'auto' (default — omit it): the renderer sizes the field from its widget type × the current column count — at the pin this repo builds against (`.objectui-sha` = `31971ff1e28f`), only textarea, markdown, html, richtext and repeater resolve to the full column count (repeater reaches it through the wide `field:grid` widget it maps to). 'full': resolves to the form grid's full column count. How far down the container-query tiers that span is emitted is the renderer's, not this key's: at that same pin the renderer emits one clamped col-span class per multi-column tier (`@md:col-span-2 @2xl:col-span-3` for a 3-column grid), so the field takes the whole row at every multi-column tier, not just the widest. | +| **span** | `Enum<'auto' \| 'full'>` | optional (default: `"auto"`) | Relative field width. 'auto' (default — omit it): the renderer sizes the field from its widget type × the current column count — at the pin this repo builds against (`.objectui-sha` = `89cad75d5570`), only textarea, markdown, html, richtext and repeater resolve to the full column count (repeater reaches it through the wide `field:grid` widget it maps to). 'full': resolves to the form grid's full column count. How far down the container-query tiers that span is emitted is the renderer's, not this key's: at that same pin the renderer emits one clamped col-span class per multi-column tier (`@md:col-span-2 @2xl:col-span-3` for a 3-column grid), so the field takes the whole row at every multi-column tier, not just the widest. | | **widget** | `string` | optional | Custom widget/component name (overrides type-based inference) | | **language** | `string` | optional | Code editor language (for type=code) | | **keyField** | `{ field?: string; label?: string \| Record; placeholder?: string \| Record; helpText?: string \| Record; … }` | optional | Key column config for record-typed fields | diff --git a/packages/sdui-parser/objectui-lockstep.json b/packages/sdui-parser/objectui-lockstep.json index c8842fa2881..9836b05b742 100644 --- a/packages/sdui-parser/objectui-lockstep.json +++ b/packages/sdui-parser/objectui-lockstep.json @@ -6,8 +6,8 @@ ], "objectui": { "repo": "https://github.com/objectstack-ai/objectui.git", - "rev": "31971ff1e28f89cfc45f0c19bc5b05e443f28b79", - "revDate": "2026-10-01T07:33:37+00:00", + "rev": "89cad75d55702cc4f267bead5bf267de575d5842", + "revDate": "2026-10-02T06:25:01+00:00", "source": "packages/sdui-parser/src", "files": [ "packages/sdui-parser/src/body-dialect.ts", @@ -21,7 +21,7 @@ "packages/sdui-parser/src/validate.ts" ] }, - "recordedAgainstPin": "31971ff1e28f89cfc45f0c19bc5b05e443f28b79", + "recordedAgainstPin": "89cad75d55702cc4f267bead5bf267de575d5842", "grammarRegion": { "file": "packages/sdui-parser/src/parse.ts", "delimiter": "/* ---------------------- the JS literal subset (#6614) ---------------------- */", diff --git a/packages/spec/src/data/api-methods-batch-conformance.test.ts b/packages/spec/src/data/api-methods-batch-conformance.test.ts index 750b64dabad..8d4983771ac 100644 --- a/packages/spec/src/data/api-methods-batch-conformance.test.ts +++ b/packages/spec/src/data/api-methods-batch-conformance.test.ts @@ -61,11 +61,21 @@ const SINGLE_RECORD_WRITE_ONLY: Record = { // `revoked` on ONE key. The multi-select surface this rule protects does not // exist for API keys, and the shape a future one would take does not need // `bulk` either — both read off the console build this release pins - // (`.objectui-sha` = `31971ff1e`, `packages/plugin-grid`; re-measured at - // that pin, 2026-10-01. On the hop off `e420df310`, `ObjectGrid.tsx` changed + // (`.objectui-sha` = `89cad75d5`, `packages/plugin-grid`; re-measured at + // that pin, 2026-10-02. On the hop off `31971ff1e`, `ObjectGrid.tsx` changed + // again (42 insertions, 17 deletions: objectui#11322's built-in bulk-delete + // gate asking `partitionRowsByPredicate` directly and objectui#11254's + // mobile-card percent width, plus their two import lines, each edited in + // place), every hunk either a same-length import edit or below the + // selection block, which did NOT move: `ObjectGrid.tsx:4791-4818` here as at + // `31971ff1e`, still hashing to `c88443302d40c2db739ddb235470bafa29056e2e` + // (hash-object of the block), re-READ with the same reading below; + // `hooks/useBulkExecutor.ts` is byte-identical to `31971ff1e` and its + // `:298-303` still hashes to `01083348330f10a201cdf1078b4c21c236402b6a`. + // At `31971ff1e`, 2026-10-01: on the hop off `e420df310`, `ObjectGrid.tsx` changed // again (41 insertions, 1 deletion: objectui#10689's re-read on a harvested // query input), every hunk above the selection block, which only MOVED by - // +40: `ObjectGrid.tsx:4791-4818` here (`4751-4778` at `e420df310`), still + // +40: `ObjectGrid.tsx:4791-4818` there (`4751-4778` at `e420df310`), still // hashing to `c88443302d40c2db739ddb235470bafa29056e2e` (hash-object of the // block), re-READ with the same reading below; `hooks/useBulkExecutor.ts` is // byte-identical to `e420df310` and its `:298-303` still hashes to @@ -91,7 +101,7 @@ const SINGLE_RECORD_WRITE_ONLY: Record = { // re-READ with the same reading below; `hooks/useBulkExecutor.ts` is // byte-identical to `dd3f7e1be` and its `:298-303` still hashes to // `01083348330f10a201cdf1078b4c21c236402b6a`. Previously measured at - // `e420df310`, `db11afd49`, `dd3f7e1be`, `f8a9d0fb0`, `62597c588`, + // `31971ff1e`, `e420df310`, `db11afd49`, `dd3f7e1be`, `f8a9d0fb0`, `62597c588`, // `87af769e9`, `53ded82bf`, `a472b0716`, `00d3f09c5`, `67dadd602`, before // that at `d8ec8d6d4`, `9602dc820`, `190fbd01d`, `9a3daf8d3`, originally at // `6314e87f2`. On the hop off `f8a9d0fb0`, `ObjectGrid.tsx` changed hard diff --git a/packages/spec/src/kernel/functional-completeness.ts b/packages/spec/src/kernel/functional-completeness.ts index bf21a64dd6e..788af993882 100644 --- a/packages/spec/src/kernel/functional-completeness.ts +++ b/packages/spec/src/kernel/functional-completeness.ts @@ -287,7 +287,12 @@ export function checkFieldCompleteness(def: unknown): CompletenessFinding[] { * English sentence. So the loss is total rather than partial — every * record, on every object — and the author is told at render time as well * as here. Both reads hold at the pin this repo builds against - * (`.objectui-sha` = `31971ff1e`, re-read 2026-10-01: `ObjectCalendar.tsx` + * (`.objectui-sha` = `89cad75d5`, re-read 2026-10-02: on the hop off + * `31971ff1e` `ObjectCalendar.tsx` and `ListView.tsx` are byte-identical, + * so `getCalendarConfig` `:294`, the `if (!calendarConfig)` arm `:1296` and + * its `tt(…)` lines `:1303-1304` did not move, every `case` arm is + * byte-identical, and the `en` / `zh` / `de` `calendar.configRequired` + * strings did not change. At `31971ff1e` (2026-10-01) `ObjectCalendar.tsx` * changed on the hop off `e420df310` only at its `navigation` read * (objectui#8652 declared the key and dropped that read's cast, 11 * insertions, 19 deletions), below `getCalendarConfig`, which is @@ -329,8 +334,14 @@ export function checkFieldCompleteness(def: unknown): CompletenessFinding[] { * This repo already records the same deletion one door over: the #13817 * check in `../ui/view.zod.ts` names objectui#7029 as its runtime half. * - `gantt` → NO fallback, and no silence [#19630]. Measured at the pin - * this repo builds against (`.objectui-sha` = `31971ff1e`, re-read - * 2026-10-01; on the hop off `e420df310` `ObjectGantt.tsx` is byte-identical, + * this repo builds against (`.objectui-sha` = `89cad75d5`, re-read + * 2026-10-02; on the hop off `31971ff1e` `ObjectGantt.tsx` changed (47 + * insertions, 10 deletions: objectui#11254's field-scale width on the + * number and percent rows, objectui#11355's uncast shadowed-flat-key read, + * one import line), none of it in `getGanttConfig` or the refusal arm, which + * are byte-identical and moved `:607` → `:608` and `:2261` → `:2298`, and + * `ListView.tsx` is byte-identical, `case 'gantt'` with it; at `31971ff1e` + * (2026-10-01), on the hop off `e420df310` `ObjectGantt.tsx` is byte-identical, * so `getGanttConfig` `:607` and the `if (!ganttConfig)` arm `:2261` did not * move, and `ListView.tsx`'s `case 'gantt'` is byte-identical; at * `e420df310` (2026-09-30), on the hop off `db11afd49`, `ObjectGantt.tsx` changed again @@ -371,8 +382,15 @@ export function checkFieldCompleteness(def: unknown): CompletenessFinding[] { * requires. So the view does not draw a blank chart: it refuses, by name. * - `timeline` → date axis: NO fallback [#19630]; title: `titleField || 'name'`, * which still stands. Measured at the same pin (`.objectui-sha` = - * `31971ff1e`; on the hop onto this pin `ListView.tsx`'s `case 'timeline'` - * and `resolveTimelineDateBinding` are byte-identical, and + * `89cad75d5`; on the hop off `31971ff1e` `ListView.tsx` is byte-identical, + * `case 'timeline'` and `resolveTimelineDateBinding` with it, and + * `ObjectTimeline.tsx` changed only in two `navigation` comments + * (objectui#11293 / objectui#11168 slice 5, 16 insertions, 7 deletions: + * an absent key opens nothing rather than resolving the hook's `page`), so + * the start-date chain and the refusal arm are byte-identical and MOVED + * `:568-570` → `:574-576` and `:902` → `:911`. At `31971ff1e`, on the hop + * off `e420df310`, `ListView.tsx`'s `case 'timeline'` + * and `resolveTimelineDateBinding` were byte-identical, and * `ObjectTimeline.tsx` changed above both reads (objectui#8654's typed * `navigation` member, 42 insertions, 2 deletions), so the start-date chain * and the refusal arm are byte-identical and MOVED `:533-535` → `:568-570` @@ -405,10 +423,19 @@ export function checkFieldCompleteness(def: unknown): CompletenessFinding[] { * block does render; the warning still fires there, because the block the * view TYPE names is the one that is missing. Unchanged by this row. * - `map` → NO fallback, and no silence [#19630]. Measured at the same - * pin (`.objectui-sha` = `31971ff1e`; on the hop onto this pin + * pin (`.objectui-sha` = `89cad75d5`; on the hop off `31971ff1e` + * `ListView.tsx` is byte-identical, `case 'map'` and `resolveListMapConfig` + * with it, and `ObjectMap.tsx` changed (11 insertions, 4 deletions) in + * `warnOnShadowedFlatMapKeys`' cast (objectui#11355) and in `getMapConfig`'s + * `style` precedence — `mapStyle` before `map.style` on the declared-block + * return too (objectui#11168 slice 3) — which touches no coordinate read: + * `getMapConfig` is unmoved at `:387` and still guesses no field name, + * `hasCoordinateBinding` and the refusal arm are byte-identical and moved + * `:486` → `:493` and `:1284` → `:1291`. At `31971ff1e` (2026-10-01) * `ObjectMap.tsx`, `ListView.tsx`'s `case 'map'` and `resolveListMapConfig` - * are byte-identical, so `getMapConfig` `:387`, `hasCoordinateBinding` - * `:486` and the refusal arm `:1284` did not move. At `e420df310` + * were byte-identical to `e420df310`, so `getMapConfig` `:387`, + * `hasCoordinateBinding` `:486` and the refusal arm `:1284` did not move. + * At `e420df310` * `ObjectMap.tsx` changed only in the record-source docblock above * `getMapConfig` (16 insertions, 17 deletions, objectui#8348), so * `getMapConfig`, `hasCoordinateBinding` and the refusal arm are diff --git a/packages/spec/src/migrations/entries/semantic/18.kernel-health-check-and-hot-reload-durations-unit-in-key.ts b/packages/spec/src/migrations/entries/semantic/18.kernel-health-check-and-hot-reload-durations-unit-in-key.ts index 51d711932e3..3c4f1d49635 100644 --- a/packages/spec/src/migrations/entries/semantic/18.kernel-health-check-and-hot-reload-durations-unit-in-key.ts +++ b/packages/spec/src/migrations/entries/semantic/18.kernel-health-check-and-hot-reload-durations-unit-in-key.ts @@ -52,13 +52,13 @@ export const entry: SemanticMigration = { + 'the audience that does not parse. Measured on 884e8347d: the only in-repo readers are ' + 'packages/core/src/health-monitor.ts and packages/core/src/hot-reload.ts, both moved in ' + 'this same change; and the pinned objectui checkout — the pin this repo builds ' - + 'against, `.objectui-sha` = `31971ff1e28f89cfc45f0c19bc5b05e443f28b79` — names ' + + 'against, `.objectui-sha` = `89cad75d55702cc4f267bead5bf267de575d5842` — names ' + 'neither def and neither key: all thirteen exports of plugin-lifecycle-advanced.zod.ts and ' - + 'the string debounceDelay each occur 0 times across its 9912 tracked files (0 across the 9800 at e420df310, the 9546 at db11afd49, the 9283 at dd3f7e1be, the ' + + 'the string debounceDelay each occur 0 times across its 10071 tracked files (0 across the 9912 at 31971ff1e, the 9800 at e420df310, the 9546 at db11afd49, the 9283 at dd3f7e1be, the ' + '8512 at f8a9d0fb0 and the 8303 at 62597c588 too), against lit ' + 'controls objectstack 12966 and @objectstack/spec 4997 on the same corpus at 87af769e9, ' + 'which re-count to 13125 and 5043 respectively at 62597c588, to 13347 and 5123 at ' - + 'f8a9d0fb0, to 13745 and 5466 at dd3f7e1be, to 14704 and 5545 at db11afd49, to 15352 and 6024 at e420df310 and to 15691 and 6206 at this pin (git grep -o -F, the method that reproduces ' + + 'f8a9d0fb0, to 13745 and 5466 at dd3f7e1be, to 14704 and 5545 at db11afd49, to 15352 and 6024 at e420df310, to 15691 and 6206 at 31971ff1e and to 16044 and 6461 at this pin (git grep -o -F, the method that reproduces ' + 'every earlier count).', acceptanceCriteria: 'Every producer and reader of a PluginHealthCheck spells intervalMs and timeoutMs, and every ' diff --git a/packages/spec/src/migrations/entries/semantic/18.kernel-runtime-config-timeout-unit-in-key.ts b/packages/spec/src/migrations/entries/semantic/18.kernel-runtime-config-timeout-unit-in-key.ts index 5f58767697c..5a85a1dce15 100644 --- a/packages/spec/src/migrations/entries/semantic/18.kernel-runtime-config-timeout-unit-in-key.ts +++ b/packages/spec/src/migrations/entries/semantic/18.kernel-runtime-config-timeout-unit-in-key.ts @@ -46,10 +46,10 @@ export const entry: SemanticMigration = { + 'spells timeout 0 times; outside the zod file and its test the only live occurrences are the ' + 'generated rows in content/docs/references/kernel/plugin-security-advanced.mdx, which this ' + 'rename regenerates. The pinned objectui checkout — this is the pin we build against, ' - + '`.objectui-sha` = `31971ff1e28f89cfc45f0c19bc5b05e443f28b79`, re-read from this tree — ' + + '`.objectui-sha` = `89cad75d55702cc4f267bead5bf267de575d5842`, re-read from this tree — ' + 'spells resourceLimits.timeout 0 times across ' - + '9912 tracked files, against lit controls timeout 1303, RuntimeConfig 273 and resourceLimits ' - + '2 on the same corpus (0 across 9800, and 1293 / 273 / 2, at e420df310; 0 across 9546, and 1197 / 273 / 2, at db11afd49; 0 across 9283, and 1172 / 263 / 2, at dd3f7e1be; 0 across 8512, and 1096 / 245 / 2, at f8a9d0fb0; 0 across 8303, and ' + + '10071 tracked files, against lit controls timeout 1331, RuntimeConfig 273 and resourceLimits ' + + '2 on the same corpus (0 across 9912, and 1303 / 273 / 2, at 31971ff1e; 0 across 9800, and 1293 / 273 / 2, at e420df310; 0 across 9546, and 1197 / 273 / 2, at db11afd49; 0 across 9283, and 1172 / 263 / 2, at dd3f7e1be; 0 across 8512, and 1096 / 245 / 2, at f8a9d0fb0; 0 across 8303, and ' + '1086 / 240 / 2, at 62597c588); both resourceLimits hits are prose in packages/app-shell recording ' + 'that objectui\'s own AppShellRuntimeConfig shares not one key with the spec\'s ' + 'RuntimeConfig, so nothing there authors this key and no pin bump is owed. ADR-0087.', diff --git a/packages/spec/src/migrations/entries/semantic/18.logging-durations-unit-in-key.ts b/packages/spec/src/migrations/entries/semantic/18.logging-durations-unit-in-key.ts index e6ede3b3fd7..1941e15c83b 100644 --- a/packages/spec/src/migrations/entries/semantic/18.logging-durations-unit-in-key.ts +++ b/packages/spec/src/migrations/entries/semantic/18.logging-durations-unit-in-key.ts @@ -47,10 +47,10 @@ export const entry: SemanticMigration = { + 'no in-repo runtime reads any of the four — outside `packages/spec/src/system/logging.zod.ts` ' + 'and its test the only occurrences are the generated rows in ' + '`content/docs/references/system/logging.mdx`, which this rename regenerates; and the pinned ' - + 'objectui checkout — `.objectui-sha` = `31971ff1e28f89cfc45f0c19bc5b05e443f28b79` — spells ' + + 'objectui checkout — `.objectui-sha` = `89cad75d55702cc4f267bead5bf267de575d5842` — spells ' + '`flushInterval` 0 times, `initialDelay` 0, `HttpDestinationConfig` 0 and `LoggingConfig` 0 ' - + 'across its 9912 tracked files, against lit controls `useState` 2469 and `timeout` 1303 on ' - + 'the same corpus (all four 0 across 9800, against 2464 and 1293, at e420df310, 0 across 9546, against 2449 and 1197, at db11afd49, 0 across 9283, against 2435 and 1172, at dd3f7e1be, 0 across 8512, ' + + 'across its 10071 tracked files, against lit controls `useState` 2470 and `timeout` 1331 on ' + + 'the same corpus (all four 0 across 9912, against 2469 and 1303, at 31971ff1e, 0 across 9800, against 2464 and 1293, at e420df310, 0 across 9546, against 2449 and 1197, at db11afd49, 0 across 9283, against 2435 and 1172, at dd3f7e1be, 0 across 8512, ' + 'against 2391 and 1096, at f8a9d0fb0, and 0 across ' + '8303, against 2389 and 1086, at 62597c588).', acceptanceCriteria: diff --git a/packages/spec/src/migrations/entries/semantic/18.system-metrics-jsdoc-durations-unit-in-key.ts b/packages/spec/src/migrations/entries/semantic/18.system-metrics-jsdoc-durations-unit-in-key.ts index 68ed1db5810..a236d052fd6 100644 --- a/packages/spec/src/migrations/entries/semantic/18.system-metrics-jsdoc-durations-unit-in-key.ts +++ b/packages/spec/src/migrations/entries/semantic/18.system-metrics-jsdoc-durations-unit-in-key.ts @@ -73,10 +73,11 @@ export const entry: SemanticMigration = { + 'against a lit control of 1195 defineStack occurrences on that same corpus at fc28c1d38 ' + '(1195 again at 9b62f54671); and the objectui ' + 'checkout this repo builds against — this is the pin, ' - + '`.objectui-sha` = `31971ff1e28f89cfc45f0c19bc5b05e443f28b79`, re-read from this tree — ' - + 'spells all six metrics def names and both distinctive keys 0 times across 9912 tracked ' - + 'files at that sha, against lit controls window 3916, timeout 1303, period 234, ' - + 'interval 196 and metrics 354 on that same corpus and sha (0 across 9800, against 3873 / ' + + '`.objectui-sha` = `89cad75d55702cc4f267bead5bf267de575d5842`, re-read from this tree — ' + + 'spells all six metrics def names and both distinctive keys 0 times across 10071 tracked ' + + 'files at that sha, against lit controls window 4002, timeout 1331, period 231, ' + + 'interval 196 and metrics 355 on that same corpus and sha (0 across 9912, against 3916 / ' + + '1303 / 234 / 196 / 354, at 31971ff1e, 0 across 9800, against 3873 / ' + '1293 / 233 / 196 / 352, at e420df310, 0 across 9546, against 3772 / ' + '1197 / 228 / 196 / 341, at db11afd49, 0 across 9283, against 3681 / 1172 / 183 / 176 / 340, at dd3f7e1be, 0 across 8512, against 3581 / ' + '1096 / 171 / 179 / 326, at f8a9d0fb0, and 0 across 8303, against 3526 / 1086 / 170 / 179 / ' diff --git a/packages/spec/src/migrations/entries/semantic/18.system-tracing-otel-exporter-durations-unit-in-key.ts b/packages/spec/src/migrations/entries/semantic/18.system-tracing-otel-exporter-durations-unit-in-key.ts index ff96dc038a8..6475b66dd73 100644 --- a/packages/spec/src/migrations/entries/semantic/18.system-tracing-otel-exporter-durations-unit-in-key.ts +++ b/packages/spec/src/migrations/entries/semantic/18.system-tracing-otel-exporter-durations-unit-in-key.ts @@ -69,12 +69,13 @@ export const entry: SemanticMigration = { + 'dark control of 0; inside packages/spec the ' + 'only occurrences are tracing.zod.ts, its test, and the generated rows in ' + 'content/docs/references/system/tracing.mdx, which this rename regenerates. And the ' - + 'pinned objectui checkout — `.objectui-sha` = `31971ff1e28f89cfc45f0c19bc5b05e443f28b79` — names none of it: all 37 exports of ' - + 'tracing.zod.ts and each of the four key names occur 0 times across the 9912 files ' - + 'tracked at that sha (the 486 Span and 53 SpanSchema hits are objectui\'s own HTML ' + + 'pinned objectui checkout — `.objectui-sha` = `89cad75d55702cc4f267bead5bf267de575d5842` — names none of it: all 37 exports of ' + + 'tracing.zod.ts and each of the four key names occur 0 times across the 10071 files ' + + 'tracked at that sha (the 489 Span and 56 SpanSchema hits are objectui\'s own HTML ' + 'text-span component, TextSpanSchema, an unrelated name, plus colSpan and prose), against ' - + 'two lit controls on that same corpus and sha: 15691 hits for the bare token objectstack, ' - + 'and 6206 for the package specifier @objectstack/spec (at e420df310: 0 across 9800, Span 486, ' + + 'two lit controls on that same corpus and sha: 16044 hits for the bare token objectstack, ' + + 'and 6461 for the package specifier @objectstack/spec (at 31971ff1e: 0 across 9912, Span 486, ' + + '15691 and 6206; at e420df310: 0 across 9800, Span 486, ' + '15352 and 6024; at db11afd49: 0 across 9546, Span 486, ' + '14704 and 5545; at dd3f7e1be: 0 across 9283, Span 485, 13745 and 5466; at f8a9d0fb0: 0 across 8512, ' + 'Span 488, 13347 and 5123; at 62597c588: 0 across 8303, Span 486, 13125 and 5043).', diff --git a/packages/spec/src/migrations/entries/semantic/18.tenant-schema-cache-ttl-unit-in-key.ts b/packages/spec/src/migrations/entries/semantic/18.tenant-schema-cache-ttl-unit-in-key.ts index eb409f35d42..f3bb632fd4a 100644 --- a/packages/spec/src/migrations/entries/semantic/18.tenant-schema-cache-ttl-unit-in-key.ts +++ b/packages/spec/src/migrations/entries/semantic/18.tenant-schema-cache-ttl-unit-in-key.ts @@ -31,9 +31,9 @@ export const entry: SemanticMigration = { + 'bd25e897dc: no in-repo runtime reads the key — outside `packages/spec/src/system/tenant.zod.ts` ' + 'and its test the only occurrences are the four generated rows in ' + '`content/docs/references/system/tenant.mdx`, which this rename regenerates; and the pinned ' - + 'objectui checkout — `.objectui-sha` = `31971ff1e28f89cfc45f0c19bc5b05e443f28b79` — spells it 0 ' - + 'times across 9912 tracked files, against lit controls `TTL` 181 and `tenant` 1237 on the ' - + 'same corpus (0 across 9800, against 181 and 1235, at e420df310; 0 across 9546, against 181 and 1200, at db11afd49; 0 across 9283, against 181 and 1185, at dd3f7e1be; 0 across 8512, against 156 and 1034, at f8a9d0fb0; 0 across 8303, against 156 ' + + 'objectui checkout — `.objectui-sha` = `89cad75d55702cc4f267bead5bf267de575d5842` — spells it 0 ' + + 'times across 10071 tracked files, against lit controls `TTL` 181 and `tenant` 1237 on the ' + + 'same corpus (0 across 9912, against 181 and 1237, at 31971ff1e; 0 across 9800, against 181 and 1235, at e420df310; 0 across 9546, against 181 and 1200, at db11afd49; 0 across 9283, against 181 and 1185, at dd3f7e1be; 0 across 8512, against 156 and 1034, at f8a9d0fb0; 0 across 8303, against 156 ' + 'and 987, at 62597c588).', acceptanceCriteria: 'Every schema-level tenant isolation source spells `performance.schemaCacheTtlSeconds`; ' diff --git a/packages/spec/src/migrations/registry.ts b/packages/spec/src/migrations/registry.ts index eccf5ae27c2..364959d3782 100644 --- a/packages/spec/src/migrations/registry.ts +++ b/packages/spec/src/migrations/registry.ts @@ -13287,13 +13287,13 @@ const step18: MigrationStep = { + 'the audience that does not parse. Measured on 884e8347d: the only in-repo readers are ' + 'packages/core/src/health-monitor.ts and packages/core/src/hot-reload.ts, both moved in ' + 'this same change; and the pinned objectui checkout — the pin this repo builds ' - + 'against, `.objectui-sha` = `31971ff1e28f89cfc45f0c19bc5b05e443f28b79` — names ' + + 'against, `.objectui-sha` = `89cad75d55702cc4f267bead5bf267de575d5842` — names ' + 'neither def and neither key: all thirteen exports of plugin-lifecycle-advanced.zod.ts and ' - + 'the string debounceDelay each occur 0 times across its 9912 tracked files (0 across the 9800 at e420df310, the 9546 at db11afd49, the 9283 at dd3f7e1be, the ' + + 'the string debounceDelay each occur 0 times across its 10071 tracked files (0 across the 9912 at 31971ff1e, the 9800 at e420df310, the 9546 at db11afd49, the 9283 at dd3f7e1be, the ' + '8512 at f8a9d0fb0 and the 8303 at 62597c588 too), against lit ' + 'controls objectstack 12966 and @objectstack/spec 4997 on the same corpus at 87af769e9, ' + 'which re-count to 13125 and 5043 respectively at 62597c588, to 13347 and 5123 at ' - + 'f8a9d0fb0, to 13745 and 5466 at dd3f7e1be, to 14704 and 5545 at db11afd49, to 15352 and 6024 at e420df310 and to 15691 and 6206 at this pin (git grep -o -F, the method that reproduces ' + + 'f8a9d0fb0, to 13745 and 5466 at dd3f7e1be, to 14704 and 5545 at db11afd49, to 15352 and 6024 at e420df310, to 15691 and 6206 at 31971ff1e and to 16044 and 6461 at this pin (git grep -o -F, the method that reproduces ' + 'every earlier count).', acceptanceCriteria: 'Every producer and reader of a PluginHealthCheck spells intervalMs and timeoutMs, and every ' @@ -13498,10 +13498,10 @@ const step18: MigrationStep = { + 'spells timeout 0 times; outside the zod file and its test the only live occurrences are the ' + 'generated rows in content/docs/references/kernel/plugin-security-advanced.mdx, which this ' + 'rename regenerates. The pinned objectui checkout — this is the pin we build against, ' - + '`.objectui-sha` = `31971ff1e28f89cfc45f0c19bc5b05e443f28b79`, re-read from this tree — ' + + '`.objectui-sha` = `89cad75d55702cc4f267bead5bf267de575d5842`, re-read from this tree — ' + 'spells resourceLimits.timeout 0 times across ' - + '9912 tracked files, against lit controls timeout 1303, RuntimeConfig 273 and resourceLimits ' - + '2 on the same corpus (0 across 9800, and 1293 / 273 / 2, at e420df310; 0 across 9546, and 1197 / 273 / 2, at db11afd49; 0 across 9283, and 1172 / 263 / 2, at dd3f7e1be; 0 across 8512, and 1096 / 245 / 2, at f8a9d0fb0; 0 across 8303, and ' + + '10071 tracked files, against lit controls timeout 1331, RuntimeConfig 273 and resourceLimits ' + + '2 on the same corpus (0 across 9912, and 1303 / 273 / 2, at 31971ff1e; 0 across 9800, and 1293 / 273 / 2, at e420df310; 0 across 9546, and 1197 / 273 / 2, at db11afd49; 0 across 9283, and 1172 / 263 / 2, at dd3f7e1be; 0 across 8512, and 1096 / 245 / 2, at f8a9d0fb0; 0 across 8303, and ' + '1086 / 240 / 2, at 62597c588); both resourceLimits hits are prose in packages/app-shell recording ' + 'that objectui\'s own AppShellRuntimeConfig shares not one key with the spec\'s ' + 'RuntimeConfig, so nothing there authors this key and no pin bump is owed. ADR-0087.', @@ -13737,10 +13737,10 @@ const step18: MigrationStep = { + 'no in-repo runtime reads any of the four — outside `packages/spec/src/system/logging.zod.ts` ' + 'and its test the only occurrences are the generated rows in ' + '`content/docs/references/system/logging.mdx`, which this rename regenerates; and the pinned ' - + 'objectui checkout — `.objectui-sha` = `31971ff1e28f89cfc45f0c19bc5b05e443f28b79` — spells ' + + 'objectui checkout — `.objectui-sha` = `89cad75d55702cc4f267bead5bf267de575d5842` — spells ' + '`flushInterval` 0 times, `initialDelay` 0, `HttpDestinationConfig` 0 and `LoggingConfig` 0 ' - + 'across its 9912 tracked files, against lit controls `useState` 2469 and `timeout` 1303 on ' - + 'the same corpus (all four 0 across 9800, against 2464 and 1293, at e420df310, 0 across 9546, against 2449 and 1197, at db11afd49, 0 across 9283, against 2435 and 1172, at dd3f7e1be, 0 across 8512, ' + + 'across its 10071 tracked files, against lit controls `useState` 2470 and `timeout` 1331 on ' + + 'the same corpus (all four 0 across 9912, against 2469 and 1303, at 31971ff1e, 0 across 9800, against 2464 and 1293, at e420df310, 0 across 9546, against 2449 and 1197, at db11afd49, 0 across 9283, against 2435 and 1172, at dd3f7e1be, 0 across 8512, ' + 'against 2391 and 1096, at f8a9d0fb0, and 0 across ' + '8303, against 2389 and 1086, at 62597c588).', acceptanceCriteria: @@ -17396,10 +17396,11 @@ const step18: MigrationStep = { + 'against a lit control of 1195 defineStack occurrences on that same corpus at fc28c1d38 ' + '(1195 again at 9b62f54671); and the objectui ' + 'checkout this repo builds against — this is the pin, ' - + '`.objectui-sha` = `31971ff1e28f89cfc45f0c19bc5b05e443f28b79`, re-read from this tree — ' - + 'spells all six metrics def names and both distinctive keys 0 times across 9912 tracked ' - + 'files at that sha, against lit controls window 3916, timeout 1303, period 234, ' - + 'interval 196 and metrics 354 on that same corpus and sha (0 across 9800, against 3873 / ' + + '`.objectui-sha` = `89cad75d55702cc4f267bead5bf267de575d5842`, re-read from this tree — ' + + 'spells all six metrics def names and both distinctive keys 0 times across 10071 tracked ' + + 'files at that sha, against lit controls window 4002, timeout 1331, period 231, ' + + 'interval 196 and metrics 355 on that same corpus and sha (0 across 9912, against 3916 / ' + + '1303 / 234 / 196 / 354, at 31971ff1e, 0 across 9800, against 3873 / ' + '1293 / 233 / 196 / 352, at e420df310, 0 across 9546, against 3772 / ' + '1197 / 228 / 196 / 341, at db11afd49, 0 across 9283, against 3681 / 1172 / 183 / 176 / 340, at dd3f7e1be, 0 across 8512, against 3581 / ' + '1096 / 171 / 179 / 326, at f8a9d0fb0, and 0 across 8303, against 3526 / 1086 / 170 / 179 / ' @@ -17614,12 +17615,13 @@ const step18: MigrationStep = { + 'dark control of 0; inside packages/spec the ' + 'only occurrences are tracing.zod.ts, its test, and the generated rows in ' + 'content/docs/references/system/tracing.mdx, which this rename regenerates. And the ' - + 'pinned objectui checkout — `.objectui-sha` = `31971ff1e28f89cfc45f0c19bc5b05e443f28b79` — names none of it: all 37 exports of ' - + 'tracing.zod.ts and each of the four key names occur 0 times across the 9912 files ' - + 'tracked at that sha (the 486 Span and 53 SpanSchema hits are objectui\'s own HTML ' + + 'pinned objectui checkout — `.objectui-sha` = `89cad75d55702cc4f267bead5bf267de575d5842` — names none of it: all 37 exports of ' + + 'tracing.zod.ts and each of the four key names occur 0 times across the 10071 files ' + + 'tracked at that sha (the 489 Span and 56 SpanSchema hits are objectui\'s own HTML ' + 'text-span component, TextSpanSchema, an unrelated name, plus colSpan and prose), against ' - + 'two lit controls on that same corpus and sha: 15691 hits for the bare token objectstack, ' - + 'and 6206 for the package specifier @objectstack/spec (at e420df310: 0 across 9800, Span 486, ' + + 'two lit controls on that same corpus and sha: 16044 hits for the bare token objectstack, ' + + 'and 6461 for the package specifier @objectstack/spec (at 31971ff1e: 0 across 9912, Span 486, ' + + '15691 and 6206; at e420df310: 0 across 9800, Span 486, ' + '15352 and 6024; at db11afd49: 0 across 9546, Span 486, ' + '14704 and 5545; at dd3f7e1be: 0 across 9283, Span 485, 13745 and 5466; at f8a9d0fb0: 0 across 8512, ' + 'Span 488, 13347 and 5123; at 62597c588: 0 across 8303, Span 486, 13125 and 5043).', @@ -17728,9 +17730,9 @@ const step18: MigrationStep = { + 'bd25e897dc: no in-repo runtime reads the key — outside `packages/spec/src/system/tenant.zod.ts` ' + 'and its test the only occurrences are the four generated rows in ' + '`content/docs/references/system/tenant.mdx`, which this rename regenerates; and the pinned ' - + 'objectui checkout — `.objectui-sha` = `31971ff1e28f89cfc45f0c19bc5b05e443f28b79` — spells it 0 ' - + 'times across 9912 tracked files, against lit controls `TTL` 181 and `tenant` 1237 on the ' - + 'same corpus (0 across 9800, against 181 and 1235, at e420df310; 0 across 9546, against 181 and 1200, at db11afd49; 0 across 9283, against 181 and 1185, at dd3f7e1be; 0 across 8512, against 156 and 1034, at f8a9d0fb0; 0 across 8303, against 156 ' + + 'objectui checkout — `.objectui-sha` = `89cad75d55702cc4f267bead5bf267de575d5842` — spells it 0 ' + + 'times across 10071 tracked files, against lit controls `TTL` 181 and `tenant` 1237 on the ' + + 'same corpus (0 across 9912, against 181 and 1237, at 31971ff1e; 0 across 9800, against 181 and 1235, at e420df310; 0 across 9546, against 181 and 1200, at db11afd49; 0 across 9283, against 181 and 1185, at dd3f7e1be; 0 across 8512, against 156 and 1034, at f8a9d0fb0; 0 across 8303, against 156 ' + 'and 987, at 62597c588).', acceptanceCriteria: 'Every schema-level tenant isolation source spells `performance.schemaCacheTtlSeconds`; ' diff --git a/packages/spec/src/ui/component.test.ts b/packages/spec/src/ui/component.test.ts index 7461c2b221c..389e297876c 100644 --- a/packages/spec/src/ui/component.test.ts +++ b/packages/spec/src/ui/component.test.ts @@ -288,7 +288,12 @@ describe('PageAccordionProps variant (#6776)', () => { // same file's `ComponentRegistry.register('accordion', …)` publishes the key to // the Studio block designer at `:1220` (the `items` input, documented as // `[{ label, icon?, collapsed?, children }]`). Measured at the pin this repo -// builds against — `.objectui-sha` = `31971ff1e`. Re-derived at that pin +// builds against — `.objectui-sha` = `89cad75d5`. Re-derived at that pin +// 2026-10-02: `containers.tsx` is byte-identical across the hop from +// `31971ff1e` (`git diff --quiet`), and both anchors were re-READ in place and +// still say what this block says: the icon block `1171-1177`, inside +// `PageAccordionRenderer`'s `AccordionTrigger`, and the input `1220`, inside +// the `register('accordion', …)` inputs. At `31971ff1e`, re-derived at that pin // 2026-10-01: `containers.tsx` is byte-identical across the hop from // `e420df310` (`git diff --quiet`), and both anchors were re-READ in place and // still say what this block says: the icon block `1171-1177`, inside @@ -408,8 +413,13 @@ describe('PageTabsProps items[].value / items[].count (#5775)', () => { // same file's `ComponentRegistry.register('tabs', …)` publishes the key to the // Studio block designer at `:1005` (the `items` input, documented as // `[{ label, value?, icon?, count?, visibleWhen?, children }]`). Measured at -// the pin this repo builds against — `.objectui-sha` = `31971ff1e`. Re-derived at -// that pin 2026-10-01: `containers.tsx` is byte-identical across the hop from +// the pin this repo builds against — `.objectui-sha` = `89cad75d5`. Re-derived at +// that pin 2026-10-02: `containers.tsx` is byte-identical across the hop from +// `31971ff1e` (`git diff --quiet`), and both anchors were re-READ in place and +// still say what this block says: the icon block `946-952`, inside +// `PageTabsRenderer`'s `TabsTrigger`, and the input `1005`, inside the +// `register('tabs', …)` inputs. At `31971ff1e`, re-derived at that pin +// 2026-10-01: `containers.tsx` is byte-identical across the hop from // `e420df310` (`git diff --quiet`), and both anchors were re-READ in place and // still say what this block says: the icon block `946-952`, inside // `PageTabsRenderer`'s `TabsTrigger`, and the input `1005`, inside the @@ -3484,7 +3494,19 @@ describe('#7751 — object-* block props schemas', () => { // #16503 — the spec half of objectui#8172 (decision batch #68, 2026-09-07, // option A: the contract declares the capability that already ships, is // documented and is in use). Measured at the objectui pin this repo builds -// against (`.objectui-sha` = `31971ff1e`; re-measured there 2026-10-01 — +// against (`.objectui-sha` = `89cad75d5`; re-measured there 2026-10-02 — +// `plugin-kanban/src/types.ts` and `ObjectKanban.tsx` are byte-identical to +// `31971ff1e` (`git diff --quiet`), so `types.ts` still declares no `limit` +// and `:722` / `:97` did not move and were re-read in place; `index.tsx` +// changed only in the `ObjectKanbanRenderer` docblock and the `navigation` +// input's description (objectui#11293's record-navigator `page` mode), at +// `:626` and below, so the mapping did not move from `487-491`; `objectql.ts` +// MOVED the member `4588` -> `4661` byte-identical, still inside +// `ObjectKanbanSchema` (the 73 lines are declarations eight objectui commits +// of the range added above it); and `plugin-kanban.mdx` rewrote its +// `navigation` Properties row and gained a `swimlaneField` row, both below the +// `limit` row, which is byte-identical, and still teaches `limit: 250`. At +// `31971ff1e`, re-measured there 2026-10-01 — // `plugin-kanban/src/types.ts` is byte-identical to `e420df310` and still // declares no `limit`; `ObjectKanban.tsx` changed only in the comment above // its `navigation` read (objectui#8652), below both anchors, so `:722` and @@ -3541,7 +3563,7 @@ describe('#7751 — object-* block props schemas', () => { // `OBJECT_KANBAN_DATA_SOURCE`, ⚠️ `KanbanSchema` is RETIRED at this pin and // `plugin-kanban/src/types.ts` declares the member no more — the published // twin is `ObjectKanbanSchema`, declaring `limit?: number` at -// `packages/types/src/objectql.ts:4588` — and `content/docs/plugins/plugin-kanban.mdx` +// `packages/types/src/objectql.ts:4661` — and `content/docs/plugins/plugin-kanban.mdx` // teaches `limit: 250` with a Properties row. The strict map refused the key by // name — the same `unrecognized_keys` verdict as the `bogusProp` control — so an // author following the published docs wrote a node the save gate rejected. @@ -3603,7 +3625,12 @@ describe('ObjectKanbanPropsSchema limit — the row cap four objectui faces alre // since retired that block, objectui#8257). Unlike `limit` above — a key four // objectui faces already implemented, so the spec was the half that was wrong // — `quickAdd` was FORWARDED and never read: at the pin this repo builds -// against (`.objectui-sha` = `31971ff1e`; re-measured there 2026-10-01 — +// against (`.objectui-sha` = `89cad75d5`; re-measured there 2026-10-02 — +// `KanbanImpl.tsx`, `KanbanBoardCore.tsx` and `ObjectKanban.tsx` are +// byte-identical to `31971ff1e` (`git diff --quiet`), so `:621`, `:634`, +// `:78`, `:111-112` and the spread `:1639` did not move and were re-read in +// place, and the counts re-read the same, 2 / 2 / 11. At `31971ff1e`, +// re-measured there 2026-10-01 — // `KanbanImpl.tsx` and `KanbanBoardCore.tsx` are byte-identical to // `e420df310`, so `:621`, `:634`, `:78` and `:111-112` did not move and were // re-read in place; `ObjectKanban.tsx` changed only in the comment above its @@ -3740,7 +3767,11 @@ describe('ObjectKanbanPropsSchema quickAdd is retired (#17260)', () => { // #9881 and commit 60e0f900a recorded the accordion and tab items; these two close the set. // // The button record re-measured at the pin this repo builds against — -// `.objectui-sha` = `31971ff1e`, re-derived there 2026-10-01: `button.tsx`, +// `.objectui-sha` = `89cad75d5`, re-derived there 2026-10-02: `button.tsx`, +// `lazy-icon.tsx`, `resolve-icon.ts` and the generated +// `lucide-record-icon-names.ts` are byte-identical to `31971ff1e` +// (`git diff --quiet`), so every anchor below holds unmoved and was re-read in +// place. At `31971ff1e`, 2026-10-01: `button.tsx`, // `lazy-icon.tsx`, `resolve-icon.ts` and the generated // `lucide-record-icon-names.ts` are byte-identical to `e420df310` // (`git diff --quiet`), so every anchor below holds unmoved and was re-read in @@ -3890,11 +3921,32 @@ describe('ObjectMetricPropsSchema icon liveness (#10053)', () => { // // The acceptance the card names, pinned: each row's KEY SET is the one the // renderer's read points support at the pin this repo builds against -// (`.objectui-sha` = `31971ff1e`; re-measured there 2026-10-01 — -// `ObjectMap.tsx`, `ObjectGantt.tsx`, `ObjectTree.tsx` and `record-source.ts` -// are byte-identical across the hop off `e420df310` (`git diff --quiet`), so -// every anchor below holds unmoved and the set of `schema.*` keys each renderer -// reads is the one recorded at `e420df310`. At `e420df310`, 2026-09-30 — all +// (`.objectui-sha` = `89cad75d5`; re-measured there 2026-10-02 — all four +// cited files changed on the hop off `31971ff1e`, so each was re-READ, and +// the set of `schema.*` keys each renderer reads is the same at both pins. +// `ObjectMap.tsx` +11/-4: the shadowed-flat-key warning reads `schema[key]` +// typed instead of through a cast (objectui#11355), and the declared `map` +// block's return path now takes the same `style` as every other path, +// `mapStyle` first, then `map.style` (objectui#11168 slice 3) — the two keys +// it reads are unchanged, and the `style` line MOVED `400` -> `407` +// byte-identical. `ObjectGantt.tsx` +47/-10: the same typed shadowed-key read +// (objectui#11355) and the tooltip's number and percent rows taking their +// width from the field definition's `scale` through `resolveFieldScale` +// (objectui#11254) — a field-definition read, not a node key. +// `ObjectTree.tsx` +8/-17: the `navigation` read lost its cast +// (`(schema as any).navigation` `:1063` -> `schema.navigation` `:1054`, +// objectui#11168 slice 3 declaring it), the same key; the rung-1 call +// `resolveRecordSourceConfig(schema, 'view-data')` `:634` and the shorthand +// read `(rest as any).data` `:865` did not move. ⚠️ `record-source.ts` +// +4/-5 no longer lists FOUR tree tags as `view-data`: objectui `990a2d616` +// (objectui#10859 batch 8) retired the bare `tree` / `view:tree` node types, +// so the arm table keeps `object-tree` and `plugin-tree:object-tree` only, +// still `view-data`. The in-test notes below stay dated to the pins they +// name. At `31971ff1e`, 2026-10-01 — `ObjectMap.tsx`, `ObjectGantt.tsx`, +// `ObjectTree.tsx` and `record-source.ts` were byte-identical across the hop +// off `e420df310` (`git diff --quiet`), so every anchor held unmoved and the +// set of `schema.*` keys each renderer reads was the one recorded at +// `e420df310`. At `e420df310`, 2026-09-30 — all // three renderers changed on the hop off `db11afd49`, `ObjectMap.tsx` in one docblock // only, `ObjectGantt.tsx` +85/-26 (objectui#11141's inclusive date-only end, // objectui#8348, objectui#11070) and `ObjectTree.tsx` +29/-26, and the set of diff --git a/packages/spec/src/ui/component.zod.ts b/packages/spec/src/ui/component.zod.ts index 69e43b9a109..03fda207923 100644 --- a/packages/spec/src/ui/component.zod.ts +++ b/packages/spec/src/ui/component.zod.ts @@ -783,10 +783,13 @@ export const PageTabsProps = strictObject({ * false candidate a component over). * * The key is LIVE at the objectui pin this repo builds against - * (`.objectui-sha` = `31971ff1e`; re-derived at that pin 2026-10-01 — - * `containers.tsx` is byte-identical across the hop from `e420df310` + * (`.objectui-sha` = `89cad75d5`; re-derived at that pin 2026-10-02 — + * `containers.tsx` is byte-identical across the hop from `31971ff1e` * (`git diff --quiet`), so both anchors were re-READ in place, each still - * the read point this record names: `946-952` and `1005`. At `e420df310` + * the read point this record names: `946-952` and `1005`. At `31971ff1e` + * (2026-10-01) `containers.tsx` was byte-identical across the hop from + * `e420df310` (`git diff --quiet`), so both anchors were re-READ in place, + * each still the read point this record names: `946-952` and `1005`. At `e420df310` * (2026-09-30) `containers.tsx` changed again across the hop from * `db11afd49` (40 * insertions, 26 deletions: objectui#11166's `page:header` breadcrumb slot @@ -981,7 +984,15 @@ export const PageCardProps = strictObject({ * declarations identical. * * Each clause is read off the objectui pin this repo builds against - * (`.objectui-sha` = `31971ff1e28f`, re-read there 2026-10-01: across the hop + * (`.objectui-sha` = `89cad75d5570`, re-read there 2026-10-02: across the hop + * from `31971ff1e28f` `record-details.tsx`, `record-highlights.tsx`, + * `record-quick-actions.tsx` and the three `permissions` files are + * byte-identical, so NO anchor in those six moved; `record-related-list.tsx` + * gained the `localizeColumnLabels` helper above every cited line and a + * comment at its `columns` hand-off below them (objectui#10993 batch 4, + * +32/-1), so every anchor in it MOVED by 28 with its cited text + * byte-identical: `298` -> `326`, `316` -> `344`, `352` -> `380`, `365-373` + * -> `393-401`. At `31971ff1e28f`, 2026-10-01: across the hop * from `e420df310f5b` `record-details.tsx`, `record-highlights.tsx` and the * three `permissions` files are byte-identical, so NO anchor in those five * moved; `record-related-list.tsx` changed one docblock line above the gate @@ -1019,22 +1030,22 @@ export const PageCardProps = strictObject({ * * 1. CAPABILITIES, NOT OBJECT ACTIONS. Every block gates through * `perms.hasCapabilities(required)` — `record-details.tsx:244`, - * `record-highlights.tsx:102`, `record-related-list.tsx:365`, + * `record-highlights.tsx:102`, `record-related-list.tsx:393`, * `record-quick-actions.tsx:273` — and never `perms.can(objectName, …)`; * each renderer's docblock states the capability "is not object-scoped" * (`record-details.tsx:233`, `record-highlights.tsx:81`, - * `record-related-list.tsx:352`, `record-quick-actions.tsx:262`). `read` + * `record-related-list.tsx:380`, `record-quick-actions.tsx:262`). `read` * is looked up in the capability set like any other name. * 2. ALL OF THEM. `MePermissionsProvider.tsx:416` is * `required.every((p) => held.has(p))`. * 3. THE OUTCOME. Each block returns a `role="status"` "Insufficient * permissions to view …" notice instead of its content — * `record-details.tsx:244-252`, `record-highlights.tsx:160-173`, - * `record-related-list.tsx:365-373`, `record-quick-actions.tsx:273-281`. + * `record-related-list.tsx:393-401`, `record-quick-actions.tsx:273-281`. * Checks that already withhold the content run first on two of them (no * record bound, `record-details.tsx:188`; no object, - * `record-related-list.tsx:298`; the related object's read gate, - * `record-related-list.tsx:316`), which is why the text says "wherever it + * `record-related-list.tsx:326`; the related object's read gate, + * `record-related-list.tsx:344`), which is why the text says "wherever it * would otherwise render" rather than promising the notice unconditionally. * 4. PRESENTATION ONLY. The gate is renderer code: nothing in this repo's * server packages reads a page component's `requiredPermissions`. The data @@ -2221,10 +2232,13 @@ export const PageAccordionProps = strictObject({ * re-derive the same false candidate). * * The key is LIVE at the objectui pin this repo builds against - * (`.objectui-sha` = `31971ff1e`; re-derived at that pin 2026-10-01 — - * `containers.tsx` is byte-identical across the hop from `e420df310` + * (`.objectui-sha` = `89cad75d5`; re-derived at that pin 2026-10-02 — + * `containers.tsx` is byte-identical across the hop from `31971ff1e` * (`git diff --quiet`), so both anchors were re-READ in place, each still - * the read point this record names: `1171-1177` and `1220`. At `e420df310` + * the read point this record names: `1171-1177` and `1220`. At `31971ff1e` + * (2026-10-01) `containers.tsx` was byte-identical across the hop from + * `e420df310` (`git diff --quiet`), so both anchors were re-READ in place, + * each still the read point this record names: `1171-1177` and `1220`. At `e420df310` * (2026-09-30) `containers.tsx` changed again across the hop from * `db11afd49` (40 * insertions, 26 deletions: objectui#11166's `page:header` breadcrumb slot @@ -2504,11 +2518,12 @@ export const ElementButtonPropsSchema = lazySchema(() => strictObject({ * the button. * * The key is LIVE at the objectui pin this repo builds against - * (`.objectui-sha` = `31971ff1e`; re-derived at that pin 2026-10-01 — + * (`.objectui-sha` = `89cad75d5`; re-derived at that pin 2026-10-02 — * `button.tsx`, `lib/lazy-icon.tsx`, `renderers/action/resolve-icon.ts` and the - * generated `lucide-record-icon-names.ts` are all byte-identical to `e420df310` + * generated `lucide-record-icon-names.ts` are all byte-identical to `31971ff1e` * across the hop onto this pin, so every anchor below holds unmoved and was - * re-checked in place; they were byte-identical to `db11afd49` across the hop + * re-checked in place; they were byte-identical to `e420df310` across the hop + * onto `31971ff1e` (2026-10-01), byte-identical to `db11afd49` across the hop * onto `e420df310` (2026-09-30), and byte-identical to `dd3f7e1be` across the hop * onto `db11afd49` (2026-09-29) as well. At `dd3f7e1be` (2026-09-28) * `button.tsx` and `lib/lazy-icon.tsx` are byte-identical to `f8a9d0fb0` @@ -2978,9 +2993,13 @@ export const ElementTextInputPropsSchema = lazySchema(() => strictObject({ * had no row for — `action:button`, `action:group`, `action:menu`, * `action:icon`, `element:definition-list`, `element:repeater` * (`core/src/registry/public-blocks.ts:117-122` at the pin this repo builds - * against, `.objectui-sha` = `31971ff1e`; first measured at `.objectui-sha` + * against, `.objectui-sha` = `89cad75d5`; first measured at `.objectui-sha` * pin `f8a9d0fb0`, every read point below re-derived at the current pin - * 2026-10-01: `public-blocks.ts`, `auto-trigger.ts`, `static-params.ts`, + * 2026-10-02: `public-blocks.ts`, `auto-trigger.ts`, `static-params.ts`, all + * four `action-*.tsx` renderers, `basic/data-list.tsx` and `ui/button.tsx` + * are byte-identical to `31971ff1e` (`git diff --quiet`), so every anchor + * below held unmoved and was re-read in place. At `31971ff1e` (2026-10-01): + * `public-blocks.ts`, `auto-trigger.ts`, `static-params.ts`, * `action-group.tsx`, `action-menu.tsx` and `action-icon.tsx` are * byte-identical to `e420df310`, so their anchors held unmoved, and * `action-button.tsx` changed only inside its registration (+9/-1, @@ -4105,10 +4124,18 @@ export const ObjectMetricPropsSchema = lazySchema(() => strictObject({ * same record for the metric tile. * * The key is LIVE at the objectui pin this repo builds against - * (`.objectui-sha` = `31971ff1e`; re-derived at that pin 2026-10-01 — + * (`.objectui-sha` = `89cad75d5`; re-derived at that pin 2026-10-02 — + * `plugin-dashboard/src/index.tsx`, `MetricWidget.tsx`, `MetricCard.tsx` + * and `lazy-icon.tsx` are byte-identical to `31971ff1e`, so their anchors + * hold unmoved and were re-read in place; `ObjectMetricWidget.tsx` changed + * (+68/-4, objectui#11254: a `resolveFieldScale` import, the + * `widthPattern` / `ownFractionDigits` helpers and the field-width + * `inferredFormat` memo, none of it touching `icon`), and both its anchors + * MOVED with their cited text byte-identical: the destructure `230` -> + * `255`, the forward `595` -> `659`. At `31971ff1e` (2026-10-01) * `plugin-dashboard/src/index.tsx`, `ObjectMetricWidget.tsx`, - * `MetricWidget.tsx`, `MetricCard.tsx` and `lazy-icon.tsx` are all - * byte-identical to `e420df310`, so every anchor below holds unmoved and was + * `MetricWidget.tsx`, `MetricCard.tsx` and `lazy-icon.tsx` were all + * byte-identical to `e420df310`, so every anchor held unmoved and was * re-read in place; they were byte-identical to `db11afd49` across the hop * onto `e420df310` (2026-09-30) as well. At `db11afd49` (2026-09-29) * `MetricWidget.tsx` and `lazy-icon.tsx` are byte-identical to `dd3f7e1be`; @@ -4145,7 +4172,7 @@ export const ObjectMetricPropsSchema = lazySchema(() => strictObject({ * runs three files: * `plugin-dashboard/src/index.tsx:252` publishes it as a designer input * on the registered `object-metric` block; - * `ObjectMetricWidget.tsx:230` destructures it and forwards it at `:595` to + * `ObjectMetricWidget.tsx:255` destructures it and forwards it at `:659` to * `MetricWidget`; `MetricWidget.tsx:351-360` resolves it via * `getLazyIcon(icon)` — guarded on `typeof icon === 'string'`, because the * React prop also accepts a ready-made node — and `:412-421` draws it in the @@ -4234,8 +4261,11 @@ export type ObjectMetricPropsParsed = z.infer; * DESIGNER's spelling with * zero read points (#7973 class) — aliased to the `groupBy` the board reads. * `limit` (#16503) was measured later, at the pin this repo builds against - * (`.objectui-sha` = `31971ff1e`; re-measured there 2026-10-01 — - * `ObjectKanban.tsx` changed on this hop only in the comment above its + * (`.objectui-sha` = `89cad75d5`; re-measured there 2026-10-02 — + * `ObjectKanban.tsx` is byte-identical across the hop from `31971ff1e` + * (`git diff --quiet`), so the anchor did not move and was re-read in place. + * At `31971ff1e` (2026-10-01) + * `ObjectKanban.tsx` changed on that hop only in the comment above its * `navigation` read (+12/-14, objectui#8652: the key is now declared on * `ObjectKanbanSchema`), far below the anchor, which did not move and was * re-read in place. At `e420df310` (2026-09-30) @@ -4306,7 +4336,21 @@ export const ObjectKanbanPropsSchema = lazySchema(() => strictObject({ * Row cap (#16503 — the spec half of objectui#8172; decision batch #68, * 2026-09-07, option A: the contract declares the capability that already * ships, is documented and is in use). Measured at the objectui pin this - * repo builds against (`.objectui-sha` = `31971ff1e`; re-measured there + * repo builds against (`.objectui-sha` = `89cad75d5`; re-measured there + * 2026-10-02 — `ObjectKanban.tsx`, `plugin-kanban/src/types.ts` (still no + * row-cap member), `ElementDataSourceGate.tsx` and `element-data-source.ts` + * are byte-identical to `31971ff1e`, so the query `715-725`, the default + * `:97`, the `queryFilter` resolution `:584-585`, the import `:10`, + * `:218-220`, `:437-456` and `:268-272` did not move and were re-read in + * place; `plugin-kanban/src/index.tsx` changed only in the registration's + * `navigation` docblock and input description (+7/-5, objectui#11293: + * `page` now opens the record through the host's record navigator), far + * below the mapping, which did not move from `487-491`; `objectql.ts` + * MOVED the member `4588` -> `4661` byte-identical, still inside + * `ObjectKanbanSchema`; and `plugin-kanban.mdx` rewrote its `navigation` + * Properties row (objectui#11293) and gained a `swimlaneField` row + * (objectui#11355), both below the `limit` row, which, with the + * `limit: 250` snippet, did not change. At `31971ff1e`, re-measured there * 2026-10-01 — `plugin-kanban/src/types.ts` (still no row-cap member) and * `ElementDataSourceGate.tsx` are byte-identical to `e420df310`, so * `:218-220` and `:437-456` did not move; `ObjectKanban.tsx` changed only in @@ -4395,7 +4439,7 @@ export const ObjectKanbanPropsSchema = lazySchema(() => strictObject({ * through is `ObjectKanbanSchema` — ⚠️ `KanbanSchema` was RETIRED on this hop * (maintainer ruling 2026-09-09) and `plugin-kanban/src/types.ts` no longer * declares the member at all — imported at `ObjectKanban.tsx:10` and - * declaring `limit?: number` at `packages/types/src/objectql.ts:4588`, + * declaring `limit?: number` at `packages/types/src/objectql.ts:4661`, * and `content/docs/plugins/plugin-kanban.mdx` * teaches it with a typed snippet (`limit: 250`) plus a Properties row. So * an author following the published docs wrote a node the save gate @@ -4490,8 +4534,17 @@ export const ObjectKanbanPropsSchema = lazySchema(() => strictObject({ * quick-add control and no block a document can name offers one either). * * Measured at the objectui pin this repo builds against - * (`.objectui-sha` = `31971ff1e`; re-measured there 2026-10-01 — - * `KanbanImpl.tsx` and `KanbanBoardCore.tsx` are byte-identical to + * (`.objectui-sha` = `89cad75d5`; re-measured there 2026-10-02 — + * `KanbanImpl.tsx`, `KanbanBoardCore.tsx` and `ObjectKanban.tsx` are + * byte-identical to `31971ff1e`, so `:621`, `:634`, `:78` and `:1639` did + * not move and were re-read in place; `plugin-kanban/src/index.tsx` changed + * (+7/-5, objectui#11293: the `navigation` input's description and the + * comment above it now say a `page` click goes to the host's record + * navigator), every hunk at `:626` or below, so the pass-through did not + * move from `345-346` and was re-read in place, and the exported + * `KanbanRenderer` still forwards both keys to `KanbanBoardCore`, which + * `ObjectKanban` does not mount for them. At `31971ff1e` (2026-10-01) + * `KanbanImpl.tsx` and `KanbanBoardCore.tsx` were byte-identical to * `e420df310`, so `:621`, `:634` and `:78` did not move and were re-read in * place; `ObjectKanban.tsx` changed only in the comment above its * `navigation` read (objectui#8652), above the spread, which MOVED `1641` -> @@ -4540,7 +4593,7 @@ export const ObjectKanbanPropsSchema = lazySchema(() => strictObject({ * `object-kanban` node. `ObjectKanban.tsx` names neither half of the pair * in code (0 occurrences each, against 11 for the sibling `onCardClick` in the same * file — re-counted at `db11afd49`, at `f8a9d0fb0` and at `62597c588`; at - * `e420df310` and again at this pin 2 each, all four inside the two + * `e420df310`, at `31971ff1e` and again at this pin 2 each, all four inside the two * objectui#11234 comments that record the cut, and still 11 for * `onCardClick`; this record said 6, which the identical * file at `87af769e9` does not reproduce either, so the control was @@ -4560,7 +4613,7 @@ export const ObjectKanbanPropsSchema = lazySchema(() => strictObject({ * renders directly and can hand the runtime function to. ⚠️ Re-read at * `e420df310`: objectui retired the schema-only `kanban-ui` registration * long before this pin (objectui#8257; 0 registrations at `dd3f7e1be`, - * `db11afd49`, `e420df310` and this pin), and the pair now lives on the + * `db11afd49`, `e420df310`, `31971ff1e` and this pin), and the pair now lives on the * exported `KanbanRenderer` React component a host mounts directly * (`plugin-kanban/src/index.tsx:345-346`), not on any block a document can * name. ⛔ So the tombstone below prescribes "delete the key" and names no @@ -4587,7 +4640,16 @@ export const ObjectKanbanPropsSchema = lazySchema(() => strictObject({ * element schemas). * * Measured at the pin this repo builds against (`.objectui-sha` = - * `31971ff1e`; re-measured there 2026-10-01 — `ObjectKanban.tsx` changed on + * `89cad75d5`; re-measured there 2026-10-02 — `ObjectKanban.tsx` is + * byte-identical to `31971ff1e` (`git diff --quiet`), so every anchor held + * unmoved and was re-read in place: the read `1280`, the hand-off + * `1288-1289`, the overlay render `1538` and its `NavigationOverlay` + * `1554-1567`, and the card click `1663`. What did change on this hop is + * downstream of the read, not the read: objectui#11293 has the shared + * `useNavigationOverlay` hand a `page` click with no `onNavigate` to the + * record navigator the host publishes, so the `page` mode this key accepts + * now opens the record page on a standalone board under such a host. At + * `31971ff1e` (2026-10-01) `ObjectKanban.tsx` changed on * this hop in one place, the comment above the `navigation` read (+12/-14, * objectui#8652, the objectui half of the same ruling: the key is now * declared on `ObjectKanbanSchema`), so the read itself did not change and @@ -4749,7 +4811,14 @@ export const ObjectCalendarPropsSchema = lazySchema(() => strictObject({ * `object-kanban`'s above. * * Measured at the pin this repo builds against (`.objectui-sha` = - * `31971ff1e`; re-measured there 2026-10-01 — `ObjectCalendar.tsx` changed + * `89cad75d5`; re-measured there 2026-10-02 — `ObjectCalendar.tsx` is + * byte-identical to `31971ff1e` (`git diff --quiet`), so every anchor held + * unmoved and was re-read in place: the read `1018`, the hand-off + * `1020-1021`, the event click `1413`, the overlay render `1333` and its + * `NavigationOverlay` `1346-1359`; objectui#11293's `page` hand-off to the + * host's record navigator lands in the shared `useNavigationOverlay`, past + * these anchors, exactly as on `object-kanban`. At `31971ff1e` (2026-10-01) + * `ObjectCalendar.tsx` changed * across the hop from `e420df310` in one place (+11/-19, objectui#8652, the * objectui half of the same ruling): `navigation` is now DECLARED on * `ObjectCalendarSchema`, so the ledger comment `1008-1025` that recorded @@ -5146,9 +5215,29 @@ const OBJECT_MAP_FLAT_CONFIG_GUIDANCE: readonly KeySetGuidance[] = [ /** * `object-map` (objectui `plugin-map/src/ObjectMap.tsx` plus the registry shell * `plugin-map/src/index.tsx`, read at the pin this repo builds against — - * `.objectui-sha` = `31971ff1e`, re-measured there 2026-10-01: `ObjectMap.tsx` - * and `core/src/utils/record-source.ts` are byte-identical to `e420df310`, so - * every anchor in them holds unmoved and was re-read in place; `index.tsx` + * `.objectui-sha` = `89cad75d5`, re-measured there 2026-10-02: all three + * files changed across the hop from `31971ff1e`, so every anchor was + * re-mapped through the diff and re-READ. `ObjectMap.tsx` (+11/-4) changed + * in two places: objectui#11355 typed the flat-key read in + * `warnOnShadowedFlatMapKeys` in place (line-neutral, above `:364`, which did + * not move), and objectui#11168 slice 3 added a seven-line PRECEDENCE comment + * above the `mapStyle` read and made the declared-block return path keep + * `mapStyle` ahead of `map.style` (it used to hand `config.style` back + * first), so every anchor from the `mapStyle` read on MOVED down 7 with its + * cited text byte-identical — `:400` -> `:407`, `:405` -> `:412`, `:408` -> + * `:415`, `:769` -> `:776`, `:795-798` -> `:802-805`, `:857` -> `:864`, + * `:951`/`:952` -> `:958`/`:959`, `:1030`/`:1031` -> `:1037`/`:1038`, + * `:1182`/`:1183` -> `:1189`/`:1190`, `:1198` -> `:1205` — and every one above + * it did not move. `core/src/utils/record-source.ts` (+4/-5, objectui#10859 + * batch 8 retiring the bare `tree` arm) changed only below the three rungs, + * which did not move. `index.tsx` (+19/-1, objectui#11168 slice 3) gained a + * comment above the registration and `mapStyle`, `navigation` and + * `enableClustering` inputs after `sort`, and rewrote the `map` input's + * description from a three-field list into the whole block it reads, so the + * `map` input MOVED `:101` -> `:116` and its `{ name: 'map', type: 'object' }` + * head is unchanged. At `31971ff1e` (2026-10-01) `ObjectMap.tsx` + * and `core/src/utils/record-source.ts` were byte-identical to `e420df310`, so + * every anchor in them held unmoved and was re-read in place; `index.tsx` * changed (+7/-3, objectui#10859 batch 5: the comment above the registration * and the `objectName` input's description now count the node's * `dataSource` binding), the `map` input MOVING `:97` -> `:101` @@ -5208,24 +5297,29 @@ const OBJECT_MAP_FLAT_CONFIG_GUIDANCE: readonly KeySetGuidance[] = [ * it, reading an objectui docblock that was itself stale), * `staticData` (rung 2, * `record-source.ts:311`), `objectName` (rung 3, `record-source.ts:318`; also - * here at `:1183`, the `useNavigationOverlay` binding, and as a cache key at + * here at `:1190`, the `useNavigationOverlay` binding, and as a cache key at * `:240`, `:243`, `:318` and `:364`. ⚠️ The dependency-key read this record * cited at `:965` is GONE at this pin: objectui#10664 replaced the metadata - * effect whose dependency list it was with `useSettledSchema` (`:795-798`), - * keyed on the ladder's `recordSourceObjectName` (`:769`), so the object is + * effect whose dependency list it was with `useSettledSchema` (`:802-805`), + * keyed on the ladder's `recordSourceObjectName` (`:776`), so the object is * still read there, only no longer through that list), - * `filter` (`:857`, read once through `useResolvedFilter`, which resolves its - * context tokens — objectui#10666 — and holds the result, which `:951` and - * `:1030` hand to `$filter` on the inline and the object fetch respectively; + * `filter` (`:864`, read once through `useResolvedFilter`, which resolves its + * context tokens — objectui#10666 — and holds the result, which `:958` and + * `:1037` hand to `$filter` on the inline and the object fetch respectively; * at `f8a9d0fb0` both handed `schema.filter` verbatim), - * `sort` (`:952` and `:1031`, through the shared `convertSortToQueryParams` sink - * to `$orderby`), `map` (`:405` — `getMapConfig` branch 1, the author face and + * `sort` (`:959` and `:1038`, through the shared `convertSortToQueryParams` sink + * to `$orderby`), `map` (`:412` — `getMapConfig` branch 1, the author face and * the registration's declared `{ name: 'map', type: 'object' }` input, - * `plugin-map/src/index.tsx:101`; the second copy this record cited at `:78` + * `plugin-map/src/index.tsx:116`; the second copy this record cited at `:78` * belonged to the bare `map` registration, retired on objectui#10393, so * `object-map` is now the one registration declaring it), `mapStyle` - * (`:400`, `schema.mapStyle || schema.map?.style`), `navigation` (`:1182`) and - * `enableClustering` (`:1198`). + * (`:407`, `schema.mapStyle || schema.map?.style`, read ahead of `map.style` + * on every return path since objectui#11168 slice 3 — through `31971ff1e` the + * declared-block path returned `config.style || style`, so a map writing + * both drew `map.style`), `navigation` (`:1189`) and `enableClustering` + * (`:1205`). Since objectui#11168 slice 3 the registration also declares + * `mapStyle`, `navigation` and `enableClustering` inputs + * (`plugin-map/src/index.tsx:121-123`). * * Measured and deliberately NOT declared: * @@ -5242,11 +5336,11 @@ const OBJECT_MAP_FLAT_CONFIG_GUIDANCE: readonly KeySetGuidance[] = [ * * VALUE posture for `map`: {@link ListMapConfigSchema}, this repo's own block — * the later value ratchet the previous posture here deferred, taken now that the - * one-key gap is closed. `:408` validates the authored block against objectui's + * one-key gap is closed. `:415` validates the authored block against objectui's * `ObjectMapConfigSchema` and this block declares the same eight keys, `style` * included; until that declaration landed the door had to stay `z.unknown()`, * because pointing it at a schema missing `style` would have refused a value - * `getMapConfig` honours at `:400` (`schema.mapStyle || schema.map?.style`). + * `getMapConfig` honours at `:407` (`schema.mapStyle || schema.map?.style`). * `mapStyle` above is unaffected: it stays the component-level spelling read * FIRST, and is not a member of the config block. */ @@ -5284,8 +5378,15 @@ export const ObjectMapPropsSchema = lazySchema(() => strictObject({ * Base query filter — the `ViewFilterRule` ARRAY form, the one filter * orthography every `filter` door in this map shares (ui#6206-B reaching the * `object-*` family: #15449, decision batch #55, option A). Measured at the - * pin this repo builds against (`.objectui-sha` = `31971ff1e`, re-READ there - * 2026-10-01: `ObjectMap.tsx` is byte-identical to `e420df310`, so all three + * pin this repo builds against (`.objectui-sha` = `89cad75d5`, re-READ there + * 2026-10-02: `ObjectMap.tsx` changed above all three anchors + * (objectui#11168 slice 3's seven-line `mapStyle` precedence comment; + * objectui#11355's in-place typing of the flat-key read is line-neutral), so + * each MOVED down 7 with its text byte-identical, `:857` -> `:864`, `:951` + * -> `:958` and `:1030` -> `:1037`; and `plugin-map/src/index.tsx` gained a + * comment above the registration (objectui#11168 slice 3), the `filter` + * input MOVING `:104` -> `:119` byte-identical. At `31971ff1e`, re-READ there + * 2026-10-01: `ObjectMap.tsx` was byte-identical to `e420df310`, so all three * anchors held unmoved, and `plugin-map/src/index.tsx` changed above its * inputs (objectui#10859 batch 5), the `filter` input MOVING `:100` -> * `:104` byte-identical. At `e420df310`, re-READ there @@ -5305,8 +5406,8 @@ export const ObjectMapPropsSchema = lazySchema(() => strictObject({ * `schema.filter` verbatim. At `f8a9d0fb0`, byte-identical to `62597c588` * and re-READ there 2026-09-23, both anchors had MOVED 19 lines from * `:814` / `:895` with their text byte-identical, that hop changing only a - * docblock and a dev warning above them): `ObjectMap.tsx:857` reads - * `schema.filter`, and `:951` and `:1030` hand it, tokens resolved, to + * docblock and a dev warning above them): `ObjectMap.tsx:864` reads + * `schema.filter`, and `:958` and `:1037` hand it, tokens resolved, to * `$filter` on the inline and the object fetch, where the adapter lowers a * rule array exactly as it does for the kanban and the calendar. The record * form is refused at `filter`. @@ -5322,8 +5423,15 @@ export const ObjectMapPropsSchema = lazySchema(() => strictObject({ * Marker order — the `SortItem` ARRAY form, the one sort orthography every * DECLARED `sort` door on this platform carries (objectui#8221, decision batch * #77, option B). Measured at the pin this repo builds against - * (`.objectui-sha` = `31971ff1e`, re-READ there 2026-10-01 — `ObjectMap.tsx` - * is byte-identical to `e420df310`, so both anchors held unmoved, and + * (`.objectui-sha` = `89cad75d5`, re-READ there 2026-10-02 — `ObjectMap.tsx` + * changed above both anchors (objectui#11168 slice 3's seven-line `mapStyle` + * precedence comment; objectui#11355's in-place typing of the flat-key read + * is line-neutral), so both MOVED down 7 with their text byte-identical, + * `:952` -> `:959` and `:1031` -> `:1038`; and `plugin-map/src/index.tsx` + * gained a comment above the registration and three inputs after `sort` + * (objectui#11168 slice 3), the `sort` input MOVING `:105` -> `:120` + * byte-identical. At `31971ff1e`, re-READ there 2026-10-01 — `ObjectMap.tsx` + * was byte-identical to `e420df310`, so both anchors held unmoved, and * `plugin-map/src/index.tsx` changed above its inputs (objectui#10859 batch * 5), the `sort` input MOVING `:101` -> `:105` byte-identical. At * `e420df310`, re-READ there 2026-09-30 — `ObjectMap.tsx` @@ -5343,13 +5451,13 @@ export const ObjectMapPropsSchema = lazySchema(() => strictObject({ * retired (objectui#10393), still declares no `sort`. At `f8a9d0fb0` both files were byte-identical * to `62597c588`, re-READ there 2026-09-23 — both anchors had MOVED 19 * lines from `:815` / `:896` with their text byte-identical): - * `ObjectMap.tsx:952` and `:1031` + * `ObjectMap.tsx:959` and `:1038` * hand `schema.sort` to the shared `convertSortToQueryParams` sink as the * fetch's `$orderby` — the same sink `object-grid` and `object-calendar` * declare against, so the legacy string clause is refused here for the same * ruling. Through `db11afd49` `plugin-map/src/index.tsx` declared no `sort` * input at all; since objectui#8220 it declares one in this array form - * (`:105`), so the registry and this door agree. + * (`:120`), so the registry and this door agree. */ sort: z.array(SortItemSchema).optional() .describe('Marker order for the fetched records — the SortItem array form `[{ field, order }, ...]`, the one sort orthography every declared `sort` door on this platform shares; lowered to the wire `$orderby`. The legacy string clause (`name desc`) is refused — see migration `object-block-sort-item-array`'), @@ -5421,9 +5529,35 @@ const OBJECT_GANTT_FLAT_CONFIG_GUIDANCE: readonly KeySetGuidance[] = [ /** * `object-gantt` (objectui `plugin-gantt/src/ObjectGantt.tsx` plus the registry * shell `plugin-gantt/src/index.tsx`, read at the pin this repo builds against - * — `.objectui-sha` = `31971ff1e`, re-measured there 2026-10-01: - * `ObjectGantt.tsx` and `record-source.ts` are byte-identical to `e420df310`, - * so every anchor in them holds unmoved and was re-read in place; + * — `.objectui-sha` = `89cad75d5`, re-measured there 2026-10-02: all three + * files changed across the hop from `31971ff1e`, so every anchor was + * re-mapped through the diff and re-READ; NONE changed content. + * `ObjectGantt.tsx` +47/-10: one import added above `getGanttConfig` and one + * removed above it (objectui#11254's `resolveFieldScale` / + * `formatDisplayNumber`), objectui#11355 typing the flat-key read in + * `warnOnShadowedFlatGanttKeys` (+1 net), and objectui#11254's field-width + * reads in the tooltip's `number` and `percent` rows (+23 and +13) — so + * `getGanttConfig` MOVED by 1 (`:610-612` -> `:611-613`), the record-source + * ladder, the filter, the reload and its search pair by 1 (`:722` -> `:723`, + * `:918` -> `:919`, `:1063`/`:1064` -> `:1064`/`:1065`, `:1072`/`:1074` -> + * `:1073`/`:1075`, `:885-888` -> `:886-889`, `:1078-1083` -> `:1079-1084`), + * and every anchor after the tooltip by 37 (`:1633`/`:1634` -> + * `:1670`/`:1671`, `:1785`/`:1787` -> `:1822`/`:1824`, `:1923` -> `:1960`, + * `:1990` -> `:2027`, `:2302` -> `:2339`, `:2460`-`:2468` -> `:2497`-`:2505`, + * `:2503-2509` -> `:2540-2546`), each with its cited text byte-identical. + * `record-source.ts` +4/-5 (objectui#10859 batch 8 retiring the bare `tree` + * arm) changed only below the three rungs, which did not move. + * `plugin-gantt/src/index.tsx` +45/-1 (objectui#11168 slice 4): a navigation + * description constant and a comment above the registration, the `gantt` + * input's description rewritten from a member list naming `percentageField` + * (which nothing reads) into this row's own describe, and eleven inputs + * after `sort` — `navigation`, `label`, `skipWeekends`, `holidays`, + * `persistLayout`, `viewName`, `markers`, `criticalPath`, `showBaselines`, + * `readOnly`, `mobileReadOnly` (`:184-194`), every one a key this row + * declares — so the `gantt` input MOVED `:146` -> `:179` with its + * `{ name: 'gantt', type: 'object' }` head unchanged. At `31971ff1e` + * (2026-10-01) `ObjectGantt.tsx` and `record-source.ts` were byte-identical to + * `e420df310`, so every anchor in them held unmoved and was re-read in place; * `plugin-gantt/src/index.tsx` changed (+3/-2, objectui#11117: the * `objectName` input's description and the comment above the registration * now count a `dataSource.object` binding), the `gantt` input MOVING `:145` @@ -5466,46 +5600,46 @@ const OBJECT_GANTT_FLAT_CONFIG_GUIDANCE: readonly KeySetGuidance[] = [ * every number was re-derived from that tree, and the `label` one moved far * enough that the retired reading now lands in an unrelated callback.) * Read points per key: `data` (`resolveRecordSourceConfig` at - * `:722` — rung 1, `core/src/utils/record-source.ts:307`), `staticData` (rung 2, - * `record-source.ts:311`), `objectName` (rung 3; also `:1787` and `:1990` here), - * `filter` (`:918`, read once through `useResolvedFilter`, which resolves its - * context tokens — objectui#10666 — and `:1063` sends the held result to - * `$filter`; at `f8a9d0fb0` it was sent verbatim), `sort` (`:1064`, through - * `convertSortToQueryParams` to `$orderby`), `gantt` (`:610-612` — + * `:723` — rung 1, `core/src/utils/record-source.ts:307`), `staticData` (rung 2, + * `record-source.ts:311`), `objectName` (rung 3; also `:1824` and `:2027` here), + * `filter` (`:919`, read once through `useResolvedFilter`, which resolves its + * context tokens — objectui#10666 — and `:1064` sends the held result to + * `$filter`; at `f8a9d0fb0` it was sent verbatim), `sort` (`:1065`, through + * `convertSortToQueryParams` to `$orderby`), `gantt` (`:611-613` — * `getGanttConfig` branch 1, the author face and the registration's declared - * `{ name: 'gantt', type: 'object' }` input (`plugin-gantt/src/index.tsx:146`), + * `{ name: 'gantt', type: 'object' }` input (`plugin-gantt/src/index.tsx:179`), * validated there against this - * repo's own {@link GanttConfigSchema}), `navigation` (`:1923`), `label` - * (`:2505`, resolved through `resolveInlineI18nLabel` for the export file + * repo's own {@link GanttConfigSchema}), `navigation` (`:1960`), `label` + * (`:2542`, resolved through `resolveInlineI18nLabel` for the export file * name — this record said `resolveI18nLabel`, which the line did not read at * `f8a9d0fb0` either — * ⚠️ the retired reading `:1849` was the comment ABOVE that chain and at this * pin `87af769e9` was a BLANK line (nothing cites `:1849` now), two above a dependency-delete callback's own comment, * so it is re-READ here, not re-pointed), - * `skipWeekends` (`:1633`), `holidays` (`:1634`), `persistLayout` (`:1785`), - * `viewName` (`:1787`), `markers` (`:2460`), `criticalPath` (`:2463`), - * `showBaselines` (`:2466`), `readOnly` (`:2302` and `:2467`) and - * `mobileReadOnly` (`:2468`). + * `skipWeekends` (`:1670`), `holidays` (`:1671`), `persistLayout` (`:1822`), + * `viewName` (`:1824`), `markers` (`:2497`), `criticalPath` (`:2500`), + * `showBaselines` (`:2503`), `readOnly` (`:2339` and `:2504`) and + * `mobileReadOnly` (`:2505`). * * Measured and deliberately NOT declared: the flat `GanttConfig` spellings (the * flatten product — {@link OBJECT_GANTT_FLAT_CONFIG_GUIDANCE}); `title`, which * this renderer never reads (the export-name chain is `gantt.exportFileName` → - * `label` → the OBJECT's label → `objectName`, `:2503-2509`); a row cap — the + * `label` → the OBJECT's label → `objectName`, `:2540-2546`); a row cap — the * reload's `$top` is the platform ceiling, spread in as core's - * `nonGridRowCeilingQuery()` (`:1074`: one probe row past the ceiling, which + * `nonGridRowCeilingQuery()` (`:1075`: one probe row past the ceiling, which * `applyNonGridRowCeiling` slices back off; at `f8a9d0fb0` a bare * `$top: NON_GRID_ROW_CEILING_TOP`, until objectui#7508 homed the ceiling in - * core) and the renderer's own comment marks it "⛔ Not authorable" (`:1072`); and + * core) and the renderer's own comment marks it "⛔ Not authorable" (`:1073`); and * the `onTaskClick` / `onRowClick` / `onBeforeTaskUpdate` callbacks, which are * host props. ⚠️ New at `f8a9d0fb0` and recorded, not ruled: objectui#10250 * gave the renderer two more reads, `search` and `searchableFields` - * (`:885-888`, sent as `$search` / `$searchFields` at `:1078-1083`), which + * (`:886-889`, sent as `$search` / `$searchFields` at `:1079-1084`), which * `ListView.tsx` writes onto the node it generates from its toolbar Search * box — a host-generated key pair in the same position as the flatten * product, and not declared here. * * VALUE posture: `gantt` is the one config block in this family whose value - * contract is already the SPEC's — `ObjectGantt.tsx:612` validates it against + * contract is already the SPEC's — `ObjectGantt.tsx:613` validates it against * `GanttConfigSchema` imported from `@objectstack/spec/ui` — so the read point * names the schema and this door takes it rather than `z.unknown()`. The * scalars below are read as their coercions say: `!!schema.readOnly`, @@ -5583,8 +5717,18 @@ export type ObjectGanttPropsParsed = z.infer; * they flatten `options.tree` (`ListView.tsx:3756-3775`, `case 'tree'`: the * product carries these keys, the EFFECTIVE `filter` objectui#10250 added, and * NO `tree` key). Both halves re-READ at the - * pin this repo builds against (`.objectui-sha` = `31971ff1e`) on 2026-10-01 — - * `ObjectTree.tsx` is byte-identical to `e420df310`, so `281-294` and + * pin this repo builds against (`.objectui-sha` = `89cad75d5`) on 2026-10-02 — + * `ListView.tsx` is byte-identical to `31971ff1e`, so `3756-3775` and `:3770` + * did not move; `ObjectTree.tsx` changed (+8/-17, objectui#11168 slice 3 + * replacing the cast comment on its `navigation` read with a typed read), + * every line of it at `:1044` or below, so `281-294` and `233-254` did not + * move and were re-read in place; and `plugin-tree/src/index.tsx` changed + * (+73/-8: objectui#11168 slice 3 published `data`, `staticData`, `filter` + * and `navigation` inputs beside `objectName` and `tree`, and objectui#10859 + * batch 8 retired the bare `tree` / `view:tree` registration), and its one + * remaining registration, `object-tree`, still declares `tree` as an object + * input and no flat config key. At `31971ff1e`, 2026-10-01 — + * `ObjectTree.tsx` was byte-identical to `e420df310`, so `281-294` and * `233-254` did not move; `ListView.tsx` changed above its `case 'tree'` arm * (+35/-1, objectui#10689's re-read on a harvested query input), which MOVED * byte-identical `3722-3741` -> `3756-3775`, so the flat key set each reads or @@ -5642,10 +5786,28 @@ const OBJECT_TREE_FLAT_CONFIG_GUIDANCE: readonly KeySetGuidance[] = [ /** * `object-tree` (objectui `plugin-tree/src/ObjectTree.tsx` plus the registry * shell `plugin-tree/src/index.tsx`, read at the pin this repo builds against - * — `.objectui-sha` = `31971ff1e`, re-measured there 2026-10-01: - * `plugin-tree/src/index.tsx`, `ObjectTree.tsx` and - * `core/src/utils/record-source.ts` are byte-identical to `e420df310` - * (`git diff --quiet`), so every anchor below holds unmoved and was re-read in + * — `.objectui-sha` = `89cad75d5`, re-measured there 2026-10-02: all three + * cited files changed on the hop off `31971ff1e`, so every anchor was + * re-mapped through the diff and re-READ. + * `core/src/utils/record-source.ts` changed (+4/-5, objectui#10859 batch 8: + * the bare `tree` and `view:tree` rows left `RECORD_SOURCE_DATA_ARM_BY_TYPE`, + * and the docblock above it says so) below both rungs, which did not move; + * `ObjectTree.tsx` changed (+8/-17, objectui#11168 slice 3) in ONE place, the + * navigation binding, and that anchor changed CONTENT, toward this row: + * `:1063` -> `:1054` now reads `schema.navigation`, typed, where it read + * `(schema as any).navigation`; the two anchors past it MOVED by 9 with their + * text byte-identical (`:1077` -> `:1068`, `:1149` -> `:1140`) and every + * anchor above it holds unmoved; `plugin-tree/src/index.tsx` changed + * (+73/-8): objectui#11168 slice 3 rewrote `treeInputs` — `objectName` is no + * longer `required`, `tree` carries a measured description, and `data`, + * `staticData`, `filter` and `navigation` inputs are published beside them — + * so the `tree` input MOVED `27-31` -> `47-52`, its `name` / `type` lines + * byte-identical and its description rewritten; and objectui#10859 batch 8 + * retired the second `ComponentRegistry.register('tree', ...)` under the + * `view` namespace, so `object-tree` is the one key this shell registers. At + * `31971ff1e` (2026-10-01) `plugin-tree/src/index.tsx`, `ObjectTree.tsx` and + * `core/src/utils/record-source.ts` were byte-identical to `e420df310` + * (`git diff --quiet`), so every anchor held unmoved and was re-read in * place. At `e420df310` (2026-09-30) * `plugin-tree/src/index.tsx` was byte-identical to `db11afd49`; * `core/src/utils/record-source.ts` changed (+38/-27) and its three rungs MOVED @@ -5689,8 +5851,8 @@ const OBJECT_TREE_FLAT_CONFIG_GUIDANCE: readonly KeySetGuidance[] = [ * same line. Through `db11afd49` it passed `'undeclared'`, which honoured any * truthy value — WIDER than this row, the harmless direction), * `staticData` (rung 2, - * `record-source.ts:311`), `objectName` (rung 3; also `:1026`, `:1077` and - * `:1149` here, each behind `resolveRecordSourceObjectName`, plus the + * `record-source.ts:311`), `objectName` (rung 3; also `:1026`, `:1068` and + * `:1140` here, each behind `resolveRecordSourceObjectName`, plus the * parent-field detection at `:958-959`), * `filter` (`:739`, read once through `useResolvedFilter`, which resolves its * context tokens — objectui#10666 — and holds the result: `:831` sends it to @@ -5699,19 +5861,23 @@ const OBJECT_TREE_FLAT_CONFIG_GUIDANCE: readonly KeySetGuidance[] = [ * `schema.filter` verbatim, at `:753` and `:837`), `tree` (`:282`, the * nested config block `getTreeConfig` (`:281-294`) reads, and the * registration's declared `{ name: 'tree', type: 'object' }` input - * (`plugin-tree/src/index.tsx:27-31`)) and `navigation` (`:1063`, handed to - * `useNavigationOverlay` at `:1046`). + * (`plugin-tree/src/index.tsx:47-52`)) and `navigation` (`:1054`, handed to + * `useNavigationOverlay` at `:1046` — typed since objectui#11168 slice 3; + * through `31971ff1e` it was `(schema as any).navigation`, at `:1063`). * * ⚠️ `data` IS declared here, and that is the measurement, not a family * symmetry. objectui#9234 left this block's rung-1 read marked `undeclared` * because neither published face carried the key: `ObjectTreeSchema` on * `@object-ui/types` declared no `data`, no `staticData`, no `filter` and no - * `navigation` at all, and requires `objectName` (⚠️ at this pin it declares - * `filter`, in the `QueryParams['$filter']` shape, objectui#9549; the other - * three are still absent). The renderer reads all four + * `navigation` at all, and required `objectName` (at `31971ff1e` it declared + * `filter`, in the `QueryParams['$filter']` shape, objectui#9549, and the + * other three were still absent). The renderer reads all four * — so the protocol row follows the READ POINTS, which is what 「以协议为准」 * resolving for this block means, and the mirror is the face that has to - * follow. + * follow. ⚠️ At this pin it HAS followed: objectui#11168 slice 3 declares + * `data` (`ViewData`), `staticData` and `navigation` (the spec's + * `NavigationConfig`) beside `filter`, and makes `objectName` optional, on + * `ObjectTreeSchema` and on the registration's inputs alike. * * ⛔ `:865` is NOT a second site for the object arm, and at this pin it is not * a read of the authored key at all: it is `(rest as any).data`, gated by @@ -5743,8 +5909,14 @@ const OBJECT_TREE_FLAT_CONFIG_GUIDANCE: readonly KeySetGuidance[] = [ * This was also the one block of the three whose type was absent from the * tracked `sdui.manifest.json`, so `check:react-declaration-parity` reported * it as missing from the registry rather than comparing it. ⚠️ Re-read at - * `31971ff1e`: the manifest regenerated at this pin carries an `object-tree` - * entry, as the ones at `db11afd49` and `e420df310` already did. The derivation above is from + * `89cad75d5`: the tracked manifest regenerated at this pin + * (`scripts/sdui-manifest.record.json` names `89cad75d5570`) carries an + * `object-tree` entry, as the ones at `31971ff1e`, `db11afd49` and + * `e420df310` did, now publishing `data`, `filter`, `navigation`, + * `objectName`, `staticData` and `tree`; its source at this pin still + * registers `object-tree`, and `core/src/registry/public-blocks.ts`, + * byte-identical across the hop, still lists it — only the bare `tree` key, + * never a public block, is gone. The derivation above is from * the renderer's sources at the pin either way, which is what #7751's method * asks for. * @@ -5768,8 +5940,15 @@ export const ObjectTreePropsSchema = lazySchema(() => strictObject({ * holds for them because each registers through `ElementDataSourceGate`, * which lowers the spec binding onto `objectName` before the renderer sees * the node. `plugin-tree/src/index.tsx` does NOT: at the pin this repo - * builds against (`.objectui-sha` = `31971ff1e`, re-COUNTED there 2026-10-01 by - * the same method — 0 for the tree, whose shell is byte-identical, and 3 each + * builds against (`.objectui-sha` = `89cad75d5`, re-COUNTED there 2026-10-02 by + * the same method — 0 for the tree, whose shell changed on the hop + * (objectui#11168 slice 3's published inputs, objectui#10859 batch 8's + * retired bare `tree` registration) and still registers no gate, 3 each for + * `plugin-grid` (byte-identical), `plugin-gantt` and `plugin-calendar` (both + * changed on the hop), and 4 for `plugin-map` (changed on the hop, its + * wiring and the comment naming the gate unchanged); re-COUNTED at + * `31971ff1e` 2026-10-01 by + * the same method — 0 for the tree, whose shell was byte-identical, and 3 each * for `plugin-grid` (byte-identical), `plugin-gantt` and `plugin-calendar` * (both changed on the hop: objectui#11117 in each, and objectui#8652's * `navigation` input in the calendar's), but 4 for `plugin-map`: objectui#10859 batch 5 added a @@ -5873,9 +6052,26 @@ const OBJECT_TIMELINE_FLAT_CONFIG_GUIDANCE: readonly KeySetGuidance[] = [ * `object-timeline` (objectui `plugin-timeline/src/ObjectTimeline.tsx`, the * presentational `plugin-timeline/src/renderer.tsx` it composes into, and the * registry shell `plugin-timeline/src/index.tsx` — all read at the pin this - * repo builds against (`.objectui-sha` = `31971ff1e`), re-measured there - * 2026-10-01: `renderer.tsx` is byte-identical to `e420df310`, so its three - * anchors hold unmoved; `ObjectTimeline.tsx` changed (+42/-2, objectui#8654: + * repo builds against (`.objectui-sha` = `89cad75d5`), re-measured there + * 2026-10-02: `renderer.tsx` is byte-identical to `31971ff1e`, so its three + * anchors hold unmoved; `ObjectTimeline.tsx` changed (+16/-7, objectui#11168 + * slice 5) in two COMMENTS only — the `navigation` member's docblock on the + * component's props and the comment above the navigation read — every anchor + * between them MOVING by 6 (`:291` -> `:297`, `:538` -> `:544`) and every one + * past the second by 9 (`:793-796` -> `:802-805`, `:849` -> `:858`), each with + * its cited text byte-identical, and `:29` not moving; the `filter` read and + * its fetch key this record cited as `:396` / `:397` began one line early, on + * `useFilterScope`, at `31971ff1e` too, where they are `:397` / `:398`; they + * are `:403` / `:404` here. `index.tsx` changed (+80/-18, objectui#11168 + * slice 5: both registrations now spread one shared `OBJECT_TIMELINE_INPUTS` + * list that publishes the ten further keys this row declares, `objectName` + * is no longer `required`, and the `sort` / `navigation` descriptions were + * rewritten), so the `variant` input this record cited as `393-394` — a range + * that began on the `objectName` input — is re-pointed to `:446`, its own + * line, and `:333` MOVED to `:334` byte-identical. The `schema.*` read set of + * all three is unchanged. At `31971ff1e` (2026-10-01) `renderer.tsx` was + * byte-identical to `e420df310`, so its three + * anchors held unmoved; `ObjectTimeline.tsx` changed (+42/-2, objectui#8654: * a typed `navigation` member on the component's props, and the navigation * read without its cast), every anchor below line 173 MOVING by 35 (by 40 * past the navigation read) with its cited text byte-identical, and ONE @@ -5937,35 +6133,35 @@ const OBJECT_TIMELINE_FLAT_CONFIG_GUIDANCE: readonly KeySetGuidance[] = [ * directions: nothing accepted a real key and nothing refused a typo. * * Read points per key, in `ObjectTimeline.tsx` unless named otherwise: - * `objectName` (`:291` the fetch gate, `:371-374` the object-def load through - * `useSettledSchema`, `:409` the `fetchesForItself` gate — the check that + * `objectName` (`:297` the fetch gate, `:377-380` the object-def load through + * `useSettledSchema`, `:415` the `fetchesForItself` gate — the check that * sat inside the fetch effect at `:420` is hoisted to render scope at this - * pin, where `:410` also subscribes the invalidation bus on it - * (objectui#10623) and the effect reads it at `:514` — `:416` / `:474` + * pin, where `:416` also subscribes the invalidation bus on it + * (objectui#10623) and the effect reads it at `:520` — `:422` / `:480` * inside the fetch effect, - * `:785` the pull-to-refresh gate, `:596` the entry composition and `:795` - * the navigation binding), `timeline` (`:308`, + * `:791` the pull-to-refresh gate, `:602` the entry composition and `:804` + * the navigation binding), `timeline` (`:314`, * the canonical nested config every field resolution prefers), `filter` - * (`:396`, read once through `useResolvedFilter`, which resolves its context - * tokens — objectui#10666 — and holds the result; `:397` keys the fetch on - * it and `:475` sends it to `$filter`, where `f8a9d0fb0` sent `schema.filter` - * verbatim at `:341` / `:405`), `sort` (`:399`, `:476` — through + * (`:403`, read once through `useResolvedFilter`, which resolves its context + * tokens — objectui#10666 — and holds the result; `:404` keys the fetch on + * it and `:481` sends it to `$filter`, where `f8a9d0fb0` sent `schema.filter` + * verbatim at `:341` / `:405`), `sort` (`:405`, `:482` — through * the shared `convertSortToQueryParams` sink, as `object-calendar`'s does), - * `limit` (`:477`, the fetch's one top-level `$top`, through + * `limit` (`:483`, the fetch's one top-level `$top`, through * `resolveRowLimit(schema.limit, DEFAULT_TIMELINE_LIMIT)` with the default - * `100` at `:29` and the refused-cap diagnostic at `:325`), `items` (`:289`, `:409`, `:581`, - * `:811` — the authored pass-through that short-circuits the object query), - * `data` (`:290`, `:409`, `:536`, `:538` — the pre-fetched record source, + * `100` at `:29` and the refused-cap diagnostic at `:331`), `items` (`:295`, `:415`, `:587`, + * `:820` — the authored pass-through that short-circuits the object query), + * `data` (`:296`, `:415`, `:542`, `:544` — the pre-fetched record source, * read off REACT PROPS rather than `schema`; the door's own docblock carries * how an authored key reaches that channel and why a `schema.*` sweep alone * publishes a false refusal), - * `descriptionField` (`:572`), `mapping` (`:545`, `:570`, `:572`, `:573`), - * `variant` (`:849`) and `navigation` (`:793-796` → `:928` → `:983-984`). + * `descriptionField` (`:578`), `mapping` (`:551`, `:576`, `:578`, `:579`), + * `variant` (`:858`) and `navigation` (`:802-805` → `:937` → `:992-993`). * Four more are read by the presentational renderer off the schema this - * component spreads into it (`effectiveSchema`, `:912-931`): `dateFormat` + * component spreads into it (`effectiveSchema`, `:921-940`): `dateFormat` * (`plugin-timeline/src/renderer.tsx:1569`, every variant — its number was the * same at `53ded82bf` and `87af769e9`, as `plugin-timeline/src/index.tsx:333`'s - * also was, which is why the number alone is never the reading) and the gantt + * also was (`:334` since the hop off `31971ff1e`), which is why the number alone is never the reading) and the gantt * trio `rowLabel` (`plugin-timeline/src/renderer.tsx:1869`), `minDate` / * `maxDate` (`plugin-timeline/src/renderer.tsx:1794-1809`). ⚠️ All three name their * package because objectui has a second `renderer.tsx` (in `plugin-chatbot`): @@ -5977,8 +6173,8 @@ const OBJECT_TIMELINE_FLAT_CONFIG_GUIDANCE: readonly KeySetGuidance[] = [ * ({@link OBJECT_TIMELINE_FLAT_CONFIG_GUIDANCE}) — the runtime handoff * `ListView` emits, not a second authoring spelling; * - `bind` — the objectui data-scope key the section header above rules out - * for every block in this family (`:329` here); - * - `className` (`:915`) — a node-level key on `PageComponentSchema`, not a + * for every block in this family (`:335` here); + * - `className` (`:924`) — a node-level key on `PageComponentSchema`, not a * per-block prop; * - `onItemClick` / `onRowClick` — host callbacks JSON cannot carry. * @@ -5992,12 +6188,13 @@ const OBJECT_TIMELINE_FLAT_CONFIG_GUIDANCE: readonly KeySetGuidance[] = [ * reference, for the reason the ruling gives. * * ⚠️ `variant: 'gantt'` is declared because the registration declares it - * (`plugin-timeline/src/index.tsx:393-394`) and the renderer reads it — but the + * (`plugin-timeline/src/index.tsx:446`, in the one `OBJECT_TIMELINE_INPUTS` + * list both registrations spread) and the renderer reads it — but the * OBJECT-BOUND composed path REFUSES it loudly (objectui#6655, - * `ObjectTimeline.tsx:849-851`: - * `:849` gates on `!hasAuthoredItems && schema.variant === 'gantt'` and `:851` + * `ObjectTimeline.tsx:858-860`: + * `:858` gates on `!hasAuthoredItems && schema.variant === 'gantt'` and `:860` * renders `timeline-unsupported-variant`. ⚠️ The `:518` this clause carried is - * that gate at the RETIRED `53ded82bf` and a comment line at this pin. It sat on + * that gate at the RETIRED `53ded82bf` and was a comment line at `31971ff1e`. It sat on * a line the 2026-09-22 conversion never touched — and so did eight other * anchors of this record, so the untouched line is not what singles it out. * RE-READING all nine at this pin does: the other eight say here what this @@ -6047,7 +6244,19 @@ export const ObjectTimelinePropsSchema = lazySchema(() => strictObject({ * first publishes a refusal for a key the renderer honours. * * Read points at the pin this repo builds against (`.objectui-sha` = - * `31971ff1e`, re-READ there 2026-10-01 — the file changed across the hop + * `89cad75d5`, re-READ there 2026-10-02 — the file changed across the hop + * from `31971ff1e` (+16/-7, objectui#11168 slice 5) in two comments only, + * both above or away from these reads, so every anchor MOVED by 6 with its + * cited read byte-identical: `:290` -> `:296`, `:409` -> `:415`, `:514` -> + * `:520`, `:536` -> `:542`, `:538` -> `:544`, `:657-658` -> `:663-664`, + * `:688` -> `:694`. `SchemaRenderer.tsx` changed (+144/-10, objectui#11349: + * the evaluation memo's working copy is typed as renderer state, and the + * aria and text-key reads narrow through it) without touching the + * `properties.*` hoist, its strip list or the `createElement` spread, and + * `record-source.ts` changed (+4/-5) only by retiring the bare `tree` and + * `view:tree` rows, objectui#10859 batch 8 — `object-timeline` is still not + * listed — so the prop channel above still carries the key. At `31971ff1e`, + * 2026-10-01, the file changed across the hop * from `e420df310` (+42/-2, objectui#8654's typed `navigation` member and * cast-free navigation read), all of it above or away from these reads, so * every anchor MOVED by 35 with its cited read byte-identical: `:255` -> @@ -6055,9 +6264,9 @@ export const ObjectTimelinePropsSchema = lazySchema(() => strictObject({ * `:538`, `:653` -> `:688`. One was re-pointed rather than moved: the * start/end bindings this record carried as `621-622` began one line early, * on the `rawData.map` head, at `e420df310` too, where the two bindings are - * `622-623`; they are `657-658` here. `SchemaRenderer.tsx` and - * `record-source.ts` are byte-identical, so the prop channel above still - * carries the key. At `e420df310`, 2026-09-30, the file was byte-identical to + * `622-623`; they were `657-658` there. `SchemaRenderer.tsx` and + * `record-source.ts` were byte-identical, so the prop channel above still + * carried the key. At `e420df310`, 2026-09-30, the file was byte-identical to * `db11afd49`, so every anchor held unmoved; and the prop channel above * still carries the key here: `SchemaRenderer` strips an authored `data` * prop only on the types `core`'s `RECORD_SOURCE_DATA_ARM_BY_TYPE` puts on @@ -6076,13 +6285,13 @@ export const ObjectTimelinePropsSchema = lazySchema(() => strictObject({ * `recordDisplayValueAt` (`:653`, objectui#10530), not `item[titleField]`. * At `f8a9d0fb0` the file was byte-identical to `62597c588` and * `87af769e9`, where they were re-READ 2026-09-22), all in - * `ObjectTimeline.tsx`: `:290` seeds the loading state off it, `:409` + * `ObjectTimeline.tsx`: `:296` seeds the loading state off it, `:415` * SKIPS the object query when it is present (the gate the effect reads at - * `:514`), `:536` tracks it, and `:538` + * `:520`), `:542` tracks it, and `:544` * is the row source itself — `(props as any).data || boundData || * fetchedData`, so it wins over both the data-scope binding and the fetch. * Unlike `items` one line down, these rows are RECORDS: they go through the - * same `timeline` field bindings a fetched row takes (`:657-658`, `:688`). + * same `timeline` field bindings a fetched row takes (`:663-664`, `:694`). */ data: z.array(z.unknown()).optional() .describe("Pre-fetched records — read FIRST as the rail's row source, ahead of the data-scope binding and the fetch, and composed into entries through the same `timeline` field bindings a fetched row takes; authoring it suppresses the object query entirely. Distinct from `items`, which is the already-composed entry shape and wins over this key when both are written"), @@ -6283,7 +6492,11 @@ export const ComponentPropsMap = { // set from this map's keys), on the three-part evidence that vocabulary's // string-arm ledger asks of a type admitted without an enum member — all // measured at the pin this repo builds against (`.objectui-sha` = - // `31971ff1e`; re-measured there 2026-10-01: `public-blocks.ts` and + // `89cad75d5`; re-measured there 2026-10-02: `data-list.tsx`, + // `public-blocks.ts`, `block-types.ts` and `block-config.ts` all + // byte-identical to `31971ff1e` (`git diff --quiet`), so every anchor below + // holds unmoved and was re-read in place, both registrations still in the + // `element` namespace. At `31971ff1e`, 2026-10-01: `public-blocks.ts` and // `block-types.ts` byte-identical to `e420df310`; `data-list.tsx` changed // (+48/-6, objectui#11168 slice 2: both registrations publish their // spec-declared inputs), the `definition-list` registration not moving and @@ -6337,9 +6550,18 @@ export const ComponentPropsMap = { // authority for map and gantt while tree's rung-1 `data` read stayed // undeclared on every face. Key sets measured from the renderers' read // points at the pin this repo builds against (`.objectui-sha` = - // `31971ff1e`), all three re-measured there 2026-10-01 (`ObjectMap.tsx`, - // `ObjectGantt.tsx` and `ObjectTree.tsx` are byte-identical to `e420df310`, - // so no declared key set moved and no read point died. At `e420df310`, + // `89cad75d5`), all three re-measured there 2026-10-02 (all three renderers + // changed on the hop off `31971ff1e` and were re-READ: `ObjectMap.tsx` + // (+11/-4) types its shadowed-flat-key read, objectui#11355, and now reads + // `mapStyle` ahead of `map.style` on the declared block's path too, + // objectui#11168 slice 3; `ObjectGantt.tsx` (+47/-10) types the same read + // and formats its decimal and percent tooltip rows at the field's scale, + // objectui#11254; `ObjectTree.tsx` (+8/-17) reads `navigation` typed, + // without its cast, objectui#11168 slice 3. The `schema.*` read set of each + // is unchanged, so no declared key set moved and no read point died. At + // `31971ff1e`, 2026-10-01, `ObjectMap.tsx`, `ObjectGantt.tsx` and + // `ObjectTree.tsx` were byte-identical to `e420df310`, so no declared key set + // moved and no read point died. At `e420df310`, // 2026-09-30, all three renderers // changed and were re-READ: `ObjectMap.tsx` in one docblock, `ObjectGantt.tsx` // in objectui#11141's inclusive date-only end, and `ObjectTree.tsx`, whose @@ -6374,7 +6596,16 @@ export const ComponentPropsMap = { // it — so `object-timeline` was unjudged in both directions, a real key and // a typo riding through alike. Key set measured from the renderer's read // points at the pin this repo builds against (`.objectui-sha` = - // `31971ff1e`), re-measured there 2026-10-01 (`renderer.tsx` byte-identical + // `89cad75d5`), re-measured there 2026-10-02 (`renderer.tsx` byte-identical + // to `31971ff1e`; `ObjectTimeline.tsx` changed in two comments only and + // `index.tsx` for objectui#11168 slice 5 — one shared input list on both + // registrations, publishing the ten further keys this row declares, with + // `objectName` no longer required — both re-READ, the `schema.*` read set + // unchanged, so no declared key set moved and no read point died; every + // anchor moved or held with its text byte-identical, and two that had begun + // a line early were re-pointed, as the schema's header records. At + // `31971ff1e`, 2026-10-01: + // `renderer.tsx` byte-identical // to `e420df310`; `ObjectTimeline.tsx` and `index.tsx` changed for // objectui#8654 — a typed `navigation` member read without its cast, and a // `navigation` input on both registrations — both re-READ, the `schema.*` diff --git a/packages/spec/src/ui/dataset.zod.ts b/packages/spec/src/ui/dataset.zod.ts index f1b8a2b1a42..525625a9315 100644 --- a/packages/spec/src/ui/dataset.zod.ts +++ b/packages/spec/src/ui/dataset.zod.ts @@ -276,9 +276,11 @@ export const DatasetMeasureSchema = lazySchema(() => strictObject({ * and this docblock and the `describe` beneath it both said so. * * Measured at the pin this repo builds against (`.objectui-sha` = - * `31971ff1e`; re-derived at that pin 2026-10-01 — `dataset-format.ts` and - * `date-display.ts` are byte-identical to `e420df310`, so every anchor below - * held unmoved and was re-READ in place. At `e420df310` (2026-09-30) + * `89cad75d5`; re-derived at that pin 2026-10-02 — `dataset-format.ts` and + * `date-display.ts` are byte-identical to `31971ff1e`, so every anchor below + * held unmoved and was re-READ in place. At `31971ff1e` (2026-10-01) both + * files were byte-identical to `e420df310`, so every anchor held unmoved and + * was re-READ in place. At `e420df310` (2026-09-30) * `dataset-format.ts` was byte-identical to `db11afd49`, so `formatMeasureDate` `:229-263`, its call * at `:369` and its datetime arm `:259`-`:261` did not move and were re-READ * in place, and `date-display.ts` changed (+68/-1, objectui `858eafb4f`, diff --git a/packages/spec/src/ui/view.zod.ts b/packages/spec/src/ui/view.zod.ts index f0bf84e68f8..6dcb6d567bd 100644 --- a/packages/spec/src/ui/view.zod.ts +++ b/packages/spec/src/ui/view.zod.ts @@ -2136,7 +2136,23 @@ export const TreeConfigSchema = lazySchema(() => strictObject({ * byte-identical and still closed with `.strict()`, and * `LIST_VIEW_LOCAL_OVERRIDES` `1083` -> `1138`, the whole list byte-identical * and still without `map`; `ObjectMap.tsx`, `ObjectView.tsx` and the - * `ListView.tsx` anchors did not move. Each anchor quotes the line it was read at, + * `ListView.tsx` anchors did not move. RE-READ again at pin `89cad75d5` on + * 2026-10-02: that bump redded four anchors. Two are in `objectql.zod.ts`, + * which grew above them again (objectui#11168 slice 3, objectui#11276, + * objectui#10872 batch 10 and objectui#10993 batch 4 among others), and + * neither changed what it reads — `ObjectMapConfigSchema` `2123` -> `2145`, + * its ten-line declaration byte-identical and still closed with `.strict()`, + * and `LIST_VIEW_LOCAL_OVERRIDES` `1138` -> `1160`, the whole list + * byte-identical and still without `map`. The other two are the + * `getMapConfig` lines, `408` -> `415` and `413` -> `420`, and ⚠️ the second + * one's CONTENT changed: objectui#11168 slice 3 made `mapStyle` outrank + * `map.style` on the declared-block path too (seven comment lines added + * above), so the return is now `return { ...config, style };` where it was + * `return { ...config, style: config.style || style };`. It is still a spread + * of the AUTHORED block, undeclared key and all, so the reading below holds; + * only the `style` it writes over the spread changed precedence. The + * `safeParse` line is byte-identical. `ObjectView.tsx` and `ListView.tsx` are + * byte-identical, so their anchors did not move. Each anchor quotes the line it was read at, * so the next pin bump reds instead of rotting * (`check:objectui-pin-citations`): * @@ -2155,7 +2171,7 @@ export const TreeConfigSchema = lazySchema(() => strictObject({ * there, but by a whitelist and in SILENCE: no parse, no warning, no * diagnostic of any kind. * - **The renderer's own zod schema does not close the set.** - * `packages/types/src/zod/objectql.zod.ts:2123` first line + * `packages/types/src/zod/objectql.zod.ts:2145` first line * `export const ObjectMapConfigSchema = z.object({` — a plain `z.object` at `dd3f7e1be`, * NOT strict, so an undeclared key parses clean there: zero issues, no * warning. ⚠️ At `db11afd49` the declaration is closed with `.strict()` @@ -2164,10 +2180,10 @@ export const TreeConfigSchema = lazySchema(() => strictObject({ * the node with an `unrecognized_keys` issue at `map` — the flatten whitelist * above still drops the key in silence, and the spread below still returns the * authored block. `getMapConfig` consults that `safeParse` - * (`packages/plugin-map/src/ObjectMap.tsx:408` first line + * (`packages/plugin-map/src/ObjectMap.tsx:415` first line * `const result = ObjectMapConfigSchema.safeParse(config);`) only to decide * whether to `console.warn`, then returns a spread of the AUTHORED block - * (`:413` first line `return { ...config, style: config.style || style };`), + * (`:420` first line `return { ...config, style };`), * undeclared key and all. That spread is reached by objectui's own * component-node `map` prop, never by this face's flatten product ("neither * flattener emits a `map` key at all", `getMapConfig`). @@ -2178,7 +2194,7 @@ export const TreeConfigSchema = lazySchema(() => strictObject({ * `db11afd49` it is closed by `.strict()` and still warn-only). And this parse is * the only * place an author is told ANYWHERE: `map` is not in objectui's - * `LIST_VIEW_LOCAL_OVERRIDES` (`packages/types/src/zod/objectql.zod.ts:1138` + * `LIST_VIEW_LOCAL_OVERRIDES` (`packages/types/src/zod/objectql.zod.ts:1160` * first line `const LIST_VIEW_LOCAL_OVERRIDES = [`), so objectui's own * `ListViewSchema` imports THIS block by reference and the document check on * that side is this same schema. The two key sets MIRROR each other, key for @@ -3236,7 +3252,12 @@ const FormFieldBaseSchema = lazySchema(() => { * inside the `53ded82bf7...87af769e9` range, so the widest-tier-only * under-span this block used to record (#17328: one cell of two at * 720px) no longer reproduces at the pin this repo builds against - * (`.objectui-sha` = `31971ff1e`, re-read 2026-10-01: `autoLayout.ts` and + * (`.objectui-sha` = `89cad75d5`, re-read 2026-10-02: `autoLayout.ts`, + * `fields`' `field-type-alias.ts` and `form.tsx` are all byte-identical to + * `31971ff1e`, so `resolveColSpan` `:154`, `WIDE_FIELD_TYPES` `:58-69`, the + * `repeater` -> `field:grid` mapping, `spanLadderFor` `:204-231` and its one + * call site `:2986` held unmoved and were re-READ in place, so it still emits + * the ladder. At `31971ff1e`, re-read 2026-10-01: `autoLayout.ts` and * `fields`' `field-type-alias.ts` are byte-identical to `e420df310`, so * `resolveColSpan` `:154`, `WIDE_FIELD_TYPES` `:58-69` and the `repeater` -> * `field:grid` mapping held unmoved, and `form.tsx` changed on this hop — 59 @@ -3270,7 +3291,7 @@ const FormFieldBaseSchema = lazySchema(() => { * had changed only in its registration's input list, objectui#9910's * `children` slot; at `62597c588` it was byte-identical to `87af769e9`). */ - span: z.enum(['auto', 'full']).default('auto').describe("Relative field width. 'auto' (default — omit it): the renderer sizes the field from its widget type × the current column count — at the pin this repo builds against (`.objectui-sha` = `31971ff1e28f`), only textarea, markdown, html, richtext and repeater resolve to the full column count (repeater reaches it through the wide `field:grid` widget it maps to). 'full': resolves to the form grid's full column count. How far down the container-query tiers that span is emitted is the renderer's, not this key's: at that same pin the renderer emits one clamped col-span class per multi-column tier (`@md:col-span-2 @2xl:col-span-3` for a 3-column grid), so the field takes the whole row at every multi-column tier, not just the widest."), + span: z.enum(['auto', 'full']).default('auto').describe("Relative field width. 'auto' (default — omit it): the renderer sizes the field from its widget type × the current column count — at the pin this repo builds against (`.objectui-sha` = `89cad75d5570`), only textarea, markdown, html, richtext and repeater resolve to the full column count (repeater reaches it through the wide `field:grid` widget it maps to). 'full': resolves to the form grid's full column count. How far down the container-query tiers that span is emitted is the renderer's, not this key's: at that same pin the renderer emits one clamped col-span class per multi-column tier (`@md:col-span-2 @2xl:col-span-3` for a 3-column grid), so the field takes the whole row at every multi-column tier, not just the widest."), /** Custom widget override — only needed when auto-inference is insufficient */ widget: z.string().optional().describe('Custom widget/component name (overrides type-based inference)'), diff --git a/scripts/sdui-manifest.record.json b/scripts/sdui-manifest.record.json index f07e54d2e63..6007241d1cc 100644 --- a/scripts/sdui-manifest.record.json +++ b/scripts/sdui-manifest.record.json @@ -11,12 +11,12 @@ "a pin bump without regeneration goes RED there — that is the anti-rot half of the freshness gate.", "Regenerate + re-record: pnpm objectui:build && node scripts/gen-sdui-manifest-node.mjs" ], - "objectuiSha": "31971ff1e28f89cfc45f0c19bc5b05e443f28b79", + "objectuiSha": "89cad75d55702cc4f267bead5bf267de575d5842", "source": "built-tree", - "modulesRoot": ".cache/objectui-31971ff1e28f/apps/console", + "modulesRoot": ".cache/objectui-89cad75d5570/apps/console", "objectuiWorkspaceVersion": "17.6.0", "generator": "scripts/gen-sdui-manifest-node.mjs", - "generatedAt": "2026-10-01", - "sha256": "6a61f1742154aa1e67845f1a42154e0af890cdf811c95439f72e99aeb61bc7f5", + "generatedAt": "2026-10-02", + "sha256": "45341de35b91c4e624ecceeb244cce4a72c3571ccda6f2b93fd81e02faf4f5de", "components": 107 } diff --git a/sdui.manifest.json b/sdui.manifest.json index 8ed65315ae9..40fe00fe0d0 100644 --- a/sdui.manifest.json +++ b/sdui.manifest.json @@ -694,7 +694,7 @@ { "name": "navigation", "type": "object", - "description": "What a card click opens — the `{ mode, size, openNewTab, preventNavigation }` block a list view declares. With the key ABSENT a click opens the record in a drawer. `mode` is an overlay (`drawer`, `modal`, `split`, `popover`), `new_window`, `page` or `none`; write it whenever the block is written, because a block without `mode` takes the spec’s `page` default and `page` opens nothing on a board no parent view navigates for. `openNewTab: true` opens the record page in a new tab and outranks the mode, `preventNavigation: true` opens nothing, and `size` sets the overlay width. A click handler from a parent view outranks the whole key." + "description": "What a card click opens — the `{ mode, size, openNewTab, preventNavigation }` block a list view declares. With the key ABSENT a click opens the record in a drawer. `mode` is an overlay (`drawer`, `modal`, `split`, `popover`), `new_window`, `page` or `none`, and a block written without `mode` takes the spec’s `page` default. `page` opens the record page through the record navigator the host publishes (the console publishes one on its custom pages, record pages and list views); under a host that publishes none, such as an embedded renderer, there is no record page to open and the click opens nothing. `openNewTab: true` opens the record page in a new tab and outranks every mode except `none`, `preventNavigation: true` opens nothing, and `size` sets the overlay width. A click handler from a parent view outranks the whole key." }, { "name": "dataSource", @@ -761,7 +761,7 @@ { "name": "navigation", "type": "object", - "description": "What an event click opens — the `{ mode, size, openNewTab, preventNavigation }` block a list view declares. With the key ABSENT a click opens the record in a drawer. `mode` is an overlay (`drawer`, `modal`, `split`, `popover`), `new_window`, `page` or `none`; write it whenever the block is written, because a block without `mode` takes the spec’s `page` default and `page` opens nothing on a calendar no parent view navigates for. `openNewTab: true` opens the record page in a new tab and outranks the mode, `preventNavigation: true` opens nothing, and `size` sets the overlay width. An overlay mode wins over a parent view’s click handler; any other mode hands the click to it." + "description": "What an event click opens — the `{ mode, size, openNewTab, preventNavigation }` block a list view declares. With the key ABSENT a click opens the record in a drawer. `mode` is an overlay (`drawer`, `modal`, `split`, `popover`), `new_window`, `page` or `none`, and a block written without `mode` takes the spec’s `page` default. `page` opens the record page through the record navigator the host publishes (the console publishes one on its custom pages, record pages and list views); under a host that publishes none, such as an embedded renderer, there is no record page to open and the click opens nothing. `openNewTab: true` opens the record page in a new tab and outranks every mode except `none`, `preventNavigation: true` opens nothing, and `size` sets the overlay width. An overlay mode wins over a parent view’s click handler; any other mode hands the click to it." }, { "name": "dataSource", @@ -783,7 +783,7 @@ { "name": "gantt", "type": "object", - "description": "startDateField, endDateField, titleField, progressField, percentageField, colorField, dependenciesField" + "description": "Gantt-timeline configuration, the author face — the same block `ListViewSchema.gantt` declares, and the one the renderer validates this node against. Taken WHOLE when present: the flat top-level spelling beside it is ignored. The spec requires `startDateField`, `endDateField` and `titleField`, which name the record fields a task's bar starts at, ends at and is titled by; the other members (`progressField`, `colorField`, `dependenciesField`, `parentField`, `viewMode`, `exportFileName`, …) are optional." }, { "name": "data", @@ -805,6 +805,65 @@ "type": "array", "description": "Task order in `[{ field, order }]` form, ordering the rows the gantt charts. Lowered to `$orderby` on the same query." }, + { + "name": "navigation", + "type": "object", + "description": "What a task click opens — the `{ mode, size, openNewTab, preventNavigation }` block a list view declares. With the key ABSENT a click opens the task's record in a drawer, this renderer's own default. `mode` is an overlay (`drawer`, `modal`, `split`, `popover`), `new_window`, `page` or `none`, and a block written without `mode` takes the spec's `page` default. `drawer`, `modal` and `popover` open the task's record in that overlay, and `split` opens it beside the chart, which stays drawn; `none` opens nothing. `page` opens the task's record page in the same tab and `new_window` opens it in a new tab. The gantt builds that address itself from the page it is on and does not use a record navigator the host publishes, so a host that publishes one changes nothing: on the object's own list or view route (`…/OBJECT/view/VIEW`) the address is the record page `…/OBJECT/record/ID`, while on any other page, such as a custom page, `/OBJECT/record/ID` is appended to the current address. The object is `data.object` when `data` is the object provider, else `objectName`; on inline rows that name neither there is no record to open, and every mode, the default drawer included, opens nothing. `preventNavigation: true` opens nothing whatever the mode, `openNewTab: true` opens the record page in a new tab and outranks every mode except `none`, and `size` sets the overlay width." + }, + { + "name": "label", + "type": [ + "string", + "object" + ], + "description": "Gantt label — the second link of the exported PNG/PDF file-name chain, after `gantt.exportFileName` and before the bound object's own label. A string is used as written, and an inline locale map (`{ en, \"zh-CN\", … }`) gives the entry for the display locale. The chart draws it nowhere else." + }, + { + "name": "skipWeekends", + "type": "boolean", + "description": "Measure duration and auto-schedule math in WORKING days, skipping Saturdays and Sundays. The day view also folds the Saturday and Sunday columns out of its axis." + }, + { + "name": "holidays", + "type": "array", + "of": "string", + "description": "Additional non-working dates for the working calendar, ISO `yyyy-mm-dd` strings; folded into a Set for the duration math. A non-empty list turns the working calendar on by itself, without `skipWeekends`, and the day view folds each listed date's column out of its axis." + }, + { + "name": "persistLayout", + "type": "boolean", + "description": "Opt OUT of layout and filter-chip persistence — only an explicit `false` disables it; the storage key is `objectName:viewName`. The object half is `objectName`, else `data.object`, and `gantt` on inline rows that name neither. With `false` the toolbar has no save-layout button and nothing is stored." + }, + { + "name": "viewName", + "type": "string", + "description": "Layout-persistence scope, the second half of the `objectName:viewName` storage key (renderer default `'default'`). Two gantts on the same object with different names keep separate saved layouts, and a gantt restores only the layout saved under its own name." + }, + { + "name": "markers", + "type": "array", + "description": "Extra vertical reference lines drawn like the Today marker ({ date, label?, color? }). `date` places the line, and a date outside the chart's range draws none; `label` is the text drawn against it; `color` is its CSS colour, the theme's primary colour when omitted." + }, + { + "name": "criticalPath", + "type": "boolean", + "description": "Seed the critical-path highlight ON; the toolbar toggle stays available either way" + }, + { + "name": "showBaselines", + "type": "boolean", + "description": "Render the planned-vs-actual baseline bars — ON unless an explicit `false` disables it. A task draws one only when `gantt.baselineStartField` and `gantt.baselineEndField` give it both baseline dates." + }, + { + "name": "readOnly", + "type": "boolean", + "description": "Disable every write path on this gantt and lock the record drawer. A task click still opens the record, read-only." + }, + { + "name": "mobileReadOnly", + "type": "boolean", + "description": "Auto read-only on narrow viewports — ON unless an explicit `false` disables it. Narrow is under 640px: the chart's own width once it is measured, the viewport's until then. A narrow chart's own write paths are gated as under `readOnly`, read-only badge included, but the record drawer is locked by `readOnly` alone, so a task's record still opens writable. `false` keeps a narrow chart editable, and `readOnly: true` locks the chart and the drawer at any width." + }, { "name": "dataSource", "type": "object", @@ -820,7 +879,7 @@ { "name": "objectName", "type": "string", - "required": true + "description": "Object this timeline binds to. Optional because the component-level `dataSource` binding can supply the object instead — this block registers through `ElementDataSourceGate`, which lowers the binding onto this key before the renderer sees the node. A timeline drawn from `items`, `data` or a `bind` path issues no query and needs none to draw, but `navigation` still reads it: without it `page` opens nothing and `new_window` / `openNewTab` open no record page." }, { "name": "variant", @@ -839,12 +898,67 @@ { "name": "sort", "type": "array", - "description": "Entry order in `[{ field, order }]` form, ordering the records the timeline fetches. Lowered to `$orderby` on the same query." + "description": "Order of the records the timeline fetches, in `[{ field, order }]` form, lowered to `$orderby` on the same query. The rail draws entries composed from records by their start date, earliest first, whatever this order. Authored `items` or `data` suppress the query, so the key then orders nothing." }, { "name": "navigation", "type": "object", - "description": "What an entry click opens — the `{ mode, size, openNewTab, preventNavigation }` block a list view declares. Write it with `mode`: with the key ABSENT, or with a block that omits `mode` (it takes the spec’s `page` default), a click opens nothing on a timeline no parent view navigates for. `drawer`, `modal` and `popover` open the entry’s record in that overlay; `new_window` opens the record page in a new tab; `page`, `none` and `split` open nothing here, because the timeline hands the split shell no main panel. `openNewTab: true` opens the record page in a new tab and outranks the mode, `preventNavigation: true` opens nothing, and `size` sets the overlay width. A click handler from a parent view outranks the whole key." + "description": "What an entry click opens — the `{ mode, size, openNewTab, preventNavigation }` block a list view declares. With the key ABSENT a click opens nothing: this renderer supplies no drawer default. `mode` is an overlay (`drawer`, `modal`, `split`, `popover`), `new_window`, `page` or `none`, and a block written without `mode` takes the spec’s `page` default. `drawer`, `modal` and `popover` open the entry’s record in that overlay, but `split` opens nothing, because the timeline hands the split shell no main panel; `new_window` opens the record page in a new tab; `none` opens nothing. `page` opens the record page of the timeline’s `objectName` through the record navigator the host publishes (the console publishes one on its custom pages, record pages and list views); under a host that publishes none, such as an embedded renderer, or on a timeline that names no `objectName`, there is no record page to open and the click opens nothing. `preventNavigation: true` opens nothing whatever the mode, `openNewTab: true` opens the record page in a new tab and outranks every mode except `none`, and `size` sets the overlay width. On a timeline that names no `objectName`, `new_window` and `openNewTab` open no record page either: the new tab’s address is a slash and the entry’s `id` alone (its `_id` when it has no `id`, `undefined` when it has neither). A click handler from a parent view outranks the whole key." + }, + { + "name": "timeline", + "type": "object", + "description": "Timeline configuration, the author face — the same block `ListViewSchema.timeline` declares: { startDateField, endDateField, titleField, groupByField, colorField, scale }. The flat top-level spellings beside it are the runtime handoff, not a second authoring spelling. On entries composed from records, `startDateField` is the entry’s date, `endDateField` the end printed after it, `titleField` the title, `groupByField` the field whose value heads each group (without it, entries group into date buckets), and `colorField` the field whose option colour, or the value itself when it is a colour literal, paints the marker. Each outranks the flat key of the same binding, and `titleField` / `startDateField` outrank `mapping`’s `title` / `date`. `scale` sets the axis unit of the gantt branch, which on this block draws authored `items` only." + }, + { + "name": "limit", + "type": "number", + "description": "Maximum number of records loaded onto the rail (row cap); lowered to the query's top-level `$top` (renderer default 100). A timeline renders one rail with no pagination control, so this is the author's window rather than a page size. A value that is not a positive integer is ignored with a console warning, and the default cap applies." + }, + { + "name": "data", + "type": "array", + "description": "Pre-fetched records — read FIRST as the rail's row source, ahead of the data-scope binding and the fetch, and composed into entries through the same `timeline` field bindings a fetched row takes; authoring it suppresses the object query entirely. Distinct from `items`, which is the already-composed entry shape and wins over this key when both are written." + }, + { + "name": "items", + "type": "array", + "description": "Static inline entries — read ahead of every record source, `data` above included, and bypasses the object query entirely (the renderer becomes a pass-through). Each element is objectui's declared timeline element, `@object-ui/types`'s `TimelineFeedItem` (`variant` absent / `vertical` / `horizontal`) or `TimelineGanttItem` (`variant: 'gantt'`), the arm this node's `variant` selects. They are drawn as written: the `timeline` block’s field bindings, `mapping` and `descriptionField` do not apply to them." + }, + { + "name": "dateFormat", + "type": "enum", + "enum": [ + "short", + "long", + "iso" + ], + "description": "How each entry's date is rendered (renderer default `short`): `short` / `long` are locale-formatted, `iso` is the locale-free machine form." + }, + { + "name": "rowLabel", + "type": "string", + "description": "Header label for the gantt row column — read by the gantt branch only, which on this block needs authored `items`. Without it the header shows the default label." + }, + { + "name": "minDate", + "type": "string", + "description": "Pin the gantt axis start (ISO `yyyy-mm-dd`) instead of deriving it from the rows; only a non-empty value is honoured. A value that is not a date, or a `minDate` after `maxDate`, refuses the chart with a diagnostic naming it." + }, + { + "name": "maxDate", + "type": "string", + "description": "Pin the gantt axis end (ISO `yyyy-mm-dd`) instead of deriving it from the rows; only a non-empty value is honoured. A value that is not a date, or a `maxDate` before `minDate`, refuses the chart with a diagnostic naming it." + }, + { + "name": "descriptionField", + "type": "string", + "description": "Field rendered as each entry's description (renderer default `description`). It is declared flat because the `timeline` block has no member for it, and `mapping.description` outranks it when both are written." + }, + { + "name": "mapping", + "type": "object", + "description": "Record-to-entry field mapping ({ title, date, description, variant }) — the objectui-side binding record read BETWEEN the `timeline` block and the flat fallbacks. Its `variant` member (the field whose value picks each marker colour, renderer default `variant`) is the only spelling that binding has. On the vertical rail a colour that `timeline.colorField` resolves for an entry outranks that marker colour." }, { "name": "dataSource", @@ -866,7 +980,7 @@ { "name": "map", "type": "object", - "description": "latitudeField, longitudeField, titleField" + "description": "The field configuration: `latitudeField` / `longitudeField` (or one `locationField` holding a `\"lat,lng\"` string, a `{ lat, lng }` object or a `[lat, lng]` pair) place each record’s marker, and a record with no readable coordinates is not plotted; `titleField` and `descriptionField` name what the marker popup shows; `zoom` and `center` (`[latitude, longitude]`) set the initial camera, which otherwise fits the markers; `style` is a MapLibre style URL, read after the node’s `mapStyle`." }, { "name": "data", @@ -888,6 +1002,21 @@ "type": "array", "description": "Marker order in `[{ field, order }]` form, ordering the rows the map plots. Lowered to `$orderby` on the same query." }, + { + "name": "mapStyle", + "type": "string", + "description": "MapLibre style URL or spec, overriding the public demo tiles. Read before `map.style`; NOT the base node `style`, which is an inline CSS record" + }, + { + "name": "navigation", + "type": "object", + "description": "What a marker click opens — the `{ mode, size, openNewTab, preventNavigation }` block a list view declares. With the key ABSENT a click opens nothing: this renderer supplies no drawer default. `mode` is an overlay (`drawer`, `modal`, `split`, `popover`), `new_window`, `page` or `none`, and a block written without `mode` takes the spec’s `page` default. `drawer`, `modal` and `popover` open the marker’s record in that overlay, but `split` opens nothing, because the map hands the split shell no main panel; `new_window` opens the record page in a new tab; `none` opens nothing. `page` opens the record page of the map’s `objectName` through the record navigator the host publishes (the console publishes one on its custom pages, record pages and list views); under a host that publishes none, such as an embedded renderer, or on a map that names no `objectName`, there is no record page to open and the click opens nothing. `preventNavigation: true` opens nothing whatever the mode, `openNewTab: true` opens the record page in a new tab and outranks every mode except `none`, and `size` sets the overlay width. A click handler from a parent view outranks the whole key." + }, + { + "name": "enableClustering", + "type": "boolean", + "description": "Group nearby markers into one numbered cluster. Absent, the map clusters only above 100 markers; `false` turns clustering off at any count." + }, { "name": "dataSource", "type": "object", @@ -903,12 +1032,32 @@ { "name": "objectName", "type": "string", - "required": true + "description": "ObjectQL object name. The record source is one of `data`, `staticData` and `objectName`, read in that order: a tree on `data` or `staticData` never queries this object. On a tree whose rows are inline it still names the record page a new-tab click opens." }, { "name": "tree", "type": "object", - "description": "parentField, labelField, fields, defaultExpandedDepth" + "description": "The field configuration: `parentField` names the field holding each record’s parent id (auto-detected from the object’s self-referencing field when omitted), `labelField` the field drawn indented in the first column (default `name`), `fields` the further fields drawn as flat columns after it, and `defaultExpandedDepth` how many levels open on first draw (`0` shows roots only; omitted, every level is open)." + }, + { + "name": "data", + "type": "object", + "description": "A `{ provider, … }` data-source configuration, read FIRST on the record-source ladder: a tree carrying one never reaches `staticData` and never queries `objectName`. `{ provider: 'value', items }` draws those records and `{ provider: 'object', object }` queries that object, both narrowed by `filter`. The `api` and `schema` providers draw no rows on the tree. A bare array is not this key’s shape and is not a record source: the tree falls through to `staticData`, then `objectName`, so inline rows belong under `staticData`." + }, + { + "name": "staticData", + "type": "array", + "description": "Inline records, read SECOND on the record-source ladder: a `data` configuration wins and this key is then never reached, while `objectName` is read AFTER it, so a tree carrying both draws these rows and never queries that object. Each record is placed under the record its `parentField` value names, and one naming no record is drawn as a root. `filter` narrows these rows exactly as it does fetched ones." + }, + { + "name": "filter", + "type": "array", + "description": "Base query filter in the rule-array form `[{ field, operator, value }, ...]`, narrowing the records the tree draws — fetched rows and inline (`staticData`, `{ provider: 'value' }`) rows alike. Context tokens such as `{current_user_id}` are resolved first, then the filter is lowered to `$filter` on the query. A record whose parent the filter removed is drawn as a root. The MongoDB-style record form is not this key’s shape." + }, + { + "name": "navigation", + "type": "object", + "description": "What a row click opens — the `{ mode, size, openNewTab, preventNavigation }` block a list view declares. With the key ABSENT a click opens nothing: this renderer supplies no drawer default. `mode` is an overlay (`drawer`, `modal`, `split`, `popover`), `new_window`, `page` or `none`, and a block written without `mode` takes the spec’s `page` default. `drawer`, `modal` and `popover` open the row’s record in that overlay, and `split` opens it beside the tree; `new_window` opens the record page in a new tab; `none` opens nothing. `page` opens the record page of `data.object` when `data` is the object provider, else of the tree’s `objectName`, through the record navigator the host publishes (the console publishes one on its custom pages, record pages and list views); under a host that publishes none, such as an embedded renderer, or on a tree that names neither (inline rows with no `objectName`), there is no record page to open and the click opens nothing. `preventNavigation: true` opens nothing whatever the mode, `openNewTab: true` opens the record page in a new tab and outranks every mode except `none`, and `size` sets the overlay width. A click handler from a parent view outranks the whole key." } ] },