Skip to content

Commit 0bf85ea

Browse files
chore(objectui): bump the console pin to f8a9d0fb0596 (carries objectui#10221 and the objectui#9910 re-cut) with re-measured pin citations and the lockstep re-record (#20036)
Fixes #20029 Clause-②: no Moves the console pin to objectui `main` `f8a9d0fb0596` (the tip at 2026-09-24T20:41Z). That pin carries objectui#10221 (`0651e7ab4`, a currency amount's decimals come from its currency, never from `scale`), which ruling 乙 on #19910 item 2 requires before PR #19909 lands. It also carries the objectui#9910 re-cut (`5ea623ea`, containment is the declared `children` slot), which #19969 waits on. The PR folds in the #19503 / PR #19832 precedent's two steps: the sdui-parser lockstep re-record, and a re-MEASURE of the `packages/spec/src/**` citations that `check:objectui-pin-citations` names. Every spec edit is to comment or migration-rationale prose only, plus ONE `.describe()` citation re-point (the `FormField.span` pin, under PM ruling `5822830122`, option A). No schema, key, default or export changes. Clause-②: no, because every authored document is accepted and refused exactly as before. ✅ **All 47 pin citations are now green.** The one `.describe()` this PR first stopped on (`view.zod.ts:3392`, `FormField.span`) was re-pointed under PM ruling `5822830122` (option A) on #20029. See "The describe, resolved" below. ## Ancestry reading (fix → new pin: AHEAD) - **REST `compare`: NOT MEASURED.** This session's proxy refuses GitHub API reads on `objectstack-ai/objectui`. `GET /repos/objectstack-ai/objectui/compare/0651e7ab4...f8a9d0fb0` answered "GitHub access to this repository is not enabled for this session". - **In its place, measured by git** in a FULL clone of `objectstack-ai/objectui`, where `git rev-parse --is-shallow-repository` returns `false`. An exit 0 is self-proving, and an exit 1 there is not a shallow-window artefact. | command | exit | reading | |---|---|---| | `git merge-base --is-ancestor 0651e7ab4 f8a9d0fb0596` | 0 | objectui#10221 is IN the new pin | | `git rev-list --count 0651e7ab4..f8a9d0fb0596` | 14 | the new pin is 14 commits AHEAD of the fix (REST would read `ahead`) | | `git merge-base --is-ancestor 5ea623ea f8a9d0fb0596` | 0 | the objectui#9910 re-cut is IN the new pin | | `git merge-base --is-ancestor 5ea623ea 0651e7ab4` | 0 | it is an ancestor of the fix, too | | `git merge-base --is-ancestor 62597c588072 0651e7ab4` | 0 | the old pin is behind the fix (control leg) | | `git merge-base --is-ancestor 5ea623ea 62597c588072` | 1 | the re-cut was NOT in the old pin (full clone, so the exit 1 stands) | | `git rev-list --count 62597c588072..f8a9d0fb0596` | 92 | this hop's size | The bump's own changeset lists both: `(objectui 0651e7ab4)` and `(objectui 5ea623eab)`. ## What moved, and how each artefact was produced | artefact | producer | |---|---| | `.objectui-sha` + `.changeset/console-f8a9d0fb0596.md` | `bash scripts/bump-objectui.sh --no-commit f8a9d0fb0596…` exit 0. It reads 86 releasing changesets and 9 breaking (all 9 annotated, none declared major); `@objectstack/console: minor`. The generator's `adr-0087: TODO` is answered `not-required (no-migration-prescription)`, in the wording of the last bump that carried breaking entries. | | the console | `OBJECTUI_ROOT=../objectui bash scripts/build-console.sh`, through the verify lock, VERDICT command-exit 0 (691 s). The `import/jobs` bundle canary is present. `pnpm check:console-sha` exit 0: "Console dist matches the objectui pin (objectui@f8a9d0fb0596)". | | `sdui.manifest.json` + `scripts/sdui-manifest.record.json` | `node scripts/gen-sdui-manifest-node.mjs` exit 0. It wrote 59 components, sha256 `12dd4f8fbf45`. The diff is +39: the `children` slot input objectui#9910 declared on `alert`, `badge`, `box`, `button`, `card`, `container`, `flex`, `grid` and `stack`. `node scripts/check-sdui-manifest.mjs` exit 0. | | `packages/sdui-parser/objectui-lockstep.json` | `OBJECTUI_ROOT=../objectui pnpm gen:sdui-lockstep` exit 0. The diff is 3+/3-, only `rev`, `revDate` and `recordedAgainstPin`. Grammar blob `0131f27cf86d` is unchanged (214 lines), and all 26 diagnostic codes agree. `pnpm check:sdui-lockstep` exit 0: "byte-identical to objectui@f8a9d0fb0596". No parser port is owed by the lockstep gate. | | `packages/spec/src/migrations/registry.ts` | `pnpm --filter @objectstack/spec gen:migration-registry`, from the six edited entries | ## The #19969 save/render window (measured, not fixed here) In the NEW `sdui.manifest.json`, **5 of 59 components** disagree between `isContainer` (what `packages/sdui-parser/src/validate.ts` still tests) and "declares a `{ name: 'children', type: 'slot' }` input" (what the pinned renderer now decides containment by): | component | `isContainer` | `children` slot | direction | |---|---|---|---| | `badge` | false | true | the save gate warns `not-a-container` on children the renderer renders | | `alert` | false | true | same | | `button` | false | true | same. objectui states it on purpose: "⛔ Not `isContainer`: objectui#6804 ruled that flag means LAYOUT containment" (`button.tsx:97-104`) | | `page:tabs` | true | false | the save gate accepts top-level children that the slot rule does not declare (the children live in `items[].children`) | | `page:accordion` | true | false | same | Non-zero, so #19969 can be sequenced right behind this PR. The predicate is ⛔ not ported here. ## Citation re-measure: method - **Read points.** For each cited objectui file, `git diff --quiet 62597c588072 f8a9d0fb0596 -- FILE`. - An unchanged file holds its anchors by identity. The prose says so and keeps the earlier hops' history. - For a changed file, each cited span was taken at the old pin and searched for byte-for-byte at the new pin. A moved span is re-pointed. A span not found was re-READ in the new tree, and its content change is stated where it is cited. - **Corpus counts** (six migration entries + `registry.ts`). `git grep -o -F TOKEN SHA | wc -l`. The method was calibrated first: at `62597c588` it reproduces every recorded count exactly (8303 files, `objectstack` 13125, `@objectstack/spec` 5043, `timeout` 1086, `RuntimeConfig` 240, `resourceLimits` 2, `useState` 2389, `window` 3526, `period` 170, `interval` 179, `metrics` 324, `TTL` 156, `tenant` 987, `Span` 486, `SpanSchema` 53). - At `f8a9d0fb0`, all 100 dark tokens still count 0: every export of the four cited zod files plus each key name. - Only the corpus size (8512) and the lit controls move. The two new `Span` hits are `colSpan` and the word "Spanish". - `check:future-spec-major`'s measurement exemption to the sentence "controls objectstack 12966 and @objectstack/spec 4997 on the same corpus" is kept verbatim. The new figures follow it as "13347 and 5123 … at this pin", and the gate is exit 0. ## Every `packages/spec/src/**` edit, with its before → after anchor | site | objectui file(s) | reading at `f8a9d0fb0` | |---|---|---| | `api-methods-batch-conformance.test.ts` `sys_api_key` | `ObjectGrid.tsx` (changed +18/-5: objectui#10083 `rowActionsDeclared`, objectui#9909 currency locale), `useBulkExecutor.ts` (identical) | selection block `4024-4051` → `4032-4059`, still hash `c88443302d40`. `298-303` is identical (hash `01083348330f`) | | `functional-completeness.ts` calendar / gantt / timeline / map rows | `ListView.tsx` (changed: objectui#10275 `$select`; objectui#10037 / objectui#10250 self-query filter and search on gantt / tree / chart), `ObjectGantt.tsx` (changed: `$search`), `ObjectCalendar.tsx` / `ObjectTimeline.tsx` / `ObjectMap.tsx` (identical) | no calendar / gantt-date / timeline / map arm touched; prose restated | | 6 migration entries + their 6 `registry.ts` copies | whole corpus | dark tokens 0 at 8512 files; lit controls re-counted (see method) | | `component.zod.ts` / `component.test.ts` tabs + accordion `icon` | `containers.tsx` (changed, `ba0b61a60`: an import line + `page:header`) | `853-859`, `912`, `1069-1075`, `1116` did NOT move, text byte-identical | | `component.zod.ts` / `component.test.ts` button `icon` | `button.tsx` (changed, `5ea623eab`), `resolve-icon.ts` / `lazy-icon.tsx` (identical) | ⚠️ registration inputs CONTENT grew: `85-97` → `85-105` (+ `children` slot input), `defaultProps` `98-102` → `106-110`; still no `icon` input. `:43` / `:72` / `:74` unmoved | | `component.zod.ts` metric `icon` | `ObjectMetricWidget.tsx` (changed, `0651e7ab4`), `index.tsx` / `MetricWidget.tsx` (identical) | destructure `174` → `181`, forward `483` → `528`, text byte-identical | | `component.zod.ts` / `component.test.ts` kanban `limit` ×3, `quickAdd` ×2, `navigation` | `ObjectKanban.tsx` (changed, objectui#10068 `$orderby`), plugin-kanban `index.tsx` (changed), `objectql.ts`, `ElementDataSourceGate.tsx`, `ListView.tsx`, plugin-view `ObjectView.tsx` (all changed); `types.ts`, `element-data-source.ts`, `KanbanImpl.tsx`, `plugin-kanban.mdx` (identical) | ⚠️ query CONTENT gained `$orderby` (`674-679` → `680-690`), mapping gained `sort: true` (`447-450` → `507-511`); moved byte-identical: `:84`→`:85`, `:553`→`:554`, `:559`→`:565`, `:676`→`:687`, `:1210`→`:1225`, `:1218-1219`→`:1233-1234`, `:1468`→`:1483`, `:1484-1497`→`:1499-1512`, `:1563`→`:1578`, `:1587`→`:1602`, `index.tsx:313`→`:363-364`, `objectql.ts:3735`→`:3832`, Gate `316-331`→`373-388`, `192-194`→`200-202`, ListView `2979`→`3067`, `2952`→`3040`, ObjectView `1638`→`1666`, `1579`→`1607`. `onQuickAdd` / `quickAdd` still 0, `onCardClick` still 11 | | `component.zod.ts` calendar `navigation` | `ObjectCalendar.tsx` (identical) | anchors hold by identity | | `component.zod.ts` `object-map` header, `filter`, `sort` | `ObjectMap.tsx`, plugin-map `index.tsx`, `record-source.ts` (identical) | anchors hold by identity | | `component.zod.ts` `object-gantt` header | `ObjectGantt.tsx` (changed +29/-2, objectui#10250) | `:501-503`, `:613` unmoved; the rest moved 21 / 29 lines byte-identical (e.g. `844`→`865`, `1615`→`1644`, `2181`→`2210`, `2144`→`2173`). ⚠️ new undeclared reads `search` / `searchableFields` (`:776-779`, `:880-885`) are recorded, host-generated by `ListView`'s toolbar | | `component.zod.ts` flat `TreeConfig` guidance + `object-tree` header + registry-shell count | `ObjectTree.tsx` (changed +69/-3: objectui#9549, objectui#9136), `ListView.tsx` (changed); `index.tsx`, `record-source.ts` (identical) | ⚠️ two CONTENT changes, restated: the `filter.tree` stash read is DELETED (`getTreeConfig` `235-248` → `246-259`, `tree` `:236` → `:247`), and `filter` gains a second read on the inline `value` provider (`:837`); `ObjectTreeSchema` now declares `filter` (objectui#9549). Moved byte-identical: `582`→`593`, `871/922/985`→`937/988/1051`, `813-814`→`879-880`, `742`→`753`, `908`→`974`, `891`→`957`, `775`→`786`, `741-753`→`752-764`, `751`→`762`, `750`→`761`, `197-218`→`198-219`, ListView `3261-3275`→`3366-3385`, `3270`→`3380`. `ElementDataSourceGate` count re-taken: tree 0, map / gantt / grid / calendar 3 each | | `component.zod.ts` `object-timeline` header + `data` read | `renderer.tsx` (changed, `0b6b295a1`), `ObjectTimeline.tsx` / `index.tsx` (identical) | `1215`→`1240`, `1505`→`1531`, `1442-1457`→`1468-1483`, text byte-identical | | `component.zod.ts` `ComponentPropsMap` comments (map/gantt/tree; timeline) | as above | restated to match the headers | | `dataset.zod.ts` measure `format` | `dataset-format.ts`, `date-display.ts` (both changed, objectui#10026) | `formatDate` `271-306` → `355-390` and `225` → `309` byte-identical; `formatMeasureDate` `229-264` → `229-263` (comment-only change), call `370` → `369`, datetime arm `260-262` → `259-261`; the style handling is unchanged | | `view.zod.ts` view-face `limit` reach (#19228) | 9 files | instrument 1: probe 0; control 14 lines / 7 files (was 13 / 6; the new one is `RelatedList.selectFls-10186.test.tsx:314`, executable ⇒ 9 executable, was 8). Instrument 2: the same four flattening spreads and the same exclusions. Every anchor re-pointed byte-identical (e.g. `ListView.tsx:3084`→`3172`, `4702`→`4815`, `ObjectView.tsx:1725`→`1753`, `2319`→`2347`). Both verdicts stand | | `view.zod.ts` `ListMapConfigSchema` content-asserted anchors | plugin-view `ObjectView.tsx`, `objectql.zod.ts` (changed) | `case 'map':` `1764` → `1792` (17-line block identical), `ObjectMapConfigSchema` `1574` → `1589` (47-line declaration identical), `LIST_VIEW_LOCAL_OVERRIDES` `734` → `741` (list identical, still no `map`). `--verify-anchors` passes all content assertions | | `view.zod.ts` `FormField.span` DOCBLOCK | `form.tsx` (changed, `5ea623eab`: registration inputs only), `autoLayout.ts` (identical) | `spanLadderFor` `:204-231` is byte-identical, so it still emits the ladder | ## The describe, resolved (PM ruling `5822830122`, option A) The ruling widened the file surface by exactly three items, all landed in one new commit (`90f9a30`): | file | what | |---|---| | `packages/spec/src/ui/view.zod.ts` | the `FormField.span` `.describe()` citation, `.objectui-sha` = `62597c588` → `.objectui-sha` = `f8a9d0fb0596`; nothing else in the sentence changes. The claim was re-read true at the new pin: `plugin-form`'s `autoLayout.ts` is byte-identical, and `form.tsx`'s `spanLadderFor` `:204-231` is byte-identical | | `content/docs/references/ui/view.mdx` | regenerated by `pnpm --filter @objectstack/spec gen:schema && pnpm --filter @objectstack/spec gen:docs` (VERDICT command-exit 0): the two `span` rows only (+2/-2). **No other generated file moved** | | `.changeset/20029-pin-bump-describe-correction.md` | `'@objectstack/spec': patch`, stating the describe correction, in the shape of `17429-` / `19503-pin-bump-describe-corrections.md` | ## Gates `node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commands` on head `90f9a30` derives 124 families (the `view.mdx` edit adds the docs families). `--ran` reads: "124 derived famil(ies) accounted for — 121 run, 3 NOT-MEASURED". - **All run families exit 0**, among them: `pnpm --filter @objectstack/spec run check:objectui-pin-citations` ("47 … match .objectui-sha"), `pnpm check:sdui-lockstep`, `pnpm check:console-sha`, `node scripts/check-sdui-manifest.mjs`, `pnpm --filter @objectstack/spec run check:generated`, `check:docs`, `check:objectui-changeset`, `check:future-spec-major` and `check:migration-registry`. - Five docs families first read exit 3 (unbuilt `@objectstack/lint` / `formula` / `client-react`). After `turbo run build` of those closures they read exit 0: `check:doc-formula-expressions`, `check:doc-security-posture`, `check:skill-examples`, `check:docs-transcript-drift`, `check:lean-entry-closure`. - **NOT MEASURED, exit 3 (PREREQUISITE NOT MET), left to CI:** `check-plugin-teardown-shape --self-test` (shallow clone); `check:dual-build-cjs-loads` and `check:type-check-debt` (both need a full workspace build). This diff changes no code in any package those read. - **Tests:** `@objectstack/spec` vitest on `component.test.ts`, `api-methods-batch-conformance.test.ts`, `src/migrations`, `functional-completeness`, `src/ui/view*` and `src/ui/dataset*`: 26 files, 1666 / 1666 pass (head `530fc4d`); re-run on `src/ui/view*` at head `90f9a30`: 19 files, 1085 / 1085 pass. Changed lines: **884** (+600 / -284, 20 files), under the 5000 threshold. ## Acceptance notes - **Stale metric test anchors, out of the gate's population.** `component.test.ts`'s metric `icon` test body still cites `index.tsx:204`, `ObjectMetricWidget.tsx:142` / `:474` and `MetricWidget.tsx:312-321`. It carries no pin citation, so it is outside the gate's population. Those anchors were already stale before this hop: the docblock beside them reads `:237`, `:181` / `:528` and `:351-360`. Left as they are, because the gate does not name them. - **`object-kanban` reads `sort` now** (objectui#10068, via `ElementDataSourceGate` from the binding's `dataSource.sort`). The node schema declares no `sort`. The key reaches the board from the binding, not from the authored node, so this is not an authoring gap. Recorded, not acted on. - **The branch name is `claude/issue-20029-objectui-pin-bump`**, as the claim names. The console changeset is the script's own `console-f8a9d0fb0596.md` (the precedent's spelling), not a hand-named `20029-*.md`. ## 维护者速读(草稿) - **改了什么**:把控制台钉住的 objectui 版本从 `62597c588` 推进到 `f8a9d0fb0`(objectui main 当时的最新提交),其中包含货币小数位修复 objectui#10221(`0651e7ab4`)和容器判定改用 `children` 插槽的 objectui#9910(`5ea623ea`)。同时按先例重新生成 SDUI 清单、重录 sdui-parser 对齐记录,并在新版本上逐条重新核对 spec 里引用 objectui 代码行号的注释(47 处中 46 处已改)。 - **为什么改**:裁决乙要求 objectui#10221 先进入发布的控制台,PR #19909 才能落地;同一次推进也是 #19969 在等的前提。 - **风险与代价(含回滚)**:spec 只改注释和迁移说明文字,外加按 PM 裁决 `5822830122`(选项 A)把 `FormField.span` describe 里引用的钉住版本改为新版本(附 spec patch changeset,重新生成 `view.mdx`);不改任何 schema、键、默认值或导出,已写的元数据接受/拒绝结果完全不变。控制台行为随 objectui 这 92 个提交变化(其中 9 条标注 breaking,都是 objectui 自身的类型面)。清单里有 5 个组件的 `isContainer` 与 `children` 插槽不一致(badge、alert、button、page:tabs、page:accordion),这是 #19969 要补的保存/渲染窗口。回滚:还原本 PR 即可。 - **席位意见**: - **你要做的**:describe 已按裁决 A 处理,门禁全部跑绿(3 项需完整构建的留给 CI)。落地前还需要一次同档合约审查。 Dev session: `session_01BMUTTbeXStLRWxU9zEWDJq` (PM seat `domain:devx#1`, `session_01VDtqoecgES7ScQYGbFVDRv`). 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_01BMUTTbeXStLRWxU9zEWDJq --- _Generated by [Claude Code](https://claude.ai/code/session_01BMUTTbeXStLRWxU9zEWDJq)_ --------- Co-authored-by: Claude <noreply@anthropic.com>
1 parent 2274894 commit 0bf85ea

20 files changed

Lines changed: 600 additions & 284 deletions
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
---
2+
'@objectstack/spec': patch
3+
---
4+
5+
One published `describe` sentence that dates itself to the `.objectui-sha` pin is re-pointed to the pin this release builds against, objectui `f8a9d0fb0596`, after being re-read there (#20029).
6+
7+
`Clause-②: no`
8+
9+
- `FormField.span`: the `'auto'` clause says that at the pin this repo builds against, only textarea, markdown, html, richtext and repeater resolve to the full column count. It named `62597c588`. Re-read at `f8a9d0fb0596`, the claim still holds: `plugin-form`'s `autoLayout.ts` (`WIDE_FIELD_TYPES`, `resolveColSpan`) is byte-identical, and `form.tsx` changed only in its registration's input list (a `children` slot input), with `spanLadderFor` byte-identical, so `'full'` is still the whole row at every multi-column tier. Only the pin the sentence names moves.
10+
11+
No key, default, enum member or export moves: the same authored metadata is accepted and refused as before, and `content/docs/references/ui/view.mdx` is regenerated from the sentence.

‎.changeset/console-f8a9d0fb0596.md‎

Lines changed: 122 additions & 0 deletions
Large diffs are not rendered by default.

‎.objectui-sha‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
62597c588072636e9c30ea35b3d89b1e46fd765d
1+
f8a9d0fb0596f4521076628e2bbfe27e6ce67d52

‎content/docs/references/ui/view.mdx‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -199,7 +199,7 @@ Column footer summary configuration
199199
| **required** | `boolean` | optional | Required override |
200200
| **hidden** | `boolean` | optional | Hidden override |
201201
| **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. |
202-
| **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` = `62597c588`), 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. |
202+
| **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` = `f8a9d0fb0596`), 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. |
203203
| **widget** | `string` | optional | Custom widget/component name (overrides type-based inference) |
204204
| **language** | `string` | optional | Code editor language (for type=code) |
205205
| **keyField** | `{ field?: string; label?: string \| Record<string, string>; placeholder?: string \| Record<string, string>; helpText?: string \| Record<string, string>; … }` | optional | Key column config for record-typed fields |
@@ -364,7 +364,7 @@ View filter rule
364364
| **required** | `boolean` | optional | Required override |
365365
| **hidden** | `boolean` | optional | Hidden override |
366366
| **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. |
367-
| **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` = `62597c588`), 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. |
367+
| **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` = `f8a9d0fb0596`), 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. |
368368
| **widget** | `string` | optional | Custom widget/component name (overrides type-based inference) |
369369
| **language** | `string` | optional | Code editor language (for type=code) |
370370
| **keyField** | `{ field?: string; label?: string \| Record<string, string>; placeholder?: string \| Record<string, string>; helpText?: string \| Record<string, string>; … }` | optional | Key column config for record-typed fields |

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@
66
],
77
"objectui": {
88
"repo": "https://github.com/objectstack-ai/objectui.git",
9-
"rev": "62597c588072636e9c30ea35b3d89b1e46fd765d",
10-
"revDate": "2026-09-23T02:43:52+00:00",
9+
"rev": "f8a9d0fb0596f4521076628e2bbfe27e6ce67d52",
10+
"revDate": "2026-09-24T20:41:09+00:00",
1111
"source": "packages/sdui-parser/src",
1212
"files": [
1313
"packages/sdui-parser/src/body-dialect.ts",
@@ -22,7 +22,7 @@
2222
"packages/sdui-parser/src/validate.ts"
2323
]
2424
},
25-
"recordedAgainstPin": "62597c588072636e9c30ea35b3d89b1e46fd765d",
25+
"recordedAgainstPin": "f8a9d0fb0596f4521076628e2bbfe27e6ce67d52",
2626
"grammarRegion": {
2727
"file": "packages/sdui-parser/src/parse.ts",
2828
"delimiter": "/* ---------------------- the JS literal subset (#6614) ---------------------- */",

‎packages/spec/src/data/api-methods-batch-conformance.test.ts‎

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -61,17 +61,22 @@ const SINGLE_RECORD_WRITE_ONLY: Record<string, string> = {
6161
// `revoked` on ONE key. The multi-select surface this rule protects does not
6262
// exist for API keys, and the shape a future one would take does not need
6363
// `bulk` either — both read off the console build this release pins
64-
// (`.objectui-sha` = `62597c588`, `packages/plugin-grid`; re-measured at
65-
// that pin, 2026-09-23 — previously measured at `87af769e9`, `53ded82bf`,
66-
// `a472b0716`, `00d3f09c5`, `67dadd602`, before that at `d8ec8d6d4`,
67-
// `9602dc820`, `190fbd01d`, `9a3daf8d3`, originally at `6314e87f2`.
68-
// `ObjectGrid.tsx` changed again across the move off `87af769e9` (119
69-
// insertions, 9 deletions), and THIS time the selection block's CONTENT
64+
// (`.objectui-sha` = `f8a9d0fb0`, `packages/plugin-grid`; re-measured at
65+
// that pin, 2026-09-24 — previously measured at `62597c588`, `87af769e9`,
66+
// `53ded82bf`, `a472b0716`, `00d3f09c5`, `67dadd602`, before that at
67+
// `d8ec8d6d4`, `9602dc820`, `190fbd01d`, `9a3daf8d3`, originally at
68+
// `6314e87f2`. On the hop off `62597c588`, `ObjectGrid.tsx` changed again
69+
// (18 insertions, 5 deletions: objectui#10083's `rowActionsDeclared` row-menu
70+
// signal and objectui#9909's currency display locale), none of it inside the
71+
// selection block, which only MOVED: `ObjectGrid.tsx:4032-4059` here, still
72+
// hashing to `c88443302d40c2db739ddb235470bafa29056e2e`, re-READ with the
73+
// same reading below. `ObjectGrid.tsx` changed across the move off
74+
// `87af769e9` too (119 insertions, 9 deletions), and THAT time the selection block's CONTENT
7075
// moved, not only its position: objectui#10218 (`62597c588` itself)
7176
// rewrote the `selection` arm to "presence enables; an explicit off wins",
7277
// so an authored `selection` object with no `type` now selects
7378
// (`DEFAULT_SELECTION_TYPE`, `'multiple'`) where it used to fall through.
74-
// The block is `ObjectGrid.tsx:4024-4051` here — `3940-3955` at `87af769e9`,
79+
// The block was `ObjectGrid.tsx:4024-4051` at `62597c588` — `3940-3955` at `87af769e9`,
7580
// `3538-3553` at `53ded82bf` — and no longer hashes to the
7681
// `6133933199230670e29d8c7f51c558d86a0af1d2` the previous three hops
7782
// recorded (`c88443302d40c2db739ddb235470bafa29056e2e` now). Re-READ, the
@@ -86,7 +91,7 @@ const SINGLE_RECORD_WRITE_ONLY: Record<string, string> = {
8691
// numbers — arithmetic on a wrong anchor produces a fresh-looking span still
8792
// describing the wrong function. The second claim,
8893
// `hooks/useBulkExecutor.ts:298-303`, sits in a file that is byte-identical
89-
// to `87af769e9` on this hop (it last changed on the hop off `53ded82bf`, 36
94+
// to `62597c588` and to `87af769e9` on the last two hops (it last changed on the hop off `53ded82bf`, 36
9095
// insertions, 22 deletions, when it was re-READ rather than carried on file
9196
// identity): the six lines hash to
9297
// `01083348330f10a201cdf1078b4c21c236402b6a` at every one of those pins and

‎packages/spec/src/kernel/functional-completeness.ts‎

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -283,16 +283,23 @@ export function checkFieldCompleteness(def: unknown): CompletenessFinding[] {
283283
* English sentence. So the loss is total rather than partial — every
284284
* record, on every object — and the author is told at render time as well
285285
* as here. Both reads hold at the pin this repo builds against
286-
* (`.objectui-sha` = `62597c588`, re-read 2026-09-23: `ListView.tsx` is
287-
* byte-identical to `87af769e9`, and `ObjectCalendar.tsx` changed there only
288-
* in its copy), so this describes the console this repo SHIPS and not only
286+
* (`.objectui-sha` = `f8a9d0fb0`, re-read 2026-09-24: `ObjectCalendar.tsx`
287+
* is byte-identical to `62597c588`, where it had changed only in its copy;
288+
* `ListView.tsx` changed on this hop — objectui#10275's `$select` and the
289+
* self-querying `gantt` / `tree` / `chart` filter and search of
290+
* objectui#10037 / objectui#10250 — with its `case 'calendar'` arm
291+
* untouched), so this describes the console this repo SHIPS and not only
289292
* objectui's head.
290293
* This repo already records the same deletion one door over: the #13817
291294
* check in `../ui/view.zod.ts` names objectui#7029 as its runtime half.
292295
* - `gantt` → NO fallback, and no silence [#19630]. Measured at the pin
293-
* this repo builds against (`.objectui-sha` = `62597c588`; `ListView.tsx`
294-
* and `ObjectGantt.tsx` are byte-identical to `87af769e9`, where this was
295-
* first measured, re-checked 2026-09-23). ① `ListView.tsx`'s
296+
* this repo builds against (`.objectui-sha` = `f8a9d0fb0`, re-read
297+
* 2026-09-24; first measured at `87af769e9`, and both files were
298+
* byte-identical to it at `62597c588`). On this hop `ListView.tsx`'s
299+
* `case 'gantt'` gained the EFFECTIVE `filter` and the toolbar `search` /
300+
* `searchableFields` (objectui#10037, objectui#10250) and `ObjectGantt.tsx`
301+
* sends them as `$search` / `$searchFields`; neither touches the date
302+
* bindings or the config gate read below. ① `ListView.tsx`'s
296303
* `case 'gantt'` spreads `startDateField` / `endDateField` / `titleField`
297304
* only when the view DECLARED them — the `'start_date'` / `'end_date'`
298305
* floors were deleted by objectui#7070, and the `'progress'` /
@@ -305,7 +312,8 @@ export function checkFieldCompleteness(def: unknown): CompletenessFinding[] {
305312
* requires. So the view does not draw a blank chart: it refuses, by name.
306313
* - `timeline` → date axis: NO fallback [#19630]; title: `titleField || 'name'`,
307314
* which still stands. Measured at the same pin (`.objectui-sha` =
308-
* `62597c588`; `ObjectTimeline.tsx` is byte-identical to `87af769e9` too).
315+
* `f8a9d0fb0`; `ObjectTimeline.tsx` is byte-identical to `87af769e9` and
316+
* `62597c588` too, and `ListView.tsx`'s `case 'timeline'` did not move).
309317
* ① `ListView.tsx`'s `case 'timeline'` resolves the axis
310318
* through `resolveTimelineDateBinding` and spreads it only when one was
311319
* declared — the `startDateField || 'created_at'` floor was deleted by
@@ -321,9 +329,11 @@ export function checkFieldCompleteness(def: unknown): CompletenessFinding[] {
321329
* block does render; the warning still fires there, because the block the
322330
* view TYPE names is the one that is missing. Unchanged by this row.
323331
* - `map` → NO fallback, and no silence [#19630]. Measured at the same
324-
* pin (`.objectui-sha` = `62597c588`; `ObjectMap.tsx` changed on the hop
325-
* from `87af769e9` only in a docblock and a dev-warning string, objectui
326-
* `2252653d0`, and every read named below re-reads unchanged), both faces
332+
* pin (`.objectui-sha` = `f8a9d0fb0`; `ObjectMap.tsx` is byte-identical to
333+
* `62597c588`, and changed on the hop before that, from `87af769e9`, only
334+
* in a docblock and a dev-warning string, objectui `2252653d0`;
335+
* `ListView.tsx`'s `case 'map'` did not move, and every read named below
336+
* re-reads unchanged), both faces
327337
* moved together in
328338
* objectui#8169. ① `ListView.tsx`'s `case 'map'` forwards
329339
* `resolveListMapConfig(schema)` and carries no `locationField || 'location'`

‎packages/spec/src/migrations/entries/semantic/18.kernel-health-check-and-hot-reload-durations-unit-in-key.ts‎

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -45,12 +45,13 @@ export const entry: SemanticMigration = {
4545
+ 'the audience that does not parse. Measured on 884e8347d: the only in-repo readers are '
4646
+ 'packages/core/src/health-monitor.ts and packages/core/src/hot-reload.ts, both moved in '
4747
+ 'this same change; and the pinned objectui checkout — the pin this repo builds '
48-
+ 'against, `.objectui-sha` = `62597c588072636e9c30ea35b3d89b1e46fd765d` — names '
48+
+ 'against, `.objectui-sha` = `f8a9d0fb0596f4521076628e2bbfe27e6ce67d52` — names '
4949
+ 'neither def and neither key: all thirteen exports of plugin-lifecycle-advanced.zod.ts and '
50-
+ 'the string debounceDelay each occur 0 times across its 8303 tracked files, against lit '
50+
+ 'the string debounceDelay each occur 0 times across its 8512 tracked files (0 across the '
51+
+ '8303 at 62597c588 too), against lit '
5152
+ 'controls objectstack 12966 and @objectstack/spec 4997 on the same corpus at 87af769e9, '
52-
+ 'which re-count at this pin to 13125 and 5043 respectively (git grep -o -F, the method '
53-
+ 'that reproduces every earlier count).',
53+
+ 'which re-count to 13125 and 5043 respectively at 62597c588 and to 13347 and 5123 at '
54+
+ 'this pin (git grep -o -F, the method that reproduces every earlier count).',
5455
acceptanceCriteria:
5556
'Every producer and reader of a PluginHealthCheck spells intervalMs and timeoutMs, and every '
5657
+ 'one of a HotReloadConfig spells debounceDelayMs — concretely '

‎packages/spec/src/migrations/entries/semantic/18.kernel-runtime-config-timeout-unit-in-key.ts‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,10 +42,10 @@ export const entry: SemanticMigration = {
4242
+ 'spells timeout 0 times; outside the zod file and its test the only live occurrences are the '
4343
+ 'generated rows in content/docs/references/kernel/plugin-security-advanced.mdx, which this '
4444
+ 'rename regenerates. The pinned objectui checkout — this is the pin we build against, '
45-
+ '`.objectui-sha` = `62597c588072636e9c30ea35b3d89b1e46fd765d`, re-read from this tree — '
45+
+ '`.objectui-sha` = `f8a9d0fb0596f4521076628e2bbfe27e6ce67d52`, re-read from this tree — '
4646
+ 'spells resourceLimits.timeout 0 times across '
47-
+ '8303 tracked files, against lit controls timeout 1086, RuntimeConfig 240 and resourceLimits '
48-
+ '2 on the same corpus; both resourceLimits hits are prose in packages/app-shell recording '
47+
+ '8512 tracked files, against lit controls timeout 1096, RuntimeConfig 245 and resourceLimits '
48+
+ '2 on the same corpus (0 across 8303, and 1086 / 240 / 2, at 62597c588); both resourceLimits hits are prose in packages/app-shell recording '
4949
+ 'that objectui\'s own AppShellRuntimeConfig shares not one key with the spec\'s '
5050
+ 'RuntimeConfig, so nothing there authors this key and no pin bump is owed. #15939, #15678, '
5151
+ '#14478, ADR-0087.',

‎packages/spec/src/migrations/entries/semantic/18.logging-durations-unit-in-key.ts‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,10 +45,10 @@ export const entry: SemanticMigration = {
4545
+ 'no in-repo runtime reads any of the four — outside `packages/spec/src/system/logging.zod.ts` '
4646
+ 'and its test the only occurrences are the generated rows in '
4747
+ '`content/docs/references/system/logging.mdx`, which this rename regenerates; and the pinned '
48-
+ 'objectui checkout — `.objectui-sha` = `62597c588072636e9c30ea35b3d89b1e46fd765d` — spells '
48+
+ 'objectui checkout — `.objectui-sha` = `f8a9d0fb0596f4521076628e2bbfe27e6ce67d52` — spells '
4949
+ '`flushInterval` 0 times, `initialDelay` 0, `HttpDestinationConfig` 0 and `LoggingConfig` 0 '
50-
+ 'across its 8303 tracked files, against lit controls `useState` 2389 and `timeout` 1086 on '
51-
+ 'the same corpus.',
50+
+ 'across its 8512 tracked files, against lit controls `useState` 2391 and `timeout` 1096 on '
51+
+ 'the same corpus (all four 0 across 8303, against 2389 and 1086, at 62597c588).',
5252
acceptanceCriteria:
5353
'Every HTTP log destination spells `batch.flushIntervalMs`, `retry.initialDelayMs` and '
5454
+ '`timeoutMs`, and every logging buffer spells `buffer.flushIntervalMs`; authoring any of the '

0 commit comments

Comments
 (0)