From d61897e450c33db26ff6ba799fef9cca9783caa2 Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 12 Oct 2026 03:00:08 +0000 Subject: [PATCH 1/4] feat(plugin-security,platform-objects): grant forms pick a position or permission set by name from the catalog (#15204 B2) The user page's related-list add pickers listed sys_position / sys_permission_set rows, which a deployment need not hold (ADR-0131 D3/D4). Removed; New opens the grant form, whose name field declares widget position-ref / permission-ref. The legacy permission_set_id lookup is hidden from the forms. Remove is the host's row delete, measured independent of add. Co-Authored-By: Claude Claude-Session: https://claude.ai/code/session_013XKtmoR5QCUSTMjiQ3os49 --- .changeset/15204-grant-name-pickers.md | 11 ++++ ...at.server-ready-dev-admin-audience.test.ts | 8 ++- packages/cli/src/utils/format.ts | 2 +- ...user-permission-set-window-columns.test.ts | 28 ++++++++- .../src/pages/sys-user.page.ts | 60 ++++++------------- .../objects/sys-user-permission-set.object.ts | 8 +++ .../src/objects/sys-user-position.object.ts | 4 ++ .../test/grant-name-pickers.dogfood.test.ts | 59 ++++++++++++++++++ 8 files changed, 130 insertions(+), 50 deletions(-) create mode 100644 .changeset/15204-grant-name-pickers.md create mode 100644 packages/qa/dogfood/test/grant-name-pickers.dogfood.test.ts diff --git a/.changeset/15204-grant-name-pickers.md b/.changeset/15204-grant-name-pickers.md new file mode 100644 index 00000000000..85567ff1aa7 --- /dev/null +++ b/.changeset/15204-grant-name-pickers.md @@ -0,0 +1,11 @@ +--- +'@objectstack/platform-objects': patch +'@objectstack/plugin-security': patch +--- + +Setup's user page grants a position or a permission set by picking its name from the security catalog (ADR-0131 D4) + +Clause-②: no + +- `@objectstack/plugin-security`: `sys_user_position.position` declares `widget: 'position-ref'` and `sys_user_permission_set.permission_set` declares `widget: 'permission-ref'`, so the grant form offers a picker over the positions and permission sets the catalog serves, and stores the chosen name. A console without those widgets keeps the text input. `sys_user_permission_set.permission_set_id`, the legacy id that grants nothing, is now `hidden` and no longer appears on the grant form; the column stays until a later release drops its data. +- `@objectstack/platform-objects`: the user page's Positions and Permission Sets lists no longer carry the "Assign position" / "Grant permission set" buttons. Those buttons listed `sys_position` / `sys_permission_set` rows, which a deployment need not hold. Grant with the list's **New**, which opens the grant form; removing a grant is unchanged. diff --git a/packages/cli/src/utils/format.server-ready-dev-admin-audience.test.ts b/packages/cli/src/utils/format.server-ready-dev-admin-audience.test.ts index bcf8605ab36..5a7661ab1c3 100644 --- a/packages/cli/src/utils/format.server-ready-dev-admin-audience.test.ts +++ b/packages/cli/src/utils/format.server-ready-dev-admin-audience.test.ts @@ -174,10 +174,12 @@ describe('#17081 — the claim and the route are the platform\'s own declaration }); it('"grant it a permission set" is a surface the sys_user page really offers', () => { + // [#15204 B2] The grant is the Permission Sets list's "New" (the host's + // create on `sys_user_permission_set`), so the pin is that list, by title. const page = JSON.stringify(SysUserDetailPage); - expect(page).toContain('sys_user_permission_set'); - expect(page).toContain('Grant permission set'); + expect(page).toContain('"objectName":"sys_user_permission_set"'); + expect(page).toContain('"en":"Permission Sets"'); // Fabricated control: the same haystack does not answer to an invented name. - expect(page).not.toContain('Grant fabricated permission set'); + expect(page).not.toContain('"objectName":"sys_user_fabricated_grant"'); }); }); diff --git a/packages/cli/src/utils/format.ts b/packages/cli/src/utils/format.ts index 60b6aa464bb..701619ac642 100644 --- a/packages/cli/src/utils/format.ts +++ b/packages/cli/src/utils/format.ts @@ -1136,7 +1136,7 @@ export function printServerReady(opts: ServerReadyOptions) { // `Setup → Users` is `SETUP_APP` (`requiredPermissions: // ['setup.access']`, which this account holds) → the `nav_users` // contribution (`sys_user`, ungated), whose detail page carries the - // "Grant permission set" related list. Pinned against those + // "Permission Sets" related list (its New grants a set). Pinned against those // declarations in `format.server-ready-dev-admin-audience.test.ts`, so // a rename there cannot leave this sentence pointing at nothing. // • It changes no seed. What the first run CREATES is a product-shape diff --git a/packages/platform-objects/src/pages/sys-user-permission-set-window-columns.test.ts b/packages/platform-objects/src/pages/sys-user-permission-set-window-columns.test.ts index bc1515a063c..af2ac9350f6 100644 --- a/packages/platform-objects/src/pages/sys-user-permission-set-window-columns.test.ts +++ b/packages/platform-objects/src/pages/sys-user-permission-set-window-columns.test.ts @@ -47,10 +47,32 @@ describe('sys_user page — the permission-set assignments list', () => { expect(columns).toEqual(expect.arrayContaining(['permission_set', 'valid_from', 'valid_until'])); }); - it('[ADR-0131 D4] the Add picker writes the set BY NAME, and the list never shows the legacy id', () => { + it('[ADR-0131 D4] the list never shows the legacy id', () => { const list = lists[0] as any; - expect(list.add.linkField).toBe('permission_set'); - expect(list.add.picker.valueField).toBe('name'); expect(list.columns).not.toContain('permission_set_id'); }); }); + +/** + * [#15204 B2] Neither grant list carries an `add` picker. Such a picker lists + * object ROWS, and positions and permission sets live in the security catalog, + * so it would offer nothing on a database that holds no such row. "New" opens + * the grant form, whose name field picks from the catalog (`widget: + * 'position-ref'` / `'permission-ref'` on the objects); Remove is the host's + * row delete, which does not depend on `add` (measured on #15204, 6116275825). + */ +describe('sys_user page — the grant lists have no row-object add picker', () => { + for (const objectName of ['sys_user_position', 'sys_user_permission_set']) { + it(`${objectName}: one related list, and no \`add\``, () => { + const found = relatedListsOf(SysUserDetailPage, objectName); + expect(found).toHaveLength(1); + expect(found[0]).not.toHaveProperty('add'); + }); + } + + it('control: the business-unit list keeps its add picker (an object-row binding)', () => { + const found = relatedListsOf(SysUserDetailPage, 'sys_business_unit_member'); + expect(found).toHaveLength(1); + expect(found[0]).toHaveProperty('add'); + }); +}); diff --git a/packages/platform-objects/src/pages/sys-user.page.ts b/packages/platform-objects/src/pages/sys-user.page.ts index e0c8966cf8a..2f11030404f 100644 --- a/packages/platform-objects/src/pages/sys-user.page.ts +++ b/packages/platform-objects/src/pages/sys-user.page.ts @@ -189,11 +189,14 @@ export const SysUserDetailPage: Page = { icon: 'shield-check', children: [ { - // [ADR-0090 D3] Position assignments (岗位分派) — pure SDUI: - // the Add picker creates sys_user_position rows storing the - // position's MACHINE NAME (valueField: 'name'), and every - // server-side rule (the D12 delegated-admin gate, audience- - // anchor rejection) surfaces its error in the dialog. + // [ADR-0090 D3] Position assignments (岗位分派) — pure SDUI. + // [ADR-0131 D4, #15204 B2] No `add` picker: it could list + // `sys_position` ROWS only, and positions live in the security + // catalog. "New" opens the assignment form, whose `position` + // field picks a catalog position by name (`widget: + // 'position-ref'` on the object); Remove is the host's row + // delete. Every server-side rule (the D12 delegated-admin gate, + // audience-anchor rejection) surfaces its error in the form. type: 'record:related_list', properties: { objectName: 'sys_user_position', @@ -203,20 +206,6 @@ export const SysUserDetailPage: Page = { limit: 25, showViewAll: true, title: { en: 'Positions', 'zh-CN': '岗位', 'ja-JP': 'ポジション', 'es-ES': 'Puestos' }, - add: { - picker: { - object: 'sys_position', - valueField: 'name', - labelField: 'label', - }, - linkField: 'position', - label: { - en: 'Assign position', - 'zh-CN': '分配岗位', - 'ja-JP': 'ポジションを割り当て', - 'es-ES': 'Asignar puesto', - }, - }, }, }, ], @@ -224,21 +213,20 @@ export const SysUserDetailPage: Page = { { // [ADR-0091 D1] Direct permission-set grants (直接授权) — pure SDUI. // The list keys on `relationshipField: 'user_id'` (a lookup keyed by - // record id, no relationshipValueField). [ADR-0131 D4] A grant names - // its set BY NAME, so the Add picker stores the set's MACHINE NAME - // (valueField: 'name', linkField: 'permission_set'), exactly as the - // position picker above does; server-side gates (the catalog name - // refusal, delegated-admin D12) surface their reason in the dialog. - // The picker still lists `sys_permission_set` rows: the related - // list's Add picker reads object records only, and listing the - // security catalog itself is an objectui change. + // record id, no relationshipValueField). [ADR-0131 D4, #15204 B2] A + // grant names its set BY NAME, and the set lives in the security + // catalog, not in a `sys_permission_set` row, so there is no `add` + // picker (it could list object rows only). "New" opens the grant + // form, whose `permission_set` field picks a catalog set by name + // (`widget: 'permission-ref'` on the object); Remove is the host's + // row delete. Server-side gates (the catalog name refusal, + // delegated-admin D12) surface their reason in the form. // // [ADR-0091 D1/D2] `valid_from` / `valid_until` are listed because // they decide whether the grant confers anything: the resolver drops // an assignment outside its half-open window at every evaluation, so // a row showing only the set would read as a live grant when it is - // not. The Add affordance writes the two link keys alone; the window - // is set by editing the assignment row, whose object refuses a + // not. The same form sets the window, and the object refuses a // window whose end is not after its start. label: { en: 'Permission Sets', 'zh-CN': '权限集', 'ja-JP': '権限セット', 'es-ES': 'Conjuntos de permisos' }, icon: 'lock', @@ -253,20 +241,6 @@ export const SysUserDetailPage: Page = { limit: 25, showViewAll: true, title: { en: 'Permission Sets', 'zh-CN': '权限集', 'ja-JP': '権限セット', 'es-ES': 'Conjuntos de permisos' }, - add: { - picker: { - object: 'sys_permission_set', - valueField: 'name', - labelField: 'label', - }, - linkField: 'permission_set', - label: { - en: 'Grant permission set', - 'zh-CN': '授予权限集', - 'ja-JP': '権限セットを付与', - 'es-ES': 'Otorgar conjunto de permisos', - }, - }, }, }, ], diff --git a/packages/plugins/plugin-security/src/objects/sys-user-permission-set.object.ts b/packages/plugins/plugin-security/src/objects/sys-user-permission-set.object.ts index 82e475c5544..f39648826c5 100644 --- a/packages/plugins/plugin-security/src/objects/sys-user-permission-set.object.ts +++ b/packages/plugins/plugin-security/src/objects/sys-user-permission-set.object.ts @@ -81,6 +81,10 @@ export const SysUserPermissionSet = ObjectSchema.create({ permission_set_id: Field.lookup('sys_permission_set', { label: 'Permission Set (legacy id)', required: false, + // [#15204 B2] Off the forms: it grants nothing, so an editable lookup + // beside `permission_set` only invites a meaningless value. The column + // stays until its data is dropped (ADR-0131 D10). + hidden: true, description: '[ADR-0131 D10] Legacy id reference to a sys_permission_set row, dropped with its data by a later stage. ' + 'Not written and not read to grant anything: the grant names its set by permission_set.', @@ -100,6 +104,10 @@ export const SysUserPermissionSet = ObjectSchema.create({ label: 'Permission Set', required: true, maxLength: 100, + // [ADR-0131 D4, #15204 B2] Picked, not typed: the form lists the sets + // the security catalog serves and stores the chosen NAME. Falls back to + // a text input where the widget is not registered. + widget: 'permission-ref', description: '[ADR-0131 D4] Machine name of the permission set this grant holds, as the security catalog names it. ' + 'A name the catalog does not hold is refused. NULL only on a grant written before the column existed.', diff --git a/packages/plugins/plugin-security/src/objects/sys-user-position.object.ts b/packages/plugins/plugin-security/src/objects/sys-user-position.object.ts index 9df5977a917..ab2b0c0380a 100644 --- a/packages/plugins/plugin-security/src/objects/sys-user-position.object.ts +++ b/packages/plugins/plugin-security/src/objects/sys-user-position.object.ts @@ -85,6 +85,10 @@ export const SysUserPosition = ObjectSchema.create({ label: 'Position', required: true, maxLength: 100, + // [ADR-0131 D4, #15204 B2] Picked, not typed: the form lists the + // positions the security catalog serves and stores the chosen NAME. + // Falls back to a text input where the widget is not registered. + widget: 'position-ref', description: 'Position machine name (references sys_position.name).', }), diff --git a/packages/qa/dogfood/test/grant-name-pickers.dogfood.test.ts b/packages/qa/dogfood/test/grant-name-pickers.dogfood.test.ts new file mode 100644 index 00000000000..6ed8f35b952 --- /dev/null +++ b/packages/qa/dogfood/test/grant-name-pickers.dogfood.test.ts @@ -0,0 +1,59 @@ +// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license. + +/** + * [#15204 B2, ADR-0131 D4] The two grant forms pick their name from the + * security catalog, as SERVED. + * + * A grant names its position / permission set, and the catalog (not a + * `sys_position` / `sys_permission_set` row) is where those names live. The + * user page's related-list `add` pickers could list object rows only, so they + * are gone; "New" opens the grant form, and the form's name field carries a + * widget hint the console resolves to a catalog picker (`field:position-ref` + * lists `GET /meta/position`, `field:permission-ref` lists + * `GET /meta/permission`). The legacy `permission_set_id` lookup grants + * nothing and is hidden from the forms (maintainer ruling, 2026-10-12). + * + * Read from `GET /meta/object/` on a booted showcase: what the console + * actually receives, not the source declaration, so the pin fails if the spec + * strips the hint or a later layer drops it. + */ + +import { describe, it, expect, beforeAll, afterAll } from 'vitest'; +import { type VerifyStack } from '@objectstack/verify'; +import { bootShowcase } from './showcase-boot.js'; + +type ServedField = { widget?: unknown; hidden?: unknown; type?: unknown }; + +describe('[#15204 B2] grant forms pick names from the catalog', () => { + let stack: VerifyStack; + const served: Record> = {}; + + beforeAll(async () => { + stack = await bootShowcase({}); + const token = await stack.signIn(); + for (const object of ['sys_user_position', 'sys_user_permission_set']) { + const res = await stack.apiAs(token, 'GET', `/meta/object/${object}`); + expect(res.status, `GET /meta/object/${object}`).toBe(200); + const body = (await res.json()) as { item?: { fields?: Record } }; + served[object] = body.item?.fields ?? {}; + } + }, 240_000); + + afterAll(async () => { + await stack?.stop?.(); + }); + + it('sys_user_position.position is served with the position picker hint', () => { + expect(served.sys_user_position?.position?.widget).toBe('position-ref'); + }); + + it('sys_user_permission_set.permission_set is served with the permission picker hint', () => { + expect(served.sys_user_permission_set?.permission_set?.widget).toBe('permission-ref'); + }); + + it('permission_set_id is served hidden, and the name field it sits beside is not', () => { + expect(served.sys_user_permission_set?.permission_set_id?.hidden).toBe(true); + // Control: the read is not answering `hidden` for every field. + expect(served.sys_user_permission_set?.permission_set?.hidden).not.toBe(true); + }); +}); From d4c22c8fe30cd2cf0e81ba4a65b12896be03b1c1 Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 12 Oct 2026 04:01:13 +0000 Subject: [PATCH 2/4] test(cli): the platform pages' inline locale-map floor is 44 after the grant lists' add labels left (#15204 B2) Co-Authored-By: Claude Claude-Session: https://claude.ai/code/session_013XKtmoR5QCUSTMjiQ3os49 --- packages/cli/test/platform-page-i18n-parity.test.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/cli/test/platform-page-i18n-parity.test.ts b/packages/cli/test/platform-page-i18n-parity.test.ts index 5afc100a2e1..e68d60346aa 100644 --- a/packages/cli/test/platform-page-i18n-parity.test.ts +++ b/packages/cli/test/platform-page-i18n-parity.test.ts @@ -838,8 +838,9 @@ describe('shipped platform record pages -- i18n ownership (#14817)', () => { const maps = RECORD_PAGES.flatMap((page) => inlineLocaleMaps(page, page.name)); // Same refusal as the population floor: zero maps means the walk broke, not - // that the pages went monolingual. - expect(maps.length).toBeGreaterThanOrEqual(45); + // that the pages went monolingual. [#15204 B2] 44: the user page's two + // grant lists dropped their `add` pickers, and with them two label maps. + expect(maps.length).toBeGreaterThanOrEqual(44); const incomplete = maps .filter((m) => SHIPPED_LOCALES.some((locale) => !m.locales.includes(locale))) From e486abb9c8776eab0bd3c54cb3d9a7750c330282 Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 12 Oct 2026 04:01:14 +0000 Subject: [PATCH 3/4] chore(objectui): move the console pin to 088e0f705520 (objectui#12175, PR-5: position-ref / permission-ref), and re-measure the spec's pin citations Co-Authored-By: Claude Claude-Session: https://claude.ai/code/session_013XKtmoR5QCUSTMjiQ3os49 --- .changeset/console-088e0f705520.md | 44 +++++ .../objectui-pin-citations-088e0f705520.md | 18 ++ .objectui-sha | 2 +- content/docs/references/ui/view.mdx | 4 +- packages/sdui-parser/objectui-lockstep.json | 6 +- .../api-methods-batch-conformance.test.ts | 15 +- .../src/kernel/functional-completeness.ts | 18 +- ...ck-and-hot-reload-durations-unit-in-key.ts | 6 +- ...rnel-runtime-config-timeout-unit-in-key.ts | 6 +- .../18.logging-durations-unit-in-key.ts | 5 +- ...tem-metrics-jsdoc-durations-unit-in-key.ts | 6 +- ...ing-otel-exporter-durations-unit-in-key.ts | 8 +- .../18.tenant-schema-cache-ttl-unit-in-key.ts | 4 +- .../src/ui/action-outcome-messages.test.ts | 3 + packages/spec/src/ui/action.zod.ts | 3 + packages/spec/src/ui/component.test.ts | 30 +++- packages/spec/src/ui/component.zod.ts | 155 +++++++++++++++--- packages/spec/src/ui/dataset.zod.ts | 3 + packages/spec/src/ui/view.zod.ts | 15 +- scripts/sdui-manifest.record.json | 8 +- sdui.manifest.json | 2 +- 21 files changed, 290 insertions(+), 71 deletions(-) create mode 100644 .changeset/console-088e0f705520.md create mode 100644 .changeset/objectui-pin-citations-088e0f705520.md diff --git a/.changeset/console-088e0f705520.md b/.changeset/console-088e0f705520.md new file mode 100644 index 00000000000..ea1aca0aaa7 --- /dev/null +++ b/.changeset/console-088e0f705520.md @@ -0,0 +1,44 @@ +--- +"@objectstack/console": minor +--- + +Console (objectui) refreshed to `088e0f705520`. Frontend changes in this range: + +Derived from the changesets objectui declared over the range — 24 releasing of 26 changesets added across 27 non-merge commits; omitted: 2 release-nothing changesets, 1 commit carrying no changeset (they ship no package code). + +- **minor** — A record-form field can name one item of a metadata registry by its machine name: a `text` field that declares `widget: 'position-ref'` lists the position registry, and one that d… (objectui `088e0f705`) +- **minor** — **BREAKING** — Studio and the metadata admin read a metadata type's overlay flag under its new name, `allowEnvironmentOverlay`, and the read-only banners name `OS_METADATA_WRITABLE` (objectui#12… (objectui `e5311165a`) +- **minor** — The marketplace package page's **Update** button opens an update dialog, and a package README's raw HTML is no longer printed as text (objectui#12146). (objectui `82bb1d584`) +- **minor** — **BREAKING** — A form field declares `step` and `className` on both faces, so the strict authoring face stops telling authors to remove two keys that work. A built-in form branch now joins an en… (objectui `d2500d8be`) +- **minor** — "Clone to customize" on a packaged permission set calls the server's clone door (objectui#7611, objectstack ADR-0126 §7.1). (objectui `6d5879fe9`) +- **minor** — **A dashboard or a list view the server refuses you, opened by its URL, now says it was refused** (objectui#12112, the console half of objectstack#22611's ruling A). (objectui `43e150518`) +- **minor** — Setup's "Assigned users" on a permission set writes a new grant by the set's name alone (objectui#7611, after objectstack#22863, ADR-0131 stage 6b-2-pre). (objectui `faf4ce952`) +- **minor** — **BREAKING** — A form field declares `avatarField`, the record field each candidate of the search picker draws its avatar from, on both faces, so the strict authoring face stops telling authors… (objectui `c0c2f792b`) +- **minor** — A `position` decision output lists the position registry and commits position names (objectui#7611, objectstack ADR-0131 D3/D4). (objectui `8cc7158b4`) +- **minor** — The capability select lists the capability registry, and the permission-set editor's provenance badge reads the layered envelope (objectui#7611, objectstack ADR-0131 D3/D7). (objectui `53ee2f854`) +- **minor** — **BREAKING** — A form field declares the rest of the field metadata its widget reads off the `fields[]` entry, on both faces, so the strict authoring face stops telling authors to remove keys th… (objectui `0665c3be7`) +- **minor** — Screen readers hear the names of more controls in the viewer's language (objectui#12145). (objectui `e723f58ee`) +- **minor** — The suggested-bindings panel shows each suggestion's real state and can revoke an acceptance (objectui#7611, after objectstack#22854). (objectui `f962cdc09`) +- **minor** — The record feed and a related list's Add existing and fallback remove read the affordance-to-grant map, so a caller without the grant is no longer offered a write the server then… (objectui `158c75d90`) +- **minor** — A paged table's first, previous, next and last page buttons have accessible names (objectui#12124). (objectui `dc6d28e86`) +- **patch** — A position approver is read through the spec's registry binding, `{ source: 'registry', type }` (objectstack#22710): its readable label and its designer picker come from the posit… (objectui `83b9fade2`) +- **patch** — A rich-text field no longer draws hint lines above its editor (objectui#12110, ruled B). The `markdown`, `html` and `richtext` editors used to show "Format: markdown" (or "Format:… (objectui `2498a0753`) +- **patch** — The Studio app's root now opens the app's first navigation entry, like every other app's root, and `StudioHomePage`, Studio's old metadata overview, is retired (objectui#12113). (objectui `ed12d48ec`) +- **patch** — A form field's own `defaultValue` is no longer drawn in its control, so the form never shows a value it does not save (objectui#12155). (objectui `f3d540814`) +- **patch** — A grouped grid's own first, previous, next and last page buttons have accessible names (objectui#12143). (objectui `2381c07f3`) +- **patch** — Console rendering fixes from the HotCRM browser pass (objectui#12110): (objectui `5330038f4`) +- **patch** — The record page's discussion shows stored replies under their comment, and every comment offers the reply input where the caller may post one (objectui#12144). (objectui `a7d492011`) +- **patch** — A record activity feed shows an object's `activityMilestones` rows of type `completed`, such as "Case resolved", instead of hiding them as completed tasks (objectui#12106). (objectui `1d1cfe0c1`) +- **patch** — A record-source refusal (`RECORD_SOURCE_REQUIRED`, raised by every arm that requires a record source) now reports the same path every time (objectui#5250). (objectui `9b7550999`) + +⚠️ 4 of these carry a breaking change: 4 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 1 commit in this range with no `.changeset/*.md`. The code is inside the pin above and ships here, but nothing upstream declared it, so it appears 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)_ feat(scripts): the JSON-fence gate reads the published READMEs (objectui#12131, phase 2) (#12139) (objectui `ce9811c96`) + +Clause-②: no + + + +objectui range: `4997995022f8...088e0f705520` diff --git a/.changeset/objectui-pin-citations-088e0f705520.md b/.changeset/objectui-pin-citations-088e0f705520.md new file mode 100644 index 00000000000..35dd82b627f --- /dev/null +++ b/.changeset/objectui-pin-citations-088e0f705520.md @@ -0,0 +1,18 @@ +--- +'@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 `088e0f705520`. + +Clause-②: no + +Every anchor was mapped through the objectui diff `4997995022f8..088e0f705520`: 325 paths over 27 commits. Four files a record cites changed on the hop, and every cited line in them moved or held with its text byte-identical: + +- `ObjectGrid.tsx` (+27/-11: objectui#12143's grouped-pager button names and objectui#12110 item 1's column-label override): the bulk-selection block moved by +16 and still hashes to `c88443302d40`; the `keyboardNavigation`, `inlineEditable` and grid empty-state reads moved by +6 or +16. +- `data-table.tsx` (+12/-1: objectui#12124's pager button names): the five arrow-key anchors moved by +7. +- `record-related-list.tsx` (+22/-3: objectui#12082, the fallback remove reads the affordance-to-grant map): the five `requiredPermissions` gate anchors moved by +17. +- `form.tsx` (+231/-79: objectui#12130, objectui#12155, objectui#12110 and objectui#7611 PR-5): `spanLadderFor` moved by +1 and its call site by +71, both unchanged, so `FormField.span: 'full'` still takes the whole row at every multi-column tier. + +The records that cite only byte-identical files gain a hop sentence that says so. The six migration entries' corpus counts were re-taken with `git grep -o -F`, the method that reproduces every `4997995022f8` number. The corpus is now 8519 tracked files, and every retired name each entry counts still reads 0. The lit controls moved with the corpus, for example `objectstack` from 18271 to 18400 and `timeout` from 1704 to 1706. + +No key, default, enum member or export moves. diff --git a/.objectui-sha b/.objectui-sha index 97325989491..51356616906 100644 --- a/.objectui-sha +++ b/.objectui-sha @@ -1 +1 @@ -4997995022f8e65946f6362b7434685539cc72b7 +088e0f705520e82bee1d65a5fa3c1f7a26672dde diff --git a/content/docs/references/ui/view.mdx b/content/docs/references/ui/view.mdx index 11812a8b1a2..b76fc2ea119 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` = `4997995022f8`), 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` = `088e0f705520`), 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` = `4997995022f8`), 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` = `088e0f705520`), 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 9ff6726ea5b..e023aa1fbec 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": "4997995022f8e65946f6362b7434685539cc72b7", - "revDate": "2026-10-11T10:56:33+00:00", + "rev": "088e0f705520e82bee1d65a5fa3c1f7a26672dde", + "revDate": "2026-10-12T03:19:24+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": "4997995022f8e65946f6362b7434685539cc72b7", + "recordedAgainstPin": "088e0f705520e82bee1d65a5fa3c1f7a26672dde", "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 05043cc6ba0..429cb628bef 100644 --- a/packages/spec/src/data/api-methods-batch-conformance.test.ts +++ b/packages/spec/src/data/api-methods-batch-conformance.test.ts @@ -61,7 +61,20 @@ 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` = `499799502`, re-read there 2026-10-11: + // (`.objectui-sha` = `088e0f705`, re-read there 2026-10-12: + // in `packages/plugin-grid`, on the hop off `499799502`, `ObjectGrid.tsx` + // changed again (27 insertions, 11 deletions: objectui#12143's grouped-pager + // button names and objectui#12110 item 1's column-label override), none of it + // inside the selection block, which only MOVED by +16: `ObjectGrid.tsx:4997-5024` + // here (`4981-5008` at `499799502`), still hashing to + // `c88443302d40c2db739ddb235470bafa29056e2e` (hash-object of the block), + // re-READ with the same reading below; neither hunk touches the bulk defs or + // their verdicts, so the `delete` verdict line MOVED `:1787` -> `:1793` and the + // promoted def's params `:5165-5184` -> `:5181-5200` (called at `:5200` -> + // `:5216`), each byte-identical. `hooks/useBulkExecutor.ts` is byte-identical + // to `499799502` and its `:298-303` still hashes to + // `01083348330f10a201cdf1078b4c21c236402b6a`. At `499799502`, re-read there + // 2026-10-11: // in `packages/plugin-grid`, on the hop off `0df67f237`, `ObjectGrid.tsx` // changed again (89 insertions, 44 deletions: objectui#12081 item 3's // whole-set footer and objectui#12082 leg A), none of it inside the diff --git a/packages/spec/src/kernel/functional-completeness.ts b/packages/spec/src/kernel/functional-completeness.ts index b9d740f225c..64853f67e5e 100644 --- a/packages/spec/src/kernel/functional-completeness.ts +++ b/packages/spec/src/kernel/functional-completeness.ts @@ -298,7 +298,10 @@ 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` = `499799502`, re-read there 2026-10-11: + * (`.objectui-sha` = `088e0f705`, re-read there 2026-10-12: + * every objectui file this record cites is byte-identical across the hop from + * `499799502` (`git diff --quiet`), so every anchor held unmoved. At + * `499799502`, re-read there 2026-10-11: * on the hop off `0df67f237` `ObjectCalendar.tsx` and `ListView.tsx` are * byte-identical (`git diff --quiet`), so `getCalendarConfig` `:311`, the * `if (!calendarConfig)` arm `:1354` with its `tt(…)` lines `:1361-1362` and @@ -425,7 +428,10 @@ 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` = `499799502`, re-read there 2026-10-11: + * this repo builds against (`.objectui-sha` = `088e0f705`, re-read there 2026-10-12: + * every objectui file this record cites is byte-identical across the hop from + * `499799502` (`git diff --quiet`), so every anchor held unmoved. At + * `499799502`, re-read there 2026-10-11: * on the hop off `0df67f237` `ObjectGantt.tsx` changed (+27/-4, * objectui#12082, objectui `752504520`: the chart's in-chart writes read the * affordance-to-grant map), none of it in `getGanttConfig` or the refusal arm, @@ -524,6 +530,9 @@ 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` = + * `088e0f705`, re-read there 2026-10-12: + * every objectui file this record cites is byte-identical across the hop from + * `499799502` (`git diff --quiet`), so every anchor held unmoved. At * `499799502`, re-read there 2026-10-11: * every objectui file this record cites is byte-identical across the hop from * `0df67f237` (`git diff --quiet`), so every anchor held unmoved. At @@ -620,7 +629,10 @@ 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` = `499799502`, re-read there 2026-10-11: + * pin (`.objectui-sha` = `088e0f705`, re-read there 2026-10-12: + * every objectui file this record cites is byte-identical across the hop from + * `499799502` (`git diff --quiet`), so every anchor held unmoved. At + * `499799502`, re-read there 2026-10-11: * every objectui file this record cites is byte-identical across the hop from * `0df67f237` (`git diff --quiet`), so every anchor held unmoved. At * `0df67f237`, re-read there 2026-10-11: 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 a84ca1a448c..2d14b05ba62 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` = `4997995022f8e65946f6362b7434685539cc72b7` — names ' + + 'against, `.objectui-sha` = `088e0f705520e82bee1d65a5fa3c1f7a26672dde` — 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 8441 tracked files (0 across the 8424 at 0df67f237, the 8351 at 20c6d351a, the 8281 at 47b1f0bb7, the 8234 at f0268ad78, the 7754 at a58626c88, the 7650 at 0abd4f9f8, the 7632 at 9dfaca654, the 7579 at 2e818d0b5, the 10267 at ab1879721, the 10071 at 89cad75d5, the 9912 at 31971ff1e, the 9800 at e420df310, the 9546 at db11afd49, the 9283 at dd3f7e1be, the ' + + 'the string debounceDelay each occur 0 times across its 8519 tracked files (0 across the 8441 at 499799502, the 8424 at 0df67f237, the 8351 at 20c6d351a, the 8281 at 47b1f0bb7, the 8234 at f0268ad78, the 7754 at a58626c88, the 7650 at 0abd4f9f8, the 7632 at 9dfaca654, the 7579 at 2e818d0b5, the 10267 at ab1879721, the 10071 at 89cad75d5, 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, to 15691 and 6206 at 31971ff1e, to 16044 and 6461 at 89cad75d5, to 16377 and 6665 at ab1879721, to 17227 and 7134 at 2e818d0b5, to 17313 and 7186 at 9dfaca654, to 17390 and 7209 at 0abd4f9f8, to 17468 and 7246 at a58626c88, to 17956 and 7522 at f0268ad78, to 17980 and 7523 at 47b1f0bb7, to 18047 and 7545 at 20c6d351a, to 18248 and 7582 at 0df67f237 and to 18271 and 7587 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, to 16044 and 6461 at 89cad75d5, to 16377 and 6665 at ab1879721, to 17227 and 7134 at 2e818d0b5, to 17313 and 7186 at 9dfaca654, to 17390 and 7209 at 0abd4f9f8, to 17468 and 7246 at a58626c88, to 17956 and 7522 at f0268ad78, to 17980 and 7523 at 47b1f0bb7, to 18047 and 7545 at 20c6d351a, to 18248 and 7582 at 0df67f237, to 18271 and 7587 at 499799502 and to 18400 and 7603 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 d3729356a49..eccf7973b0e 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,8 @@ 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` = `4997995022f8e65946f6362b7434685539cc72b7`, re-read from this tree — ' - + 'spells resourceLimits.timeout 0 times across ' - + '8441 tracked files, against lit controls timeout 1704, RuntimeConfig 352 and resourceLimits ' - + '2 on the same corpus (0 across 8424, and 1705 / 347 / 2, at 0df67f237; 0 across 8351, and 1694 / 337 / 2, at 20c6d351a; 0 across 8281, and 1674 / 337 / 2, at 47b1f0bb7; 0 across 8234, and 1658 / 337 / 2, at f0268ad78; 0 across 7754, and 1431 / 299 / 2, at a58626c88; 0 across 7650, and 1360 / 293 / 2, at 0abd4f9f8; 0 across 7632, and 1360 / 293 / 2, at 9dfaca654; 0 across 7579, and 1351 / 276 / 2, at 2e818d0b5; 0 across 10267, and 1348 / 273 / 2, at ab1879721; 0 across 10071, and 1331 / 273 / 2, at 89cad75d5; 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 ' + + '`.objectui-sha` = `088e0f705520e82bee1d65a5fa3c1f7a26672dde`, re-read from this tree — ' + + 'spells resourceLimits.timeout 0 times across 8519 tracked files, against lit controls timeout 1706, RuntimeConfig 357 and resourceLimits 2 on the same corpus (0 across 8441, and 1704 / 352 / 2, at 499799502; 0 across 8424, and 1705 / 347 / 2, at 0df67f237; 0 across 8351, and 1694 / 337 / 2, at 20c6d351a; 0 across 8281, and 1674 / 337 / 2, at 47b1f0bb7; 0 across 8234, and 1658 / 337 / 2, at f0268ad78; 0 across 7754, and 1431 / 299 / 2, at a58626c88; 0 across 7650, and 1360 / 293 / 2, at 0abd4f9f8; 0 across 7632, and 1360 / 293 / 2, at 9dfaca654; 0 across 7579, and 1351 / 276 / 2, at 2e818d0b5; 0 across 10267, and 1348 / 273 / 2, at ab1879721; 0 across 10071, and 1331 / 273 / 2, at 89cad75d5; 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 9f6fd13981e..4edac8221dc 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,9 @@ 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` = `4997995022f8e65946f6362b7434685539cc72b7` — spells ' + + 'objectui checkout — `.objectui-sha` = `088e0f705520e82bee1d65a5fa3c1f7a26672dde` — spells ' + '`flushInterval` 0 times, `initialDelay` 0, `HttpDestinationConfig` 0 and `LoggingConfig` 0 ' - + 'across its 8441 tracked files, against lit controls `useState` 2648 and `timeout` 1704 on ' - + 'the same corpus (all four 0 across 8424, against 2645 and 1705, at 0df67f237, 0 across 8351, against 2630 and 1694, at 20c6d351a, 0 across 8281, against 2630 and 1674, at 47b1f0bb7, 0 across 8234, against 2622 and 1658, at f0268ad78, 0 across 7754, against 2491 and 1431, at a58626c88, 0 across 7650, against 2478 and 1360, at 0abd4f9f8, 0 across 7632, against 2477 and 1360, at 9dfaca654, 0 across 7579, against 2477 and 1351, at 2e818d0b5, 0 across 10267, against 2476 and 1348, at ab1879721, 0 across 10071, against 2470 and 1331, at 89cad75d5, 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, ' + + 'across its 8519 tracked files, against lit controls `useState` 2661 and `timeout` 1706 on the same corpus (all four 0 across 8441, against 2648 and 1704, at 499799502, 0 across 8424, against 2645 and 1705, at 0df67f237, 0 across 8351, against 2630 and 1694, at 20c6d351a, 0 across 8281, against 2630 and 1674, at 47b1f0bb7, 0 across 8234, against 2622 and 1658, at f0268ad78, 0 across 7754, against 2491 and 1431, at a58626c88, 0 across 7650, against 2478 and 1360, at 0abd4f9f8, 0 across 7632, against 2477 and 1360, at 9dfaca654, 0 across 7579, against 2477 and 1351, at 2e818d0b5, 0 across 10267, against 2476 and 1348, at ab1879721, 0 across 10071, against 2470 and 1331, at 89cad75d5, 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 5c7b5f1613a..1051220eb39 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,8 @@ 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` = `4997995022f8e65946f6362b7434685539cc72b7`, re-read from this tree — ' - + 'spells all six metrics def names and both distinctive keys 0 times across 8441 tracked ' - + 'files at that sha, against lit controls window 4604, timeout 1704, period 251, ' - + 'interval 238 and metrics 456 on that same corpus and sha (0 across 8424, against 4596 / ' + + '`.objectui-sha` = `088e0f705520e82bee1d65a5fa3c1f7a26672dde`, re-read from this tree — ' + + 'spells all six metrics def names and both distinctive keys 0 times across 8519 tracked files at that sha, against lit controls window 4615, timeout 1706, period 251, interval 238 and metrics 456 on that same corpus and sha (0 across 8441, against 4604 / 1704 / 251 / 238 / 456, at 499799502, 0 across 8424, against 4596 / ' + '1705 / 251 / 233 / 456, at 0df67f237, 0 across 8351, against 4470 / ' + '1694 / 249 / 213 / 456, at 20c6d351a, 0 across 8281, against 4449 / ' + '1674 / 249 / 213 / 455, at 47b1f0bb7, 0 across 8234, against 4430 / ' 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 319dc12f085..7c0d6b452a1 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,10 @@ 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` = `4997995022f8e65946f6362b7434685539cc72b7` — names none of it: all 37 exports of ' - + 'tracing.zod.ts and each of the four key names occur 0 times across the 8441 files ' - + 'tracked at that sha (the 517 Span and 57 SpanSchema hits are objectui\'s own HTML ' + + 'pinned objectui checkout — `.objectui-sha` = `088e0f705520e82bee1d65a5fa3c1f7a26672dde` — names none of it: all 37 exports of ' + + 'tracing.zod.ts and each of the four key names occur 0 times across the 8519 files tracked at that sha (the 519 Span and 57 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: 18271 hits for the bare token objectstack, ' - + 'and 7587 for the package specifier @objectstack/spec (at 0df67f237: 0 across 8424, Span 517, ' + + 'two lit controls on that same corpus and sha: 18400 hits for the bare token objectstack, and 7603 for the package specifier @objectstack/spec (at 499799502: 0 across 8441, Span 517, 18271 and 7587; at 0df67f237: 0 across 8424, Span 517, ' + '18248 and 7582; at 20c6d351a: 0 across 8351, Span 517, ' + '18047 and 7545; at 47b1f0bb7: 0 across 8281, Span 517, ' + '17980 and 7523; at f0268ad78: 0 across 8234, Span 517, ' 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 1bc6e935bae..878695c9752 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,7 @@ 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` = `4997995022f8e65946f6362b7434685539cc72b7` — spells it 0 ' - + 'times across 8441 tracked files, against lit controls `TTL` 184 and `tenant` 1362 on the ' - + 'same corpus (0 across 8424, against 184 and 1357, at 0df67f237; 0 across 8351, against 184 and 1340, at 20c6d351a; 0 across 8281, against 184 and 1338, at 47b1f0bb7; 0 across 8234, against 184 and 1338, at f0268ad78; 0 across 7754, against 184 and 1319, at a58626c88; 0 across 7650, against 182 and 1318, at 0abd4f9f8; 0 across 7632, against 182 and 1318, at 9dfaca654; 0 across 7579, against 182 and 1317, at 2e818d0b5; 0 across 10267, against 180 and 1238, at ab1879721; 0 across 10071, against 181 and 1237, at 89cad75d5; 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 ' + + 'objectui checkout — `.objectui-sha` = `088e0f705520e82bee1d65a5fa3c1f7a26672dde` — spells it 0 times across 8519 tracked files, against lit controls `TTL` 184 and `tenant` 1365 on the same corpus (0 across 8441, against 184 and 1362, at 499799502; 0 across 8424, against 184 and 1357, at 0df67f237; 0 across 8351, against 184 and 1340, at 20c6d351a; 0 across 8281, against 184 and 1338, at 47b1f0bb7; 0 across 8234, against 184 and 1338, at f0268ad78; 0 across 7754, against 184 and 1319, at a58626c88; 0 across 7650, against 182 and 1318, at 0abd4f9f8; 0 across 7632, against 182 and 1318, at 9dfaca654; 0 across 7579, against 182 and 1317, at 2e818d0b5; 0 across 10267, against 180 and 1238, at ab1879721; 0 across 10071, against 181 and 1237, at 89cad75d5; 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/action-outcome-messages.test.ts b/packages/spec/src/ui/action-outcome-messages.test.ts index 8d020f59c83..3ec9c2a512f 100644 --- a/packages/spec/src/ui/action-outcome-messages.test.ts +++ b/packages/spec/src/ui/action-outcome-messages.test.ts @@ -12,6 +12,9 @@ * runner default) and the `${result.*}` INTERPOLATION are the console's — the * reader is objectstack-ai/objectui#11344, a later link of the same ruling, * carried from the pin this repo builds against (`.objectui-sha` = + * `088e0f705`, re-read there 2026-10-12: + * every objectui file this record cites is byte-identical across the hop from + * `499799502` (`git diff --quiet`), so every anchor held unmoved. At * `499799502`, re-read there 2026-10-11: * every objectui file this record cites is byte-identical across the hop from * `0df67f237` (`git diff --quiet`), so every anchor held unmoved. At diff --git a/packages/spec/src/ui/action.zod.ts b/packages/spec/src/ui/action.zod.ts index 6ed83465a72..ea13b386485 100644 --- a/packages/spec/src/ui/action.zod.ts +++ b/packages/spec/src/ui/action.zod.ts @@ -1364,6 +1364,9 @@ const actionObject = () => strictObject({ * * Liveness: the ledger row was `planned` until the console reader landed, * and it is `live` from the pin this repo builds against (`.objectui-sha` = + * `088e0f705`, re-read there 2026-10-12: + * every objectui file this record cites is byte-identical across the hop from + * `499799502` (`git diff --quiet`), so every anchor held unmoved. At * `499799502`, re-read there 2026-10-11: * every objectui file this record cites is byte-identical across the hop from * `0df67f237` (`git diff --quiet`), so every anchor held unmoved. At diff --git a/packages/spec/src/ui/component.test.ts b/packages/spec/src/ui/component.test.ts index 4b3a11fdcd9..251be6929d5 100644 --- a/packages/spec/src/ui/component.test.ts +++ b/packages/spec/src/ui/component.test.ts @@ -288,7 +288,10 @@ describe('PageAccordionProps variant — declared because the accordion renderer // same file's `ComponentRegistry.register('accordion', …)` publishes the key to // the Studio block designer at `:1222` (the `items` input, documented as // `[{ label, icon?, collapsed?, children }]`). Measured at the pin this repo -// builds against — `.objectui-sha` = `499799502`, re-read there 2026-10-11: +// builds against — `.objectui-sha` = `088e0f705`, re-read there 2026-10-12: +// every objectui file this record cites is byte-identical across the hop from +// `499799502` (`git diff --quiet`), so every anchor held unmoved. At +// `499799502`, re-read there 2026-10-11: // every objectui file this record cites is byte-identical across the hop from // `0df67f237` (`git diff --quiet`), so every anchor held unmoved. At // `0df67f237`, re-read there 2026-10-11: @@ -457,7 +460,10 @@ describe('PageTabsProps items[].value / items[].count — declared because the t // same file's `ComponentRegistry.register('tabs', …)` publishes the key to the // Studio block designer at `:1007` (the `items` input, documented as // `[{ label, value?, icon?, count?, visibleWhen?, children }]`). Measured at -// the pin this repo builds against — `.objectui-sha` = `499799502`, re-read there 2026-10-11: +// the pin this repo builds against — `.objectui-sha` = `088e0f705`, re-read there 2026-10-12: +// every objectui file this record cites is byte-identical across the hop from +// `499799502` (`git diff --quiet`), so every anchor held unmoved. At +// `499799502`, re-read there 2026-10-11: // every objectui file this record cites is byte-identical across the hop from // `0df67f237` (`git diff --quiet`), so every anchor held unmoved. At // `0df67f237`, re-read there 2026-10-11: @@ -3499,7 +3505,10 @@ describe('object-* block props schemas — declared, so the props gate has a sch // #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` = `499799502`, re-read there 2026-10-11: +// against (`.objectui-sha` = `088e0f705`, re-read there 2026-10-12: +// every objectui file this record cites is byte-identical across the hop from +// `499799502` (`git diff --quiet`), so every anchor held unmoved. At +// `499799502`, re-read there 2026-10-11: // every objectui file this record cites is byte-identical across the hop from // `0df67f237` (`git diff --quiet`), so every anchor held unmoved. At // `0df67f237`, re-read there 2026-10-11: @@ -3713,7 +3722,10 @@ 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` = `499799502`, re-read there 2026-10-11: +// against (`.objectui-sha` = `088e0f705`, re-read there 2026-10-12: +// every objectui file this record cites is byte-identical across the hop from +// `499799502` (`git diff --quiet`), so every anchor held unmoved. At +// `499799502`, re-read there 2026-10-11: // every objectui file this record cites is byte-identical across the hop from // `0df67f237` (`git diff --quiet`), so every anchor held unmoved. At // `0df67f237`, re-read there 2026-10-11: @@ -3916,7 +3928,10 @@ describe('ObjectKanbanPropsSchema quickAdd is retired', () => { // #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` = `499799502`, re-read there 2026-10-11: +// `.objectui-sha` = `088e0f705`, re-read there 2026-10-12: +// every objectui file this record cites is byte-identical across the hop from +// `499799502` (`git diff --quiet`), so every anchor held unmoved. At +// `499799502`, re-read there 2026-10-11: // every objectui file this record cites is byte-identical across the hop from // `0df67f237` (`git diff --quiet`), so every anchor held unmoved. At // `0df67f237`, re-read there 2026-10-11: @@ -4102,7 +4117,10 @@ describe('ObjectMetricPropsSchema icon liveness', () => { // // 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` = `499799502`, re-read there 2026-10-11: +// (`.objectui-sha` = `088e0f705`, re-read there 2026-10-12: +// every objectui file this record cites is byte-identical across the hop from +// `499799502` (`git diff --quiet`), so every anchor held unmoved. At +// `499799502`, re-read there 2026-10-11: // `ObjectTree.tsx`, `ObjectMap.tsx` and `record-source.ts` are byte-identical // across the hop from `0df67f237` (`git diff --quiet`), so every anchor in them // held unmoved; `ObjectGantt.tsx` +27/-4 changed for objectui#12082 (objectui diff --git a/packages/spec/src/ui/component.zod.ts b/packages/spec/src/ui/component.zod.ts index c0d62b35a80..3d1dadadcc5 100644 --- a/packages/spec/src/ui/component.zod.ts +++ b/packages/spec/src/ui/component.zod.ts @@ -840,7 +840,10 @@ export const PageTabsProps = strictObject({ * false candidate a component over). * * The key is LIVE at the objectui pin this repo builds against - * (`.objectui-sha` = `499799502`, re-read there 2026-10-11: + * (`.objectui-sha` = `088e0f705`, re-read there 2026-10-12: + * every objectui file this record cites is byte-identical across the hop from + * `499799502` (`git diff --quiet`), so every anchor held unmoved. At + * `499799502`, re-read there 2026-10-11: * every objectui file this record cites is byte-identical across the hop from * `0df67f237` (`git diff --quiet`), so every anchor held unmoved. At * `0df67f237`, re-read there 2026-10-11: @@ -1083,7 +1086,16 @@ export const PageCardProps = strictObject({ * declarations identical. * * Each clause is read off the objectui pin this repo builds against - * (`.objectui-sha` = `4997995022f8`, re-read there 2026-10-11: + * (`.objectui-sha` = `088e0f705520`, re-read there 2026-10-12: + * across the hop from `4997995022f8` `record-related-list.tsx` (+22/-3, + * objectui#12082, objectui `158c75d90`: the FALLBACK remove now reads the + * affordance-to-grant map's `relatedRowDelete` row) changed above every cited + * line, so its five anchors MOVED by +17 with their text byte-identical — + * `:428` -> `:445`, `:415` -> `:432`, `:428-436` -> `:445-453`, `:361` -> + * `:378`, `:379` -> `:396` — and none of it touches the `requiredPermissions` + * gate this record reads; every other file it cites is byte-identical + * (`git diff --quiet`), so no other anchor moved. At `4997995022f8`, re-read + * there 2026-10-11: * every objectui file this record cites is byte-identical across the hop from * `0df67f237c5a` (`git diff --quiet`), so every anchor held unmoved. At * `0df67f237c5a`, re-read there 2026-10-11: @@ -1182,22 +1194,22 @@ export const PageCardProps = strictObject({ * * 1. CAPABILITIES, NOT OBJECT ACTIONS. Every block gates through * `perms.hasCapabilities(required)` — `record-details.tsx:347`, - * `record-highlights.tsx:102`, `record-related-list.tsx:428`, + * `record-highlights.tsx:102`, `record-related-list.tsx:445`, * `record-quick-actions.tsx:282` — and never `perms.can(objectName, …)`; * each renderer's docblock states the capability "is not object-scoped" * (`record-details.tsx:336`, `record-highlights.tsx:81`, - * `record-related-list.tsx:415`, `record-quick-actions.tsx:271`). `read` + * `record-related-list.tsx:432`, `record-quick-actions.tsx:271`). `read` * is looked up in the capability set like any other name. * 2. ALL OF THEM. `MePermissionsProvider.tsx:447` 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:347-355`, `record-highlights.tsx:160-173`, - * `record-related-list.tsx:428-436`, `record-quick-actions.tsx:282-290`. + * `record-related-list.tsx:445-453`, `record-quick-actions.tsx:282-290`. * Checks that already withhold the content run first on two of them (no * record bound, `record-details.tsx:291`; no object, - * `record-related-list.tsx:361`; the related object's read gate, - * `record-related-list.tsx:379`), which is why the text says "wherever it + * `record-related-list.tsx:378`; the related object's read gate, + * `record-related-list.tsx:396`), 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 @@ -2477,7 +2489,10 @@ export const PageAccordionProps = strictObject({ * re-derive the same false candidate). * * The key is LIVE at the objectui pin this repo builds against - * (`.objectui-sha` = `499799502`, re-read there 2026-10-11: + * (`.objectui-sha` = `088e0f705`, re-read there 2026-10-12: + * every objectui file this record cites is byte-identical across the hop from + * `499799502` (`git diff --quiet`), so every anchor held unmoved. At + * `499799502`, re-read there 2026-10-11: * every objectui file this record cites is byte-identical across the hop from * `0df67f237` (`git diff --quiet`), so every anchor held unmoved. At * `0df67f237`, re-read there 2026-10-11: @@ -2911,7 +2926,10 @@ export const ElementButtonPropsSchema = lazySchema(() => strictObject({ * the button. * * The key is LIVE at the objectui pin this repo builds against - * (`.objectui-sha` = `499799502`, re-read there 2026-10-11: + * (`.objectui-sha` = `088e0f705`, re-read there 2026-10-12: + * every objectui file this record cites is byte-identical across the hop from + * `499799502` (`git diff --quiet`), so every anchor held unmoved. At + * `499799502`, re-read there 2026-10-11: * every objectui file this record cites is byte-identical across the hop from * `0df67f237` (`git diff --quiet`), so every anchor held unmoved. At * `0df67f237`, re-read there 2026-10-11: @@ -3386,7 +3404,10 @@ 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` = `499799502`, re-read there 2026-10-11: + * against, `.objectui-sha` = `088e0f705`, re-read there 2026-10-12: + * every objectui file this record cites is byte-identical across the hop from + * `499799502` (`git diff --quiet`), so every anchor held unmoved. At + * `499799502`, re-read there 2026-10-11: * every objectui file this record cites is byte-identical across the hop from * `0df67f237` (`git diff --quiet`), so every anchor held unmoved. At * `0df67f237`, re-read there 2026-10-11: @@ -3956,7 +3977,10 @@ export type ActionIconPropsParsed = z.infer; * inventory. A member's `params` is its `ActionParam[]` input list: both * containers forward an array as `actionParams` (group `:346-348`, menu * `:270-272`, re-read at the pin this repo builds against, `.objectui-sha` = - * `499799502`, 2026-10-11: `action-group.tsx`, `action-menu.tsx` and + * `088e0f705`, 2026-10-12: `action-group.tsx`, `action-menu.tsx` and + * `static-params.ts` are byte-identical across the hop from `499799502` (`git + * diff --quiet`), so both held unmoved; at `499799502`, 2026-10-11: + * `action-group.tsx`, `action-menu.tsx` and * `static-params.ts` are byte-identical across the hop from `0df67f237` (`git * diff --quiet`), so both held unmoved; at `0df67f237`, 2026-10-11: * `action-group.tsx`, `action-menu.tsx` and @@ -4650,7 +4674,18 @@ const GridOperationsSchema = lazySchema(() => strictObject({ * control `schema.editable` in `ObjectGrid.tsx`. It was declared ahead of its * reader on purpose (the BUILD objectui#11068 chose), and its describe carried * the `[EXPERIMENTAL — not enforced]` marker that said so. Re-measured at the - * pin this repo builds against (`.objectui-sha` = `499799502`, re-read there 2026-10-11: + * pin this repo builds against (`.objectui-sha` = `088e0f705`, re-read there 2026-10-12: + * `ObjectGrid.tsx` (+27/-11: objectui#12143's grouped-pager button names and + * objectui#12110 item 1's column-label override, objectui `2381c07f3` and + * `5330038f4`) and `data-table.tsx` (+12/-1: objectui#12124's pager names, + * objectui `dc6d28e86`) changed across the hop from `499799502`, none of it a + * `keyboardNavigation` line; the read MOVED `5615` -> `5631` with its line + * byte-identical. Re-counted with `git grep keyboardNavigation` under objectui + * `packages/` and `apps/` outside test files, CHANGELOGs, READMEs and + * `packages/types`, the same filter at both pins finds the same 14 lines + * (one fewer than the 15 recorded below, a difference of filter, not of the + * tree), against 3 for the control `schema.editable` in `ObjectGrid.tsx`. At + * `499799502`, re-read there 2026-10-11: * `ObjectGrid.tsx` changed across the hop from `0df67f237` (+89/-44: * objectui#12081 item 3, objectui `69bca0af6`, and objectui#12082, objectui * `752504520`) and `data-table.tsx` is byte-identical (`git diff --quiet`); the @@ -4775,7 +4810,12 @@ export const ObjectGridPropsSchema = lazySchema(() => strictObject({ * same members, and objectui's grid follows this declaration. * * ⚠️ That gap is closed at the pin this repo builds against (`.objectui-sha` - * = `499799502`, re-read there 2026-10-11: + * = `088e0f705`, re-read there 2026-10-12: + * `ObjectGrid.tsx` changed across the hop from `499799502` (+27/-11: + * objectui#12143 and objectui#12110 item 1), every hunk above both reads (the + * last at `:6576`, the grouped pager's last button), so both MOVED by 16 with + * their lines byte-identical: `6632-6633` -> `6648-6649`, `6649-6650` -> + * `6665-6666`. At `499799502`, re-read there 2026-10-11: * `ObjectGrid.tsx` changed across the hop from `0df67f237` (+89/-44: * objectui#12081 item 3 and objectui#12082), every hunk above both reads * (the last at `:5321-5343`), so both MOVED by 45 with their lines @@ -5178,7 +5218,16 @@ export const ObjectGridPropsSchema = lazySchema(() => strictObject({ * `ComponentPropsMap` key. This record said to drop the marker in the change * that lands the BUILD at the pin, and it is dropped here. * - * Read at the pin this repo builds against (`.objectui-sha` = `499799502`, re-read there 2026-10-11: + * Read at the pin this repo builds against (`.objectui-sha` = `088e0f705`, re-read there 2026-10-12: + * `ObjectGrid.tsx` (+27/-11: objectui#12143 and objectui#12110 item 1) and + * `data-table.tsx` (+12/-1: objectui#12124's pager button names) changed + * across the hop from `499799502`, none of it in the arrow-key handling, so + * all seven anchors MOVED with their lines byte-identical — grid `5615` -> + * `5631`, `1851` -> `1857`; table `1018` -> `1025`, `2607` -> `2614`, `3101` + * -> `3108`, `2257` -> `2264`, `2283` -> `2290`; no hunk lands between the + * viewer's write verdict `objectInlineEditable` (`:1833`) and `:1857`, so + * `inlineEditable` is still the authored `editable` AND that verdict. At + * `499799502`, re-read there 2026-10-11: * `ObjectGrid.tsx` changed across the hop from `0df67f237` (+89/-44: * objectui#12081 item 3 and objectui#12082) and `data-table.tsx` is * byte-identical (`git diff --quiet`), so the five `data-table.tsx` anchors @@ -5619,7 +5668,10 @@ 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` = `499799502`, re-read there 2026-10-11: + * (`.objectui-sha` = `088e0f705`, re-read there 2026-10-12: + * every objectui file this record cites is byte-identical across the hop from + * `499799502` (`git diff --quiet`), so every anchor held unmoved. At + * `499799502`, re-read there 2026-10-11: * every objectui file this record cites is byte-identical across the hop from * `0df67f237` (`git diff --quiet`), so every anchor held unmoved. At * `0df67f237`, re-read there 2026-10-11: @@ -5879,7 +5931,10 @@ const ObjectKanbanLaneSchema = lazySchema(() => strictObject({ * 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` = `499799502`, re-read there 2026-10-11: + * (`.objectui-sha` = `088e0f705`, re-read there 2026-10-12: + * every objectui file this record cites is byte-identical across the hop from + * `499799502` (`git diff --quiet`), so every anchor held unmoved. At + * `499799502`, re-read there 2026-10-11: * every objectui file this record cites is byte-identical across the hop from * `0df67f237` (`git diff --quiet`), so every anchor held unmoved. At * `0df67f237`, re-read there 2026-10-11: @@ -6000,7 +6055,10 @@ 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` = `499799502`, re-read there 2026-10-11: + * repo builds against (`.objectui-sha` = `088e0f705`, re-read there 2026-10-12: + * every objectui file this record cites is byte-identical across the hop from + * `499799502` (`git diff --quiet`), so every anchor held unmoved. At + * `499799502`, re-read there 2026-10-11: * every objectui file this record cites is byte-identical across the hop from * `0df67f237` (`git diff --quiet`), so every anchor held unmoved. At * `0df67f237`, re-read there 2026-10-11: @@ -6293,7 +6351,10 @@ 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` = `499799502`, re-read there 2026-10-11: + * (`.objectui-sha` = `088e0f705`, re-read there 2026-10-12: + * every objectui file this record cites is byte-identical across the hop from + * `499799502` (`git diff --quiet`), so every anchor held unmoved. At + * `499799502`, re-read there 2026-10-11: * every objectui file this record cites is byte-identical across the hop from * `0df67f237` (`git diff --quiet`), so every anchor held unmoved; * `ObjectKanban.tsx` still names `quickAdd` and `onQuickAdd` 2 times each @@ -6515,6 +6576,9 @@ export const ObjectKanbanPropsSchema = lazySchema(() => strictObject({ * element schemas). * * Measured at the pin this repo builds against (`.objectui-sha` = + * `088e0f705`, re-read there 2026-10-12: + * every objectui file this record cites is byte-identical across the hop from + * `499799502` (`git diff --quiet`), so every anchor held unmoved. At * `499799502`, re-read there 2026-10-11: * every objectui file this record cites is byte-identical across the hop from * `0df67f237` (`git diff --quiet`), so every anchor held unmoved. At @@ -6744,6 +6808,9 @@ export const ObjectCalendarPropsSchema = lazySchema(() => strictObject({ * `object-kanban`'s above. * * Measured at the pin this repo builds against (`.objectui-sha` = + * `088e0f705`, re-read there 2026-10-12: + * every objectui file this record cites is byte-identical across the hop from + * `499799502` (`git diff --quiet`), so every anchor held unmoved. At * `499799502`, re-read there 2026-10-11: * every objectui file this record cites is byte-identical across the hop from * `0df67f237` (`git diff --quiet`), so every anchor held unmoved. At @@ -7970,7 +8037,10 @@ 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` = `499799502`, re-read there 2026-10-11: + * `.objectui-sha` = `088e0f705`, re-read there 2026-10-12: + * every objectui file this record cites is byte-identical across the hop from + * `499799502` (`git diff --quiet`), so every anchor held unmoved. At + * `499799502`, re-read there 2026-10-11: * every objectui file this record cites is byte-identical across the hop from * `0df67f237` (`git diff --quiet`), so every anchor held unmoved. At * `0df67f237`, re-read there 2026-10-11: @@ -8171,7 +8241,10 @@ 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` = `499799502`, re-read there 2026-10-11: + * pin this repo builds against (`.objectui-sha` = `088e0f705`, re-read there 2026-10-12: + * every objectui file this record cites is byte-identical across the hop from + * `499799502` (`git diff --quiet`), so every anchor held unmoved. At + * `499799502`, re-read there 2026-10-11: * every objectui file this record cites is byte-identical across the hop from * `0df67f237` (`git diff --quiet`), so every anchor held unmoved. At * `0df67f237`, re-read there 2026-10-11: @@ -8251,7 +8324,10 @@ 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` = `499799502`, re-read there 2026-10-11: + * (`.objectui-sha` = `088e0f705`, re-read there 2026-10-12: + * every objectui file this record cites is byte-identical across the hop from + * `499799502` (`git diff --quiet`), so every anchor held unmoved. At + * `499799502`, re-read there 2026-10-11: * every objectui file this record cites is byte-identical across the hop from * `0df67f237` (`git diff --quiet`), so every anchor held unmoved. At * `0df67f237`, re-read there 2026-10-11: @@ -8453,7 +8529,10 @@ function objectGanttMarker() { /** * `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` = `499799502`, re-read there 2026-10-11: + * — `.objectui-sha` = `088e0f705`, re-read there 2026-10-12: + * every objectui file this record cites is byte-identical across the hop from + * `499799502` (`git diff --quiet`), so every anchor held unmoved. At + * `499799502`, re-read there 2026-10-11: * `record-source.ts`, `plugin-gantt/src/index.tsx` and `ListView.tsx` are * byte-identical across the hop from `0df67f237` (`git diff --quiet`), so every * anchor in them held unmoved; `ObjectGantt.tsx` +27/-4 changed for @@ -8727,7 +8806,10 @@ export type ObjectGanttPropsParsed = z.infer; * they flatten `options.tree` (`ListView.tsx:4120-4144`, `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` = `499799502`, re-read there 2026-10-11: + * pin this repo builds against (`.objectui-sha` = `088e0f705`, re-read there 2026-10-12: + * every objectui file this record cites is byte-identical across the hop from + * `499799502` (`git diff --quiet`), so every anchor held unmoved. At + * `499799502`, re-read there 2026-10-11: * every objectui file this record cites is byte-identical across the hop from * `0df67f237` (`git diff --quiet`), so every anchor held unmoved. At * `0df67f237`, re-read there 2026-10-11: @@ -8875,7 +8957,10 @@ 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` = `499799502`, re-read there 2026-10-11: + * — `.objectui-sha` = `088e0f705`, re-read there 2026-10-12: + * every objectui file this record cites is byte-identical across the hop from + * `499799502` (`git diff --quiet`), so every anchor held unmoved. At + * `499799502`, re-read there 2026-10-11: * every objectui file this record cites is byte-identical across the hop from * `0df67f237` (`git diff --quiet`), so every anchor held unmoved. At * `0df67f237`, re-read there 2026-10-11: @@ -9074,7 +9159,10 @@ 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` = `499799502`, re-read there 2026-10-11: + * builds against (`.objectui-sha` = `088e0f705`, re-read there 2026-10-12: + * every objectui file this record cites is byte-identical across the hop from + * `499799502` (`git diff --quiet`), so every anchor held unmoved. At + * `499799502`, re-read there 2026-10-11: * re-COUNTED by the same method, 0 for the tree, 3 each for `plugin-gantt`, * `plugin-grid` and `plugin-calendar` and 4 for `plugin-map`, all five * shells byte-identical across the hop from `0df67f237` (`git diff @@ -9485,7 +9573,10 @@ function objectTimelineItemsFitVariant() { * `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` = `499799502`, re-read there 2026-10-11: + * repo builds against (`.objectui-sha` = `088e0f705`, re-read there 2026-10-12: + * every objectui file this record cites is byte-identical across the hop from + * `499799502` (`git diff --quiet`), so every anchor held unmoved. At + * `499799502`, re-read there 2026-10-11: * every objectui file this record cites is byte-identical across the hop from * `0df67f237` (`git diff --quiet`), so every anchor held unmoved. At * `0df67f237`, re-read there 2026-10-11: @@ -9745,6 +9836,9 @@ 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` = + * `088e0f705`, re-read there 2026-10-12: + * every objectui file this record cites is byte-identical across the hop from + * `499799502` (`git diff --quiet`), so every anchor held unmoved. At * `499799502`, re-read there 2026-10-11: * every objectui file this record cites is byte-identical across the hop from * `0df67f237` (`git diff --quiet`), so every anchor held unmoved. At @@ -10111,6 +10205,9 @@ 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` = + // `088e0f705`, re-read there 2026-10-12: + // every objectui file this record cites is byte-identical across the hop from + // `499799502` (`git diff --quiet`), so every anchor held unmoved. At // `499799502`, re-read there 2026-10-11: // every objectui file this record cites is byte-identical across the hop from // `0df67f237` (`git diff --quiet`), so every anchor held unmoved. At @@ -10220,6 +10317,9 @@ 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` = + // `088e0f705`, re-read there 2026-10-12: + // every objectui file this record cites is byte-identical across the hop from + // `499799502` (`git diff --quiet`), so every anchor held unmoved. At // `499799502`, re-read there 2026-10-11: // `ObjectTree.tsx` and `ObjectMap.tsx` are byte-identical to `0df67f237` // (`git diff --quiet`); `ObjectGantt.tsx` (+27/-4) changed for objectui#12082 @@ -10310,6 +10410,9 @@ 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` = + // `088e0f705`, re-read there 2026-10-12: + // every objectui file this record cites is byte-identical across the hop from + // `499799502` (`git diff --quiet`), so every anchor held unmoved. At // `499799502`, re-read there 2026-10-11: // every objectui file this record cites is byte-identical across the hop from // `0df67f237` (`git diff --quiet`), so every anchor held unmoved. At diff --git a/packages/spec/src/ui/dataset.zod.ts b/packages/spec/src/ui/dataset.zod.ts index 72928729c88..b769ad37d3f 100644 --- a/packages/spec/src/ui/dataset.zod.ts +++ b/packages/spec/src/ui/dataset.zod.ts @@ -283,6 +283,9 @@ 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` = + * `088e0f705`, re-read there 2026-10-12: + * every objectui file this record cites is byte-identical across the hop from + * `499799502` (`git diff --quiet`), so every anchor held unmoved. At * `499799502`, re-read there 2026-10-11: * every objectui file this record cites is byte-identical across the hop from * `0df67f237` (`git diff --quiet`), so every anchor held unmoved. At diff --git a/packages/spec/src/ui/view.zod.ts b/packages/spec/src/ui/view.zod.ts index 2fe8f9026c3..71b9fe85d48 100644 --- a/packages/spec/src/ui/view.zod.ts +++ b/packages/spec/src/ui/view.zod.ts @@ -3429,7 +3429,18 @@ 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` = `499799502`, re-read there 2026-10-11: + * (`.objectui-sha` = `088e0f705`, re-read there 2026-10-12: + * `autoLayout.ts` and `fields`' `field-type-alias.ts` are byte-identical to + * `499799502` (`git diff --quiet`), so `resolveColSpan` `:154`, + * `WIDE_FIELD_TYPES` `:58-69` and the `repeater` -> `field:grid` mapping held + * unmoved, and `form.tsx` changed on this hop — 231 insertions, 79 deletions: + * objectui#12130 (`step` / `className`, objectui `d2500d8be`), objectui#12155 + * (a field-level `defaultValue` is no longer drawn, `f3d540814`), + * objectui#12110 (`5330038f4`) and PR-5's registry-ref widgets + * (`088e0f705`) — none of it inside `spanLadderFor`, which MOVED `:274-301` + * -> `:275-302` byte-identical, and its one call site MOVED `:3258` -> + * `:3329` with the call byte-identical, so it still emits the ladder. At + * `499799502`, re-read there 2026-10-11: * `autoLayout.ts` and `fields`' `field-type-alias.ts` are byte-identical to * `0df67f237` (`git diff --quiet`), so `resolveColSpan` `:154`, * `WIDE_FIELD_TYPES` `:58-69` and the `repeater` -> `field:grid` mapping held @@ -3532,7 +3543,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` = `4997995022f8`), 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` = `088e0f705520`), 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 9089e121ea0..746c7553b1d 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": "4997995022f8e65946f6362b7434685539cc72b7", + "objectuiSha": "088e0f705520e82bee1d65a5fa3c1f7a26672dde", "source": "built-tree", - "modulesRoot": ".cache/objectui-4997995022f8/apps/console", + "modulesRoot": ".cache/objectui-088e0f705520/apps/console", "objectuiWorkspaceVersion": "17.7.0", "generator": "scripts/gen-sdui-manifest-node.mjs", - "generatedAt": "2026-10-11", - "sha256": "9d87162a3ef60676c6aed69ecf2703693bdbbf66d5ef798c9d770f3112f86217", + "generatedAt": "2026-10-12", + "sha256": "a799c55a18d6854faaffbf3eee8a959bf142e12109cee62890de46a327fe4db4", "components": 107 } diff --git a/sdui.manifest.json b/sdui.manifest.json index a335e13646f..10fefd454a1 100644 --- a/sdui.manifest.json +++ b/sdui.manifest.json @@ -1712,7 +1712,7 @@ { "name": "showCompleted", "type": "boolean", - "description": "Include completed activities (sys_activity type \"completed\", which surfaces as a task item). Off by default." + "description": "Include completed activities (sys_activity type \"completed\", which surfaces as a task item). Off by default. A milestone row (metadata.kind \"milestone\") is not a completed activity and shows either way." }, { "name": "unifiedTimeline", From 7de0f00c91aaaecd2d70ba59695d373baa290bf1 Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 12 Oct 2026 04:59:24 +0000 Subject: [PATCH 4/4] Revert the console pin move: the pin follows #22874 (#15204 B2) This reverts commit e486abb9c8776eab0bd3c54cb3d9a7750c330282. .objectui-sha is #22874's single-writer path, and objectui from e5311165 on reads allowEnvironmentOverlay only, which main's server sends once #22874 lands. The pin move returns as its own PR after #22874. Co-Authored-By: Claude Claude-Session: https://claude.ai/code/session_013XKtmoR5QCUSTMjiQ3os49 --- .changeset/console-088e0f705520.md | 44 ----- .../objectui-pin-citations-088e0f705520.md | 18 -- .objectui-sha | 2 +- content/docs/references/ui/view.mdx | 4 +- packages/sdui-parser/objectui-lockstep.json | 6 +- .../api-methods-batch-conformance.test.ts | 15 +- .../src/kernel/functional-completeness.ts | 18 +- ...ck-and-hot-reload-durations-unit-in-key.ts | 6 +- ...rnel-runtime-config-timeout-unit-in-key.ts | 6 +- .../18.logging-durations-unit-in-key.ts | 5 +- ...tem-metrics-jsdoc-durations-unit-in-key.ts | 6 +- ...ing-otel-exporter-durations-unit-in-key.ts | 8 +- .../18.tenant-schema-cache-ttl-unit-in-key.ts | 4 +- .../src/ui/action-outcome-messages.test.ts | 3 - packages/spec/src/ui/action.zod.ts | 3 - packages/spec/src/ui/component.test.ts | 30 +--- packages/spec/src/ui/component.zod.ts | 155 +++--------------- packages/spec/src/ui/dataset.zod.ts | 3 - packages/spec/src/ui/view.zod.ts | 15 +- scripts/sdui-manifest.record.json | 8 +- sdui.manifest.json | 2 +- 21 files changed, 71 insertions(+), 290 deletions(-) delete mode 100644 .changeset/console-088e0f705520.md delete mode 100644 .changeset/objectui-pin-citations-088e0f705520.md diff --git a/.changeset/console-088e0f705520.md b/.changeset/console-088e0f705520.md deleted file mode 100644 index ea1aca0aaa7..00000000000 --- a/.changeset/console-088e0f705520.md +++ /dev/null @@ -1,44 +0,0 @@ ---- -"@objectstack/console": minor ---- - -Console (objectui) refreshed to `088e0f705520`. Frontend changes in this range: - -Derived from the changesets objectui declared over the range — 24 releasing of 26 changesets added across 27 non-merge commits; omitted: 2 release-nothing changesets, 1 commit carrying no changeset (they ship no package code). - -- **minor** — A record-form field can name one item of a metadata registry by its machine name: a `text` field that declares `widget: 'position-ref'` lists the position registry, and one that d… (objectui `088e0f705`) -- **minor** — **BREAKING** — Studio and the metadata admin read a metadata type's overlay flag under its new name, `allowEnvironmentOverlay`, and the read-only banners name `OS_METADATA_WRITABLE` (objectui#12… (objectui `e5311165a`) -- **minor** — The marketplace package page's **Update** button opens an update dialog, and a package README's raw HTML is no longer printed as text (objectui#12146). (objectui `82bb1d584`) -- **minor** — **BREAKING** — A form field declares `step` and `className` on both faces, so the strict authoring face stops telling authors to remove two keys that work. A built-in form branch now joins an en… (objectui `d2500d8be`) -- **minor** — "Clone to customize" on a packaged permission set calls the server's clone door (objectui#7611, objectstack ADR-0126 §7.1). (objectui `6d5879fe9`) -- **minor** — **A dashboard or a list view the server refuses you, opened by its URL, now says it was refused** (objectui#12112, the console half of objectstack#22611's ruling A). (objectui `43e150518`) -- **minor** — Setup's "Assigned users" on a permission set writes a new grant by the set's name alone (objectui#7611, after objectstack#22863, ADR-0131 stage 6b-2-pre). (objectui `faf4ce952`) -- **minor** — **BREAKING** — A form field declares `avatarField`, the record field each candidate of the search picker draws its avatar from, on both faces, so the strict authoring face stops telling authors… (objectui `c0c2f792b`) -- **minor** — A `position` decision output lists the position registry and commits position names (objectui#7611, objectstack ADR-0131 D3/D4). (objectui `8cc7158b4`) -- **minor** — The capability select lists the capability registry, and the permission-set editor's provenance badge reads the layered envelope (objectui#7611, objectstack ADR-0131 D3/D7). (objectui `53ee2f854`) -- **minor** — **BREAKING** — A form field declares the rest of the field metadata its widget reads off the `fields[]` entry, on both faces, so the strict authoring face stops telling authors to remove keys th… (objectui `0665c3be7`) -- **minor** — Screen readers hear the names of more controls in the viewer's language (objectui#12145). (objectui `e723f58ee`) -- **minor** — The suggested-bindings panel shows each suggestion's real state and can revoke an acceptance (objectui#7611, after objectstack#22854). (objectui `f962cdc09`) -- **minor** — The record feed and a related list's Add existing and fallback remove read the affordance-to-grant map, so a caller without the grant is no longer offered a write the server then… (objectui `158c75d90`) -- **minor** — A paged table's first, previous, next and last page buttons have accessible names (objectui#12124). (objectui `dc6d28e86`) -- **patch** — A position approver is read through the spec's registry binding, `{ source: 'registry', type }` (objectstack#22710): its readable label and its designer picker come from the posit… (objectui `83b9fade2`) -- **patch** — A rich-text field no longer draws hint lines above its editor (objectui#12110, ruled B). The `markdown`, `html` and `richtext` editors used to show "Format: markdown" (or "Format:… (objectui `2498a0753`) -- **patch** — The Studio app's root now opens the app's first navigation entry, like every other app's root, and `StudioHomePage`, Studio's old metadata overview, is retired (objectui#12113). (objectui `ed12d48ec`) -- **patch** — A form field's own `defaultValue` is no longer drawn in its control, so the form never shows a value it does not save (objectui#12155). (objectui `f3d540814`) -- **patch** — A grouped grid's own first, previous, next and last page buttons have accessible names (objectui#12143). (objectui `2381c07f3`) -- **patch** — Console rendering fixes from the HotCRM browser pass (objectui#12110): (objectui `5330038f4`) -- **patch** — The record page's discussion shows stored replies under their comment, and every comment offers the reply input where the caller may post one (objectui#12144). (objectui `a7d492011`) -- **patch** — A record activity feed shows an object's `activityMilestones` rows of type `completed`, such as "Case resolved", instead of hiding them as completed tasks (objectui#12106). (objectui `1d1cfe0c1`) -- **patch** — A record-source refusal (`RECORD_SOURCE_REQUIRED`, raised by every arm that requires a record source) now reports the same path every time (objectui#5250). (objectui `9b7550999`) - -⚠️ 4 of these carry a breaking change: 4 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 1 commit in this range with no `.changeset/*.md`. The code is inside the pin above and ships here, but nothing upstream declared it, so it appears 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)_ feat(scripts): the JSON-fence gate reads the published READMEs (objectui#12131, phase 2) (#12139) (objectui `ce9811c96`) - -Clause-②: no - - - -objectui range: `4997995022f8...088e0f705520` diff --git a/.changeset/objectui-pin-citations-088e0f705520.md b/.changeset/objectui-pin-citations-088e0f705520.md deleted file mode 100644 index 35dd82b627f..00000000000 --- a/.changeset/objectui-pin-citations-088e0f705520.md +++ /dev/null @@ -1,18 +0,0 @@ ---- -'@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 `088e0f705520`. - -Clause-②: no - -Every anchor was mapped through the objectui diff `4997995022f8..088e0f705520`: 325 paths over 27 commits. Four files a record cites changed on the hop, and every cited line in them moved or held with its text byte-identical: - -- `ObjectGrid.tsx` (+27/-11: objectui#12143's grouped-pager button names and objectui#12110 item 1's column-label override): the bulk-selection block moved by +16 and still hashes to `c88443302d40`; the `keyboardNavigation`, `inlineEditable` and grid empty-state reads moved by +6 or +16. -- `data-table.tsx` (+12/-1: objectui#12124's pager button names): the five arrow-key anchors moved by +7. -- `record-related-list.tsx` (+22/-3: objectui#12082, the fallback remove reads the affordance-to-grant map): the five `requiredPermissions` gate anchors moved by +17. -- `form.tsx` (+231/-79: objectui#12130, objectui#12155, objectui#12110 and objectui#7611 PR-5): `spanLadderFor` moved by +1 and its call site by +71, both unchanged, so `FormField.span: 'full'` still takes the whole row at every multi-column tier. - -The records that cite only byte-identical files gain a hop sentence that says so. The six migration entries' corpus counts were re-taken with `git grep -o -F`, the method that reproduces every `4997995022f8` number. The corpus is now 8519 tracked files, and every retired name each entry counts still reads 0. The lit controls moved with the corpus, for example `objectstack` from 18271 to 18400 and `timeout` from 1704 to 1706. - -No key, default, enum member or export moves. diff --git a/.objectui-sha b/.objectui-sha index 51356616906..97325989491 100644 --- a/.objectui-sha +++ b/.objectui-sha @@ -1 +1 @@ -088e0f705520e82bee1d65a5fa3c1f7a26672dde +4997995022f8e65946f6362b7434685539cc72b7 diff --git a/content/docs/references/ui/view.mdx b/content/docs/references/ui/view.mdx index b76fc2ea119..11812a8b1a2 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` = `088e0f705520`), 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` = `4997995022f8`), 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` = `088e0f705520`), 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` = `4997995022f8`), 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 e023aa1fbec..9ff6726ea5b 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": "088e0f705520e82bee1d65a5fa3c1f7a26672dde", - "revDate": "2026-10-12T03:19:24+00:00", + "rev": "4997995022f8e65946f6362b7434685539cc72b7", + "revDate": "2026-10-11T10:56:33+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": "088e0f705520e82bee1d65a5fa3c1f7a26672dde", + "recordedAgainstPin": "4997995022f8e65946f6362b7434685539cc72b7", "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 429cb628bef..05043cc6ba0 100644 --- a/packages/spec/src/data/api-methods-batch-conformance.test.ts +++ b/packages/spec/src/data/api-methods-batch-conformance.test.ts @@ -61,20 +61,7 @@ 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` = `088e0f705`, re-read there 2026-10-12: - // in `packages/plugin-grid`, on the hop off `499799502`, `ObjectGrid.tsx` - // changed again (27 insertions, 11 deletions: objectui#12143's grouped-pager - // button names and objectui#12110 item 1's column-label override), none of it - // inside the selection block, which only MOVED by +16: `ObjectGrid.tsx:4997-5024` - // here (`4981-5008` at `499799502`), still hashing to - // `c88443302d40c2db739ddb235470bafa29056e2e` (hash-object of the block), - // re-READ with the same reading below; neither hunk touches the bulk defs or - // their verdicts, so the `delete` verdict line MOVED `:1787` -> `:1793` and the - // promoted def's params `:5165-5184` -> `:5181-5200` (called at `:5200` -> - // `:5216`), each byte-identical. `hooks/useBulkExecutor.ts` is byte-identical - // to `499799502` and its `:298-303` still hashes to - // `01083348330f10a201cdf1078b4c21c236402b6a`. At `499799502`, re-read there - // 2026-10-11: + // (`.objectui-sha` = `499799502`, re-read there 2026-10-11: // in `packages/plugin-grid`, on the hop off `0df67f237`, `ObjectGrid.tsx` // changed again (89 insertions, 44 deletions: objectui#12081 item 3's // whole-set footer and objectui#12082 leg A), none of it inside the diff --git a/packages/spec/src/kernel/functional-completeness.ts b/packages/spec/src/kernel/functional-completeness.ts index 64853f67e5e..b9d740f225c 100644 --- a/packages/spec/src/kernel/functional-completeness.ts +++ b/packages/spec/src/kernel/functional-completeness.ts @@ -298,10 +298,7 @@ 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` = `088e0f705`, re-read there 2026-10-12: - * every objectui file this record cites is byte-identical across the hop from - * `499799502` (`git diff --quiet`), so every anchor held unmoved. At - * `499799502`, re-read there 2026-10-11: + * (`.objectui-sha` = `499799502`, re-read there 2026-10-11: * on the hop off `0df67f237` `ObjectCalendar.tsx` and `ListView.tsx` are * byte-identical (`git diff --quiet`), so `getCalendarConfig` `:311`, the * `if (!calendarConfig)` arm `:1354` with its `tt(…)` lines `:1361-1362` and @@ -428,10 +425,7 @@ 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` = `088e0f705`, re-read there 2026-10-12: - * every objectui file this record cites is byte-identical across the hop from - * `499799502` (`git diff --quiet`), so every anchor held unmoved. At - * `499799502`, re-read there 2026-10-11: + * this repo builds against (`.objectui-sha` = `499799502`, re-read there 2026-10-11: * on the hop off `0df67f237` `ObjectGantt.tsx` changed (+27/-4, * objectui#12082, objectui `752504520`: the chart's in-chart writes read the * affordance-to-grant map), none of it in `getGanttConfig` or the refusal arm, @@ -530,9 +524,6 @@ 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` = - * `088e0f705`, re-read there 2026-10-12: - * every objectui file this record cites is byte-identical across the hop from - * `499799502` (`git diff --quiet`), so every anchor held unmoved. At * `499799502`, re-read there 2026-10-11: * every objectui file this record cites is byte-identical across the hop from * `0df67f237` (`git diff --quiet`), so every anchor held unmoved. At @@ -629,10 +620,7 @@ 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` = `088e0f705`, re-read there 2026-10-12: - * every objectui file this record cites is byte-identical across the hop from - * `499799502` (`git diff --quiet`), so every anchor held unmoved. At - * `499799502`, re-read there 2026-10-11: + * pin (`.objectui-sha` = `499799502`, re-read there 2026-10-11: * every objectui file this record cites is byte-identical across the hop from * `0df67f237` (`git diff --quiet`), so every anchor held unmoved. At * `0df67f237`, re-read there 2026-10-11: 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 2d14b05ba62..a84ca1a448c 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` = `088e0f705520e82bee1d65a5fa3c1f7a26672dde` — names ' + + 'against, `.objectui-sha` = `4997995022f8e65946f6362b7434685539cc72b7` — 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 8519 tracked files (0 across the 8441 at 499799502, the 8424 at 0df67f237, the 8351 at 20c6d351a, the 8281 at 47b1f0bb7, the 8234 at f0268ad78, the 7754 at a58626c88, the 7650 at 0abd4f9f8, the 7632 at 9dfaca654, the 7579 at 2e818d0b5, the 10267 at ab1879721, the 10071 at 89cad75d5, the 9912 at 31971ff1e, the 9800 at e420df310, the 9546 at db11afd49, the 9283 at dd3f7e1be, the ' + + 'the string debounceDelay each occur 0 times across its 8441 tracked files (0 across the 8424 at 0df67f237, the 8351 at 20c6d351a, the 8281 at 47b1f0bb7, the 8234 at f0268ad78, the 7754 at a58626c88, the 7650 at 0abd4f9f8, the 7632 at 9dfaca654, the 7579 at 2e818d0b5, the 10267 at ab1879721, the 10071 at 89cad75d5, 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, to 15691 and 6206 at 31971ff1e, to 16044 and 6461 at 89cad75d5, to 16377 and 6665 at ab1879721, to 17227 and 7134 at 2e818d0b5, to 17313 and 7186 at 9dfaca654, to 17390 and 7209 at 0abd4f9f8, to 17468 and 7246 at a58626c88, to 17956 and 7522 at f0268ad78, to 17980 and 7523 at 47b1f0bb7, to 18047 and 7545 at 20c6d351a, to 18248 and 7582 at 0df67f237, to 18271 and 7587 at 499799502 and to 18400 and 7603 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, to 16044 and 6461 at 89cad75d5, to 16377 and 6665 at ab1879721, to 17227 and 7134 at 2e818d0b5, to 17313 and 7186 at 9dfaca654, to 17390 and 7209 at 0abd4f9f8, to 17468 and 7246 at a58626c88, to 17956 and 7522 at f0268ad78, to 17980 and 7523 at 47b1f0bb7, to 18047 and 7545 at 20c6d351a, to 18248 and 7582 at 0df67f237 and to 18271 and 7587 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 eccf7973b0e..d3729356a49 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,8 +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` = `088e0f705520e82bee1d65a5fa3c1f7a26672dde`, re-read from this tree — ' - + 'spells resourceLimits.timeout 0 times across 8519 tracked files, against lit controls timeout 1706, RuntimeConfig 357 and resourceLimits 2 on the same corpus (0 across 8441, and 1704 / 352 / 2, at 499799502; 0 across 8424, and 1705 / 347 / 2, at 0df67f237; 0 across 8351, and 1694 / 337 / 2, at 20c6d351a; 0 across 8281, and 1674 / 337 / 2, at 47b1f0bb7; 0 across 8234, and 1658 / 337 / 2, at f0268ad78; 0 across 7754, and 1431 / 299 / 2, at a58626c88; 0 across 7650, and 1360 / 293 / 2, at 0abd4f9f8; 0 across 7632, and 1360 / 293 / 2, at 9dfaca654; 0 across 7579, and 1351 / 276 / 2, at 2e818d0b5; 0 across 10267, and 1348 / 273 / 2, at ab1879721; 0 across 10071, and 1331 / 273 / 2, at 89cad75d5; 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 ' + + '`.objectui-sha` = `4997995022f8e65946f6362b7434685539cc72b7`, re-read from this tree — ' + + 'spells resourceLimits.timeout 0 times across ' + + '8441 tracked files, against lit controls timeout 1704, RuntimeConfig 352 and resourceLimits ' + + '2 on the same corpus (0 across 8424, and 1705 / 347 / 2, at 0df67f237; 0 across 8351, and 1694 / 337 / 2, at 20c6d351a; 0 across 8281, and 1674 / 337 / 2, at 47b1f0bb7; 0 across 8234, and 1658 / 337 / 2, at f0268ad78; 0 across 7754, and 1431 / 299 / 2, at a58626c88; 0 across 7650, and 1360 / 293 / 2, at 0abd4f9f8; 0 across 7632, and 1360 / 293 / 2, at 9dfaca654; 0 across 7579, and 1351 / 276 / 2, at 2e818d0b5; 0 across 10267, and 1348 / 273 / 2, at ab1879721; 0 across 10071, and 1331 / 273 / 2, at 89cad75d5; 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 4edac8221dc..9f6fd13981e 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,9 +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` = `088e0f705520e82bee1d65a5fa3c1f7a26672dde` — spells ' + + 'objectui checkout — `.objectui-sha` = `4997995022f8e65946f6362b7434685539cc72b7` — spells ' + '`flushInterval` 0 times, `initialDelay` 0, `HttpDestinationConfig` 0 and `LoggingConfig` 0 ' - + 'across its 8519 tracked files, against lit controls `useState` 2661 and `timeout` 1706 on the same corpus (all four 0 across 8441, against 2648 and 1704, at 499799502, 0 across 8424, against 2645 and 1705, at 0df67f237, 0 across 8351, against 2630 and 1694, at 20c6d351a, 0 across 8281, against 2630 and 1674, at 47b1f0bb7, 0 across 8234, against 2622 and 1658, at f0268ad78, 0 across 7754, against 2491 and 1431, at a58626c88, 0 across 7650, against 2478 and 1360, at 0abd4f9f8, 0 across 7632, against 2477 and 1360, at 9dfaca654, 0 across 7579, against 2477 and 1351, at 2e818d0b5, 0 across 10267, against 2476 and 1348, at ab1879721, 0 across 10071, against 2470 and 1331, at 89cad75d5, 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, ' + + 'across its 8441 tracked files, against lit controls `useState` 2648 and `timeout` 1704 on ' + + 'the same corpus (all four 0 across 8424, against 2645 and 1705, at 0df67f237, 0 across 8351, against 2630 and 1694, at 20c6d351a, 0 across 8281, against 2630 and 1674, at 47b1f0bb7, 0 across 8234, against 2622 and 1658, at f0268ad78, 0 across 7754, against 2491 and 1431, at a58626c88, 0 across 7650, against 2478 and 1360, at 0abd4f9f8, 0 across 7632, against 2477 and 1360, at 9dfaca654, 0 across 7579, against 2477 and 1351, at 2e818d0b5, 0 across 10267, against 2476 and 1348, at ab1879721, 0 across 10071, against 2470 and 1331, at 89cad75d5, 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 1051220eb39..5c7b5f1613a 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,8 +73,10 @@ 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` = `088e0f705520e82bee1d65a5fa3c1f7a26672dde`, re-read from this tree — ' - + 'spells all six metrics def names and both distinctive keys 0 times across 8519 tracked files at that sha, against lit controls window 4615, timeout 1706, period 251, interval 238 and metrics 456 on that same corpus and sha (0 across 8441, against 4604 / 1704 / 251 / 238 / 456, at 499799502, 0 across 8424, against 4596 / ' + + '`.objectui-sha` = `4997995022f8e65946f6362b7434685539cc72b7`, re-read from this tree — ' + + 'spells all six metrics def names and both distinctive keys 0 times across 8441 tracked ' + + 'files at that sha, against lit controls window 4604, timeout 1704, period 251, ' + + 'interval 238 and metrics 456 on that same corpus and sha (0 across 8424, against 4596 / ' + '1705 / 251 / 233 / 456, at 0df67f237, 0 across 8351, against 4470 / ' + '1694 / 249 / 213 / 456, at 20c6d351a, 0 across 8281, against 4449 / ' + '1674 / 249 / 213 / 455, at 47b1f0bb7, 0 across 8234, against 4430 / ' 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 7c0d6b452a1..319dc12f085 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,10 +69,12 @@ 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` = `088e0f705520e82bee1d65a5fa3c1f7a26672dde` — names none of it: all 37 exports of ' - + 'tracing.zod.ts and each of the four key names occur 0 times across the 8519 files tracked at that sha (the 519 Span and 57 SpanSchema hits are objectui\'s own HTML ' + + 'pinned objectui checkout — `.objectui-sha` = `4997995022f8e65946f6362b7434685539cc72b7` — names none of it: all 37 exports of ' + + 'tracing.zod.ts and each of the four key names occur 0 times across the 8441 files ' + + 'tracked at that sha (the 517 Span and 57 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: 18400 hits for the bare token objectstack, and 7603 for the package specifier @objectstack/spec (at 499799502: 0 across 8441, Span 517, 18271 and 7587; at 0df67f237: 0 across 8424, Span 517, ' + + 'two lit controls on that same corpus and sha: 18271 hits for the bare token objectstack, ' + + 'and 7587 for the package specifier @objectstack/spec (at 0df67f237: 0 across 8424, Span 517, ' + '18248 and 7582; at 20c6d351a: 0 across 8351, Span 517, ' + '18047 and 7545; at 47b1f0bb7: 0 across 8281, Span 517, ' + '17980 and 7523; at f0268ad78: 0 across 8234, Span 517, ' 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 878695c9752..1bc6e935bae 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,7 +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` = `088e0f705520e82bee1d65a5fa3c1f7a26672dde` — spells it 0 times across 8519 tracked files, against lit controls `TTL` 184 and `tenant` 1365 on the same corpus (0 across 8441, against 184 and 1362, at 499799502; 0 across 8424, against 184 and 1357, at 0df67f237; 0 across 8351, against 184 and 1340, at 20c6d351a; 0 across 8281, against 184 and 1338, at 47b1f0bb7; 0 across 8234, against 184 and 1338, at f0268ad78; 0 across 7754, against 184 and 1319, at a58626c88; 0 across 7650, against 182 and 1318, at 0abd4f9f8; 0 across 7632, against 182 and 1318, at 9dfaca654; 0 across 7579, against 182 and 1317, at 2e818d0b5; 0 across 10267, against 180 and 1238, at ab1879721; 0 across 10071, against 181 and 1237, at 89cad75d5; 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 ' + + 'objectui checkout — `.objectui-sha` = `4997995022f8e65946f6362b7434685539cc72b7` — spells it 0 ' + + 'times across 8441 tracked files, against lit controls `TTL` 184 and `tenant` 1362 on the ' + + 'same corpus (0 across 8424, against 184 and 1357, at 0df67f237; 0 across 8351, against 184 and 1340, at 20c6d351a; 0 across 8281, against 184 and 1338, at 47b1f0bb7; 0 across 8234, against 184 and 1338, at f0268ad78; 0 across 7754, against 184 and 1319, at a58626c88; 0 across 7650, against 182 and 1318, at 0abd4f9f8; 0 across 7632, against 182 and 1318, at 9dfaca654; 0 across 7579, against 182 and 1317, at 2e818d0b5; 0 across 10267, against 180 and 1238, at ab1879721; 0 across 10071, against 181 and 1237, at 89cad75d5; 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/action-outcome-messages.test.ts b/packages/spec/src/ui/action-outcome-messages.test.ts index 3ec9c2a512f..8d020f59c83 100644 --- a/packages/spec/src/ui/action-outcome-messages.test.ts +++ b/packages/spec/src/ui/action-outcome-messages.test.ts @@ -12,9 +12,6 @@ * runner default) and the `${result.*}` INTERPOLATION are the console's — the * reader is objectstack-ai/objectui#11344, a later link of the same ruling, * carried from the pin this repo builds against (`.objectui-sha` = - * `088e0f705`, re-read there 2026-10-12: - * every objectui file this record cites is byte-identical across the hop from - * `499799502` (`git diff --quiet`), so every anchor held unmoved. At * `499799502`, re-read there 2026-10-11: * every objectui file this record cites is byte-identical across the hop from * `0df67f237` (`git diff --quiet`), so every anchor held unmoved. At diff --git a/packages/spec/src/ui/action.zod.ts b/packages/spec/src/ui/action.zod.ts index ea13b386485..6ed83465a72 100644 --- a/packages/spec/src/ui/action.zod.ts +++ b/packages/spec/src/ui/action.zod.ts @@ -1364,9 +1364,6 @@ const actionObject = () => strictObject({ * * Liveness: the ledger row was `planned` until the console reader landed, * and it is `live` from the pin this repo builds against (`.objectui-sha` = - * `088e0f705`, re-read there 2026-10-12: - * every objectui file this record cites is byte-identical across the hop from - * `499799502` (`git diff --quiet`), so every anchor held unmoved. At * `499799502`, re-read there 2026-10-11: * every objectui file this record cites is byte-identical across the hop from * `0df67f237` (`git diff --quiet`), so every anchor held unmoved. At diff --git a/packages/spec/src/ui/component.test.ts b/packages/spec/src/ui/component.test.ts index 251be6929d5..4b3a11fdcd9 100644 --- a/packages/spec/src/ui/component.test.ts +++ b/packages/spec/src/ui/component.test.ts @@ -288,10 +288,7 @@ describe('PageAccordionProps variant — declared because the accordion renderer // same file's `ComponentRegistry.register('accordion', …)` publishes the key to // the Studio block designer at `:1222` (the `items` input, documented as // `[{ label, icon?, collapsed?, children }]`). Measured at the pin this repo -// builds against — `.objectui-sha` = `088e0f705`, re-read there 2026-10-12: -// every objectui file this record cites is byte-identical across the hop from -// `499799502` (`git diff --quiet`), so every anchor held unmoved. At -// `499799502`, re-read there 2026-10-11: +// builds against — `.objectui-sha` = `499799502`, re-read there 2026-10-11: // every objectui file this record cites is byte-identical across the hop from // `0df67f237` (`git diff --quiet`), so every anchor held unmoved. At // `0df67f237`, re-read there 2026-10-11: @@ -460,10 +457,7 @@ describe('PageTabsProps items[].value / items[].count — declared because the t // same file's `ComponentRegistry.register('tabs', …)` publishes the key to the // Studio block designer at `:1007` (the `items` input, documented as // `[{ label, value?, icon?, count?, visibleWhen?, children }]`). Measured at -// the pin this repo builds against — `.objectui-sha` = `088e0f705`, re-read there 2026-10-12: -// every objectui file this record cites is byte-identical across the hop from -// `499799502` (`git diff --quiet`), so every anchor held unmoved. At -// `499799502`, re-read there 2026-10-11: +// the pin this repo builds against — `.objectui-sha` = `499799502`, re-read there 2026-10-11: // every objectui file this record cites is byte-identical across the hop from // `0df67f237` (`git diff --quiet`), so every anchor held unmoved. At // `0df67f237`, re-read there 2026-10-11: @@ -3505,10 +3499,7 @@ describe('object-* block props schemas — declared, so the props gate has a sch // #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` = `088e0f705`, re-read there 2026-10-12: -// every objectui file this record cites is byte-identical across the hop from -// `499799502` (`git diff --quiet`), so every anchor held unmoved. At -// `499799502`, re-read there 2026-10-11: +// against (`.objectui-sha` = `499799502`, re-read there 2026-10-11: // every objectui file this record cites is byte-identical across the hop from // `0df67f237` (`git diff --quiet`), so every anchor held unmoved. At // `0df67f237`, re-read there 2026-10-11: @@ -3722,10 +3713,7 @@ 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` = `088e0f705`, re-read there 2026-10-12: -// every objectui file this record cites is byte-identical across the hop from -// `499799502` (`git diff --quiet`), so every anchor held unmoved. At -// `499799502`, re-read there 2026-10-11: +// against (`.objectui-sha` = `499799502`, re-read there 2026-10-11: // every objectui file this record cites is byte-identical across the hop from // `0df67f237` (`git diff --quiet`), so every anchor held unmoved. At // `0df67f237`, re-read there 2026-10-11: @@ -3928,10 +3916,7 @@ describe('ObjectKanbanPropsSchema quickAdd is retired', () => { // #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` = `088e0f705`, re-read there 2026-10-12: -// every objectui file this record cites is byte-identical across the hop from -// `499799502` (`git diff --quiet`), so every anchor held unmoved. At -// `499799502`, re-read there 2026-10-11: +// `.objectui-sha` = `499799502`, re-read there 2026-10-11: // every objectui file this record cites is byte-identical across the hop from // `0df67f237` (`git diff --quiet`), so every anchor held unmoved. At // `0df67f237`, re-read there 2026-10-11: @@ -4117,10 +4102,7 @@ describe('ObjectMetricPropsSchema icon liveness', () => { // // 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` = `088e0f705`, re-read there 2026-10-12: -// every objectui file this record cites is byte-identical across the hop from -// `499799502` (`git diff --quiet`), so every anchor held unmoved. At -// `499799502`, re-read there 2026-10-11: +// (`.objectui-sha` = `499799502`, re-read there 2026-10-11: // `ObjectTree.tsx`, `ObjectMap.tsx` and `record-source.ts` are byte-identical // across the hop from `0df67f237` (`git diff --quiet`), so every anchor in them // held unmoved; `ObjectGantt.tsx` +27/-4 changed for objectui#12082 (objectui diff --git a/packages/spec/src/ui/component.zod.ts b/packages/spec/src/ui/component.zod.ts index 3d1dadadcc5..c0d62b35a80 100644 --- a/packages/spec/src/ui/component.zod.ts +++ b/packages/spec/src/ui/component.zod.ts @@ -840,10 +840,7 @@ export const PageTabsProps = strictObject({ * false candidate a component over). * * The key is LIVE at the objectui pin this repo builds against - * (`.objectui-sha` = `088e0f705`, re-read there 2026-10-12: - * every objectui file this record cites is byte-identical across the hop from - * `499799502` (`git diff --quiet`), so every anchor held unmoved. At - * `499799502`, re-read there 2026-10-11: + * (`.objectui-sha` = `499799502`, re-read there 2026-10-11: * every objectui file this record cites is byte-identical across the hop from * `0df67f237` (`git diff --quiet`), so every anchor held unmoved. At * `0df67f237`, re-read there 2026-10-11: @@ -1086,16 +1083,7 @@ export const PageCardProps = strictObject({ * declarations identical. * * Each clause is read off the objectui pin this repo builds against - * (`.objectui-sha` = `088e0f705520`, re-read there 2026-10-12: - * across the hop from `4997995022f8` `record-related-list.tsx` (+22/-3, - * objectui#12082, objectui `158c75d90`: the FALLBACK remove now reads the - * affordance-to-grant map's `relatedRowDelete` row) changed above every cited - * line, so its five anchors MOVED by +17 with their text byte-identical — - * `:428` -> `:445`, `:415` -> `:432`, `:428-436` -> `:445-453`, `:361` -> - * `:378`, `:379` -> `:396` — and none of it touches the `requiredPermissions` - * gate this record reads; every other file it cites is byte-identical - * (`git diff --quiet`), so no other anchor moved. At `4997995022f8`, re-read - * there 2026-10-11: + * (`.objectui-sha` = `4997995022f8`, re-read there 2026-10-11: * every objectui file this record cites is byte-identical across the hop from * `0df67f237c5a` (`git diff --quiet`), so every anchor held unmoved. At * `0df67f237c5a`, re-read there 2026-10-11: @@ -1194,22 +1182,22 @@ export const PageCardProps = strictObject({ * * 1. CAPABILITIES, NOT OBJECT ACTIONS. Every block gates through * `perms.hasCapabilities(required)` — `record-details.tsx:347`, - * `record-highlights.tsx:102`, `record-related-list.tsx:445`, + * `record-highlights.tsx:102`, `record-related-list.tsx:428`, * `record-quick-actions.tsx:282` — and never `perms.can(objectName, …)`; * each renderer's docblock states the capability "is not object-scoped" * (`record-details.tsx:336`, `record-highlights.tsx:81`, - * `record-related-list.tsx:432`, `record-quick-actions.tsx:271`). `read` + * `record-related-list.tsx:415`, `record-quick-actions.tsx:271`). `read` * is looked up in the capability set like any other name. * 2. ALL OF THEM. `MePermissionsProvider.tsx:447` 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:347-355`, `record-highlights.tsx:160-173`, - * `record-related-list.tsx:445-453`, `record-quick-actions.tsx:282-290`. + * `record-related-list.tsx:428-436`, `record-quick-actions.tsx:282-290`. * Checks that already withhold the content run first on two of them (no * record bound, `record-details.tsx:291`; no object, - * `record-related-list.tsx:378`; the related object's read gate, - * `record-related-list.tsx:396`), which is why the text says "wherever it + * `record-related-list.tsx:361`; the related object's read gate, + * `record-related-list.tsx:379`), 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 @@ -2489,10 +2477,7 @@ export const PageAccordionProps = strictObject({ * re-derive the same false candidate). * * The key is LIVE at the objectui pin this repo builds against - * (`.objectui-sha` = `088e0f705`, re-read there 2026-10-12: - * every objectui file this record cites is byte-identical across the hop from - * `499799502` (`git diff --quiet`), so every anchor held unmoved. At - * `499799502`, re-read there 2026-10-11: + * (`.objectui-sha` = `499799502`, re-read there 2026-10-11: * every objectui file this record cites is byte-identical across the hop from * `0df67f237` (`git diff --quiet`), so every anchor held unmoved. At * `0df67f237`, re-read there 2026-10-11: @@ -2926,10 +2911,7 @@ export const ElementButtonPropsSchema = lazySchema(() => strictObject({ * the button. * * The key is LIVE at the objectui pin this repo builds against - * (`.objectui-sha` = `088e0f705`, re-read there 2026-10-12: - * every objectui file this record cites is byte-identical across the hop from - * `499799502` (`git diff --quiet`), so every anchor held unmoved. At - * `499799502`, re-read there 2026-10-11: + * (`.objectui-sha` = `499799502`, re-read there 2026-10-11: * every objectui file this record cites is byte-identical across the hop from * `0df67f237` (`git diff --quiet`), so every anchor held unmoved. At * `0df67f237`, re-read there 2026-10-11: @@ -3404,10 +3386,7 @@ 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` = `088e0f705`, re-read there 2026-10-12: - * every objectui file this record cites is byte-identical across the hop from - * `499799502` (`git diff --quiet`), so every anchor held unmoved. At - * `499799502`, re-read there 2026-10-11: + * against, `.objectui-sha` = `499799502`, re-read there 2026-10-11: * every objectui file this record cites is byte-identical across the hop from * `0df67f237` (`git diff --quiet`), so every anchor held unmoved. At * `0df67f237`, re-read there 2026-10-11: @@ -3977,10 +3956,7 @@ export type ActionIconPropsParsed = z.infer; * inventory. A member's `params` is its `ActionParam[]` input list: both * containers forward an array as `actionParams` (group `:346-348`, menu * `:270-272`, re-read at the pin this repo builds against, `.objectui-sha` = - * `088e0f705`, 2026-10-12: `action-group.tsx`, `action-menu.tsx` and - * `static-params.ts` are byte-identical across the hop from `499799502` (`git - * diff --quiet`), so both held unmoved; at `499799502`, 2026-10-11: - * `action-group.tsx`, `action-menu.tsx` and + * `499799502`, 2026-10-11: `action-group.tsx`, `action-menu.tsx` and * `static-params.ts` are byte-identical across the hop from `0df67f237` (`git * diff --quiet`), so both held unmoved; at `0df67f237`, 2026-10-11: * `action-group.tsx`, `action-menu.tsx` and @@ -4674,18 +4650,7 @@ const GridOperationsSchema = lazySchema(() => strictObject({ * control `schema.editable` in `ObjectGrid.tsx`. It was declared ahead of its * reader on purpose (the BUILD objectui#11068 chose), and its describe carried * the `[EXPERIMENTAL — not enforced]` marker that said so. Re-measured at the - * pin this repo builds against (`.objectui-sha` = `088e0f705`, re-read there 2026-10-12: - * `ObjectGrid.tsx` (+27/-11: objectui#12143's grouped-pager button names and - * objectui#12110 item 1's column-label override, objectui `2381c07f3` and - * `5330038f4`) and `data-table.tsx` (+12/-1: objectui#12124's pager names, - * objectui `dc6d28e86`) changed across the hop from `499799502`, none of it a - * `keyboardNavigation` line; the read MOVED `5615` -> `5631` with its line - * byte-identical. Re-counted with `git grep keyboardNavigation` under objectui - * `packages/` and `apps/` outside test files, CHANGELOGs, READMEs and - * `packages/types`, the same filter at both pins finds the same 14 lines - * (one fewer than the 15 recorded below, a difference of filter, not of the - * tree), against 3 for the control `schema.editable` in `ObjectGrid.tsx`. At - * `499799502`, re-read there 2026-10-11: + * pin this repo builds against (`.objectui-sha` = `499799502`, re-read there 2026-10-11: * `ObjectGrid.tsx` changed across the hop from `0df67f237` (+89/-44: * objectui#12081 item 3, objectui `69bca0af6`, and objectui#12082, objectui * `752504520`) and `data-table.tsx` is byte-identical (`git diff --quiet`); the @@ -4810,12 +4775,7 @@ export const ObjectGridPropsSchema = lazySchema(() => strictObject({ * same members, and objectui's grid follows this declaration. * * ⚠️ That gap is closed at the pin this repo builds against (`.objectui-sha` - * = `088e0f705`, re-read there 2026-10-12: - * `ObjectGrid.tsx` changed across the hop from `499799502` (+27/-11: - * objectui#12143 and objectui#12110 item 1), every hunk above both reads (the - * last at `:6576`, the grouped pager's last button), so both MOVED by 16 with - * their lines byte-identical: `6632-6633` -> `6648-6649`, `6649-6650` -> - * `6665-6666`. At `499799502`, re-read there 2026-10-11: + * = `499799502`, re-read there 2026-10-11: * `ObjectGrid.tsx` changed across the hop from `0df67f237` (+89/-44: * objectui#12081 item 3 and objectui#12082), every hunk above both reads * (the last at `:5321-5343`), so both MOVED by 45 with their lines @@ -5218,16 +5178,7 @@ export const ObjectGridPropsSchema = lazySchema(() => strictObject({ * `ComponentPropsMap` key. This record said to drop the marker in the change * that lands the BUILD at the pin, and it is dropped here. * - * Read at the pin this repo builds against (`.objectui-sha` = `088e0f705`, re-read there 2026-10-12: - * `ObjectGrid.tsx` (+27/-11: objectui#12143 and objectui#12110 item 1) and - * `data-table.tsx` (+12/-1: objectui#12124's pager button names) changed - * across the hop from `499799502`, none of it in the arrow-key handling, so - * all seven anchors MOVED with their lines byte-identical — grid `5615` -> - * `5631`, `1851` -> `1857`; table `1018` -> `1025`, `2607` -> `2614`, `3101` - * -> `3108`, `2257` -> `2264`, `2283` -> `2290`; no hunk lands between the - * viewer's write verdict `objectInlineEditable` (`:1833`) and `:1857`, so - * `inlineEditable` is still the authored `editable` AND that verdict. At - * `499799502`, re-read there 2026-10-11: + * Read at the pin this repo builds against (`.objectui-sha` = `499799502`, re-read there 2026-10-11: * `ObjectGrid.tsx` changed across the hop from `0df67f237` (+89/-44: * objectui#12081 item 3 and objectui#12082) and `data-table.tsx` is * byte-identical (`git diff --quiet`), so the five `data-table.tsx` anchors @@ -5668,10 +5619,7 @@ 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` = `088e0f705`, re-read there 2026-10-12: - * every objectui file this record cites is byte-identical across the hop from - * `499799502` (`git diff --quiet`), so every anchor held unmoved. At - * `499799502`, re-read there 2026-10-11: + * (`.objectui-sha` = `499799502`, re-read there 2026-10-11: * every objectui file this record cites is byte-identical across the hop from * `0df67f237` (`git diff --quiet`), so every anchor held unmoved. At * `0df67f237`, re-read there 2026-10-11: @@ -5931,10 +5879,7 @@ const ObjectKanbanLaneSchema = lazySchema(() => strictObject({ * 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` = `088e0f705`, re-read there 2026-10-12: - * every objectui file this record cites is byte-identical across the hop from - * `499799502` (`git diff --quiet`), so every anchor held unmoved. At - * `499799502`, re-read there 2026-10-11: + * (`.objectui-sha` = `499799502`, re-read there 2026-10-11: * every objectui file this record cites is byte-identical across the hop from * `0df67f237` (`git diff --quiet`), so every anchor held unmoved. At * `0df67f237`, re-read there 2026-10-11: @@ -6055,10 +6000,7 @@ 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` = `088e0f705`, re-read there 2026-10-12: - * every objectui file this record cites is byte-identical across the hop from - * `499799502` (`git diff --quiet`), so every anchor held unmoved. At - * `499799502`, re-read there 2026-10-11: + * repo builds against (`.objectui-sha` = `499799502`, re-read there 2026-10-11: * every objectui file this record cites is byte-identical across the hop from * `0df67f237` (`git diff --quiet`), so every anchor held unmoved. At * `0df67f237`, re-read there 2026-10-11: @@ -6351,10 +6293,7 @@ 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` = `088e0f705`, re-read there 2026-10-12: - * every objectui file this record cites is byte-identical across the hop from - * `499799502` (`git diff --quiet`), so every anchor held unmoved. At - * `499799502`, re-read there 2026-10-11: + * (`.objectui-sha` = `499799502`, re-read there 2026-10-11: * every objectui file this record cites is byte-identical across the hop from * `0df67f237` (`git diff --quiet`), so every anchor held unmoved; * `ObjectKanban.tsx` still names `quickAdd` and `onQuickAdd` 2 times each @@ -6576,9 +6515,6 @@ export const ObjectKanbanPropsSchema = lazySchema(() => strictObject({ * element schemas). * * Measured at the pin this repo builds against (`.objectui-sha` = - * `088e0f705`, re-read there 2026-10-12: - * every objectui file this record cites is byte-identical across the hop from - * `499799502` (`git diff --quiet`), so every anchor held unmoved. At * `499799502`, re-read there 2026-10-11: * every objectui file this record cites is byte-identical across the hop from * `0df67f237` (`git diff --quiet`), so every anchor held unmoved. At @@ -6808,9 +6744,6 @@ export const ObjectCalendarPropsSchema = lazySchema(() => strictObject({ * `object-kanban`'s above. * * Measured at the pin this repo builds against (`.objectui-sha` = - * `088e0f705`, re-read there 2026-10-12: - * every objectui file this record cites is byte-identical across the hop from - * `499799502` (`git diff --quiet`), so every anchor held unmoved. At * `499799502`, re-read there 2026-10-11: * every objectui file this record cites is byte-identical across the hop from * `0df67f237` (`git diff --quiet`), so every anchor held unmoved. At @@ -8037,10 +7970,7 @@ 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` = `088e0f705`, re-read there 2026-10-12: - * every objectui file this record cites is byte-identical across the hop from - * `499799502` (`git diff --quiet`), so every anchor held unmoved. At - * `499799502`, re-read there 2026-10-11: + * `.objectui-sha` = `499799502`, re-read there 2026-10-11: * every objectui file this record cites is byte-identical across the hop from * `0df67f237` (`git diff --quiet`), so every anchor held unmoved. At * `0df67f237`, re-read there 2026-10-11: @@ -8241,10 +8171,7 @@ 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` = `088e0f705`, re-read there 2026-10-12: - * every objectui file this record cites is byte-identical across the hop from - * `499799502` (`git diff --quiet`), so every anchor held unmoved. At - * `499799502`, re-read there 2026-10-11: + * pin this repo builds against (`.objectui-sha` = `499799502`, re-read there 2026-10-11: * every objectui file this record cites is byte-identical across the hop from * `0df67f237` (`git diff --quiet`), so every anchor held unmoved. At * `0df67f237`, re-read there 2026-10-11: @@ -8324,10 +8251,7 @@ 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` = `088e0f705`, re-read there 2026-10-12: - * every objectui file this record cites is byte-identical across the hop from - * `499799502` (`git diff --quiet`), so every anchor held unmoved. At - * `499799502`, re-read there 2026-10-11: + * (`.objectui-sha` = `499799502`, re-read there 2026-10-11: * every objectui file this record cites is byte-identical across the hop from * `0df67f237` (`git diff --quiet`), so every anchor held unmoved. At * `0df67f237`, re-read there 2026-10-11: @@ -8529,10 +8453,7 @@ function objectGanttMarker() { /** * `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` = `088e0f705`, re-read there 2026-10-12: - * every objectui file this record cites is byte-identical across the hop from - * `499799502` (`git diff --quiet`), so every anchor held unmoved. At - * `499799502`, re-read there 2026-10-11: + * — `.objectui-sha` = `499799502`, re-read there 2026-10-11: * `record-source.ts`, `plugin-gantt/src/index.tsx` and `ListView.tsx` are * byte-identical across the hop from `0df67f237` (`git diff --quiet`), so every * anchor in them held unmoved; `ObjectGantt.tsx` +27/-4 changed for @@ -8806,10 +8727,7 @@ export type ObjectGanttPropsParsed = z.infer; * they flatten `options.tree` (`ListView.tsx:4120-4144`, `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` = `088e0f705`, re-read there 2026-10-12: - * every objectui file this record cites is byte-identical across the hop from - * `499799502` (`git diff --quiet`), so every anchor held unmoved. At - * `499799502`, re-read there 2026-10-11: + * pin this repo builds against (`.objectui-sha` = `499799502`, re-read there 2026-10-11: * every objectui file this record cites is byte-identical across the hop from * `0df67f237` (`git diff --quiet`), so every anchor held unmoved. At * `0df67f237`, re-read there 2026-10-11: @@ -8957,10 +8875,7 @@ 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` = `088e0f705`, re-read there 2026-10-12: - * every objectui file this record cites is byte-identical across the hop from - * `499799502` (`git diff --quiet`), so every anchor held unmoved. At - * `499799502`, re-read there 2026-10-11: + * — `.objectui-sha` = `499799502`, re-read there 2026-10-11: * every objectui file this record cites is byte-identical across the hop from * `0df67f237` (`git diff --quiet`), so every anchor held unmoved. At * `0df67f237`, re-read there 2026-10-11: @@ -9159,10 +9074,7 @@ 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` = `088e0f705`, re-read there 2026-10-12: - * every objectui file this record cites is byte-identical across the hop from - * `499799502` (`git diff --quiet`), so every anchor held unmoved. At - * `499799502`, re-read there 2026-10-11: + * builds against (`.objectui-sha` = `499799502`, re-read there 2026-10-11: * re-COUNTED by the same method, 0 for the tree, 3 each for `plugin-gantt`, * `plugin-grid` and `plugin-calendar` and 4 for `plugin-map`, all five * shells byte-identical across the hop from `0df67f237` (`git diff @@ -9573,10 +9485,7 @@ function objectTimelineItemsFitVariant() { * `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` = `088e0f705`, re-read there 2026-10-12: - * every objectui file this record cites is byte-identical across the hop from - * `499799502` (`git diff --quiet`), so every anchor held unmoved. At - * `499799502`, re-read there 2026-10-11: + * repo builds against (`.objectui-sha` = `499799502`, re-read there 2026-10-11: * every objectui file this record cites is byte-identical across the hop from * `0df67f237` (`git diff --quiet`), so every anchor held unmoved. At * `0df67f237`, re-read there 2026-10-11: @@ -9836,9 +9745,6 @@ 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` = - * `088e0f705`, re-read there 2026-10-12: - * every objectui file this record cites is byte-identical across the hop from - * `499799502` (`git diff --quiet`), so every anchor held unmoved. At * `499799502`, re-read there 2026-10-11: * every objectui file this record cites is byte-identical across the hop from * `0df67f237` (`git diff --quiet`), so every anchor held unmoved. At @@ -10205,9 +10111,6 @@ 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` = - // `088e0f705`, re-read there 2026-10-12: - // every objectui file this record cites is byte-identical across the hop from - // `499799502` (`git diff --quiet`), so every anchor held unmoved. At // `499799502`, re-read there 2026-10-11: // every objectui file this record cites is byte-identical across the hop from // `0df67f237` (`git diff --quiet`), so every anchor held unmoved. At @@ -10317,9 +10220,6 @@ 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` = - // `088e0f705`, re-read there 2026-10-12: - // every objectui file this record cites is byte-identical across the hop from - // `499799502` (`git diff --quiet`), so every anchor held unmoved. At // `499799502`, re-read there 2026-10-11: // `ObjectTree.tsx` and `ObjectMap.tsx` are byte-identical to `0df67f237` // (`git diff --quiet`); `ObjectGantt.tsx` (+27/-4) changed for objectui#12082 @@ -10410,9 +10310,6 @@ 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` = - // `088e0f705`, re-read there 2026-10-12: - // every objectui file this record cites is byte-identical across the hop from - // `499799502` (`git diff --quiet`), so every anchor held unmoved. At // `499799502`, re-read there 2026-10-11: // every objectui file this record cites is byte-identical across the hop from // `0df67f237` (`git diff --quiet`), so every anchor held unmoved. At diff --git a/packages/spec/src/ui/dataset.zod.ts b/packages/spec/src/ui/dataset.zod.ts index b769ad37d3f..72928729c88 100644 --- a/packages/spec/src/ui/dataset.zod.ts +++ b/packages/spec/src/ui/dataset.zod.ts @@ -283,9 +283,6 @@ 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` = - * `088e0f705`, re-read there 2026-10-12: - * every objectui file this record cites is byte-identical across the hop from - * `499799502` (`git diff --quiet`), so every anchor held unmoved. At * `499799502`, re-read there 2026-10-11: * every objectui file this record cites is byte-identical across the hop from * `0df67f237` (`git diff --quiet`), so every anchor held unmoved. At diff --git a/packages/spec/src/ui/view.zod.ts b/packages/spec/src/ui/view.zod.ts index 71b9fe85d48..2fe8f9026c3 100644 --- a/packages/spec/src/ui/view.zod.ts +++ b/packages/spec/src/ui/view.zod.ts @@ -3429,18 +3429,7 @@ 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` = `088e0f705`, re-read there 2026-10-12: - * `autoLayout.ts` and `fields`' `field-type-alias.ts` are byte-identical to - * `499799502` (`git diff --quiet`), so `resolveColSpan` `:154`, - * `WIDE_FIELD_TYPES` `:58-69` and the `repeater` -> `field:grid` mapping held - * unmoved, and `form.tsx` changed on this hop — 231 insertions, 79 deletions: - * objectui#12130 (`step` / `className`, objectui `d2500d8be`), objectui#12155 - * (a field-level `defaultValue` is no longer drawn, `f3d540814`), - * objectui#12110 (`5330038f4`) and PR-5's registry-ref widgets - * (`088e0f705`) — none of it inside `spanLadderFor`, which MOVED `:274-301` - * -> `:275-302` byte-identical, and its one call site MOVED `:3258` -> - * `:3329` with the call byte-identical, so it still emits the ladder. At - * `499799502`, re-read there 2026-10-11: + * (`.objectui-sha` = `499799502`, re-read there 2026-10-11: * `autoLayout.ts` and `fields`' `field-type-alias.ts` are byte-identical to * `0df67f237` (`git diff --quiet`), so `resolveColSpan` `:154`, * `WIDE_FIELD_TYPES` `:58-69` and the `repeater` -> `field:grid` mapping held @@ -3543,7 +3532,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` = `088e0f705520`), 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` = `4997995022f8`), 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 746c7553b1d..9089e121ea0 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": "088e0f705520e82bee1d65a5fa3c1f7a26672dde", + "objectuiSha": "4997995022f8e65946f6362b7434685539cc72b7", "source": "built-tree", - "modulesRoot": ".cache/objectui-088e0f705520/apps/console", + "modulesRoot": ".cache/objectui-4997995022f8/apps/console", "objectuiWorkspaceVersion": "17.7.0", "generator": "scripts/gen-sdui-manifest-node.mjs", - "generatedAt": "2026-10-12", - "sha256": "a799c55a18d6854faaffbf3eee8a959bf142e12109cee62890de46a327fe4db4", + "generatedAt": "2026-10-11", + "sha256": "9d87162a3ef60676c6aed69ecf2703693bdbbf66d5ef798c9d770f3112f86217", "components": 107 } diff --git a/sdui.manifest.json b/sdui.manifest.json index 10fefd454a1..a335e13646f 100644 --- a/sdui.manifest.json +++ b/sdui.manifest.json @@ -1712,7 +1712,7 @@ { "name": "showCompleted", "type": "boolean", - "description": "Include completed activities (sys_activity type \"completed\", which surfaces as a task item). Off by default. A milestone row (metadata.kind \"milestone\") is not a completed activity and shows either way." + "description": "Include completed activities (sys_activity type \"completed\", which surfaces as a task item). Off by default." }, { "name": "unifiedTimeline",