From a3bc0f61761e1ceacaf09dc9fa1cc7bb12087d6c Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 19 Oct 2026 07:36:00 +0000 Subject: [PATCH 01/13] chore: bump objectstack to 2ec6827962ac feat(metadata-protocol): the draft save records draftChanges per key path; the save declares its surface (?surface=studio|api, copilot in-process only) (#24418) objectstack@2ec6827962ac95a7bdbdad413fd74f65ca238e07 Moved with scripts/bump-objectstack.sh. pnpm install left pnpm-lock.yaml unchanged: the seven pinned packages declare the same dependencies. Claude-Session: https://claude.ai/code/session_0188TsgPV8kQXfuRuKmkj2ks Co-authored-by: Claude --- .objectstack-sha | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.objectstack-sha b/.objectstack-sha index f928c13fd3..0b15ee08ca 100644 --- a/.objectstack-sha +++ b/.objectstack-sha @@ -1 +1 @@ -2c9bf9430a1198bfaa5c0de9ff4a811838c6869c +2ec6827962ac95a7bdbdad413fd74f65ca238e07 From 054467eed02f259aeaae99c04dc1b5d2732ddb6b Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 19 Oct 2026 08:22:13 +0000 Subject: [PATCH 02/13] feat(types,components): follow the page checks and the action row patch retirement at the new pin - @object-ui/types attaches the spec's checkPageMainRegionWidth on both page nodes beside checkPageRegionPlacement, and checkPageRecordBindingPlacement on the page-kind node only (it reads the kind from type, like checkPageDefaultPlacement); the census accounts for both. - The two passing-keys fixtures stop authoring width 'large' on main. - action:button and action:icon stop publishing the row patch input the spec retired; the operation input says the row runs its named action. - The layout guide says a main region takes only width 'full'. Claude-Session: https://claude.ai/code/session_0188TsgPV8kQXfuRuKmkj2ks Co-authored-by: Claude --- content/docs/guide/layout.md | 6 ++ .../validate-passing-keys-11440.test.ts | 2 +- .../src/renderers/action/action-button.tsx | 11 +-- .../src/renderers/action/action-icon.tsx | 11 +-- .../__tests__/passing-keys-arms-11440.test.ts | 2 +- .../spec-object-refinements-7715.test.ts | 76 ++++++++++++++++++- packages/types/src/zod/layout.zod.ts | 52 +++++++++---- 7 files changed, 127 insertions(+), 33 deletions(-) diff --git a/content/docs/guide/layout.md b/content/docs/guide/layout.md index 48312a4406..ec33323544 100644 --- a/content/docs/guide/layout.md +++ b/content/docs/guide/layout.md @@ -293,6 +293,12 @@ grow: `utility` is the narrowest and suits settings and forms, `record` (the def } ``` +A page laid out in `regions` can drop the cap altogether: a `main` region declared +`width: 'full'` makes the page full-bleed. That is the only `width` a `main` region takes. +The template decides how wide `main` is (the space `sidebar` and `aside` leave, or one grid +cell on `dashboard`), so `'small'`, `'medium'` and `'large'` on `main` are refused at that +region's `width`, as `@objectstack/spec` refuses them. Other regions keep all four values. + `pageType` is more than a width. A `record` page leaves its heading to a `page:header` block, so a `title` on a page with no `pageType` draws no heading. That is one more reason the settings page above says `utility`. diff --git a/packages/cli/src/__tests__/validate-passing-keys-11440.test.ts b/packages/cli/src/__tests__/validate-passing-keys-11440.test.ts index 69b87d9f13..a52f151684 100644 --- a/packages/cli/src/__tests__/validate-passing-keys-11440.test.ts +++ b/packages/cli/src/__tests__/validate-passing-keys-11440.test.ts @@ -95,7 +95,7 @@ describe('objectui validate — the documents objectui#11440 arms', () => { kind: 'full', regions: [ { name: 'header', width: 'full', components: [{ type: 'page:header', properties: { title: 'Welcome to the CRM' } }] }, - { name: 'main', width: 'large', components: [{ type: 'element:text', properties: { content: 'A sample page.' } }] }, + { name: 'main', components: [{ type: 'element:text', properties: { content: 'A sample page.' } }] }, ], }); expect(text).not.toContain('Schema validation failed'); diff --git a/packages/components/src/renderers/action/action-button.tsx b/packages/components/src/renderers/action/action-button.tsx index 354e1a84dc..c33c0d9c0c 100644 --- a/packages/components/src/renderers/action/action-button.tsx +++ b/packages/components/src/renderers/action/action-button.tsx @@ -580,18 +580,15 @@ ComponentRegistry.register('button', ActionButtonRenderer, { description: 'How an `api` action shapes its request body: `flat` (the default) or `{ wrap: KEY }` to nest the collected values under that key, with `bodyExtra` beside it', }, + // objectui#12971: no `patch` input. `@objectstack/spec` retired a row's own + // `patch` (objectstack#24394): the row runs the declared action its `name` + // names, and the route writes THAT action's `patch`. { name: 'operation', type: 'enum', enum: ['update'], description: - '`update` declares a single-record field write: the runner dispatches it to the platform action route with `patch` merged under the collected values', - }, - { - name: 'patch', - type: 'object', - description: - 'For `operation: update`: the field values written, merged UNDER the values the user supplies, so a collected value of the same name wins', + '`update` declares a single-record field write: the row runs the declared action its `name` names, so it needs a `name`. The runner posts the collected values to the platform action route under that name, and the route writes that action\'s own `patch`', }, { name: 'confirmText', diff --git a/packages/components/src/renderers/action/action-icon.tsx b/packages/components/src/renderers/action/action-icon.tsx index 56ef0aa375..3d2ba2a96c 100644 --- a/packages/components/src/renderers/action/action-icon.tsx +++ b/packages/components/src/renderers/action/action-icon.tsx @@ -411,18 +411,15 @@ ComponentRegistry.register('icon', ActionIconRenderer, { description: 'How an `api` action shapes its request body: `flat` (the default) or `{ wrap: KEY }` to nest the collected values under that key, with `bodyExtra` beside it', }, + // objectui#12971: no `patch` input. `@objectstack/spec` retired a row's own + // `patch` (objectstack#24394): the row runs the declared action its `name` + // names, and the route writes THAT action's `patch`. { name: 'operation', type: 'enum', enum: ['update'], description: - '`update` declares a single-record field write: the runner dispatches it to the platform action route with `patch` merged under the collected values', - }, - { - name: 'patch', - type: 'object', - description: - 'For `operation: update`: the field values written, merged UNDER the values the user supplies, so a collected value of the same name wins', + '`update` declares a single-record field write: the row runs the declared action its `name` names, so it needs a `name`. The runner posts the collected values to the platform action route under that name, and the route writes that action\'s own `patch`', }, { name: 'confirmText', diff --git a/packages/types/src/__tests__/passing-keys-arms-11440.test.ts b/packages/types/src/__tests__/passing-keys-arms-11440.test.ts index c10b25d44e..41a8fa56a6 100644 --- a/packages/types/src/__tests__/passing-keys-arms-11440.test.ts +++ b/packages/types/src/__tests__/passing-keys-arms-11440.test.ts @@ -80,7 +80,7 @@ const specPage = (kind: string) => ({ kind: 'full', regions: [ { name: 'header', width: 'full', components: [{ type: 'page:header', properties: { title: 'Welcome' } }] }, - { name: 'main', width: 'large', components: [{ type: 'element:text', properties: { content: 'Hello' } }] }, + { name: 'main', components: [{ type: 'element:text', properties: { content: 'Hello' } }] }, ], }); diff --git a/packages/types/src/__tests__/spec-object-refinements-7715.test.ts b/packages/types/src/__tests__/spec-object-refinements-7715.test.ts index ef54378953..5d7737c10a 100644 --- a/packages/types/src/__tests__/spec-object-refinements-7715.test.ts +++ b/packages/types/src/__tests__/spec-object-refinements-7715.test.ts @@ -235,6 +235,72 @@ describe('objectui#12626 — the Page `isDefault` placement refusal reaches the }); }); +describe('objectui#12971 — the Page `main` region width refusal reaches objectui on both page nodes', () => { + const region = (name: string, width?: string) => ({ name, ...(width === undefined ? {} : { width }), components: [] }); + + it.each([ + ['`large` on `main`', { regions: [region('main', 'large')] }, 'regions.0.width'], + ['`small` on a `Main` region (names match case-insensitively)', { regions: [region('header'), region('Main', 'small')] }, 'regions.1.width'], + ['`medium` on `main` of a `dashboard` page', { template: 'dashboard', regions: [region('main', 'medium')] }, 'regions.0.width'], + ])('%s: the spec refuses it, and objectui refuses with the spec\'s own issue on both page nodes', (_label, extra, at) => { + const spec = SpecPageSchema.safeParse(specPage(extra)); + expect(spec.success).toBe(false); + const specIssue = spec.error!.issues.find((i) => i.path.join('.') === at); + expect(specIssue?.code).toBe('custom'); + + const kindNode = { ...extra, type: 'home' }; + for (const r of [PageNodeSchema.safeParse(pageNode(extra)), safeValidateSchema(pageNode(extra)), safeValidateSchema(kindNode)]) { + expect(r.success).toBe(false); + const issues = r.error!.issues.map((i) => ({ code: i.code, path: i.path.join('.'), message: i.message })); + expect(issues).toContainEqual({ code: 'custom', path: at, message: specIssue!.message }); + } + }); + + it('controls: `full` on `main`, no `width` on `main`, and `large` on another region pass on the spec and both page nodes', () => { + for (const extra of [ + { regions: [region('main', 'full')] }, + { regions: [region('main')] }, + { regions: [region('main'), region('aside', 'large')] }, + ]) { + expect(SpecPageSchema.safeParse(specPage(extra)).success).toBe(true); + expect(PageNodeSchema.safeParse(pageNode(extra)).success).toBe(true); + expect(safeValidateSchema(pageNode(extra)).success).toBe(true); + expect(safeValidateSchema({ ...extra, type: 'home' }).success).toBe(true); + } + }); +}); + +describe('objectui#12971 — the Page `record` binding placement refusal reaches the page-kind node, and only there', () => { + const record = { object: 'account' }; + + it.each([ + ['a `home` page', { type: 'home', record }], + ['a `utility` page', { type: 'utility', record }], + ['a `record` page bound to an object', { type: 'record', object: 'account', record }], + ])('%s with a `record` binding: the spec refuses at `record`, and the kind node refuses with the spec\'s own issue', (_label, extra) => { + const spec = SpecPageSchema.safeParse(specPage(extra)); + expect(spec.success).toBe(false); + const specIssue = spec.error!.issues.find((i) => i.path.join('.') === 'record'); + expect(specIssue?.code).toBe('custom'); + + const r = safeValidateSchema(extra); + expect(r.success).toBe(false); + expect(r.error!.issues.map((i) => ({ code: i.code, path: i.path.join('.'), message: i.message }))) + .toContainEqual({ code: 'custom', path: 'record', message: specIssue!.message }); + }); + + it('controls: an `app` page with a `record` binding passes the spec, a kind page without one passes the kind node, and the `page` node does not judge it', () => { + expect(SpecPageSchema.safeParse(specPage({ type: 'app', record })).success).toBe(true); + expect(safeValidateSchema({ type: 'home' }).success).toBe(true); + // The `page` node's `type` is the discriminator and the kind lives on `pageType`, + // so the check is not attached there: a `record` binding on it is not refused at `record`. + for (const extra of [{ pageType: 'app', record }, { record }]) { + const r = PageNodeSchema.safeParse(pageNode(extra)); + expect(r.success, JSON.stringify(r.error?.issues)).toBe(true); + } + }); +}); + // ── The census: every object-level check the spec runs is accounted for ───── /** @@ -283,11 +349,15 @@ const SITES = [ // `checkPageRegionPlacement` joined at 18.0.0-next.2 and was attached by objectui#12626: it // reads `kind` and `template` (by reference) and each region's `name`, which objectui's own // region carries with the meaning `page.tsx` places it by; measured in its describe block above. + // `checkPageMainRegionWidth` joined after 18.0.0-next.3 (objectstack#24326) and was attached + // by objectui#12971: it reads each region's `name` and `width`, which objectui's own region + // carries with the meaning `page.tsx` reads them by; measured in its describe block above. attached: [ 'checkPageSourceCompleteness', 'checkPageRequiresKind', 'checkPageSlotPair', 'checkPageRegionPlacement', + 'checkPageMainRegionWidth', ], // `checkPagePrintComposition` joined at 18 (the `print` page, ruling B′ on objectstack#8346). // It reads `type` and `regions`, and this node carries NEITHER by reference: both are in @@ -298,7 +368,11 @@ const SITES = [ // `type`, which on this node is the component discriminator `'page'`, so attached it would // refuse every `isDefault`; `PageKindNodeSchema`, whose `type` is the page kind, attaches it // (objectui#12626, measured in its describe block above). - notAttachable: ['checkPagePrintComposition', 'checkPageDefaultPlacement'], + // `checkPageRecordBindingPlacement` joined after 18.0.0-next.3 (objectstack#24275). It judges + // `record` by the page's `type` the same way, so attached here it would refuse every `record`, + // a `pageType: 'app'` page's included; `PageKindNodeSchema` attaches it (objectui#12971, + // measured in its describe block above). + notAttachable: ['checkPagePrintComposition', 'checkPageDefaultPlacement', 'checkPageRecordBindingPlacement'], }, { site: 'ListViewSchema (objectql.zod.ts)', diff --git a/packages/types/src/zod/layout.zod.ts b/packages/types/src/zod/layout.zod.ts index 1c0186e21f..1e46e7fa45 100644 --- a/packages/types/src/zod/layout.zod.ts +++ b/packages/types/src/zod/layout.zod.ts @@ -23,6 +23,8 @@ import { PageTypeSchema as SpecPageTypeSchema, PageVariableSchema as SpecPageVariableSchema, checkPageDefaultPlacement, + checkPageMainRegionWidth, + checkPageRecordBindingPlacement, checkPageRegionPlacement, checkPageRequiresKind, checkPageSlotPair, @@ -1368,29 +1370,41 @@ export const PageNodeSchema = BaseSchema.extend(SpecPageFields.shape).extend({ // does not place: on a page that names a slotted template it is drawn // nowhere and the page shows a refusal (objectui#12476); on a page that // names no template it is still stacked under `main`. - // The spec's `PageSchema` carries six on objectstack `main` (the installed - // 18.0.0-next.2 still carries the removed one below); these four are attached as-is: the first - // three read `kind`, `source`, `requires` and `slots`, which this node carries - // by reference — none is in {@link PAGE_SPEC_EXCLUDED} nor overridden above. + // - a region named `main` (case-insensitively) with `width` `'small'`, + // `'medium'` or `'large'` is refused at `regions.N.width`, because no + // layout reads `main.width` except `'full'`, which lifts the page's + // max-width cap (`checkPageMainRegionWidth`, objectstack#24326; attached + // by objectui#12971). It reads each region's `name` and `width`, which + // this node's own {@link PageNodeRegionSchema} carries with the same + // meaning: `page.tsx` places `main` by its lowercased `name` and reads its + // `width` only for `'full'`. + // The checks listed above are attached as-is: the first three read `kind`, + // `source`, `requires` and `slots`, which this node carries by reference — + // none is in {@link PAGE_SPEC_EXCLUDED} nor overridden above. // The page-parse judge of a view-data component's retired `api` binding is no // longer among them: objectstack#23784 removed it from the spec, which now // leaves that verdict to the component-props lint rule at the save door // (`validateComponentProps`, `@objectstack/lint`). So a slotted block naming // `api` passes here, as it passes the spec's own `PageSchema`; a region // block is still refused by its arm in the component union (measured in - // `__tests__/page-component-view-data-12666.test.ts`). The fifth, `checkPagePrintComposition`, + // `__tests__/page-component-view-data-12666.test.ts`). `checkPagePrintComposition` // reads `type` and `regions` as the PAGE's own, which this node does NOT carry - // by reference, so it is not attached; the census below records why. The - // sixth, `checkPageDefaultPlacement` (18.0.0-next.2), judges `isDefault` by - // the page's `type`, and on this node `type` is the component discriminator - // (`'page'`), so attached here it would refuse every `isDefault`; it is - // attached on {@link PageKindNodeSchema} below, whose `type` IS the page kind. + // by reference, so it is not attached; the census below records why. + // `checkPageDefaultPlacement` (18.0.0-next.2) judges `isDefault` by the page's + // `type`, and on this node `type` is the component discriminator (`'page'`), + // so attached here it would refuse every `isDefault`; it is attached on + // {@link PageKindNodeSchema} below, whose `type` IS the page kind. + // `checkPageRecordBindingPlacement` (objectstack#24275) refuses the page + // `record` binding on any page whose `type` is not `app`. It reads `type` the + // same way, so attached here it would refuse every `record`, a `pageType: + // 'app'` page's included; it is attached on the kind node only (objectui#12971). // `__tests__/spec-object-refinements-7715.test.ts` re-derives the count, so a // check the spec adds to `PageSchema` later reddens there. .superRefine(checkPageSourceCompleteness) .superRefine(checkPageRequiresKind) .superRefine(checkPageSlotPair) - .superRefine(checkPageRegionPlacement); + .superRefine(checkPageRegionPlacement) + .superRefine(checkPageMainRegionWidth); /** * The spec page KINDS a node may carry in `type` (objectui#11440): `record`, @@ -1438,10 +1452,11 @@ const { type: _pageNodeTypeLiteral, ...PAGE_NODE_MEMBERS } = PageNodeSchema.shap * member is {@link PageNodeSchema}'s own, by reference, and that node already * takes the spec's `PageSchema` fields by reference through * {@link SpecPageFields}. Its four refusals (`actions`, `breadcrumbs`, - * `maxWidth`, `padding`), the `body` refusal and the spec's four attachable + * `maxWidth`, `padding`), the `body` refusal and the spec's attachable * object-level checks (`source`, `requires` by `kind`, the `details` / - * `tabs` slot pair, and region placement by `template`) come with it. The spec's - * `isDefault` placement check is attached here only: it reads the page + * `tabs` slot pair, region placement by `template`, and the `main` region's + * `width`) come with it. The spec's `isDefault` placement check and its + * `record` binding placement check are attached here only: each reads the page * kind from `type`, which this node carries and the `page` node does not. `regions` stays the node's own * {@link PageNodeRegionSchema}, so each region component is judged by this * union at every depth, as on `page`. @@ -1454,9 +1469,14 @@ export const PageKindNodeSchema: PageKindNodeSchemaType = BaseSchema.extend({ type: PAGE_KIND_NODE_TYPE.describe('The spec page kind — `record`, `home` or `utility` (`@objectstack/spec` `PageTypeSchema`)'), }).superRefine(checkPageSourceCompleteness).superRefine(checkPageRequiresKind).superRefine(checkPageSlotPair) .superRefine(checkPageRegionPlacement) + .superRefine(checkPageMainRegionWidth) // On this node `type` is the spec page kind, the field the spec's - // `checkPageDefaultPlacement` judges `isDefault` by (objectui#12626). - .superRefine(checkPageDefaultPlacement); + // `checkPageDefaultPlacement` judges `isDefault` by (objectui#12626), and + // `checkPageRecordBindingPlacement` judges `record` by (objectui#12971): none + // of the three kinds is `app`, so a `record` binding is refused here, as the + // spec refuses it. + .superRefine(checkPageDefaultPlacement) + .superRefine(checkPageRecordBindingPlacement); /** * The TYPE of {@link PageKindNodeSchema}, written out BY REFERENCE to the From bbf5d4b78bddc57c9fd78c3bc4c0e56bd134e6d7 Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 19 Oct 2026 10:22:18 +0000 Subject: [PATCH 03/13] test(console,app-shell,types,plugin-tree): re-pin the spec facts the new objectstack pin moves - registry-inputs-spec-parity: list-view gains a ComponentPropsMap row and is judged (60 -> 61 carried, 40 -> 41 judged); record:json and marketplace:installed-list are retired upstream, so their ledger entries read RETIRED UPSTREAM; the two row patch tombstones are pinned by name and the patch member pin leaves with the input. - block-config: record:json is no longer a PageComponentType, so its palette exclusion goes. - record-highlights-layout-9187: the row gains emptyState. - ObjectTree.schemaTyped-8655: the list-view row declares navigation and tree. - action-button-icon-inputs-11168: patch leaves the published-key list. Claude-Session: https://claude.ai/code/session_0188TsgPV8kQXfuRuKmkj2ks Co-authored-by: Claude --- .../registry-inputs-spec-parity.test.ts | 45 ++++++++++++++++--- .../metadata-admin/previews/block-types.ts | 9 ++-- .../action-button-icon-inputs-11168.test.tsx | 8 +++- .../src/ObjectTree.schemaTyped-8655.test.ts | 14 ++++-- .../record-highlights-layout-9187.test.ts | 5 ++- 5 files changed, 61 insertions(+), 20 deletions(-) diff --git a/apps/console/src/__tests__/registry-inputs-spec-parity.test.ts b/apps/console/src/__tests__/registry-inputs-spec-parity.test.ts index f0d0920965..e71a4aa736 100644 --- a/apps/console/src/__tests__/registry-inputs-spec-parity.test.ts +++ b/apps/console/src/__tests__/registry-inputs-spec-parity.test.ts @@ -662,6 +662,22 @@ const MINOR_17_6_BLOCKS = ['record:line_items']; /** Does the spec this tree resolves carry the 17.6.0 set? `every`, for the reason `specCarriesGaBlocks` gives. */ const specCarries176Blocks = MINOR_17_6_BLOCKS.every((type) => type in ComponentPropsMap); +/** + * The one block the objectstack `main` pin after 18.0.0-next.3 newly carries + * (objectui#12971): the map went from 60 entries to 61 when `list-view` gained + * its row (objectstack#22444, landed as `194a42d1f7`), the list view's own + * schema. `@object-ui/plugin-list` registers it eagerly with `inputs`, so this + * file JUDGES it from that pin on. + * + * Same shape as `MINOR_17_6_BLOCKS`: this repo registered the block with + * `inputs` before the spec described it, so what moved at the bump is the + * SPEC's side. It enters `covered` the moment the installed spec carries it. + */ +const MINOR_18_MAIN_BLOCKS = ['list-view']; + +/** Does the spec this tree resolves carry the post-next.3 set? `every`, for the reason `specCarriesGaBlocks` gives. */ +const specCarries18MainBlocks = MINOR_18_MAIN_BLOCKS.every((type) => type in ComponentPropsMap); + const EXPECTED_COVERED = [ ...PINNED_EXPECTED_COVERED, ...LAZY_REGISTERED_BLOCKS, @@ -670,6 +686,7 @@ const EXPECTED_COVERED = [ ...(specCarries175Blocks ? MINOR_17_5_BLOCKS : []), ...(specCarries175LoadedBlocks ? MINOR_17_5_LOADED_BLOCKS : []), ...(specCarries176Blocks ? MINOR_17_6_BLOCKS : []), + ...(specCarries18MainBlocks ? MINOR_18_MAIN_BLOCKS : []), ].sort(); /** @@ -974,7 +991,7 @@ const UNJUDGED_SPEC_BLOCKS: Record = { 'global:notifications': 'EMPTY SPEC SHAPE. Same shape and same reasoning as `app:launcher` above: `app-shell/src/views/global-notifications-renderer.tsx` registers it propless because the spec shape is empty, and that registration is not in this file\'s import graph. objectui#8176.', 'marketplace:installed-list': - 'EMPTY SPEC SHAPE. New in `@objectstack/spec` 17.3.0, which declares it with no top-level key at all. Not registered here since objectui#12733: objectstack#23933 stopped serving the one page that rendered it, and the list that page led to is Setup → Packages filtered to Marketplace, whose rows carry its actions (`MarketplaceRowActions.installedAppsPins.test.tsx`). The empty shape is the load-bearing half either way; the spec retiring the type makes this entry RETIRED UPSTREAM. objectui#7122, objectui#12733, ledger objectui#8176.', + 'RETIRED UPSTREAM. Retired by name on the objectstack `main` pin after `@objectstack/spec` 18.0.0-next.3 (objectstack#24255, landed as `14a8bd2693`): out of `PageComponentType`, named in `RETIRED_PAGE_COMPONENT_TYPES`, and its row `retiredComponentProps` — a `never` that refuses every props bag, `{}` included, with a message that names Setup → Packages filtered to Marketplace as the Installed Apps list — so there is no authoring surface for either direction to judge. Until that pin it stood here as EMPTY SPEC SHAPE, unregistered since objectui#12733. objectui#12971, ledger objectui#8176.', 'mcp:connect-agent': 'EMPTY SPEC SHAPE. New in `@objectstack/spec` 17.3.0, which declares it with no top-level key at all. Registered propless by `@object-ui/app-shell` (`src/console/connect/ConnectAgentWidget.tsx`), outside this file\'s import graph; the empty shape is the load-bearing half either way. objectui#7122, ledger objectui#8176.', 'record:approval_decision': @@ -984,7 +1001,7 @@ const UNJUDGED_SPEC_BLOCKS: Record = { 'record:attachments': 'EMPTY SPEC SHAPE. New in `@objectstack/spec` 18 (objectui#12030), which declares it with no top-level key at all. Registered by `@object-ui/app-shell` (`src/views/record-attachments-renderer.tsx`), outside this file\'s import graph; the empty shape is the load-bearing half either way, exactly as for `app:launcher` above. objectui#12030, ledger objectui#8176.', 'record:json': - 'NOT REGISTERED, DELIBERATELY. New in `@objectstack/spec` 18.0.0-next.3 (objectstack#23745, landed as `97b8e7a51d`) for the approval request page\'s raw-payload panel, which objectui#12490 was to render. The maintainer then dropped that face (pointer 6232139151 on objectui#12490: no business need for an approver to read JSON), so no renderer is built, the served-page edit closed unmerged, and the type is filed for retirement upstream (objectstack#24162). Registering it forces this entry out; the spec retiring it makes this entry RETIRED UPSTREAM. objectui#12873, ledger objectui#8176.', + 'RETIRED UPSTREAM. Retired by name on the objectstack `main` pin after `@objectstack/spec` 18.0.0-next.3 (objectstack#24162, landed as `030a7b83e8`), the only release that declared it: out of `PageComponentType`, named in `RETIRED_PAGE_COMPONENT_TYPES`, and its row `retiredComponentProps` — a `never` that refuses every props bag, `{}` included — so there is no authoring surface for either direction to judge. Until that pin it stood here as NOT REGISTERED, DELIBERATELY: the maintainer dropped the approval request page\'s raw-payload panel it was declared for (pointer 6232139151 on objectui#12490). objectui#12873, objectui#12971, ledger objectui#8176.', // The fourth class, and the only one that is not mechanically "unjudgeable": // OWED. The 17.5.0 bump booked four blocks here — new in that spec, registered // with `registerLazy` by the console (`register-plugins.ts`) and not loaded by @@ -2701,7 +2718,8 @@ interface MemberPin { /** * The member pins objectui#11168 slice 1 registered for the array/object-armed - * keys `action:button` and `action:icon` publish. ONE file drives both blocks + * keys `action:button` and `action:icon` publish (`patch` left with the input, + * which the spec retired on a row, objectui#12971). ONE file drives both blocks * through the same rows (`describe.each`), so each key's claim is identical on * the two and is written once here; `actionLeafMemberPins` spells it out per * block, so every id below still names its block and its key. @@ -2719,8 +2737,6 @@ const ACTION_LEAF_MEMBER_CLAIMS: Record = { 'Members are request-body fields, merged into the body the runner\'s built-in `api` executor sends, LAST: a member overrides a static `properties.params` value of the same name while the other static values survive; without the key the body is the static values alone (objectui#11168 slice 1).', bodyShape: 'The `object` arm\'s one member is `wrap`: `{ wrap: \'data\' }` nests the static values under `data` with `bodyExtra` riding flat beside it, while `flat` and an absent key send the same flat body — asserted on the body the runner\'s built-in `api` executor sends (objectui#11168 slice 1).', - patch: - 'Members are field values for `operation: update`, merged UNDER the supplied values on the way to the write route (the `script` dispatch the runner hands an update to): a member the user also supplies loses, a member only `patch` carries is written, and the same `patch` without `operation` is merged by nothing (objectui#11168 slice 1).', locations: 'Members are placement names, read at dispatch by `@object-ui/core`\'s `createServerActionHandler` (the console\'s `script` handler is built on it): a list carrying a record-scoped member (`record_header`) refuses to run with no record or selection in scope — an error toast and no request — while an object-level list (`list_toolbar`) runs (objectui#11168 slice 1).', toast: @@ -4602,8 +4618,15 @@ describe('registry `inputs` vs `@objectstack/spec` ComponentPropsMap (repo-wide) // one new block, `record:json`, which this repo deliberately does not // register (its ledger entry says why), so it is ledgered (12 -> 13). // `judged` and `registeredPropless` do not move. 40 + 7 + 13 = 60. - specCarried: 60, - judged: 40, + // + // 60 -> 61 on the objectstack `main` pin after 18.0.0-next.3 + // (objectui#12971): one new row, `list-view`, registered eagerly with + // `inputs`, so it is judged (`MINOR_18_MAIN_BLOCKS`, 40 -> 41). The same + // pin retires `record:json` and `marketplace:installed-list`, whose rows + // stay as refusal doors and whose ledger entries now read RETIRED + // UPSTREAM, so `ledgeredUnjudgeable` does not move. 41 + 7 + 13 = 61. + specCarried: 61, + judged: 41, registeredPropless: 7, ledgeredUnjudgeable: 13, }); @@ -5285,6 +5308,14 @@ describe('registry `inputs` vs `@objectstack/spec` ComponentPropsMap (repo-wide) ['element:record_picker', 'filter'], ['element:record_picker', 'sort'], ['element:record_picker', 'limit'], + // Two more, harvested at the objectstack `main` pin after 18.0.0-next.3 + // (objectui#12971): objectstack#24394 retired a page action row's own + // `patch` (the row runs the declared action its `name` names, whose + // `patch` the route writes). These two were PUBLISHED, not exempted, so + // the forward direction is what turned red, and the registry stopped + // publishing them in the same change. + ['action:button', 'patch'], + ['action:icon', 'patch'], ]; for (const [type, key] of HARVESTED) { diff --git a/packages/app-shell/src/views/metadata-admin/previews/block-types.ts b/packages/app-shell/src/views/metadata-admin/previews/block-types.ts index f5562efbeb..98dbe3af69 100644 --- a/packages/app-shell/src/views/metadata-admin/previews/block-types.ts +++ b/packages/app-shell/src/views/metadata-admin/previews/block-types.ts @@ -240,12 +240,9 @@ export const PALETTE_EXCLUSIONS: Record = { 'record:approvals': 'renders (registered by `@object-ui/app-shell`), not yet offered: `@objectstack/spec` 18 added the type, and offering it in the palette is a Studio decision the version bump does not make', 'record:attachments': 'renders (registered by `@object-ui/app-shell`), not yet offered: `@objectstack/spec` 18 added the type, and offering it in the palette is a Studio decision the version bump does not make', 'record:approval_decision': 'renders (registered by `@object-ui/app-shell`), not yet offered: `@objectstack/spec` 18 added the type, and offering it in the palette is a Studio decision its registration does not make', - // - // `@objectstack/spec` 18.0.0-next.3 added `record:json` (objectstack#23745) for - // the approval request page's raw-payload panel. The maintainer dropped that - // face before objectui built it (objectui#12490), so nothing here registers - // the type, and it is filed for retirement upstream (objectstack#24162). - 'record:json': 'not rendered by objectui: `@objectstack/spec` 18.0.0-next.3 added it for a raw-payload panel the maintainer dropped (objectui#12490), so nothing registers it, and it is filed for retirement upstream (objectstack#24162)', + // `record:json` stood here from 18.0.0-next.3 until the spec retired it + // (objectstack#24162): it is no longer a `PageComponentType`, so it needs no + // exclusion (objectui#12971). }; /** diff --git a/packages/components/src/renderers/action/__tests__/action-button-icon-inputs-11168.test.tsx b/packages/components/src/renderers/action/__tests__/action-button-icon-inputs-11168.test.tsx index b06d79dfa2..eb2e54880d 100644 --- a/packages/components/src/renderers/action/__tests__/action-button-icon-inputs-11168.test.tsx +++ b/packages/components/src/renderers/action/__tests__/action-button-icon-inputs-11168.test.tsx @@ -79,10 +79,14 @@ import '../action-icon'; const BLOCKS = ['action:button', 'action:icon'] as const; type Block = (typeof BLOCKS)[number]; -/** The spec keys slice 1 published on both blocks. */ +/** + * The spec keys slice 1 published on both blocks. `patch` left the list when the + * spec retired a row's own `patch` (objectstack#24394) and the registry stopped + * publishing it (objectui#12971). + */ const LEAF_KEYS = [ 'visible', 'disabled', 'params', 'description', 'openIn', 'method', 'bodyExtra', 'bodyShape', - 'operation', 'patch', 'confirmText', 'successMessage', 'errorMessage', 'refreshAfter', + 'operation', 'confirmText', 'successMessage', 'errorMessage', 'refreshAfter', 'locations', 'toast', 'resultDialog', 'onSuccess', 'objectName', ]; diff --git a/packages/plugin-tree/src/ObjectTree.schemaTyped-8655.test.ts b/packages/plugin-tree/src/ObjectTree.schemaTyped-8655.test.ts index 1fe09889d3..c6fe50ec2f 100644 --- a/packages/plugin-tree/src/ObjectTree.schemaTyped-8655.test.ts +++ b/packages/plugin-tree/src/ObjectTree.schemaTyped-8655.test.ts @@ -402,11 +402,14 @@ describe('objectui#8655 — the spec has no element schema for this node', () => }); describe('objectui#8655 — `navigation` is objectui#8652\'s, its unlock HAS happened, and objectui#11168 mirrored it', () => { - it('the spec declares it on seven element entries since 17.5.0, this one included', () => { + it('the spec declares it on seven element entries since 17.5.0, this one included, and on the `list-view` row', () => { // Through 17.4.0: ONE entry, `object-grid`, and not this one. 17.5.0 met // objectui#8652's unlock criterion (objectui#11073); mirroring is that - // card's ruled second step. + // card's ruled second step. The spec after 18.0.0-next.3 gives `list-view` + // a `ComponentPropsMap` row (objectstack#22444), the list view's own + // schema, which carries the view-level `navigation` (objectui#12971). expect(specElementsDeclaring('navigation')).toEqual([ + 'list-view', 'object-calendar', 'object-gantt', 'object-grid', @@ -461,10 +464,13 @@ describe('objectui#8655 — `tree` was a VIEW-level block, and since 17.5.0 the expect(blockKeys).toEqual(['defaultExpandedDepth', 'fields', 'labelField', 'parentField']); }); - it('…and ONE element face declares a `tree` key since 17.5.0 — this node\'s (control: one key that IS on four)', () => { + it('…and ONE element face declares a `tree` key since 17.5.0 — this node\'s — beside the `list-view` row (control: one key that IS on four)', () => { // `[]` through 17.4.0. The premise this describe is named for expired at // the bump (objectui#11073): see the UPDATE note in this file's header. - expect(specElementsDeclaring('tree')).toEqual(['object-tree']); + // The `list-view` row the spec gained after 18.0.0-next.3 (objectstack#22444) + // is the list view's own schema, so its `tree` IS the view-level block this + // describe is named for, not a second element face (objectui#12971). + expect(specElementsDeclaring('tree')).toEqual(['list-view', 'object-tree']); // FIRING CONTROL on that zero, same instrument, same corpus. expect(specElementsDeclaring('filter').length).toBeGreaterThan(3); }); diff --git a/packages/types/src/__tests__/record-highlights-layout-9187.test.ts b/packages/types/src/__tests__/record-highlights-layout-9187.test.ts index ea283d5482..93bc4a1d61 100644 --- a/packages/types/src/__tests__/record-highlights-layout-9187.test.ts +++ b/packages/types/src/__tests__/record-highlights-layout-9187.test.ts @@ -142,9 +142,12 @@ describe('objectui#9187 — record:highlights `layout` against the installed spe // `@objectstack/spec` 17.5.0 added the record-block security members // (`requiredPermissions`, `redactFields`, `enforceFieldSecurity`) beside // `layout` (objectui#11073). `layout`'s closed set above did not move, so - // every pin in this file still describes the contract as it stands. + // every pin in this file still describes the contract as it stands. The + // spec after 18.0.0-next.3 added `emptyState` to the bound record blocks + // (objectstack#24270), beside `layout` again (objectui#12971). expect(Object.keys(RecordHighlightsProps.def.shape).sort()).toEqual([ 'aria', + 'emptyState', 'enforceFieldSecurity', 'fields', 'layout', From 8db9aaf1b2fbf35eec5b67f96312b3878b641112 Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 19 Oct 2026 10:58:11 +0000 Subject: [PATCH 04/13] chore: restamp the installed-pin claims the new pin re-measures The pinned build reads 18.0.0-next.4, so check:installed-pin-claims named 25 files claiming 18.0.0-next.3. Each sentence's fact was re-measured on the new pin (a node probe over @objectstack/spec, @objectstack/lint and the automation schema, plus source identity of the automation engine and view.zod.ts between the two pins) and holds, so the stamp moves. The two lockfile-integrity self-test lines are a synthetic registry key, ledgered historical. Claude-Session: https://claude.ai/code/session_0188TsgPV8kQXfuRuKmkj2ks Co-authored-by: Claude --- .../src/__tests__/registry-inputs-spec-parity.test.ts | 6 +++--- .../app-shell/src/views/metadata-admin/celAuthoring.ts | 2 +- .../inspectors/FlowNodeInspector.declaredDefault.test.tsx | 2 +- .../inspectors/flow-node-config.startGates-12780.test.ts | 2 +- .../inspectors/flowSingleBrace-12329.test.tsx | 2 +- .../previews/flow-canvas-seeds.saveErrors-10948.test.tsx | 2 +- packages/core/src/evaluator/optionRules.ts | 2 +- packages/plugin-calendar/src/ObjectCalendar.tsx | 2 +- .../src/__tests__/calendarUnionReads-8651.test.tsx | 2 +- packages/plugin-designer/src/MetadataFieldsPage.tsx | 2 +- packages/plugin-detail/src/index.tsx | 4 ++-- .../src/__tests__/formSectionGroupReference-7051.test.tsx | 2 +- .../__tests__/masterDetailDetailsMembers-8071.test.tsx | 2 +- .../plugin-gantt/src/readme-navigation-example.test.ts | 2 +- packages/plugin-kanban/src/index.tsx | 2 +- .../src/__tests__/chartconfig-aria-retired-4044.test.ts | 2 +- .../dashboard-aria-retired-contract-twins.test.ts | 4 ++-- .../__tests__/object-view-unmirrored-keys-7779.test.ts | 2 +- .../src/__tests__/record-details-top-level-9040.test.ts | 2 +- .../src/__tests__/spec-object-refinements-7715.test.ts | 4 ++-- packages/types/src/field-types.ts | 6 +++--- packages/types/src/objectql.ts | 2 +- packages/types/src/record-components.ts | 6 +++--- packages/types/src/zod/objectql.zod.ts | 4 ++-- scripts/check-installed-spec-pin-claims.mjs | 8 ++++++++ 25 files changed, 42 insertions(+), 34 deletions(-) diff --git a/apps/console/src/__tests__/registry-inputs-spec-parity.test.ts b/apps/console/src/__tests__/registry-inputs-spec-parity.test.ts index e71a4aa736..5de03097b2 100644 --- a/apps/console/src/__tests__/registry-inputs-spec-parity.test.ts +++ b/apps/console/src/__tests__/registry-inputs-spec-parity.test.ts @@ -2966,11 +2966,11 @@ const MEMBER_PINS: Record = { }, 'object-grid.data': { file: 'packages/plugin-grid/src/__tests__/gridDataInputContract.test.ts', - pins: 'The `object` arm is `ViewDataSchema` discriminated on `provider`: each of the three providers parses and the retired `api` one is refused (spec 18.0.0-next.3, objectui#12370), none of them is an array, the declaration is one shape across both registered tags so the alias cannot drift, and it is pinned at compile time too (objectui#5090).', + pins: 'The `object` arm is `ViewDataSchema` discriminated on `provider`: each of the three providers parses and the retired `api` one is refused (spec 18.0.0-next.4, objectui#12370, objectui#12971), none of them is an array, the declaration is one shape across both registered tags so the alias cannot drift, and it is pinned at compile time too (objectui#5090).', }, 'object-grid.conditionalFormatting': { file: 'packages/plugin-grid/src/__tests__/gridRowDecorationMembers-8071.test.tsx', - pins: 'The members read inside ONE formatting rule, asserted on the `style` attribute of the `` the grid paints. THREE alternative predicate members with a PRECEDENCE between them — one rule carrying `condition`, `expression` and the native `field`/`operator`/`value` triple, each naming a DIFFERENT row, is decided by `condition`; drop it and `expression` decides; drop that and the triple does — so a renderer reading any two of them as equivalent is red in a specific direction rather than merely unpinned. FOUR style members, and the sharp one is a RENAME: `backgroundColor` and `borderColor` keep their authored names on the way to the DOM while `textColor` is read as the CSS `color`, so keeping the authored spelling hands React a key it silently drops — same rules, same background, the text colour gone with nothing thrown. `style` is pinned as the BASE the three colour members override rather than replace (a non-colour member of it survives alongside the override). Two rule-list facts complete it: FIRST-MATCH-WINS with no merge (the second matching rule\'s own `textColor` never lands) and a rule carrying NO predicate member is SKIPPED rather than read as always-true, with the rule after it still deciding. ⚠️ Since objectui#11533 the AUTHORED member is ONE dialect, `{ condition, style }`: `expression`, the native triple and the three top-level colour members are refused by name on `ObjectGridSchema` and the list view (`packages/types/src/__tests__/grid-list-view-conditional-formatting-11533.test.ts`), so the rows that write them pin STORED-rule reads, which the resolver keeps as compatibility arms; a last block pins the two facts side by side — the stored native rule refused at authoring and painted at render, with its respelling painting the same row. The registration is an `array` arm; the installed spec row (18.0.0-next.3, re-measured by objectui#12030, objectui#12370, objectui#12626, objectui#12873) takes the list view\'s own `{ condition, style }` rule and refuses the native members and any other key, so the spec fixes the AUTHORED shape and the read site is the rest of the member contract, the stored-rule compatibility arms included (objectui#8071 slice 12).', + pins: 'The members read inside ONE formatting rule, asserted on the `style` attribute of the `` the grid paints. THREE alternative predicate members with a PRECEDENCE between them — one rule carrying `condition`, `expression` and the native `field`/`operator`/`value` triple, each naming a DIFFERENT row, is decided by `condition`; drop it and `expression` decides; drop that and the triple does — so a renderer reading any two of them as equivalent is red in a specific direction rather than merely unpinned. FOUR style members, and the sharp one is a RENAME: `backgroundColor` and `borderColor` keep their authored names on the way to the DOM while `textColor` is read as the CSS `color`, so keeping the authored spelling hands React a key it silently drops — same rules, same background, the text colour gone with nothing thrown. `style` is pinned as the BASE the three colour members override rather than replace (a non-colour member of it survives alongside the override). Two rule-list facts complete it: FIRST-MATCH-WINS with no merge (the second matching rule\'s own `textColor` never lands) and a rule carrying NO predicate member is SKIPPED rather than read as always-true, with the rule after it still deciding. ⚠️ Since objectui#11533 the AUTHORED member is ONE dialect, `{ condition, style }`: `expression`, the native triple and the three top-level colour members are refused by name on `ObjectGridSchema` and the list view (`packages/types/src/__tests__/grid-list-view-conditional-formatting-11533.test.ts`), so the rows that write them pin STORED-rule reads, which the resolver keeps as compatibility arms; a last block pins the two facts side by side — the stored native rule refused at authoring and painted at render, with its respelling painting the same row. The registration is an `array` arm; the installed spec row (18.0.0-next.4, re-measured by objectui#12030, objectui#12370, objectui#12626, objectui#12873, objectui#12971) takes the list view\'s own `{ condition, style }` rule and refuses the native members and any other key, so the spec fixes the AUTHORED shape and the read site is the rest of the member contract, the stored-rule compatibility arms included (objectui#8071 slice 12).', }, 'object-grid.operations': { file: 'packages/plugin-grid/src/__tests__/gridOperationsMembers-8071.test.tsx', @@ -3046,7 +3046,7 @@ const MEMBER_PINS: Record = { }, 'object-kanban.conditionalFormatting': { file: 'packages/plugin-kanban/src/__tests__/ObjectKanban.structuredMembersReachTheirSinks-8313.test.tsx', - pins: 'Members are card STYLE RULES in ONE dialect since objectui#11522, the spec list view\'s `{ condition, style }`, and it reaches the sink: a rule colours the matching card and only it, a second rule aimed at the other card does the same, and the whole `style` map arrives, with the sibling card in the same render as the live non-matching control so a green cannot come from two unstyled cards agreeing. The retired native `{ field, operator, value }` and flat-colour dialects are refused by name on the types side (`packages/types/src/__tests__/kanban-conditional-formatting.test.ts`); these rows are their respellings, painting the same cards. ⛔ NOT an identity pin and not a wire pin: `ObjectKanban.tsx` never names this key at all (measured zero, against nine for `cardFields` in the same file) — it rides the `{ ...schema }` spread into `KanbanRenderer`, which forwards it to `KanbanImpl`\'s `getCardStyles`. That makes the pin load-bearing in a way the others are not: an edit replacing that spread with an explicit key list drops the key silently and nothing else in the repo would notice. The installed spec row (18.0.0-next.3, re-measured by objectui#12030, objectui#12370, objectui#12626, objectui#12873) takes the list view\'s own `{ condition, style }` rule, so the spec fixes the authored shape and the read site is the rest of the member contract (objectui#8313).', + pins: 'Members are card STYLE RULES in ONE dialect since objectui#11522, the spec list view\'s `{ condition, style }`, and it reaches the sink: a rule colours the matching card and only it, a second rule aimed at the other card does the same, and the whole `style` map arrives, with the sibling card in the same render as the live non-matching control so a green cannot come from two unstyled cards agreeing. The retired native `{ field, operator, value }` and flat-colour dialects are refused by name on the types side (`packages/types/src/__tests__/kanban-conditional-formatting.test.ts`); these rows are their respellings, painting the same cards. ⛔ NOT an identity pin and not a wire pin: `ObjectKanban.tsx` never names this key at all (measured zero, against nine for `cardFields` in the same file) — it rides the `{ ...schema }` spread into `KanbanRenderer`, which forwards it to `KanbanImpl`\'s `getCardStyles`. That makes the pin load-bearing in a way the others are not: an edit replacing that spread with an explicit key list drops the key silently and nothing else in the repo would notice. The installed spec row (18.0.0-next.4, re-measured by objectui#12030, objectui#12370, objectui#12626, objectui#12873, objectui#12971) takes the list view\'s own `{ condition, style }` rule, so the spec fixes the authored shape and the read site is the rest of the member contract (objectui#8313).', }, 'object-kanban.data': { file: 'packages/plugin-kanban/src/__tests__/ObjectKanban.structuredMembersReachTheirSinks-8313.test.tsx', diff --git a/packages/app-shell/src/views/metadata-admin/celAuthoring.ts b/packages/app-shell/src/views/metadata-admin/celAuthoring.ts index 8aa6dd3ab1..bc0a9d6b37 100644 --- a/packages/app-shell/src/views/metadata-admin/celAuthoring.ts +++ b/packages/app-shell/src/views/metadata-admin/celAuthoring.ts @@ -428,7 +428,7 @@ function loadRowCanon(): Promise { * not re-derived — and the engine's own message ships with it. * * ⚠️ The reason is NOT that the engine's message refuses a `record.` - * rewrite. Measured against the installed 18.0.0-next.3 (objectui#12030, objectui#12370, objectui#12626, objectui#12873), it mostly PRESCRIBES one: the + * rewrite. Measured against the installed 18.0.0-next.4 (objectui#12030, objectui#12370, objectui#12626, objectui#12873, objectui#12971), it mostly PRESCRIBES one: the * `current_user` text CONTAINS "To gate on record state, rewrite the predicate * against `record`." — one of the three remedies it offers, and NOT where it * ends (measured: `includes` true, `endsWith` false; every covered slot's text diff --git a/packages/app-shell/src/views/metadata-admin/inspectors/FlowNodeInspector.declaredDefault.test.tsx b/packages/app-shell/src/views/metadata-admin/inspectors/FlowNodeInspector.declaredDefault.test.tsx index c82fba5ed2..466d62363d 100644 --- a/packages/app-shell/src/views/metadata-admin/inspectors/FlowNodeInspector.declaredDefault.test.tsx +++ b/packages/app-shell/src/views/metadata-admin/inspectors/FlowNodeInspector.declaredDefault.test.tsx @@ -381,7 +381,7 @@ describe('boolean: a declared defaultValue seeds the control (objectui#8451, arm // ⇒ `screen.waitForInput` is the offline undeclared boolean that sentence // says does not exist — and it is undeclared CORRECTLY, so ⛔ do not read // this as an objectui#9277-class omission waiting to be declared. Measured - // on the installed `@objectstack/spec` (18.0.0-next.3, objectui#12030, objectui#12370, objectui#12626, objectui#12873): `waitForInput` is typed + // on the installed `@objectstack/spec` (18.0.0-next.4, objectui#12030, objectui#12370, objectui#12626, objectui#12873, objectui#12971): `waitForInput` is typed // `z.boolean().optional()` with no `.default(...)`, so an omitted key // materialises nothing and there is no spec answer for a declaration to // mirror. Declaring one here would invent a default the runtime does not diff --git a/packages/app-shell/src/views/metadata-admin/inspectors/flow-node-config.startGates-12780.test.ts b/packages/app-shell/src/views/metadata-admin/inspectors/flow-node-config.startGates-12780.test.ts index 959c23d86b..455c2c6184 100644 --- a/packages/app-shell/src/views/metadata-admin/inspectors/flow-node-config.startGates-12780.test.ts +++ b/packages/app-shell/src/views/metadata-admin/inspectors/flow-node-config.startGates-12780.test.ts @@ -6,7 +6,7 @@ * * The table below is what `@objectstack/service-automation`'s * `AutomationEngine` and the trigger packages read, at objectstack - * `18.0.0-next.3` (the installed `@objectstack/spec` line): + * `18.0.0-next.4` (the installed `@objectstack/spec` line): * * - `secret`: the API trigger arms from `config.secret` (`trigger-api`). * - `objectName`: lifted into the `record_change` binding, which the diff --git a/packages/app-shell/src/views/metadata-admin/inspectors/flowSingleBrace-12329.test.tsx b/packages/app-shell/src/views/metadata-admin/inspectors/flowSingleBrace-12329.test.tsx index d2588742c8..2377d41056 100644 --- a/packages/app-shell/src/views/metadata-admin/inspectors/flowSingleBrace-12329.test.tsx +++ b/packages/app-shell/src/views/metadata-admin/inspectors/flowSingleBrace-12329.test.tsx @@ -6,7 +6,7 @@ * * objectstack#19939 S7 deleted the engine's single-brace resolver: a value slot * refuses a `{…}` token, a text slot reads `{{ }}` holes, and every other flow - * string is a literal. The installed spec (`18.0.0-next.3`) publishes no + * string is a literal. The installed spec (`18.0.0-next.4`) publishes no * `xExpression: 'template'` mark. So the picker has two spellings left — the * bare reference and the `{{ }}` hole — and a literal position has no picker. * diff --git a/packages/app-shell/src/views/metadata-admin/previews/flow-canvas-seeds.saveErrors-10948.test.tsx b/packages/app-shell/src/views/metadata-admin/previews/flow-canvas-seeds.saveErrors-10948.test.tsx index 794bf63b54..994b385f4f 100644 --- a/packages/app-shell/src/views/metadata-admin/previews/flow-canvas-seeds.saveErrors-10948.test.tsx +++ b/packages/app-shell/src/views/metadata-admin/previews/flow-canvas-seeds.saveErrors-10948.test.tsx @@ -2,7 +2,7 @@ /** * objectui#10948 — what the designer's live `FlowSchema` pass says about a node - * the author has ADDED but not yet configured, on the installed spec (18.0.0-next.3). + * the author has ADDED but not yet configured, on the installed spec (18.0.0-next.4). * * Spec 17.5.0 carries objectstack#20316 (a node config key its executor * contract requires, left out, and a decision branch with no `label`, are diff --git a/packages/core/src/evaluator/optionRules.ts b/packages/core/src/evaluator/optionRules.ts index c5a2608865..21e0fa0f4e 100644 --- a/packages/core/src/evaluator/optionRules.ts +++ b/packages/core/src/evaluator/optionRules.ts @@ -118,7 +118,7 @@ export function resolveVisibleOptions( * This is deliberately NOT the lenient renderer fallback AGENTS.md #0.1 * forbids. That rule governs metadata the contract REFUSES ("if the metadata * is off-spec, fix it at the producer"); an empty label is metadata the - * contract ACCEPTS. Measured on the installed `@objectstack/spec` 18.0.0-next.3, + * contract ACCEPTS. Measured on the installed `@objectstack/spec` 18.0.0-next.4, * `SelectOptionSchema`: * * { value: 'low', label: 'Low' } -> ACCEPT (lit control) diff --git a/packages/plugin-calendar/src/ObjectCalendar.tsx b/packages/plugin-calendar/src/ObjectCalendar.tsx index d5409ec9d2..ed616e6caf 100644 --- a/packages/plugin-calendar/src/ObjectCalendar.tsx +++ b/packages/plugin-calendar/src/ObjectCalendar.tsx @@ -1428,7 +1428,7 @@ export const ObjectCalendar: React.FC = ({ * * `@objectstack/spec`'s `CalendarConfigSchema` is a `strictObject` whose ONE * required key is `startDateField`; `titleField` is optional. Re-measured on - * the installed 18.0.0-next.3 (objectui#12030, objectui#12370, objectui#12626, objectui#12873), three legs: `{}` and `{ titleField: 't' }` both fail + * the installed 18.0.0-next.4 (objectui#12030, objectui#12370, objectui#12626, objectui#12873, objectui#12971), three legs: `{}` and `{ titleField: 't' }` both fail * `invalid_type` at `startDateField`, and `{ startDateField: 'd' }` parses * CLEAN. The spec's own note on that schema names THIS renderer as the * reason — `resolveTitle` above takes an explicit `titleField` when present diff --git a/packages/plugin-calendar/src/__tests__/calendarUnionReads-8651.test.tsx b/packages/plugin-calendar/src/__tests__/calendarUnionReads-8651.test.tsx index 02b265ef85..2baf7983fc 100644 --- a/packages/plugin-calendar/src/__tests__/calendarUnionReads-8651.test.tsx +++ b/packages/plugin-calendar/src/__tests__/calendarUnionReads-8651.test.tsx @@ -179,7 +179,7 @@ const LEDGERED_OTHER_CARD_READS: readonly string[] = []; * `ObjectCalendarSchema` and must stay so. * * ⚠️ The ground is NOT that the spec singles these two out. MEASURED on - * installed `@objectstack/spec` 18.0.0-next.3: `ComponentPropsMap['object-calendar']` + * installed `@objectstack/spec` 18.0.0-next.4: `ComponentPropsMap['object-calendar']` * is STRICT and declares exactly ten flat members — `calendar` `data` * `defaultView` `filter` `loading` `locale` `navigation` `objectName` `sort` * `staticData` (nine through 17.4.0; 17.5.0 added `navigation`) — diff --git a/packages/plugin-designer/src/MetadataFieldsPage.tsx b/packages/plugin-designer/src/MetadataFieldsPage.tsx index 1ab322acd3..aa5bec8c5f 100644 --- a/packages/plugin-designer/src/MetadataFieldsPage.tsx +++ b/packages/plugin-designer/src/MetadataFieldsPage.tsx @@ -184,7 +184,7 @@ function isDesignerAuthorableType(raw: unknown): raw is DesignerFieldType { * ## Why reading the retired spelling is a RENAME here and not a laundering * * `@objectstack/spec` treats the two as one key under two spellings and says - * so in the refusal itself. Measured on the installed 18.0.0-next.3 (objectui#12030, objectui#12370, objectui#12626, objectui#12873): + * so in the refusal itself. Measured on the installed 18.0.0-next.4 (objectui#12030, objectui#12370, objectui#12626, objectui#12873, objectui#12971): * * FieldSchema.safeParse({ type: 'lookup', label: 'L', referenceTo: 'account' }) * => success = false diff --git a/packages/plugin-detail/src/index.tsx b/packages/plugin-detail/src/index.tsx index 83512206a3..e6232fe092 100644 --- a/packages/plugin-detail/src/index.tsx +++ b/packages/plugin-detail/src/index.tsx @@ -969,7 +969,7 @@ ComponentRegistry.register('alert', RecordAlertRenderer, { // through `pickLocalized`, which is exactly what these descriptions teach. // Declaring the map arm therefore adds no shape the block does not already // honour; it stops the manifest gate warning `type-mismatch` on the - // recommended write. (The row DOES exist as of the installed 18.0.0-next.3 — read + // recommended write. (The row DOES exist as of the installed 18.0.0-next.4 — read // for `visible` below, objectui#9100 — so the "no entry" reading is stale; // these two arms are unaffected either way.) { name: 'title', type: ['string', 'object'], description: 'Accepts an inline translation map ({ en, "zh-CN", … })' }, @@ -977,7 +977,7 @@ ComponentRegistry.register('alert', RecordAlertRenderer, { // objectui#9100 — the spec accepts three arms here and the renderer now // resolves all three, so a single `'string'` was the declaration-narrower- // than-the-contract family of objectui#4581, one layer up. Measured on the - // INSTALLED `@objectstack/spec` 18.0.0-next.3 (`dist/ui/index.d.ts`, the + // INSTALLED `@objectstack/spec` 18.0.0-next.4 (`dist/ui/index.d.ts`, the // `ComponentPropsMap['record:alert']` row): `visible` is // `boolean | string | { dialect: 'cel'|'cron'|'template', source?, … }`, // and `renderers/record-alert.tsx` hands whichever arrives to diff --git a/packages/plugin-form/src/__tests__/formSectionGroupReference-7051.test.tsx b/packages/plugin-form/src/__tests__/formSectionGroupReference-7051.test.tsx index 1e886f7662..ad3c7cd360 100644 --- a/packages/plugin-form/src/__tests__/formSectionGroupReference-7051.test.tsx +++ b/packages/plugin-form/src/__tests__/formSectionGroupReference-7051.test.tsx @@ -448,7 +448,7 @@ describe('objectui#7051 — resolveSectionGroupReferences', () => { /** * ⭐ The second axis. The card asks that group-owned presentation keys beside * `group`, and `group` on a wizard step, not be SILENTLY accepted. Measured - * against the installed `@objectstack/spec` (18.0.0-next.3): both are refused at PARSE + * against the installed `@objectstack/spec` (18.0.0-next.4): both are refused at PARSE * — a stronger door than the lint that objectui#8497 concluded owns EXISTENCE * checking, and a different one. So authored metadata carrying either never * reaches this renderer at all; the renderer's own reports above exist for the diff --git a/packages/plugin-form/src/__tests__/masterDetailDetailsMembers-8071.test.tsx b/packages/plugin-form/src/__tests__/masterDetailDetailsMembers-8071.test.tsx index acdbf0504e..6158db6edd 100644 --- a/packages/plugin-form/src/__tests__/masterDetailDetailsMembers-8071.test.tsx +++ b/packages/plugin-form/src/__tests__/masterDetailDetailsMembers-8071.test.tsx @@ -504,7 +504,7 @@ type SpecDetailEntry = NonNullable[numbe * The config IS the spec's entry minus `sortField`, by reference * (objectui#11396): a member the spec adds, drops or retypes lands on the * config with no hand edit, and a hand-written restatement that drifts is red - * here before it is red anywhere else. The installed 18.0.0-next.3 entry carries a + * here before it is red anywhere else. The installed 18.0.0-next.4 entry carries a * `retiredKey()` tombstone for `sortField` (objectstack-ai/objectstack#21589); * 17.6.0 declared it as a string, and the subtraction removes the key either * way. ⛔ No row here pins which of the two shapes the spec has; the `Spec Main diff --git a/packages/plugin-gantt/src/readme-navigation-example.test.ts b/packages/plugin-gantt/src/readme-navigation-example.test.ts index 5504213ae0..0251180602 100644 --- a/packages/plugin-gantt/src/readme-navigation-example.test.ts +++ b/packages/plugin-gantt/src/readme-navigation-example.test.ts @@ -79,7 +79,7 @@ * * WARNING: `declaredMembers()` cannot derive that key's retirement. When this * was written the spec in the lockfile (17.4.0) still DECLARED `view` as a live - * member. The installed `@objectstack/spec` 18.0.0-next.3 lands it as a tombstone, + * member. The installed `@objectstack/spec` 18.0.0-next.4 lands it as a tombstone, * as 17.5.0 through 17.7.0 did (objectui#11073 measured it, objectui#11438, * objectui#11717 and objectui#12030 again: a `never` * schema, and `{ view: 'detail' }` is diff --git a/packages/plugin-kanban/src/index.tsx b/packages/plugin-kanban/src/index.tsx index d9b6336b83..84396e70be 100644 --- a/packages/plugin-kanban/src/index.tsx +++ b/packages/plugin-kanban/src/index.tsx @@ -554,7 +554,7 @@ export const ObjectKanbanRenderer: React.FC<{ schema: any; [key: string]: any }> * ## Why these keys were added * * `@objectstack/spec`'s `ComponentPropsMap['object-kanban']` carries FIFTEEN - * top-level keys on the installed 18.0.0-next.3 pin, fourteen of them live, the + * top-level keys on the installed 18.0.0-next.4 pin, fourteen of them live, the * same set as 17.5.0 through 17.7.0: 17.5.0 * added `navigation` and turned `quickAdd` into a tombstone (typed `never`, * refused by name — objectui#8285's ruled retirement, landed). This list diff --git a/packages/types/src/__tests__/chartconfig-aria-retired-4044.test.ts b/packages/types/src/__tests__/chartconfig-aria-retired-4044.test.ts index 646e373d99..69ba41841a 100644 --- a/packages/types/src/__tests__/chartconfig-aria-retired-4044.test.ts +++ b/packages/types/src/__tests__/chartconfig-aria-retired-4044.test.ts @@ -30,7 +30,7 @@ * - **TypeScript.** `complex.ts` re-typed `chartConfig` as `any`, so an * authored `aria` compiled. The member now takes `aria` from the spec's own * input type, which is the spec's retired-key type (the branded `[REMOVED]` - * mark at the pinned 18.0.0-next.3 and on objectstack `main`, bare `undefined` + * mark at the pinned 18.0.0-next.4 and on objectstack `main`, bare `undefined` * through 17.5.0; both * spellings are `retired-key-type.ts`'s), so an authored value is a compile * error. diff --git a/packages/types/src/__tests__/dashboard-aria-retired-contract-twins.test.ts b/packages/types/src/__tests__/dashboard-aria-retired-contract-twins.test.ts index b653f23675..c384f3846c 100644 --- a/packages/types/src/__tests__/dashboard-aria-retired-contract-twins.test.ts +++ b/packages/types/src/__tests__/dashboard-aria-retired-contract-twins.test.ts @@ -29,7 +29,7 @@ * objectui#9736 closed that half. The interface now extends the spec's own * `Dashboard` input type (`Omit< Dashboard, … >` over the exclusion list its * mirror reads), so it inherits the spec's tombstone as a DECLARED member typed - * as the spec's retired key (the branded `[REMOVED]` mark at the pinned 18.0.0-next.3 + * as the spec's retired key (the branded `[REMOVED]` mark at the pinned 18.0.0-next.4 * and on objectstack `main`, bare `undefined` through 17.5.0) — `aria` is back in the declared key * set, but only as a refusal, * and an authored value is a compile error: the same verdict the Zod twin gives @@ -52,7 +52,7 @@ describe('the TS interface declares `aria` only as the spec tombstone (objectui# it('`aria` is declared, typed as the spec\'s retired key; the neighbours it stood beside still are', () => { // Type-level pins, erased at runtime. `aria` is a DECLARED key again — the // spec projection carries the tombstone — and its type admits no value: - // the branded `[REMOVED]` mark at the pinned 18.0.0-next.3 and on objectstack + // the branded `[REMOVED]` mark at the pinned 18.0.0-next.4 and on objectstack // `main`, bare `undefined` through 17.5.0 (both spellings are // `retired-key-type.ts`'s, objectui#11330). const ariaDeclared: 'aria' extends Declared ? true : false = true; diff --git a/packages/types/src/__tests__/object-view-unmirrored-keys-7779.test.ts b/packages/types/src/__tests__/object-view-unmirrored-keys-7779.test.ts index 3564ea7758..3986f99ca5 100644 --- a/packages/types/src/__tests__/object-view-unmirrored-keys-7779.test.ts +++ b/packages/types/src/__tests__/object-view-unmirrored-keys-7779.test.ts @@ -339,7 +339,7 @@ const NAMED_VIEW_ABSENT_CONTROL = 'stickyHeader'; /** * The protocol's own member set for a named list view — `ObjectListViewSchema`'s - * shape, off `@objectstack/spec` as installed (18.0.0-next.3). ⛔ Not a copy of the + * shape, off `@objectstack/spec` as installed (18.0.0-next.4). ⛔ Not a copy of the * objectui face and ⛔ not a hand list: it is read off the schema object, so a * spec bump that moves a key moves this. */ diff --git a/packages/types/src/__tests__/record-details-top-level-9040.test.ts b/packages/types/src/__tests__/record-details-top-level-9040.test.ts index 3a1fcfebc9..f0b199c598 100644 --- a/packages/types/src/__tests__/record-details-top-level-9040.test.ts +++ b/packages/types/src/__tests__/record-details-top-level-9040.test.ts @@ -174,7 +174,7 @@ type _KeyofStillResolvesOnThisInterface = Expect< /** * The contract's face, untouched by this removal: the tombstone accepts nothing. * Its type is the spec's retired-key type — the branded `[REMOVED]` mark at the - * pinned 18.0.0-next.3 and on objectstack `main`, + * pinned 18.0.0-next.4 and on objectstack `main`, * bare `undefined` through 17.5.0 — and the helper accepts * exactly those two spellings (objectui#11330). */ diff --git a/packages/types/src/__tests__/spec-object-refinements-7715.test.ts b/packages/types/src/__tests__/spec-object-refinements-7715.test.ts index 5d7737c10a..20df08ce39 100644 --- a/packages/types/src/__tests__/spec-object-refinements-7715.test.ts +++ b/packages/types/src/__tests__/spec-object-refinements-7715.test.ts @@ -345,7 +345,7 @@ const SITES = [ // objectui#12370's view-data check left this list with objectui#12666: objectstack#23784 // removed it from the spec, and 18.0.0-next.3 is the first release without it (objectstack // `a35f7a6`). The census below accounts for it by what it judges, not by name - // (`specChecksRemovedOnMain`), which on the installed 18.0.0-next.3 finds nothing. + // (`specChecksRemovedOnMain`), which on the installed 18.0.0-next.4 finds nothing. // `checkPageRegionPlacement` joined at 18.0.0-next.2 and was attached by objectui#12626: it // reads `kind` and `template` (by reference) and each region's `name`, which objectui's own // region carries with the meaning `page.tsx` places it by; measured in its describe block above. @@ -450,7 +450,7 @@ const PAGE_SITE = 'SpecPageFields → PageNodeSchema (layout.zod.ts)'; * against its own spec tree, so no file here may name that export. Through * 18.0.0-next.2 the spec exported it and attached it to `PageSchema`, where * the census would miscount by one; 18.0.0-next.3 dropped it (objectstack - * `a35f7a6`), and on the installed 18.0.0-next.3 this answers empty. This reads every + * `a35f7a6`), and on the installed 18.0.0-next.4 this answers empty. This reads every * exported check no site names and keeps the ones that refuse a slotted * `object-grid` naming `api` at its `properties.data.provider`: on next.2 that * is exactly the removed judge, and on a spec without it the list is empty, so diff --git a/packages/types/src/field-types.ts b/packages/types/src/field-types.ts index 36beae5c44..f69ab2881c 100644 --- a/packages/types/src/field-types.ts +++ b/packages/types/src/field-types.ts @@ -25,7 +25,7 @@ import type { Field as SpecField } from '@objectstack/spec/data'; * sibling field names, or `{ field, param }` entries mapping a sibling onto the * remote query parameter a dependent lookup filters by. * - * Measured on the installed `@objectstack/spec` (18.0.0-next.3), `FieldSchema` declares + * Measured on the installed `@objectstack/spec` (18.0.0-next.4), `FieldSchema` declares * `dependsOn` as an OPTIONAL ARRAY of `string | { field, param? }` — never a * bare string. That is deliberately narrower than `DependsOnInput` (`form.ts`), * the shape the widget prop `FieldWidgetComponentProps.dependsOn` and @@ -343,7 +343,7 @@ export interface MarkdownFieldMetadata extends BaseFieldMetadata { * annotated literal rejected. Follows the `TextareaFieldMetadata` precedent. * * A DECLARED spec key as of `@objectstack/spec` 17.3.0, which implements that - * same ruling. Measured on the installed `@objectstack/spec` 18.0.0-next.3: + * same ruling. Measured on the installed `@objectstack/spec` 18.0.0-next.4: * `FieldSchema` ACCEPTS `rows` on all four of textarea/markdown/html/ * richtext, as an integer of at least 1 — a non-integer answers * `invalid_type` and 0 answers `too_small`, so "declared" does not mean "any @@ -692,7 +692,7 @@ export interface SelectOptionMetadata extends SelectOptionBase { * * A DECLARED `SelectOptionSchema` key as of `@objectstack/spec` 17.3.0, * which implements the objectui#6153 half of that ruling. Measured on the - * installed `@objectstack/spec` 18.0.0-next.3: an option carrying `description` + * installed `@objectstack/spec` 18.0.0-next.4: an option carrying `description` * is ACCEPTED, as a string (a non-string answers `invalid_type`; the empty * string is valid), and a field whose `options` carry it parses whole. ⇒ it * may now be written into authored object metadata, which is the point of diff --git a/packages/types/src/objectql.ts b/packages/types/src/objectql.ts index 015a74a6e0..a735366877 100644 --- a/packages/types/src/objectql.ts +++ b/packages/types/src/objectql.ts @@ -4219,7 +4219,7 @@ export interface ObjectCalendarSchema extends BaseSchema { * (the spec's own `ObjectCalendarPropsSchema`) declares * `z.array(z.unknown()).optional()`, described *"Pre-fetched records — skips * the internal fetch"*. - * MEASURED on the installed artifact at `@objectstack/spec` 18.0.0-next.3 — the + * MEASURED on the installed artifact at `@objectstack/spec` 18.0.0-next.4 — the * version this repository's `pnpm-lock.yaml` resolves — through the published * `@objectstack/spec/ui` entry point: the provider block returns * `success=false` with `expected: 'array'` at `path: ['data']`, the array diff --git a/packages/types/src/record-components.ts b/packages/types/src/record-components.ts index c1013f673c..d8f83cb430 100644 --- a/packages/types/src/record-components.ts +++ b/packages/types/src/record-components.ts @@ -107,7 +107,7 @@ export interface RecordDetailsComponentProps { * It was `number` here until objectui#8604, which is the wrong PRIMITIVE * TYPE, not merely a wider range: `{ columns: 2 }` compiled locally and the * contract refused it at publish with `invalid_value` at `columns` (measured - * on the installed pin, 18.0.0-next.3, against a control — `columns: '2'` — that + * on the installed pin, 18.0.0-next.4, against a control — `columns: '2'` — that * parses green on the same instrument). Contract-first (Commandment #0.1): * the code moves to the contract's spelling, and today's `columns: 2` * authors are the defect surfacing rather than collateral damage. @@ -358,7 +358,7 @@ export interface RecordHighlightsComponentProps { * `RecordHighlightsProps.fields[]`'s object arm declares exactly * `name`/`label`/`type`/`readonly` and carries a `never` catchall, i.e. it is * `$strict`: an unlisted key is REFUSED, not stripped, and the refusal takes - * the WHOLE document with it. Measured on the installed pin, 18.0.0-next.3, + * the WHOLE document with it. Measured on the installed pin, 18.0.0-next.4, * `RecordHighlightsProps.safeParse({ fields: [{ name: 'x', icon: 'star' }] })` * is RED with `invalid_union` at `fields.0`. So `{ name: 'amount', icon: * 'dollar-sign' }` type-checked here and was refused at the door — a green @@ -390,7 +390,7 @@ export interface RecordHighlightsComponentProps { * `z.enum(['horizontal','vertical'])` behind a `.default('horizontal')`). * * It offered a third value, `grid`, until objectui#9187, and the contract - * never accepted it: measured on the installed pin, 18.0.0-next.3, + * never accepted it: measured on the installed pin, 18.0.0-next.4, * `RecordHighlightsProps.safeParse({ fields: ['name'], layout: 'grid' })` is * RED with `invalid_value` at `layout`. So `{ layout: 'grid' }` type-checked * here and was refused at the door — a green local build and a rejection at diff --git a/packages/types/src/zod/objectql.zod.ts b/packages/types/src/zod/objectql.zod.ts index a89fecf11b..c35237af2b 100644 --- a/packages/types/src/zod/objectql.zod.ts +++ b/packages/types/src/zod/objectql.zod.ts @@ -1774,7 +1774,7 @@ const KanbanConfig = stripImportedDefaults(SpecListViewSchema).shape.kanban.unwr * `@objectstack/spec` 17.4.0 (the version in the lockfile then) rather than * reading it — RE-RUN on 17.5.0 (objectui#11073), whose answer moved, as the * last bullet says, RE-RUN on 17.6.0 (objectui#11438), on 17.7.0 (objectui#11717), - * and again on the installed 18.0.0-next.3 (objectui#12030, objectui#12370, objectui#12626, objectui#12873), each of which answers + * and again on the installed 18.0.0-next.4 (objectui#12030, objectui#12370, objectui#12626, objectui#12873, objectui#12971), each of which answers * every bullet below as 17.5.0 did: * * - `CalendarConfigSchema`'s `strictObject` options carry `surface` and @@ -1799,7 +1799,7 @@ const KanbanConfig = stripImportedDefaults(SpecListViewSchema).shape.kanban.unwr * prescribes neither. `endField` still draws no hint, and a one-char typo * still resolves by distance (`titleFeld` → `titleField`) — all three * measured on 17.5.0, again on 17.6.0 (objectui#11438), on 17.7.0 - * (objectui#11717), and again on the installed 18.0.0-next.3 (objectui#12030, objectui#12370, objectui#12626, objectui#12873). + * (objectui#11717), and again on the installed 18.0.0-next.4 (objectui#12030, objectui#12370, objectui#12626, objectui#12873, objectui#12971). * * ⇒ through 17.4.0 a generic typo-distance suggester picked the wrong sibling. * It was not a declaration, it contradicted no declaration, and ⛔ no upstream diff --git a/scripts/check-installed-spec-pin-claims.mjs b/scripts/check-installed-spec-pin-claims.mjs index a340393f50..34e93c7b6a 100644 --- a/scripts/check-installed-spec-pin-claims.mjs +++ b/scripts/check-installed-spec-pin-claims.mjs @@ -942,6 +942,14 @@ export const LEDGER = [ class: "historical", why: "Anchored to a named commit: \"`5488ae7` is objectui#12030's branch commit: `main` at `cea429b` with `@objectstack/*` 18.0.0-next.0 resolved\" describes the tree the eager-closure baseline was measured on. A measurement that names its tree is a record, not a claim about today (objectui#12370).", }, + { + file: "scripts/check-lockfile-integrity.mjs", + package: "@objectstack/spec", + version: "18.0.0-next.3", + sites: 2, + class: "historical", + why: "Two lines of the gate's own `--self-test`, neither a claim about today: `@objectstack/spec@18.0.0-next.3` is a synthetic REGISTRY lockfile key the fixture sets beside the pinned build (`file:` directory) to show a registry copy is a duplication and a move onto the build is clean. The line's `pinned` is the build's name, and the fixture means a registry version that is NOT the pin, so it never restamps (objectui#12971).", + }, ]; // ── The run ────────────────────────────────────────────────────────────────── From 8af192673089d65104480e1c6d5d94971af3a5c0 Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 19 Oct 2026 10:58:41 +0000 Subject: [PATCH 05/13] chore(changeset): name each change the objectstack pin bump follows Claude-Session: https://claude.ai/code/session_0188TsgPV8kQXfuRuKmkj2ks Co-authored-by: Claude --- .../12971-objectstack-pin-main-2ec6827962.md | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 .changeset/12971-objectstack-pin-main-2ec6827962.md diff --git a/.changeset/12971-objectstack-pin-main-2ec6827962.md b/.changeset/12971-objectstack-pin-main-2ec6827962.md new file mode 100644 index 0000000000..8ad7bda18c --- /dev/null +++ b/.changeset/12971-objectstack-pin-main-2ec6827962.md @@ -0,0 +1,27 @@ +--- +"@object-ui/types": minor +"@object-ui/components": minor +"@object-ui/app-shell": minor +"@object-ui/console": minor +"@object-ui/runner": minor +--- + +Build `@objectstack/*` from objectstack `main` `2ec6827962` (objectui#12971). + +`.objectstack-sha` moves from `2c9bf9430a`, the commit `@objectstack/spec` `18.0.0-next.3` was released from, to `2ec6827962`, a commit on objectstack `main` whose packages read `18.0.0-next.4`. The console and the runner bundle `@objectstack/*` built from it. No package's `@objectstack/*` range changes. + +Clause-②: no (narrowing) + +**Accept sets that narrow with it.** `@object-ui/types` validates a page through the spec's own page checks, so `safeValidateSchema`, `StrictAnyComponentSchema` and `objectui validate` now refuse: + +- A region named `main` with `width: 'small'`, `'medium'` or `'large'`, on a `page` node and on a page-kind node (`type: 'record'`, `'home'` or `'utility'`). FROM accepted on both faces TO refused at the region's `width`, with the spec's message (`checkPageMainRegionWidth`). No layout reads those three values on `main`; the template decides its width. Delete `width` to keep the page as it renders, or write `width: 'full'` for a full-bleed page. Other regions keep all four values. +- A `record` binding on a page-kind node. FROM kept unvalidated by `safeValidateSchema` and refused as an undeclared key by `StrictAnyComponentSchema` TO refused on both at `record`, with the spec's message (`checkPageRecordBindingPlacement`): only a `type: 'app'` page binds a row. The check reads the page kind from `type`, so it does not judge a `page` node, whose kind is `pageType`. + +**A published input that leaves.** `action:button` and `action:icon` no longer publish a `patch` input. FROM published TO absent: the spec retired a page action row's own `patch`. A row's `operation: 'update'` runs the declared action its `name` names, and the platform action route writes that action's `patch`. The `operation` input's description now says so. + +**Keys that arrive with the spec, by reference.** Two keys the spec added are taken by reference, so the strict face now accepts them where it refused them as undeclared. Their renderer halves are separate work: + +- `emptyState` on `record:details`, `record:highlights` and `record:quick_actions`. +- `record` on a `page` node. + +**A palette exclusion that goes.** `record:json` is retired in the spec and is no longer a page component type, so the page designer's palette drops its exclusion entry. Nothing the palette offers changes. From 37906b12b760ac9d8b3344650ab503d37e72dc7f Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 19 Oct 2026 10:59:27 +0000 Subject: [PATCH 06/13] test(app-shell): ObjectSchema gains defaultRowScope at the new pin (45 -> 46) Claude-Session: https://claude.ai/code/session_0188TsgPV8kQXfuRuKmkj2ks Co-authored-by: Claude --- .../services/MetadataService.specKeyObjectPayload.test.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/app-shell/src/services/MetadataService.specKeyObjectPayload.test.ts b/packages/app-shell/src/services/MetadataService.specKeyObjectPayload.test.ts index 76ded92d73..98a8175e34 100644 --- a/packages/app-shell/src/services/MetadataService.specKeyObjectPayload.test.ts +++ b/packages/app-shell/src/services/MetadataService.specKeyObjectPayload.test.ts @@ -163,8 +163,12 @@ describe('the instrument', () => { // 45 at `@objectstack/spec` 18.0.0-next.0, which adopted `attachedOnRead` // (measured against a 17.7.0 control: gained set exactly `['attachedOnRead']`, // lost set empty; objectui#12030). Re-pointed the same way. + // 46 on the objectstack `main` pin after 18.0.0-next.3, which adopted + // `defaultRowScope` (objectstack#24398; measured against the next.3 pin: the + // one top-level key `ObjectSchema` gains between the two commits, none lost; + // objectui#12971). Re-pointed the same way. const accept = new Set(Object.keys(ObjectSchema.shape as Record)); - expect(accept.size).toBe(45); + expect(accept.size).toBe(46); // `fieldGroups` is the only grouping key on the object, and it groups the // FIELDS INSIDE one object — it is not a category for objects themselves, // so `group` has no mapping target here. From 595421c0c8f944b3b39c6fb637c58265c0869e12 Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 19 Oct 2026 11:38:35 +0000 Subject: [PATCH 07/13] test(types,console): register the two new page checks at the import boundary; keep the 17.3.0 sentence the pin-claims control reads imported-defaults-8317 lists checkPageMainRegionWidth and checkPageRecordBindingPlacement as refinement exceptions (functions, not schemas). The retired marketplace:installed-list ledger entry keeps its "New in 17.3.0" history, the real line check-installed-spec-pin-claims' refusal control reads. Claude-Session: https://claude.ai/code/session_0188TsgPV8kQXfuRuKmkj2ks Co-authored-by: Claude --- .../src/__tests__/registry-inputs-spec-parity.test.ts | 4 ++-- .../types/src/__tests__/imported-defaults-8317.test.ts | 7 +++++++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/apps/console/src/__tests__/registry-inputs-spec-parity.test.ts b/apps/console/src/__tests__/registry-inputs-spec-parity.test.ts index 5de03097b2..0ad4da53c1 100644 --- a/apps/console/src/__tests__/registry-inputs-spec-parity.test.ts +++ b/apps/console/src/__tests__/registry-inputs-spec-parity.test.ts @@ -991,7 +991,7 @@ const UNJUDGED_SPEC_BLOCKS: Record = { 'global:notifications': 'EMPTY SPEC SHAPE. Same shape and same reasoning as `app:launcher` above: `app-shell/src/views/global-notifications-renderer.tsx` registers it propless because the spec shape is empty, and that registration is not in this file\'s import graph. objectui#8176.', 'marketplace:installed-list': - 'RETIRED UPSTREAM. Retired by name on the objectstack `main` pin after `@objectstack/spec` 18.0.0-next.3 (objectstack#24255, landed as `14a8bd2693`): out of `PageComponentType`, named in `RETIRED_PAGE_COMPONENT_TYPES`, and its row `retiredComponentProps` — a `never` that refuses every props bag, `{}` included, with a message that names Setup → Packages filtered to Marketplace as the Installed Apps list — so there is no authoring surface for either direction to judge. Until that pin it stood here as EMPTY SPEC SHAPE, unregistered since objectui#12733. objectui#12971, ledger objectui#8176.', + 'RETIRED UPSTREAM. `@objectstack/spec` retired it by name after 18.0.0-next.3 (objectstack#24255, landed as `14a8bd2693`): out of `PageComponentType`, named in `RETIRED_PAGE_COMPONENT_TYPES`, and its row `retiredComponentProps` — a `never` that refuses every props bag, `{}` included, with a message that names the Packages view that replaces it — so there is no authoring surface for either direction to judge. Before that it stood here as EMPTY SPEC SHAPE. New in `@objectstack/spec` 17.3.0, which declared it with no top-level key at all; not registered here since objectui#12733, whose Setup → Packages list filtered to Marketplace carries its actions (`MarketplaceRowActions.installedAppsPins.test.tsx`). objectui#7122, objectui#12733, objectui#12971, ledger objectui#8176.', 'mcp:connect-agent': 'EMPTY SPEC SHAPE. New in `@objectstack/spec` 17.3.0, which declares it with no top-level key at all. Registered propless by `@object-ui/app-shell` (`src/console/connect/ConnectAgentWidget.tsx`), outside this file\'s import graph; the empty shape is the load-bearing half either way. objectui#7122, ledger objectui#8176.', 'record:approval_decision': @@ -1001,7 +1001,7 @@ const UNJUDGED_SPEC_BLOCKS: Record = { 'record:attachments': 'EMPTY SPEC SHAPE. New in `@objectstack/spec` 18 (objectui#12030), which declares it with no top-level key at all. Registered by `@object-ui/app-shell` (`src/views/record-attachments-renderer.tsx`), outside this file\'s import graph; the empty shape is the load-bearing half either way, exactly as for `app:launcher` above. objectui#12030, ledger objectui#8176.', 'record:json': - 'RETIRED UPSTREAM. Retired by name on the objectstack `main` pin after `@objectstack/spec` 18.0.0-next.3 (objectstack#24162, landed as `030a7b83e8`), the only release that declared it: out of `PageComponentType`, named in `RETIRED_PAGE_COMPONENT_TYPES`, and its row `retiredComponentProps` — a `never` that refuses every props bag, `{}` included — so there is no authoring surface for either direction to judge. Until that pin it stood here as NOT REGISTERED, DELIBERATELY: the maintainer dropped the approval request page\'s raw-payload panel it was declared for (pointer 6232139151 on objectui#12490). objectui#12873, objectui#12971, ledger objectui#8176.', + 'RETIRED UPSTREAM. `@objectstack/spec` retired it by name after 18.0.0-next.3 (objectstack#24162, landed as `030a7b83e8`), the only release that declared it: out of `PageComponentType`, named in `RETIRED_PAGE_COMPONENT_TYPES`, and its row `retiredComponentProps` — a `never` that refuses every props bag, `{}` included — so there is no authoring surface for either direction to judge. Before that it stood here as NOT REGISTERED, DELIBERATELY: the maintainer dropped the approval request page\'s raw-payload panel it was declared for (pointer 6232139151 on objectui#12490). objectui#12873, objectui#12971, ledger objectui#8176.', // The fourth class, and the only one that is not mechanically "unjudgeable": // OWED. The 17.5.0 bump booked four blocks here — new in that spec, registered // with `registerLazy` by the console (`register-plugins.ts`) and not loaded by diff --git a/packages/types/src/__tests__/imported-defaults-8317.test.ts b/packages/types/src/__tests__/imported-defaults-8317.test.ts index 5532e121cd..91fb2eade5 100644 --- a/packages/types/src/__tests__/imported-defaults-8317.test.ts +++ b/packages/types/src/__tests__/imported-defaults-8317.test.ts @@ -147,6 +147,8 @@ import { checkPageSlotPair, checkPageRegionPlacement, checkPageDefaultPlacement, + checkPageMainRegionWidth, + checkPageRecordBindingPlacement, VIEW_METADATA_MEMBERS as SpecViewMetadataMembers, // objectui#12736 — the form option's spec shape: the form-view option. FormSelectOptionSchema as SpecFormSelectOptionSchema, @@ -722,6 +724,11 @@ describe('the import boundary strips every imported default (objectui#8317)', () // `PageKindNodeSchema`, and `isDefault` placement, on `PageKindNodeSchema` only. ['checkPageRegionPlacement', checkPageRegionPlacement], ['checkPageDefaultPlacement', checkPageDefaultPlacement], + // objectui#12971: the two page checks objectstack `main` adds to `PageSchema` after + // 18.0.0-next.3 — the `main` region's `width`, re-attached on `PageNodeSchema` and + // `PageKindNodeSchema`, and `record` binding placement, on `PageKindNodeSchema` only. + ['checkPageMainRegionWidth', checkPageMainRegionWidth], + ['checkPageRecordBindingPlacement', checkPageRecordBindingPlacement], // objectui#12670: the list view chart-binding check `@objectstack/spec` 18 carries on // `ListViewSchema`, attached on the authored page `list-view` node's bag // (`ListViewPropsBag`), whose `type` is the spec's view kind. From 9310c0eadbeeecd4caceece45506a0bf448b122c Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 19 Oct 2026 11:38:56 +0000 Subject: [PATCH 08/13] test(app-shell): the second ObjectSchema key-count guard re-points to 46 (defaultRowScope) Claude-Session: https://claude.ai/code/session_0188TsgPV8kQXfuRuKmkj2ks Co-authored-by: Claude --- .../services/MetadataService.retiredObjectEnabled.test.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/app-shell/src/services/MetadataService.retiredObjectEnabled.test.ts b/packages/app-shell/src/services/MetadataService.retiredObjectEnabled.test.ts index 4a41a5c4e1..3ba79cb0ad 100644 --- a/packages/app-shell/src/services/MetadataService.retiredObjectEnabled.test.ts +++ b/packages/app-shell/src/services/MetadataService.retiredObjectEnabled.test.ts @@ -149,8 +149,12 @@ describe('objectui#6238 · the schema oracle — both tombstone keys are refused // 45 at `@objectstack/spec` 18.0.0-next.0, which adopted `attachedOnRead` // (measured against a 17.7.0 control: gained set exactly `['attachedOnRead']`, // lost set empty; objectui#12030). Re-pointed the same way. + // 46 on the objectstack `main` pin after 18.0.0-next.3, which adopted + // `defaultRowScope` (objectstack#24398; measured against the next.3 pin: the + // one top-level key `ObjectSchema` gains between the two commits, none lost; + // objectui#12971). Re-pointed the same way. const accept = new Set(Object.keys(ObjectSchema.shape as Record)); - expect(accept.size).toBe(45); + expect(accept.size).toBe(46); expect(accept.has('enable')).toBe(true); expect(accept.has('enabled')).toBe(false); expect(accept.has('_deleted')).toBe(false); From c888e40789a8098dc7b1f347e34297498165ca84 Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 19 Oct 2026 11:55:42 +0000 Subject: [PATCH 09/13] chore(pin): the committed .objectstack-pin manifests are 2ec6827962's Written by `node scripts/objectstack-pin.mjs build --write-manifests` at the new pin (objectui#13008 committed them after this branch was cut). Only the packed versions move, 18.0.0-next.3 -> 18.0.0-next.4; `pnpm install` leaves pnpm-lock.yaml unchanged. Claude-Session: https://claude.ai/code/session_0188TsgPV8kQXfuRuKmkj2ks Co-authored-by: Claude --- .objectstack-pin/client/package.json | 30 +++++++++++------------ .objectstack-pin/core/package.json | 8 +++--- .objectstack-pin/formula/package.json | 4 +-- .objectstack-pin/lint/package.json | 8 +++--- .objectstack-pin/sdui-parser/package.json | 2 +- .objectstack-pin/spec/package.json | 2 +- .objectstack-pin/types/package.json | 4 +-- 7 files changed, 29 insertions(+), 29 deletions(-) diff --git a/.objectstack-pin/client/package.json b/.objectstack-pin/client/package.json index 1891aedc34..f3558e2cbc 100644 --- a/.objectstack-pin/client/package.json +++ b/.objectstack-pin/client/package.json @@ -1,6 +1,6 @@ { "name": "@objectstack/client", - "version": "18.0.0-next.3", + "version": "18.0.0-next.4", "license": "Apache-2.0", "description": "Official Client SDK for ObjectStack Protocol", "main": "dist/index.js", @@ -13,23 +13,23 @@ } }, "dependencies": { - "@objectstack/core": "18.0.0-next.3", - "@objectstack/spec": "18.0.0-next.3" + "@objectstack/core": "18.0.0-next.4", + "@objectstack/spec": "18.0.0-next.4" }, "devDependencies": { "@hono/node-server": "^2.1.1", - "@objectstack/driver-sqlite-wasm": "18.0.0-next.3", - "@objectstack/hono": "18.0.0-next.3", - "@objectstack/metadata-core": "18.0.0-next.3", - "@objectstack/metadata-protocol": "18.0.0-next.3", - "@objectstack/objectql": "18.0.0-next.3", - "@objectstack/platform-objects": "18.0.0-next.3", - "@objectstack/plugin-auth": "18.0.0-next.3", - "@objectstack/plugin-hono-server": "18.0.0-next.3", - "@objectstack/rest": "18.0.0-next.3", - "@objectstack/runtime": "18.0.0-next.3", - "@objectstack/service-analytics": "18.0.0-next.3", - "@objectstack/service-automation": "18.0.0-next.3", + "@objectstack/driver-sqlite-wasm": "18.0.0-next.4", + "@objectstack/hono": "18.0.0-next.4", + "@objectstack/metadata-core": "18.0.0-next.4", + "@objectstack/metadata-protocol": "18.0.0-next.4", + "@objectstack/objectql": "18.0.0-next.4", + "@objectstack/platform-objects": "18.0.0-next.4", + "@objectstack/plugin-auth": "18.0.0-next.4", + "@objectstack/plugin-hono-server": "18.0.0-next.4", + "@objectstack/rest": "18.0.0-next.4", + "@objectstack/runtime": "18.0.0-next.4", + "@objectstack/service-analytics": "18.0.0-next.4", + "@objectstack/service-automation": "18.0.0-next.4", "tsx": "^4.23.15", "typescript": "^6.0.3", "vitest": "^4.1.11" diff --git a/.objectstack-pin/core/package.json b/.objectstack-pin/core/package.json index c86e1eb84e..79f8915b75 100644 --- a/.objectstack-pin/core/package.json +++ b/.objectstack-pin/core/package.json @@ -1,6 +1,6 @@ { "name": "@objectstack/core", - "version": "18.0.0-next.3", + "version": "18.0.0-next.4", "license": "Apache-2.0", "description": "Microkernel Core for ObjectStack", "type": "module", @@ -19,7 +19,7 @@ } }, "devDependencies": { - "@objectstack/metadata-core": "18.0.0-next.3", + "@objectstack/metadata-core": "18.0.0-next.4", "@objectstack/refd-timer-testkit": "0.1.0", "@types/node": "^26.6.3", "esbuild": "^0.28.2", @@ -27,8 +27,8 @@ "vitest": "^4.1.11" }, "dependencies": { - "@objectstack/spec": "18.0.0-next.3", - "@objectstack/types": "18.0.0-next.3", + "@objectstack/spec": "18.0.0-next.4", + "@objectstack/types": "18.0.0-next.4", "zod": "^4.6.5" }, "keywords": [ diff --git a/.objectstack-pin/formula/package.json b/.objectstack-pin/formula/package.json index e942c3fabf..46db1fa21a 100644 --- a/.objectstack-pin/formula/package.json +++ b/.objectstack-pin/formula/package.json @@ -1,6 +1,6 @@ { "name": "@objectstack/formula", - "version": "18.0.0-next.3", + "version": "18.0.0-next.4", "license": "Apache-2.0", "description": "ObjectStack canonical expression engine — CEL (cel-js) + ObjectStack stdlib + dialect registry", "main": "dist/index.js", @@ -14,7 +14,7 @@ }, "dependencies": { "@marcbachmann/cel-js": "^8.0.0", - "@objectstack/spec": "18.0.0-next.3" + "@objectstack/spec": "18.0.0-next.4" }, "devDependencies": { "@types/node": "^26.6.3", diff --git a/.objectstack-pin/lint/package.json b/.objectstack-pin/lint/package.json index 7494aeaca9..ede9e85ee0 100644 --- a/.objectstack-pin/lint/package.json +++ b/.objectstack-pin/lint/package.json @@ -1,6 +1,6 @@ { "name": "@objectstack/lint", - "version": "18.0.0-next.3", + "version": "18.0.0-next.4", "license": "Apache-2.0", "description": "Static, build-time validation for an ObjectStack metadata graph — dashboard widget bindings, CEL/predicate expressions, and more. Pure (stack) => Issue[] functions shared by the CLI's `os validate` and any other consumer (e.g. AI authoring). Depends on @objectstack/spec; never on a runtime.", "type": "module", @@ -39,9 +39,9 @@ } }, "dependencies": { - "@objectstack/formula": "18.0.0-next.3", - "@objectstack/sdui-parser": "18.0.0-next.3", - "@objectstack/spec": "18.0.0-next.3", + "@objectstack/formula": "18.0.0-next.4", + "@objectstack/sdui-parser": "18.0.0-next.4", + "@objectstack/spec": "18.0.0-next.4", "ajv": "^8.20.0", "ajv-formats": "^3.0.1", "sucrase": "^3.35.1", diff --git a/.objectstack-pin/sdui-parser/package.json b/.objectstack-pin/sdui-parser/package.json index dd6a1c5aa4..32299ea17e 100644 --- a/.objectstack-pin/sdui-parser/package.json +++ b/.objectstack-pin/sdui-parser/package.json @@ -1,6 +1,6 @@ { "name": "@objectstack/sdui-parser", - "version": "18.0.0-next.3", + "version": "18.0.0-next.4", "license": "Apache-2.0", "description": "ObjectStack constrained JSX-source → SDUI SchemaNode tree compiler (parse, never execute). Isomorphic, zero React. ADR-0080.", "main": "dist/index.js", diff --git a/.objectstack-pin/spec/package.json b/.objectstack-pin/spec/package.json index 0d72da08ca..617fed142a 100644 --- a/.objectstack-pin/spec/package.json +++ b/.objectstack-pin/spec/package.json @@ -1,6 +1,6 @@ { "name": "@objectstack/spec", - "version": "18.0.0-next.3", + "version": "18.0.0-next.4", "description": "ObjectStack Protocol & Specification - TypeScript Interfaces, JSON Schemas, and Convention Configurations", "license": "Apache-2.0", "main": "dist/index.js", diff --git a/.objectstack-pin/types/package.json b/.objectstack-pin/types/package.json index 1ecc7e72ed..f6db750660 100644 --- a/.objectstack-pin/types/package.json +++ b/.objectstack-pin/types/package.json @@ -1,6 +1,6 @@ { "name": "@objectstack/types", - "version": "18.0.0-next.3", + "version": "18.0.0-next.4", "license": "Apache-2.0", "description": "Shared interfaces describing the ObjectStack Runtime environment", "main": "dist/index.js", @@ -18,7 +18,7 @@ } }, "dependencies": { - "@objectstack/spec": "18.0.0-next.3" + "@objectstack/spec": "18.0.0-next.4" }, "devDependencies": { "typescript": "^6.0.3", From 110bf6fd1978818620967f6ae8acf00c2629ff59 Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 19 Oct 2026 12:12:54 +0000 Subject: [PATCH 10/13] chore: bump objectstack to f4755a68a797 (past the 18.0.0-next.5 release) docs(skills): objectstack-data says which hook doors provide ctx.title (#24289) (#24504) objectstack@f4755a68a797d5a000cb8bd1c942cb2a9862108e The first move (2ec6827962) built packages that read 18.0.0-next.4, a version objectstack never published or tagged, so the live-e2e backend pin (e2e/live/ci/backend.env, held equal to the lockfile's spec version by ci-cd-pipeline-doc.test.ts) had no published pair. f4755a68a7 is the newest objectstack main commit green at this move (150 check-runs completed, none failed) and is past the 18.0.0-next.5 release commit 820fd5aef0, so its packages read 18.0.0-next.5, which npm publishes and @objectstack/cli@18.0.0-next.5 tags. - scripts/bump-objectstack.sh --no-commit built it and wrote the packed manifests; pnpm install leaves pnpm-lock.yaml unchanged. - OBJECTSTACK_VERSION=18.0.0-next.5 in backend.env. - The installed-pin claims move next.4 -> next.5: the same node probe reads every fact identically on the new pin, and service-automation's engine diff between the two pins touches none of the reads the start-gate table names. Claude-Session: https://claude.ai/code/session_0188TsgPV8kQXfuRuKmkj2ks Co-authored-by: Claude --- ...27962.md => 12971-objectstack-pin-main.md} | 4 +-- .objectstack-pin/client/package.json | 30 +++++++++---------- .objectstack-pin/core/package.json | 8 ++--- .objectstack-pin/formula/package.json | 4 +-- .objectstack-pin/lint/package.json | 8 ++--- .objectstack-pin/sdui-parser/package.json | 2 +- .objectstack-pin/spec/package.json | 2 +- .objectstack-pin/types/package.json | 4 +-- .objectstack-sha | 2 +- .../registry-inputs-spec-parity.test.ts | 6 ++-- e2e/live/ci/backend.env | 2 +- .../src/views/metadata-admin/celAuthoring.ts | 2 +- ...FlowNodeInspector.declaredDefault.test.tsx | 2 +- .../flow-node-config.startGates-12780.test.ts | 2 +- .../inspectors/flowSingleBrace-12329.test.tsx | 2 +- ...low-canvas-seeds.saveErrors-10948.test.tsx | 2 +- packages/core/src/evaluator/optionRules.ts | 2 +- .../plugin-calendar/src/ObjectCalendar.tsx | 2 +- .../calendarUnionReads-8651.test.tsx | 2 +- .../src/MetadataFieldsPage.tsx | 2 +- packages/plugin-detail/src/index.tsx | 4 +-- .../formSectionGroupReference-7051.test.tsx | 2 +- .../masterDetailDetailsMembers-8071.test.tsx | 2 +- .../src/readme-navigation-example.test.ts | 2 +- packages/plugin-kanban/src/index.tsx | 2 +- .../chartconfig-aria-retired-4044.test.ts | 2 +- ...hboard-aria-retired-contract-twins.test.ts | 4 +-- .../object-view-unmirrored-keys-7779.test.ts | 2 +- .../record-details-top-level-9040.test.ts | 2 +- .../spec-object-refinements-7715.test.ts | 4 +-- packages/types/src/field-types.ts | 6 ++-- packages/types/src/objectql.ts | 2 +- packages/types/src/record-components.ts | 6 ++-- packages/types/src/zod/objectql.zod.ts | 4 +-- 34 files changed, 67 insertions(+), 67 deletions(-) rename .changeset/{12971-objectstack-pin-main-2ec6827962.md => 12971-objectstack-pin-main.md} (86%) diff --git a/.changeset/12971-objectstack-pin-main-2ec6827962.md b/.changeset/12971-objectstack-pin-main.md similarity index 86% rename from .changeset/12971-objectstack-pin-main-2ec6827962.md rename to .changeset/12971-objectstack-pin-main.md index 8ad7bda18c..5397be6cca 100644 --- a/.changeset/12971-objectstack-pin-main-2ec6827962.md +++ b/.changeset/12971-objectstack-pin-main.md @@ -6,9 +6,9 @@ "@object-ui/runner": minor --- -Build `@objectstack/*` from objectstack `main` `2ec6827962` (objectui#12971). +Build `@objectstack/*` from objectstack `main` `f4755a68a7` (objectui#12971). -`.objectstack-sha` moves from `2c9bf9430a`, the commit `@objectstack/spec` `18.0.0-next.3` was released from, to `2ec6827962`, a commit on objectstack `main` whose packages read `18.0.0-next.4`. The console and the runner bundle `@objectstack/*` built from it. No package's `@objectstack/*` range changes. +`.objectstack-sha` moves from `2c9bf9430a`, the commit `@objectstack/spec` `18.0.0-next.3` was released from, to `f4755a68a7`, a commit on objectstack `main` after the `18.0.0-next.5` release, so its packages read `18.0.0-next.5`. The console and the runner bundle `@objectstack/*` built from it. No package's `@objectstack/*` range changes. Clause-②: no (narrowing) diff --git a/.objectstack-pin/client/package.json b/.objectstack-pin/client/package.json index f3558e2cbc..6f55f8e787 100644 --- a/.objectstack-pin/client/package.json +++ b/.objectstack-pin/client/package.json @@ -1,6 +1,6 @@ { "name": "@objectstack/client", - "version": "18.0.0-next.4", + "version": "18.0.0-next.5", "license": "Apache-2.0", "description": "Official Client SDK for ObjectStack Protocol", "main": "dist/index.js", @@ -13,23 +13,23 @@ } }, "dependencies": { - "@objectstack/core": "18.0.0-next.4", - "@objectstack/spec": "18.0.0-next.4" + "@objectstack/core": "18.0.0-next.5", + "@objectstack/spec": "18.0.0-next.5" }, "devDependencies": { "@hono/node-server": "^2.1.1", - "@objectstack/driver-sqlite-wasm": "18.0.0-next.4", - "@objectstack/hono": "18.0.0-next.4", - "@objectstack/metadata-core": "18.0.0-next.4", - "@objectstack/metadata-protocol": "18.0.0-next.4", - "@objectstack/objectql": "18.0.0-next.4", - "@objectstack/platform-objects": "18.0.0-next.4", - "@objectstack/plugin-auth": "18.0.0-next.4", - "@objectstack/plugin-hono-server": "18.0.0-next.4", - "@objectstack/rest": "18.0.0-next.4", - "@objectstack/runtime": "18.0.0-next.4", - "@objectstack/service-analytics": "18.0.0-next.4", - "@objectstack/service-automation": "18.0.0-next.4", + "@objectstack/driver-sqlite-wasm": "18.0.0-next.5", + "@objectstack/hono": "18.0.0-next.5", + "@objectstack/metadata-core": "18.0.0-next.5", + "@objectstack/metadata-protocol": "18.0.0-next.5", + "@objectstack/objectql": "18.0.0-next.5", + "@objectstack/platform-objects": "18.0.0-next.5", + "@objectstack/plugin-auth": "18.0.0-next.5", + "@objectstack/plugin-hono-server": "18.0.0-next.5", + "@objectstack/rest": "18.0.0-next.5", + "@objectstack/runtime": "18.0.0-next.5", + "@objectstack/service-analytics": "18.0.0-next.5", + "@objectstack/service-automation": "18.0.0-next.5", "tsx": "^4.23.15", "typescript": "^6.0.3", "vitest": "^4.1.11" diff --git a/.objectstack-pin/core/package.json b/.objectstack-pin/core/package.json index 79f8915b75..7923a176b9 100644 --- a/.objectstack-pin/core/package.json +++ b/.objectstack-pin/core/package.json @@ -1,6 +1,6 @@ { "name": "@objectstack/core", - "version": "18.0.0-next.4", + "version": "18.0.0-next.5", "license": "Apache-2.0", "description": "Microkernel Core for ObjectStack", "type": "module", @@ -19,7 +19,7 @@ } }, "devDependencies": { - "@objectstack/metadata-core": "18.0.0-next.4", + "@objectstack/metadata-core": "18.0.0-next.5", "@objectstack/refd-timer-testkit": "0.1.0", "@types/node": "^26.6.3", "esbuild": "^0.28.2", @@ -27,8 +27,8 @@ "vitest": "^4.1.11" }, "dependencies": { - "@objectstack/spec": "18.0.0-next.4", - "@objectstack/types": "18.0.0-next.4", + "@objectstack/spec": "18.0.0-next.5", + "@objectstack/types": "18.0.0-next.5", "zod": "^4.6.5" }, "keywords": [ diff --git a/.objectstack-pin/formula/package.json b/.objectstack-pin/formula/package.json index 46db1fa21a..1c88694b93 100644 --- a/.objectstack-pin/formula/package.json +++ b/.objectstack-pin/formula/package.json @@ -1,6 +1,6 @@ { "name": "@objectstack/formula", - "version": "18.0.0-next.4", + "version": "18.0.0-next.5", "license": "Apache-2.0", "description": "ObjectStack canonical expression engine — CEL (cel-js) + ObjectStack stdlib + dialect registry", "main": "dist/index.js", @@ -14,7 +14,7 @@ }, "dependencies": { "@marcbachmann/cel-js": "^8.0.0", - "@objectstack/spec": "18.0.0-next.4" + "@objectstack/spec": "18.0.0-next.5" }, "devDependencies": { "@types/node": "^26.6.3", diff --git a/.objectstack-pin/lint/package.json b/.objectstack-pin/lint/package.json index ede9e85ee0..0460a6e763 100644 --- a/.objectstack-pin/lint/package.json +++ b/.objectstack-pin/lint/package.json @@ -1,6 +1,6 @@ { "name": "@objectstack/lint", - "version": "18.0.0-next.4", + "version": "18.0.0-next.5", "license": "Apache-2.0", "description": "Static, build-time validation for an ObjectStack metadata graph — dashboard widget bindings, CEL/predicate expressions, and more. Pure (stack) => Issue[] functions shared by the CLI's `os validate` and any other consumer (e.g. AI authoring). Depends on @objectstack/spec; never on a runtime.", "type": "module", @@ -39,9 +39,9 @@ } }, "dependencies": { - "@objectstack/formula": "18.0.0-next.4", - "@objectstack/sdui-parser": "18.0.0-next.4", - "@objectstack/spec": "18.0.0-next.4", + "@objectstack/formula": "18.0.0-next.5", + "@objectstack/sdui-parser": "18.0.0-next.5", + "@objectstack/spec": "18.0.0-next.5", "ajv": "^8.20.0", "ajv-formats": "^3.0.1", "sucrase": "^3.35.1", diff --git a/.objectstack-pin/sdui-parser/package.json b/.objectstack-pin/sdui-parser/package.json index 32299ea17e..8a9958c0ba 100644 --- a/.objectstack-pin/sdui-parser/package.json +++ b/.objectstack-pin/sdui-parser/package.json @@ -1,6 +1,6 @@ { "name": "@objectstack/sdui-parser", - "version": "18.0.0-next.4", + "version": "18.0.0-next.5", "license": "Apache-2.0", "description": "ObjectStack constrained JSX-source → SDUI SchemaNode tree compiler (parse, never execute). Isomorphic, zero React. ADR-0080.", "main": "dist/index.js", diff --git a/.objectstack-pin/spec/package.json b/.objectstack-pin/spec/package.json index 617fed142a..2c0ab2c59d 100644 --- a/.objectstack-pin/spec/package.json +++ b/.objectstack-pin/spec/package.json @@ -1,6 +1,6 @@ { "name": "@objectstack/spec", - "version": "18.0.0-next.4", + "version": "18.0.0-next.5", "description": "ObjectStack Protocol & Specification - TypeScript Interfaces, JSON Schemas, and Convention Configurations", "license": "Apache-2.0", "main": "dist/index.js", diff --git a/.objectstack-pin/types/package.json b/.objectstack-pin/types/package.json index f6db750660..541ffa61ac 100644 --- a/.objectstack-pin/types/package.json +++ b/.objectstack-pin/types/package.json @@ -1,6 +1,6 @@ { "name": "@objectstack/types", - "version": "18.0.0-next.4", + "version": "18.0.0-next.5", "license": "Apache-2.0", "description": "Shared interfaces describing the ObjectStack Runtime environment", "main": "dist/index.js", @@ -18,7 +18,7 @@ } }, "dependencies": { - "@objectstack/spec": "18.0.0-next.4" + "@objectstack/spec": "18.0.0-next.5" }, "devDependencies": { "typescript": "^6.0.3", diff --git a/.objectstack-sha b/.objectstack-sha index 0b15ee08ca..ff6357d136 100644 --- a/.objectstack-sha +++ b/.objectstack-sha @@ -1 +1 @@ -2ec6827962ac95a7bdbdad413fd74f65ca238e07 +f4755a68a797d5a000cb8bd1c942cb2a9862108e diff --git a/apps/console/src/__tests__/registry-inputs-spec-parity.test.ts b/apps/console/src/__tests__/registry-inputs-spec-parity.test.ts index 0ad4da53c1..bb2f2b8fd7 100644 --- a/apps/console/src/__tests__/registry-inputs-spec-parity.test.ts +++ b/apps/console/src/__tests__/registry-inputs-spec-parity.test.ts @@ -2966,11 +2966,11 @@ const MEMBER_PINS: Record = { }, 'object-grid.data': { file: 'packages/plugin-grid/src/__tests__/gridDataInputContract.test.ts', - pins: 'The `object` arm is `ViewDataSchema` discriminated on `provider`: each of the three providers parses and the retired `api` one is refused (spec 18.0.0-next.4, objectui#12370, objectui#12971), none of them is an array, the declaration is one shape across both registered tags so the alias cannot drift, and it is pinned at compile time too (objectui#5090).', + pins: 'The `object` arm is `ViewDataSchema` discriminated on `provider`: each of the three providers parses and the retired `api` one is refused (spec 18.0.0-next.5, objectui#12370, objectui#12971), none of them is an array, the declaration is one shape across both registered tags so the alias cannot drift, and it is pinned at compile time too (objectui#5090).', }, 'object-grid.conditionalFormatting': { file: 'packages/plugin-grid/src/__tests__/gridRowDecorationMembers-8071.test.tsx', - pins: 'The members read inside ONE formatting rule, asserted on the `style` attribute of the `` the grid paints. THREE alternative predicate members with a PRECEDENCE between them — one rule carrying `condition`, `expression` and the native `field`/`operator`/`value` triple, each naming a DIFFERENT row, is decided by `condition`; drop it and `expression` decides; drop that and the triple does — so a renderer reading any two of them as equivalent is red in a specific direction rather than merely unpinned. FOUR style members, and the sharp one is a RENAME: `backgroundColor` and `borderColor` keep their authored names on the way to the DOM while `textColor` is read as the CSS `color`, so keeping the authored spelling hands React a key it silently drops — same rules, same background, the text colour gone with nothing thrown. `style` is pinned as the BASE the three colour members override rather than replace (a non-colour member of it survives alongside the override). Two rule-list facts complete it: FIRST-MATCH-WINS with no merge (the second matching rule\'s own `textColor` never lands) and a rule carrying NO predicate member is SKIPPED rather than read as always-true, with the rule after it still deciding. ⚠️ Since objectui#11533 the AUTHORED member is ONE dialect, `{ condition, style }`: `expression`, the native triple and the three top-level colour members are refused by name on `ObjectGridSchema` and the list view (`packages/types/src/__tests__/grid-list-view-conditional-formatting-11533.test.ts`), so the rows that write them pin STORED-rule reads, which the resolver keeps as compatibility arms; a last block pins the two facts side by side — the stored native rule refused at authoring and painted at render, with its respelling painting the same row. The registration is an `array` arm; the installed spec row (18.0.0-next.4, re-measured by objectui#12030, objectui#12370, objectui#12626, objectui#12873, objectui#12971) takes the list view\'s own `{ condition, style }` rule and refuses the native members and any other key, so the spec fixes the AUTHORED shape and the read site is the rest of the member contract, the stored-rule compatibility arms included (objectui#8071 slice 12).', + pins: 'The members read inside ONE formatting rule, asserted on the `style` attribute of the `` the grid paints. THREE alternative predicate members with a PRECEDENCE between them — one rule carrying `condition`, `expression` and the native `field`/`operator`/`value` triple, each naming a DIFFERENT row, is decided by `condition`; drop it and `expression` decides; drop that and the triple does — so a renderer reading any two of them as equivalent is red in a specific direction rather than merely unpinned. FOUR style members, and the sharp one is a RENAME: `backgroundColor` and `borderColor` keep their authored names on the way to the DOM while `textColor` is read as the CSS `color`, so keeping the authored spelling hands React a key it silently drops — same rules, same background, the text colour gone with nothing thrown. `style` is pinned as the BASE the three colour members override rather than replace (a non-colour member of it survives alongside the override). Two rule-list facts complete it: FIRST-MATCH-WINS with no merge (the second matching rule\'s own `textColor` never lands) and a rule carrying NO predicate member is SKIPPED rather than read as always-true, with the rule after it still deciding. ⚠️ Since objectui#11533 the AUTHORED member is ONE dialect, `{ condition, style }`: `expression`, the native triple and the three top-level colour members are refused by name on `ObjectGridSchema` and the list view (`packages/types/src/__tests__/grid-list-view-conditional-formatting-11533.test.ts`), so the rows that write them pin STORED-rule reads, which the resolver keeps as compatibility arms; a last block pins the two facts side by side — the stored native rule refused at authoring and painted at render, with its respelling painting the same row. The registration is an `array` arm; the installed spec row (18.0.0-next.5, re-measured by objectui#12030, objectui#12370, objectui#12626, objectui#12873, objectui#12971) takes the list view\'s own `{ condition, style }` rule and refuses the native members and any other key, so the spec fixes the AUTHORED shape and the read site is the rest of the member contract, the stored-rule compatibility arms included (objectui#8071 slice 12).', }, 'object-grid.operations': { file: 'packages/plugin-grid/src/__tests__/gridOperationsMembers-8071.test.tsx', @@ -3046,7 +3046,7 @@ const MEMBER_PINS: Record = { }, 'object-kanban.conditionalFormatting': { file: 'packages/plugin-kanban/src/__tests__/ObjectKanban.structuredMembersReachTheirSinks-8313.test.tsx', - pins: 'Members are card STYLE RULES in ONE dialect since objectui#11522, the spec list view\'s `{ condition, style }`, and it reaches the sink: a rule colours the matching card and only it, a second rule aimed at the other card does the same, and the whole `style` map arrives, with the sibling card in the same render as the live non-matching control so a green cannot come from two unstyled cards agreeing. The retired native `{ field, operator, value }` and flat-colour dialects are refused by name on the types side (`packages/types/src/__tests__/kanban-conditional-formatting.test.ts`); these rows are their respellings, painting the same cards. ⛔ NOT an identity pin and not a wire pin: `ObjectKanban.tsx` never names this key at all (measured zero, against nine for `cardFields` in the same file) — it rides the `{ ...schema }` spread into `KanbanRenderer`, which forwards it to `KanbanImpl`\'s `getCardStyles`. That makes the pin load-bearing in a way the others are not: an edit replacing that spread with an explicit key list drops the key silently and nothing else in the repo would notice. The installed spec row (18.0.0-next.4, re-measured by objectui#12030, objectui#12370, objectui#12626, objectui#12873, objectui#12971) takes the list view\'s own `{ condition, style }` rule, so the spec fixes the authored shape and the read site is the rest of the member contract (objectui#8313).', + pins: 'Members are card STYLE RULES in ONE dialect since objectui#11522, the spec list view\'s `{ condition, style }`, and it reaches the sink: a rule colours the matching card and only it, a second rule aimed at the other card does the same, and the whole `style` map arrives, with the sibling card in the same render as the live non-matching control so a green cannot come from two unstyled cards agreeing. The retired native `{ field, operator, value }` and flat-colour dialects are refused by name on the types side (`packages/types/src/__tests__/kanban-conditional-formatting.test.ts`); these rows are their respellings, painting the same cards. ⛔ NOT an identity pin and not a wire pin: `ObjectKanban.tsx` never names this key at all (measured zero, against nine for `cardFields` in the same file) — it rides the `{ ...schema }` spread into `KanbanRenderer`, which forwards it to `KanbanImpl`\'s `getCardStyles`. That makes the pin load-bearing in a way the others are not: an edit replacing that spread with an explicit key list drops the key silently and nothing else in the repo would notice. The installed spec row (18.0.0-next.5, re-measured by objectui#12030, objectui#12370, objectui#12626, objectui#12873, objectui#12971) takes the list view\'s own `{ condition, style }` rule, so the spec fixes the authored shape and the read site is the rest of the member contract (objectui#8313).', }, 'object-kanban.data': { file: 'packages/plugin-kanban/src/__tests__/ObjectKanban.structuredMembersReachTheirSinks-8313.test.tsx', diff --git a/e2e/live/ci/backend.env b/e2e/live/ci/backend.env index 5b4e1ae39f..aba0e6984d 100644 --- a/e2e/live/ci/backend.env +++ b/e2e/live/ci/backend.env @@ -14,7 +14,7 @@ # # This file declares exactly ONE @objectstack pin, and that is the whole # design: the commit is derived from it, see below. -OBJECTSTACK_VERSION=18.0.0-next.3 +OBJECTSTACK_VERSION=18.0.0-next.5 # There is deliberately no OBJECTSTACK_REF key here. The objectstack-ai/objectstack # commit the showcase app metadata is sparse-checked-out from is DERIVED at diff --git a/packages/app-shell/src/views/metadata-admin/celAuthoring.ts b/packages/app-shell/src/views/metadata-admin/celAuthoring.ts index bc0a9d6b37..d0b4c2851d 100644 --- a/packages/app-shell/src/views/metadata-admin/celAuthoring.ts +++ b/packages/app-shell/src/views/metadata-admin/celAuthoring.ts @@ -428,7 +428,7 @@ function loadRowCanon(): Promise { * not re-derived — and the engine's own message ships with it. * * ⚠️ The reason is NOT that the engine's message refuses a `record.` - * rewrite. Measured against the installed 18.0.0-next.4 (objectui#12030, objectui#12370, objectui#12626, objectui#12873, objectui#12971), it mostly PRESCRIBES one: the + * rewrite. Measured against the installed 18.0.0-next.5 (objectui#12030, objectui#12370, objectui#12626, objectui#12873, objectui#12971), it mostly PRESCRIBES one: the * `current_user` text CONTAINS "To gate on record state, rewrite the predicate * against `record`." — one of the three remedies it offers, and NOT where it * ends (measured: `includes` true, `endsWith` false; every covered slot's text diff --git a/packages/app-shell/src/views/metadata-admin/inspectors/FlowNodeInspector.declaredDefault.test.tsx b/packages/app-shell/src/views/metadata-admin/inspectors/FlowNodeInspector.declaredDefault.test.tsx index 466d62363d..a2e541c11d 100644 --- a/packages/app-shell/src/views/metadata-admin/inspectors/FlowNodeInspector.declaredDefault.test.tsx +++ b/packages/app-shell/src/views/metadata-admin/inspectors/FlowNodeInspector.declaredDefault.test.tsx @@ -381,7 +381,7 @@ describe('boolean: a declared defaultValue seeds the control (objectui#8451, arm // ⇒ `screen.waitForInput` is the offline undeclared boolean that sentence // says does not exist — and it is undeclared CORRECTLY, so ⛔ do not read // this as an objectui#9277-class omission waiting to be declared. Measured - // on the installed `@objectstack/spec` (18.0.0-next.4, objectui#12030, objectui#12370, objectui#12626, objectui#12873, objectui#12971): `waitForInput` is typed + // on the installed `@objectstack/spec` (18.0.0-next.5, objectui#12030, objectui#12370, objectui#12626, objectui#12873, objectui#12971): `waitForInput` is typed // `z.boolean().optional()` with no `.default(...)`, so an omitted key // materialises nothing and there is no spec answer for a declaration to // mirror. Declaring one here would invent a default the runtime does not diff --git a/packages/app-shell/src/views/metadata-admin/inspectors/flow-node-config.startGates-12780.test.ts b/packages/app-shell/src/views/metadata-admin/inspectors/flow-node-config.startGates-12780.test.ts index 455c2c6184..f87da53cae 100644 --- a/packages/app-shell/src/views/metadata-admin/inspectors/flow-node-config.startGates-12780.test.ts +++ b/packages/app-shell/src/views/metadata-admin/inspectors/flow-node-config.startGates-12780.test.ts @@ -6,7 +6,7 @@ * * The table below is what `@objectstack/service-automation`'s * `AutomationEngine` and the trigger packages read, at objectstack - * `18.0.0-next.4` (the installed `@objectstack/spec` line): + * `18.0.0-next.5` (the installed `@objectstack/spec` line): * * - `secret`: the API trigger arms from `config.secret` (`trigger-api`). * - `objectName`: lifted into the `record_change` binding, which the diff --git a/packages/app-shell/src/views/metadata-admin/inspectors/flowSingleBrace-12329.test.tsx b/packages/app-shell/src/views/metadata-admin/inspectors/flowSingleBrace-12329.test.tsx index 2377d41056..ac5cc49c21 100644 --- a/packages/app-shell/src/views/metadata-admin/inspectors/flowSingleBrace-12329.test.tsx +++ b/packages/app-shell/src/views/metadata-admin/inspectors/flowSingleBrace-12329.test.tsx @@ -6,7 +6,7 @@ * * objectstack#19939 S7 deleted the engine's single-brace resolver: a value slot * refuses a `{…}` token, a text slot reads `{{ }}` holes, and every other flow - * string is a literal. The installed spec (`18.0.0-next.4`) publishes no + * string is a literal. The installed spec (`18.0.0-next.5`) publishes no * `xExpression: 'template'` mark. So the picker has two spellings left — the * bare reference and the `{{ }}` hole — and a literal position has no picker. * diff --git a/packages/app-shell/src/views/metadata-admin/previews/flow-canvas-seeds.saveErrors-10948.test.tsx b/packages/app-shell/src/views/metadata-admin/previews/flow-canvas-seeds.saveErrors-10948.test.tsx index 994b385f4f..418e6b7993 100644 --- a/packages/app-shell/src/views/metadata-admin/previews/flow-canvas-seeds.saveErrors-10948.test.tsx +++ b/packages/app-shell/src/views/metadata-admin/previews/flow-canvas-seeds.saveErrors-10948.test.tsx @@ -2,7 +2,7 @@ /** * objectui#10948 — what the designer's live `FlowSchema` pass says about a node - * the author has ADDED but not yet configured, on the installed spec (18.0.0-next.4). + * the author has ADDED but not yet configured, on the installed spec (18.0.0-next.5). * * Spec 17.5.0 carries objectstack#20316 (a node config key its executor * contract requires, left out, and a decision branch with no `label`, are diff --git a/packages/core/src/evaluator/optionRules.ts b/packages/core/src/evaluator/optionRules.ts index 21e0fa0f4e..e7c06f899d 100644 --- a/packages/core/src/evaluator/optionRules.ts +++ b/packages/core/src/evaluator/optionRules.ts @@ -118,7 +118,7 @@ export function resolveVisibleOptions( * This is deliberately NOT the lenient renderer fallback AGENTS.md #0.1 * forbids. That rule governs metadata the contract REFUSES ("if the metadata * is off-spec, fix it at the producer"); an empty label is metadata the - * contract ACCEPTS. Measured on the installed `@objectstack/spec` 18.0.0-next.4, + * contract ACCEPTS. Measured on the installed `@objectstack/spec` 18.0.0-next.5, * `SelectOptionSchema`: * * { value: 'low', label: 'Low' } -> ACCEPT (lit control) diff --git a/packages/plugin-calendar/src/ObjectCalendar.tsx b/packages/plugin-calendar/src/ObjectCalendar.tsx index ed616e6caf..f0c90a8054 100644 --- a/packages/plugin-calendar/src/ObjectCalendar.tsx +++ b/packages/plugin-calendar/src/ObjectCalendar.tsx @@ -1428,7 +1428,7 @@ export const ObjectCalendar: React.FC = ({ * * `@objectstack/spec`'s `CalendarConfigSchema` is a `strictObject` whose ONE * required key is `startDateField`; `titleField` is optional. Re-measured on - * the installed 18.0.0-next.4 (objectui#12030, objectui#12370, objectui#12626, objectui#12873, objectui#12971), three legs: `{}` and `{ titleField: 't' }` both fail + * the installed 18.0.0-next.5 (objectui#12030, objectui#12370, objectui#12626, objectui#12873, objectui#12971), three legs: `{}` and `{ titleField: 't' }` both fail * `invalid_type` at `startDateField`, and `{ startDateField: 'd' }` parses * CLEAN. The spec's own note on that schema names THIS renderer as the * reason — `resolveTitle` above takes an explicit `titleField` when present diff --git a/packages/plugin-calendar/src/__tests__/calendarUnionReads-8651.test.tsx b/packages/plugin-calendar/src/__tests__/calendarUnionReads-8651.test.tsx index 2baf7983fc..25f8ce1a9c 100644 --- a/packages/plugin-calendar/src/__tests__/calendarUnionReads-8651.test.tsx +++ b/packages/plugin-calendar/src/__tests__/calendarUnionReads-8651.test.tsx @@ -179,7 +179,7 @@ const LEDGERED_OTHER_CARD_READS: readonly string[] = []; * `ObjectCalendarSchema` and must stay so. * * ⚠️ The ground is NOT that the spec singles these two out. MEASURED on - * installed `@objectstack/spec` 18.0.0-next.4: `ComponentPropsMap['object-calendar']` + * installed `@objectstack/spec` 18.0.0-next.5: `ComponentPropsMap['object-calendar']` * is STRICT and declares exactly ten flat members — `calendar` `data` * `defaultView` `filter` `loading` `locale` `navigation` `objectName` `sort` * `staticData` (nine through 17.4.0; 17.5.0 added `navigation`) — diff --git a/packages/plugin-designer/src/MetadataFieldsPage.tsx b/packages/plugin-designer/src/MetadataFieldsPage.tsx index aa5bec8c5f..61799316ce 100644 --- a/packages/plugin-designer/src/MetadataFieldsPage.tsx +++ b/packages/plugin-designer/src/MetadataFieldsPage.tsx @@ -184,7 +184,7 @@ function isDesignerAuthorableType(raw: unknown): raw is DesignerFieldType { * ## Why reading the retired spelling is a RENAME here and not a laundering * * `@objectstack/spec` treats the two as one key under two spellings and says - * so in the refusal itself. Measured on the installed 18.0.0-next.4 (objectui#12030, objectui#12370, objectui#12626, objectui#12873, objectui#12971): + * so in the refusal itself. Measured on the installed 18.0.0-next.5 (objectui#12030, objectui#12370, objectui#12626, objectui#12873, objectui#12971): * * FieldSchema.safeParse({ type: 'lookup', label: 'L', referenceTo: 'account' }) * => success = false diff --git a/packages/plugin-detail/src/index.tsx b/packages/plugin-detail/src/index.tsx index e6232fe092..ce09f916cc 100644 --- a/packages/plugin-detail/src/index.tsx +++ b/packages/plugin-detail/src/index.tsx @@ -969,7 +969,7 @@ ComponentRegistry.register('alert', RecordAlertRenderer, { // through `pickLocalized`, which is exactly what these descriptions teach. // Declaring the map arm therefore adds no shape the block does not already // honour; it stops the manifest gate warning `type-mismatch` on the - // recommended write. (The row DOES exist as of the installed 18.0.0-next.4 — read + // recommended write. (The row DOES exist as of the installed 18.0.0-next.5 — read // for `visible` below, objectui#9100 — so the "no entry" reading is stale; // these two arms are unaffected either way.) { name: 'title', type: ['string', 'object'], description: 'Accepts an inline translation map ({ en, "zh-CN", … })' }, @@ -977,7 +977,7 @@ ComponentRegistry.register('alert', RecordAlertRenderer, { // objectui#9100 — the spec accepts three arms here and the renderer now // resolves all three, so a single `'string'` was the declaration-narrower- // than-the-contract family of objectui#4581, one layer up. Measured on the - // INSTALLED `@objectstack/spec` 18.0.0-next.4 (`dist/ui/index.d.ts`, the + // INSTALLED `@objectstack/spec` 18.0.0-next.5 (`dist/ui/index.d.ts`, the // `ComponentPropsMap['record:alert']` row): `visible` is // `boolean | string | { dialect: 'cel'|'cron'|'template', source?, … }`, // and `renderers/record-alert.tsx` hands whichever arrives to diff --git a/packages/plugin-form/src/__tests__/formSectionGroupReference-7051.test.tsx b/packages/plugin-form/src/__tests__/formSectionGroupReference-7051.test.tsx index ad3c7cd360..261cec23e3 100644 --- a/packages/plugin-form/src/__tests__/formSectionGroupReference-7051.test.tsx +++ b/packages/plugin-form/src/__tests__/formSectionGroupReference-7051.test.tsx @@ -448,7 +448,7 @@ describe('objectui#7051 — resolveSectionGroupReferences', () => { /** * ⭐ The second axis. The card asks that group-owned presentation keys beside * `group`, and `group` on a wizard step, not be SILENTLY accepted. Measured - * against the installed `@objectstack/spec` (18.0.0-next.4): both are refused at PARSE + * against the installed `@objectstack/spec` (18.0.0-next.5): both are refused at PARSE * — a stronger door than the lint that objectui#8497 concluded owns EXISTENCE * checking, and a different one. So authored metadata carrying either never * reaches this renderer at all; the renderer's own reports above exist for the diff --git a/packages/plugin-form/src/__tests__/masterDetailDetailsMembers-8071.test.tsx b/packages/plugin-form/src/__tests__/masterDetailDetailsMembers-8071.test.tsx index 6158db6edd..c295dc0160 100644 --- a/packages/plugin-form/src/__tests__/masterDetailDetailsMembers-8071.test.tsx +++ b/packages/plugin-form/src/__tests__/masterDetailDetailsMembers-8071.test.tsx @@ -504,7 +504,7 @@ type SpecDetailEntry = NonNullable[numbe * The config IS the spec's entry minus `sortField`, by reference * (objectui#11396): a member the spec adds, drops or retypes lands on the * config with no hand edit, and a hand-written restatement that drifts is red - * here before it is red anywhere else. The installed 18.0.0-next.4 entry carries a + * here before it is red anywhere else. The installed 18.0.0-next.5 entry carries a * `retiredKey()` tombstone for `sortField` (objectstack-ai/objectstack#21589); * 17.6.0 declared it as a string, and the subtraction removes the key either * way. ⛔ No row here pins which of the two shapes the spec has; the `Spec Main diff --git a/packages/plugin-gantt/src/readme-navigation-example.test.ts b/packages/plugin-gantt/src/readme-navigation-example.test.ts index 0251180602..2ddeeb624a 100644 --- a/packages/plugin-gantt/src/readme-navigation-example.test.ts +++ b/packages/plugin-gantt/src/readme-navigation-example.test.ts @@ -79,7 +79,7 @@ * * WARNING: `declaredMembers()` cannot derive that key's retirement. When this * was written the spec in the lockfile (17.4.0) still DECLARED `view` as a live - * member. The installed `@objectstack/spec` 18.0.0-next.4 lands it as a tombstone, + * member. The installed `@objectstack/spec` 18.0.0-next.5 lands it as a tombstone, * as 17.5.0 through 17.7.0 did (objectui#11073 measured it, objectui#11438, * objectui#11717 and objectui#12030 again: a `never` * schema, and `{ view: 'detail' }` is diff --git a/packages/plugin-kanban/src/index.tsx b/packages/plugin-kanban/src/index.tsx index 84396e70be..33863d6e1c 100644 --- a/packages/plugin-kanban/src/index.tsx +++ b/packages/plugin-kanban/src/index.tsx @@ -554,7 +554,7 @@ export const ObjectKanbanRenderer: React.FC<{ schema: any; [key: string]: any }> * ## Why these keys were added * * `@objectstack/spec`'s `ComponentPropsMap['object-kanban']` carries FIFTEEN - * top-level keys on the installed 18.0.0-next.4 pin, fourteen of them live, the + * top-level keys on the installed 18.0.0-next.5 pin, fourteen of them live, the * same set as 17.5.0 through 17.7.0: 17.5.0 * added `navigation` and turned `quickAdd` into a tombstone (typed `never`, * refused by name — objectui#8285's ruled retirement, landed). This list diff --git a/packages/types/src/__tests__/chartconfig-aria-retired-4044.test.ts b/packages/types/src/__tests__/chartconfig-aria-retired-4044.test.ts index 69ba41841a..9ae97d2345 100644 --- a/packages/types/src/__tests__/chartconfig-aria-retired-4044.test.ts +++ b/packages/types/src/__tests__/chartconfig-aria-retired-4044.test.ts @@ -30,7 +30,7 @@ * - **TypeScript.** `complex.ts` re-typed `chartConfig` as `any`, so an * authored `aria` compiled. The member now takes `aria` from the spec's own * input type, which is the spec's retired-key type (the branded `[REMOVED]` - * mark at the pinned 18.0.0-next.4 and on objectstack `main`, bare `undefined` + * mark at the pinned 18.0.0-next.5 and on objectstack `main`, bare `undefined` * through 17.5.0; both * spellings are `retired-key-type.ts`'s), so an authored value is a compile * error. diff --git a/packages/types/src/__tests__/dashboard-aria-retired-contract-twins.test.ts b/packages/types/src/__tests__/dashboard-aria-retired-contract-twins.test.ts index c384f3846c..cda25da806 100644 --- a/packages/types/src/__tests__/dashboard-aria-retired-contract-twins.test.ts +++ b/packages/types/src/__tests__/dashboard-aria-retired-contract-twins.test.ts @@ -29,7 +29,7 @@ * objectui#9736 closed that half. The interface now extends the spec's own * `Dashboard` input type (`Omit< Dashboard, … >` over the exclusion list its * mirror reads), so it inherits the spec's tombstone as a DECLARED member typed - * as the spec's retired key (the branded `[REMOVED]` mark at the pinned 18.0.0-next.4 + * as the spec's retired key (the branded `[REMOVED]` mark at the pinned 18.0.0-next.5 * and on objectstack `main`, bare `undefined` through 17.5.0) — `aria` is back in the declared key * set, but only as a refusal, * and an authored value is a compile error: the same verdict the Zod twin gives @@ -52,7 +52,7 @@ describe('the TS interface declares `aria` only as the spec tombstone (objectui# it('`aria` is declared, typed as the spec\'s retired key; the neighbours it stood beside still are', () => { // Type-level pins, erased at runtime. `aria` is a DECLARED key again — the // spec projection carries the tombstone — and its type admits no value: - // the branded `[REMOVED]` mark at the pinned 18.0.0-next.4 and on objectstack + // the branded `[REMOVED]` mark at the pinned 18.0.0-next.5 and on objectstack // `main`, bare `undefined` through 17.5.0 (both spellings are // `retired-key-type.ts`'s, objectui#11330). const ariaDeclared: 'aria' extends Declared ? true : false = true; diff --git a/packages/types/src/__tests__/object-view-unmirrored-keys-7779.test.ts b/packages/types/src/__tests__/object-view-unmirrored-keys-7779.test.ts index 3986f99ca5..f8f0ba8d1b 100644 --- a/packages/types/src/__tests__/object-view-unmirrored-keys-7779.test.ts +++ b/packages/types/src/__tests__/object-view-unmirrored-keys-7779.test.ts @@ -339,7 +339,7 @@ const NAMED_VIEW_ABSENT_CONTROL = 'stickyHeader'; /** * The protocol's own member set for a named list view — `ObjectListViewSchema`'s - * shape, off `@objectstack/spec` as installed (18.0.0-next.4). ⛔ Not a copy of the + * shape, off `@objectstack/spec` as installed (18.0.0-next.5). ⛔ Not a copy of the * objectui face and ⛔ not a hand list: it is read off the schema object, so a * spec bump that moves a key moves this. */ diff --git a/packages/types/src/__tests__/record-details-top-level-9040.test.ts b/packages/types/src/__tests__/record-details-top-level-9040.test.ts index f0b199c598..9c4683fdad 100644 --- a/packages/types/src/__tests__/record-details-top-level-9040.test.ts +++ b/packages/types/src/__tests__/record-details-top-level-9040.test.ts @@ -174,7 +174,7 @@ type _KeyofStillResolvesOnThisInterface = Expect< /** * The contract's face, untouched by this removal: the tombstone accepts nothing. * Its type is the spec's retired-key type — the branded `[REMOVED]` mark at the - * pinned 18.0.0-next.4 and on objectstack `main`, + * pinned 18.0.0-next.5 and on objectstack `main`, * bare `undefined` through 17.5.0 — and the helper accepts * exactly those two spellings (objectui#11330). */ diff --git a/packages/types/src/__tests__/spec-object-refinements-7715.test.ts b/packages/types/src/__tests__/spec-object-refinements-7715.test.ts index 20df08ce39..6a1d9e0f49 100644 --- a/packages/types/src/__tests__/spec-object-refinements-7715.test.ts +++ b/packages/types/src/__tests__/spec-object-refinements-7715.test.ts @@ -345,7 +345,7 @@ const SITES = [ // objectui#12370's view-data check left this list with objectui#12666: objectstack#23784 // removed it from the spec, and 18.0.0-next.3 is the first release without it (objectstack // `a35f7a6`). The census below accounts for it by what it judges, not by name - // (`specChecksRemovedOnMain`), which on the installed 18.0.0-next.4 finds nothing. + // (`specChecksRemovedOnMain`), which on the installed 18.0.0-next.5 finds nothing. // `checkPageRegionPlacement` joined at 18.0.0-next.2 and was attached by objectui#12626: it // reads `kind` and `template` (by reference) and each region's `name`, which objectui's own // region carries with the meaning `page.tsx` places it by; measured in its describe block above. @@ -450,7 +450,7 @@ const PAGE_SITE = 'SpecPageFields → PageNodeSchema (layout.zod.ts)'; * against its own spec tree, so no file here may name that export. Through * 18.0.0-next.2 the spec exported it and attached it to `PageSchema`, where * the census would miscount by one; 18.0.0-next.3 dropped it (objectstack - * `a35f7a6`), and on the installed 18.0.0-next.4 this answers empty. This reads every + * `a35f7a6`), and on the installed 18.0.0-next.5 this answers empty. This reads every * exported check no site names and keeps the ones that refuse a slotted * `object-grid` naming `api` at its `properties.data.provider`: on next.2 that * is exactly the removed judge, and on a spec without it the list is empty, so diff --git a/packages/types/src/field-types.ts b/packages/types/src/field-types.ts index f69ab2881c..87060efad2 100644 --- a/packages/types/src/field-types.ts +++ b/packages/types/src/field-types.ts @@ -25,7 +25,7 @@ import type { Field as SpecField } from '@objectstack/spec/data'; * sibling field names, or `{ field, param }` entries mapping a sibling onto the * remote query parameter a dependent lookup filters by. * - * Measured on the installed `@objectstack/spec` (18.0.0-next.4), `FieldSchema` declares + * Measured on the installed `@objectstack/spec` (18.0.0-next.5), `FieldSchema` declares * `dependsOn` as an OPTIONAL ARRAY of `string | { field, param? }` — never a * bare string. That is deliberately narrower than `DependsOnInput` (`form.ts`), * the shape the widget prop `FieldWidgetComponentProps.dependsOn` and @@ -343,7 +343,7 @@ export interface MarkdownFieldMetadata extends BaseFieldMetadata { * annotated literal rejected. Follows the `TextareaFieldMetadata` precedent. * * A DECLARED spec key as of `@objectstack/spec` 17.3.0, which implements that - * same ruling. Measured on the installed `@objectstack/spec` 18.0.0-next.4: + * same ruling. Measured on the installed `@objectstack/spec` 18.0.0-next.5: * `FieldSchema` ACCEPTS `rows` on all four of textarea/markdown/html/ * richtext, as an integer of at least 1 — a non-integer answers * `invalid_type` and 0 answers `too_small`, so "declared" does not mean "any @@ -692,7 +692,7 @@ export interface SelectOptionMetadata extends SelectOptionBase { * * A DECLARED `SelectOptionSchema` key as of `@objectstack/spec` 17.3.0, * which implements the objectui#6153 half of that ruling. Measured on the - * installed `@objectstack/spec` 18.0.0-next.4: an option carrying `description` + * installed `@objectstack/spec` 18.0.0-next.5: an option carrying `description` * is ACCEPTED, as a string (a non-string answers `invalid_type`; the empty * string is valid), and a field whose `options` carry it parses whole. ⇒ it * may now be written into authored object metadata, which is the point of diff --git a/packages/types/src/objectql.ts b/packages/types/src/objectql.ts index a735366877..a10fd0d9cb 100644 --- a/packages/types/src/objectql.ts +++ b/packages/types/src/objectql.ts @@ -4219,7 +4219,7 @@ export interface ObjectCalendarSchema extends BaseSchema { * (the spec's own `ObjectCalendarPropsSchema`) declares * `z.array(z.unknown()).optional()`, described *"Pre-fetched records — skips * the internal fetch"*. - * MEASURED on the installed artifact at `@objectstack/spec` 18.0.0-next.4 — the + * MEASURED on the installed artifact at `@objectstack/spec` 18.0.0-next.5 — the * version this repository's `pnpm-lock.yaml` resolves — through the published * `@objectstack/spec/ui` entry point: the provider block returns * `success=false` with `expected: 'array'` at `path: ['data']`, the array diff --git a/packages/types/src/record-components.ts b/packages/types/src/record-components.ts index d8f83cb430..2285440001 100644 --- a/packages/types/src/record-components.ts +++ b/packages/types/src/record-components.ts @@ -107,7 +107,7 @@ export interface RecordDetailsComponentProps { * It was `number` here until objectui#8604, which is the wrong PRIMITIVE * TYPE, not merely a wider range: `{ columns: 2 }` compiled locally and the * contract refused it at publish with `invalid_value` at `columns` (measured - * on the installed pin, 18.0.0-next.4, against a control — `columns: '2'` — that + * on the installed pin, 18.0.0-next.5, against a control — `columns: '2'` — that * parses green on the same instrument). Contract-first (Commandment #0.1): * the code moves to the contract's spelling, and today's `columns: 2` * authors are the defect surfacing rather than collateral damage. @@ -358,7 +358,7 @@ export interface RecordHighlightsComponentProps { * `RecordHighlightsProps.fields[]`'s object arm declares exactly * `name`/`label`/`type`/`readonly` and carries a `never` catchall, i.e. it is * `$strict`: an unlisted key is REFUSED, not stripped, and the refusal takes - * the WHOLE document with it. Measured on the installed pin, 18.0.0-next.4, + * the WHOLE document with it. Measured on the installed pin, 18.0.0-next.5, * `RecordHighlightsProps.safeParse({ fields: [{ name: 'x', icon: 'star' }] })` * is RED with `invalid_union` at `fields.0`. So `{ name: 'amount', icon: * 'dollar-sign' }` type-checked here and was refused at the door — a green @@ -390,7 +390,7 @@ export interface RecordHighlightsComponentProps { * `z.enum(['horizontal','vertical'])` behind a `.default('horizontal')`). * * It offered a third value, `grid`, until objectui#9187, and the contract - * never accepted it: measured on the installed pin, 18.0.0-next.4, + * never accepted it: measured on the installed pin, 18.0.0-next.5, * `RecordHighlightsProps.safeParse({ fields: ['name'], layout: 'grid' })` is * RED with `invalid_value` at `layout`. So `{ layout: 'grid' }` type-checked * here and was refused at the door — a green local build and a rejection at diff --git a/packages/types/src/zod/objectql.zod.ts b/packages/types/src/zod/objectql.zod.ts index c35237af2b..779f804204 100644 --- a/packages/types/src/zod/objectql.zod.ts +++ b/packages/types/src/zod/objectql.zod.ts @@ -1774,7 +1774,7 @@ const KanbanConfig = stripImportedDefaults(SpecListViewSchema).shape.kanban.unwr * `@objectstack/spec` 17.4.0 (the version in the lockfile then) rather than * reading it — RE-RUN on 17.5.0 (objectui#11073), whose answer moved, as the * last bullet says, RE-RUN on 17.6.0 (objectui#11438), on 17.7.0 (objectui#11717), - * and again on the installed 18.0.0-next.4 (objectui#12030, objectui#12370, objectui#12626, objectui#12873, objectui#12971), each of which answers + * and again on the installed 18.0.0-next.5 (objectui#12030, objectui#12370, objectui#12626, objectui#12873, objectui#12971), each of which answers * every bullet below as 17.5.0 did: * * - `CalendarConfigSchema`'s `strictObject` options carry `surface` and @@ -1799,7 +1799,7 @@ const KanbanConfig = stripImportedDefaults(SpecListViewSchema).shape.kanban.unwr * prescribes neither. `endField` still draws no hint, and a one-char typo * still resolves by distance (`titleFeld` → `titleField`) — all three * measured on 17.5.0, again on 17.6.0 (objectui#11438), on 17.7.0 - * (objectui#11717), and again on the installed 18.0.0-next.4 (objectui#12030, objectui#12370, objectui#12626, objectui#12873, objectui#12971). + * (objectui#11717), and again on the installed 18.0.0-next.5 (objectui#12030, objectui#12370, objectui#12626, objectui#12873, objectui#12971). * * ⇒ through 17.4.0 a generic typo-distance suggester picked the wrong sibling. * It was not a declaration, it contradicted no declaration, and ⛔ no upstream From 8f9f2994d0732ba991b7da70a3d00163ab909590 Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 19 Oct 2026 12:30:32 +0000 Subject: [PATCH 11/13] feat(types,app-shell): a navigation entry's dataSource, by reference from the spec's nav-item base objectstack#24332 gave the spec's shared nav-item base one API data source (ElementApiDataSourceSchema), which navigation-spec-parity and the nav editor's base-key pins read off the installed spec. NavigationItemSchema takes it by reference (it stripped the key before), the NavigationItem type derives it from the spec's ObjectNavItem, and the nav editor's base-key table keeps it on a change of type. The spec marks it planned; nothing here reads it. Claude-Session: https://claude.ai/code/session_0188TsgPV8kQXfuRuKmkj2ks Co-authored-by: Claude --- .changeset/12971-objectstack-pin-main.md | 1 + .../inspectors/nav-target.navEntryTypes-11790.test.ts | 1 + .../src/views/metadata-admin/inspectors/nav-target.ts | 4 ++++ packages/types/src/app.ts | 7 +++++++ packages/types/src/zod/app.zod.ts | 8 ++++++++ 5 files changed, 21 insertions(+) diff --git a/.changeset/12971-objectstack-pin-main.md b/.changeset/12971-objectstack-pin-main.md index 5397be6cca..360981e2ec 100644 --- a/.changeset/12971-objectstack-pin-main.md +++ b/.changeset/12971-objectstack-pin-main.md @@ -23,5 +23,6 @@ Clause-②: no (narrowing) - `emptyState` on `record:details`, `record:highlights` and `record:quick_actions`. - `record` on a `page` node. +- `dataSource` on a navigation entry, every member but a separator. `NavigationItemSchema` and the `NavigationItem` type take the spec's `ElementApiDataSourceSchema` by reference; before, `NavigationItemSchema` stripped the key. The spec describes it as planned, and the console does not read it yet. **A palette exclusion that goes.** `record:json` is retired in the spec and is no longer a page component type, so the page designer's palette drops its exclusion entry. Nothing the palette offers changes. diff --git a/packages/app-shell/src/views/metadata-admin/inspectors/nav-target.navEntryTypes-11790.test.ts b/packages/app-shell/src/views/metadata-admin/inspectors/nav-target.navEntryTypes-11790.test.ts index eaaf8654e0..c70fa82982 100644 --- a/packages/app-shell/src/views/metadata-admin/inspectors/nav-target.navEntryTypes-11790.test.ts +++ b/packages/app-shell/src/views/metadata-admin/inspectors/nav-target.navEntryTypes-11790.test.ts @@ -98,6 +98,7 @@ const BASE_VALUES: Record = { badge: 'NEW', badgeVariant: 'secondary', visible: "'admin' in current_user.positions", + dataSource: { provider: 'api', read: { url: '/api/v1/cloud/home' }, path: 'data.environments' }, requiredPermissions: ['task.read'], requiresObject: 'acme_task', requiresService: 'ai', diff --git a/packages/app-shell/src/views/metadata-admin/inspectors/nav-target.ts b/packages/app-shell/src/views/metadata-admin/inspectors/nav-target.ts index 4474c87e95..007881baa6 100644 --- a/packages/app-shell/src/views/metadata-admin/inspectors/nav-target.ts +++ b/packages/app-shell/src/views/metadata-admin/inspectors/nav-target.ts @@ -69,6 +69,10 @@ const NAV_ENTRY_BASE_KEYS = [ 'badge', 'badgeVariant', 'visible', + // The spec's base declares it since the objectstack `main` pin after + // 18.0.0-next.3 (objectstack#24332): the API binding `visible` reads, so a + // change of type keeps it beside `visible` (objectui#12971). + 'dataSource', 'requiredPermissions', 'requiresObject', 'requiresService', diff --git a/packages/types/src/app.ts b/packages/types/src/app.ts index 16d78debdc..c55466fcca 100644 --- a/packages/types/src/app.ts +++ b/packages/types/src/app.ts @@ -290,6 +290,13 @@ export interface NavigationEntryItem { /** Required permissions to see/access this item */ requiredPermissions?: string[]; + /** + * One API data source whose bound value {@link visible} reads as `data` — + * the spec's shared nav-item base member, by reference (objectui#12971). + * The spec describes it as planned and not yet rendered. + */ + dataSource?: SpecObjectNavItem['dataSource']; + /** * Runtime capability gate — name of an object that must be registered * in the runtime's SchemaRegistry for this entry to render. Used to diff --git a/packages/types/src/zod/app.zod.ts b/packages/types/src/zod/app.zod.ts index 074f0be2c0..a8df21a2b8 100644 --- a/packages/types/src/zod/app.zod.ts +++ b/packages/types/src/zod/app.zod.ts @@ -20,6 +20,7 @@ import { z } from 'zod'; import { AppSchema as SpecAppSchema, AppContextSelectorSchema as SpecAppContextSelectorSchema, + ElementApiDataSourceSchema as SpecElementApiDataSourceSchema, I18nLabelSchema as SpecI18nLabelSchema, NavigationAreaSchema as SpecNavigationAreaSchema, // ⚠️ NOT a crossing, so it stays RAW — see THE IMPORT BOUNDARY below. This is @@ -253,6 +254,13 @@ const NavigationItemObject = z.object({ // Visibility & Permissions visible: z.union([z.boolean(), z.string()]).optional().describe('Visibility expression'), + // objectui#12971: the spec's shared nav-item base declares one API data source + // (objectstack#24332, `ElementApiDataSourceSchema` by reference), whose bound + // value an entry's `visible` reads as `data`. Taken by reference for the + // reason `runAction` is declared above: this schema strips unknown keys, so an + // authored binding would have validated clean and been thrown away. The spec + // describes it as planned and not yet rendered; the console does not read it. + dataSource: stripImportedDefaults(SpecElementApiDataSourceSchema).optional().describe("One API data source whose bound value the entry's `visible` reads as `data` (`@objectstack/spec` `ElementApiDataSourceSchema`). Planned in the spec; the console does not read it yet"), requiredPermissions: z.array(z.string()).optional().describe('Required permissions'), // Runtime capability gates. `NavigationRenderer` has always honoured these // and `NavigationItem` has always declared them — only this schema lagged, From 1a0f3d09306ae1fd11c8533d58aa9acb0cfbcd62 Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 19 Oct 2026 12:55:54 +0000 Subject: [PATCH 12/13] =?UTF-8?q?test(console):=20book=20the=20list-view?= =?UTF-8?q?=20row's=20differences=20OWED=20to=20objectui#13047=20and=20emp?= =?UTF-8?q?tyState=20to=20objectui#12932;=20Clause-=E2=91=A1=20reads=20yes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Seat decisions on objectui#12971 (record 6267645900): - D1 = A, under objectui#11111 decision 3 = B: the 38 list-view spec keys the registration does not publish and its 6 owed member pins are booked OWED to objectui#13047 (expires 2026-11-18). Caps rise to exactly the booked entries (unpublishedKeys 38, memberPins 6, MEMBER_PIN_EXEMPTION_CEILING 6); nothing is declared. - D2 = A, the objectui#12370 precedent: three UNPUBLISHED_EXEMPTIONS entries for emptyState on record:details, record:highlights and record:quick_actions, owned by objectui#12932. - D4 = B: the changeset reads Clause-②: yes and lists both directions, the narrowings with the spec's messages. Claude-Session: https://claude.ai/code/session_0188TsgPV8kQXfuRuKmkj2ks Co-authored-by: Claude --- .changeset/12971-objectstack-pin-main.md | 10 +- .../registry-inputs-spec-parity.test.ts | 131 ++++++++++++++++-- 2 files changed, 126 insertions(+), 15 deletions(-) diff --git a/.changeset/12971-objectstack-pin-main.md b/.changeset/12971-objectstack-pin-main.md index 360981e2ec..86f69f803a 100644 --- a/.changeset/12971-objectstack-pin-main.md +++ b/.changeset/12971-objectstack-pin-main.md @@ -10,16 +10,18 @@ Build `@objectstack/*` from objectstack `main` `f4755a68a7` (objectui#12971). `.objectstack-sha` moves from `2c9bf9430a`, the commit `@objectstack/spec` `18.0.0-next.3` was released from, to `f4755a68a7`, a commit on objectstack `main` after the `18.0.0-next.5` release, so its packages read `18.0.0-next.5`. The console and the runner bundle `@objectstack/*` built from it. No package's `@objectstack/*` range changes. -Clause-②: no (narrowing) +Clause-②: yes + +The pin moves `@object-ui/types`' accept sets both ways: keys the spec added arrive by reference and widen them, and checks the spec added narrow them. Both are listed below. **Accept sets that narrow with it.** `@object-ui/types` validates a page through the spec's own page checks, so `safeValidateSchema`, `StrictAnyComponentSchema` and `objectui validate` now refuse: -- A region named `main` with `width: 'small'`, `'medium'` or `'large'`, on a `page` node and on a page-kind node (`type: 'record'`, `'home'` or `'utility'`). FROM accepted on both faces TO refused at the region's `width`, with the spec's message (`checkPageMainRegionWidth`). No layout reads those three values on `main`; the template decides its width. Delete `width` to keep the page as it renders, or write `width: 'full'` for a full-bleed page. Other regions keep all four values. -- A `record` binding on a page-kind node. FROM kept unvalidated by `safeValidateSchema` and refused as an undeclared key by `StrictAnyComponentSchema` TO refused on both at `record`, with the spec's message (`checkPageRecordBindingPlacement`): only a `type: 'app'` page binds a row. The check reads the page kind from `type`, so it does not judge a `page` node, whose kind is `pageType`. +- A region named `main` with `width: 'small'`, `'medium'` or `'large'`, on a `page` node and on a page-kind node (`type: 'record'`, `'home'` or `'utility'`). FROM accepted on both faces TO refused at the region's `width`, with the spec's message (`checkPageMainRegionWidth`), which opens: "Region `main` is refused with `width: 'large'` (since @objectstack/spec 18): a `main` region takes only `width: 'full'`." No layout reads those three values on `main`; the template decides its width. Delete `width` to keep the page as it renders, or write `width: 'full'` for a full-bleed page. Other regions keep all four values. +- A `record` binding on a page-kind node. FROM kept unvalidated by `safeValidateSchema` and refused as an undeclared key by `StrictAnyComponentSchema` TO refused on both at `record`, with the spec's message (`checkPageRecordBindingPlacement`), for example on a `home` page: "`record` binds the row of an `app` page, and this page is `type: 'home'`, which has no row to bind. Delete `record`, or make the page `type: 'app'`." The check reads the page kind from `type`, so it does not judge a `page` node, whose kind is `pageType`. **A published input that leaves.** `action:button` and `action:icon` no longer publish a `patch` input. FROM published TO absent: the spec retired a page action row's own `patch`. A row's `operation: 'update'` runs the declared action its `name` names, and the platform action route writes that action's `patch`. The `operation` input's description now says so. -**Keys that arrive with the spec, by reference.** Two keys the spec added are taken by reference, so the strict face now accepts them where it refused them as undeclared. Their renderer halves are separate work: +**Accept sets that widen with it.** Three keys the spec added are taken by reference, so `StrictAnyComponentSchema` and `objectui validate` now accept them where they refused them as undeclared. Their renderer halves are separate work: - `emptyState` on `record:details`, `record:highlights` and `record:quick_actions`. - `record` on a `page` node. diff --git a/apps/console/src/__tests__/registry-inputs-spec-parity.test.ts b/apps/console/src/__tests__/registry-inputs-spec-parity.test.ts index bb2f2b8fd7..0d1f8cd966 100644 --- a/apps/console/src/__tests__/registry-inputs-spec-parity.test.ts +++ b/apps/console/src/__tests__/registry-inputs-spec-parity.test.ts @@ -784,6 +784,17 @@ function isRetiredUpstream(type: string): boolean { * so the card owns no entry now and the four GA blocks carry no OWED entry * again (see THE FOUR GA BLOCKS below). * + * A sixth owner, under the objectstack `main` pin bump (objectui#12971, past + * `@objectstack/spec` 18.0.0-next.3): the seat decision D1 = A on that card + * (record 6267645900) applies decision 3 = B to the bump's one group with no + * owner, `list-view`, which that pin gives a `ComponentPropsMap` row + * (objectstack#22444), so this file judges it: + * + * - objectui#13047 — every entry on `list-view`: the 38 keys its spec row + * declares that `inputs` does not publish, and the 6 member pins its + * array/object-armed inputs owe. Expires 2026-11-18, thirty days from the + * decision, or when that card lands. + * * Each owner card decides every key by its own measurement: declare what the * renderer honours, refuse or retire what it does not. ⛔ Batch-declaring an * input a renderer does not honour is the failure decision 3 = B exists to @@ -818,8 +829,9 @@ const OBJECTUI_11438_EXPIRES = '2026-11-02'; /** * The owner cards, and nothing else may own an entry: the three decision 3 = B * names, objectui#11536, which objectui#11438 ruling A′ filed for the 17.6.0 - * bump's one group with no owner, and objectui#11068, whose row ruling A″ - * booked to it. + * bump's one group with no owner, objectui#11068, whose row ruling A″ + * booked to it, and objectui#13047, which the seat decision on objectui#12971 + * filed for the objectstack `main` pin bump's `list-view` row. */ const OBJECTUI_11111_OWNERS = [ 'objectui#11168', @@ -827,12 +839,20 @@ const OBJECTUI_11111_OWNERS = [ 'objectui#8649', 'objectui#11536', 'objectui#11068', + 'objectui#13047', ] as const; type Objectui11111Owner = (typeof OBJECTUI_11111_OWNERS)[number]; /** The ruling every entry cites, whichever bump booked it. */ const DECISION_3_B = 'objectui#11111 decision 3 = B (record 5902351047)'; +/** + * The objectstack `main` pin bump's bookings' date (objectui#12971): the seat + * decision that applied decision 3 = B to it (record 6267645900, 2026-10-19), + * plus thirty days, the distance every earlier booking kept from its ruling. + */ +const OBJECTUI_12971_EXPIRES = '2026-11-18'; + /** * Where each owner's entries were booked: the bump that surfaced them, the * record that booked them, and their expiry. The 17.5.0 owners were booked by @@ -856,6 +876,11 @@ const OBJECTUI_11111_BOOKINGS: Record< bookedBy: `objectui#11438 ruling A″ (record 5968177777), which books row 1 of the 17.6.0 bump in the shape of ${DECISION_3_B}`, expires: OBJECTUI_11438_EXPIRES, }, + 'objectui#13047': { + bump: 'objectstack `main` pin (objectui#12971)', + bookedBy: `the seat decision D1 = A on objectui#12971 (record 6267645900), which applies ${DECISION_3_B} to the objectstack \`main\` pin bump`, + expires: OBJECTUI_12971_EXPIRES, + }, }; /** The security triple 17.5.0 declares on exactly the three record blocks (objectui#8649's). */ @@ -864,16 +889,36 @@ const FIELD_SECURITY_TRIPLE = ['enforceFieldSecurity', 'redactFields', 'required /** Every entry the ruling books starts with this, so the caps can count them. */ const OWED_PREFIX = 'OWED TO '; -// The two helpers that wrote a booked entry — `OWED_TO` (the reason: owner, +// The two helpers that write a booked entry: `OWED_TO` (the reason: owner, // what is owed, the booking record and the expiry) and `owedEntries` (one -// entry per key of a block) — left with the last entry they wrote: -// `action:button.undoable`, struck by objectui#11168's last slice. Every ledger -// is empty and every cap below is 0. The cap test still reads each ledger for -// the `OWED TO ` prefix, so anything booked again is counted against a cap of 0 -// and goes red until a ruling books it with an owner and an expiry. +// entry per key of a block). They left with `action:button.undoable`, struck by +// objectui#11168's last slice, and came back with the objectstack `main` pin +// bump (objectui#12971), whose `list-view` differences the seat booked to +// objectui#13047 under decision 3 = B (record 6267645900). + +/** The reason a booked entry carries: owner, what is owed, the booking record and the expiry. */ +const OWED_TO = (owner: Objectui11111Owner, what: string): string => { + const { bump, bookedBy, expires } = OBJECTUI_11111_BOOKINGS[owner]; + return ( + `${OWED_PREFIX}${owner}. ${what} Booked by ${bookedBy}: ` + + `the ${bump} bump re-pins and declares nothing; ${owner} decides it by its own measurement. ` + + `Expires ${expires}, or when ${owner} lands, whichever is first.` + ); +}; + +/** `BLOCK.KEY` entries for every listed key of one block, all with the same owner and reason. */ +const owedEntries = ( + type: string, + keys: readonly string[], + owner: Objectui11111Owner, + what: string, +): Record => + Object.fromEntries(keys.map((key) => [`${type}.${key}`, OWED_TO(owner, what)])); /** Which owner the ruling routes an entry id to — asserted against every entry's reason. */ function objectui11111OwnerOf(id: string): Objectui11111Owner { + // The seat decision on objectui#12971 (record 6267645900) routes by BLOCK: every entry on `list-view` is objectui#13047's. + if (id.slice(0, id.indexOf('.')) === 'list-view') return 'objectui#13047'; // objectui#11438 ruling A′ routes by BLOCK: every entry on `record:line_items` is objectui#11536's. if (id.slice(0, id.indexOf('.')) === 'record:line_items') return 'objectui#11536'; // Ruling A″ routes by exact ID: row 1 is this one key, and objectui#11068 owns nothing else. @@ -899,9 +944,9 @@ const owedIdsOf = (ledger: Record): string[] => const OBJECTUI_11111_LEDGER_CAPS = { unjudgedBlocks: 0, // objectui#11168 loaded and judged all four: slice 3 object-map and object-tree, slice 4 object-gantt, slice 5 object-timeline offSpecInputs: 0, // objectui#11168 slice 1 retired action:group.name - unpublishedKeys: 0, // objectui#11168: 0 (its last slice declared action:button undoable, ruling B on objectui#11754; the two `endpoint` entries had left at the 17.6.0 bump, objectui#11438, when the spec stopped declaring the key); objectui#8652: 0, objectui#8649: 0, objectui#11536: 0 and objectui#11068: 0 (each struck by its landing; objectui#11536 declared all ten record:line_items keys, objectui#11068's build published object-grid keyboardNavigation) + unpublishedKeys: 38, // objectui#13047: 38 (list-view, booked by the seat decision D1 = A on objectui#12971, record 6267645900); objectui#11168: 0 (its last slice declared action:button undoable, ruling B on objectui#11754; the two `endpoint` entries had left at the 17.6.0 bump, objectui#11438, when the spec stopped declaring the key); objectui#8652: 0, objectui#8649: 0, objectui#11536: 0 and objectui#11068: 0 (each struck by its landing; objectui#11536 declared all ten record:line_items keys, objectui#11068's build published object-grid keyboardNavigation) refusedArms: 0, // objectui#11168: slice 2 narrowed element:definition-list.columns, slice 3 object-form.layout - memberPins: 0, // objectui#11168 slice 2 pinned element:definition-list.items and element:repeater ×3; objectui#11536 pinned record:line_items columns and dataSource + memberPins: 6, // objectui#13047: 6 (list-view data, columns, filter, sort, options and dataSource, booked by the same decision); objectui#11168 slice 2 pinned element:definition-list.items and element:repeater ×3; objectui#11536 pinned record:line_items columns and dataSource } as const; /** @@ -1602,6 +1647,45 @@ const UNPUBLISHED_EXEMPTIONS: Record = { // (objectui#12030): every one of the six is a tombstone now, so each entry // went dangling and stale and was deleted. The repeater reads none of its // four either (objectui#12345), and nothing here publishes the keys. + + /* + * ⚠️ THE OBJECTSTACK `main` PIN BOOKINGS — the seat decision D1 = A on + * objectui#12971 (record 6267645900), which applies objectui#11111 decision + * 3 = B to the pin bump. + * + * The spec keys the `list-view` row declares from that pin on (objectstack#22444) + * that the registration's `inputs` do not publish. The bump declares nothing: + * objectui#13047 measures each key against `ListViewBlock` / `ListView`, + * declares what is honoured and leaves the rest out. Capped at + * `OBJECTUI_11111_LEDGER_CAPS.unpublishedKeys`. + */ + ...owedEntries( + 'list-view', + [ + 'name', 'label', 'description', 'searchableFields', 'filterableFields', 'userFilters', 'resizable', + 'compactToolbar', 'selection', 'navigation', 'pagination', 'kanban', 'calendar', 'gantt', 'gallery', + 'timeline', 'chart', 'map', 'tree', 'sharing', 'requiredPermissions', 'rowHeight', 'grouping', + 'rowColor', 'hiddenFields', 'fieldOrder', 'rowActions', 'bulkActions', 'bulkActionDefs', + 'conditionalFormatting', 'inlineEdit', 'exportOptions', 'userActions', 'appearance', 'addRecord', + 'showRecordCount', 'allowPrinting', 'emptyState', + ], + 'objectui#13047', + 'A SPEC KEY NOT PUBLISHED: `list-view` entered `covered` with the objectstack `main` pin and its `inputs` omit this key its spec row declares.', + ), + + // The seat decision D2 = A on objectui#12971 (record 6267645900), the + // objectui#12370 precedent (`record:related_list.parentDataSource`, owner + // objectui#12294): `emptyState` on the three bound record blocks + // (objectstack#24270) is declared by the spec and drawn by no renderer here + // yet, so publishing it would advertise configuration the platform drops. + // objectui#12932 owns the renderer and declares the input with it, striking + // these three. + 'record:details.emptyState': + 'Declared by the spec from the objectstack `main` pin (objectstack#24270): the empty state a bound record block draws when its `dataSource` answers no row. No renderer here draws it yet; objectui#12932 draws it and declares it on the registration.', + 'record:highlights.emptyState': + 'Declared by the spec from the objectstack `main` pin (objectstack#24270): the empty state a bound record block draws when its `dataSource` answers no row. No renderer here draws it yet; objectui#12932 draws it and declares it on the registration.', + 'record:quick_actions.emptyState': + 'Declared by the spec from the objectstack `main` pin (objectstack#24270): the empty state a bound record block draws when its `dataSource` answers no row. No renderer here draws it yet; objectui#12932 draws it and declares it on the registration.', }; /** @@ -3599,6 +3683,19 @@ const MEMBER_PIN_EXEMPTIONS: Record = { // both, and the two array keys it declared (`filter`, `sort`) with them, // each registered in `MEMBER_PINS`, so no booking is left. Header kept as a // landmark for a future grep. + + // ⚠️ OBJECTSTACK `main` PIN BOOKINGS — the seat decision D1 = A on + // objectui#12971 (record 6267645900), which applies objectui#11111 decision + // 3 = B to the pin bump. The array/object-armed inputs of `list-view`, the + // block that pin newly judges, owed a member pin by objectui#13047. Counted + // into `MEMBER_PIN_EXEMPTION_CEILING` (0 -> 6) and capped at these six; that + // card's pins strike them. + ...owedEntries( + 'list-view', + ['data', 'columns', 'filter', 'sort', 'options', 'dataSource'], + 'objectui#13047', + 'A MEMBER PIN OWED: this `list-view` input is array/object-armed on a block the objectstack `main` pin newly judges, and no pin states its members.', + ), }; /** @@ -4432,8 +4529,19 @@ const NEWLY_JUDGED_UNPINNED_MEMBERS: string[] = []; * deleted their two booked entries. The two array keys it declared beside them * (`filter`, `sort`) entered the population already pinned, so nothing stands * in the list and the ceiling follows it back to 0. + * + * ## 0 -> 6 (objectui#12971, the objectstack `main` pin bump) — a RULING, not + * room, the rise the 17.5.0 and 17.6.0 bumps took + * + * The pin newly judges `list-view`, which brings six array/object-armed inputs + * with no pin: `data`, `columns`, `filter`, `sort`, `options` and `dataSource`. + * The seat decision D1 = A on objectui#12971 (record 6267645900) applies + * objectui#11111 decision 3 = B to the bump, so all six are booked OWED to + * objectui#13047. 0 + 6 booked = 6, and `the objectui#11111 ledger is capped + * at exactly the entries it lists` caps the six and routes each to + * objectui#13047, whose pins take this back to 0. */ -const MEMBER_PIN_EXEMPTION_CEILING = 0; +const MEMBER_PIN_EXEMPTION_CEILING = 6; /** * Every test file a member pin can live in, as LAZY `?raw` loaders. @@ -6117,6 +6225,7 @@ describe('registry `inputs` vs `@objectstack/spec` ComponentPropsMap (repo-wide) 'objectui#8649': 0, 'objectui#11536': 0, 'objectui#11068': 0, + 'objectui#13047': 44, }); }); }); From 4a292e16221d9f16d70111bdfe8d39400582c0cf Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 19 Oct 2026 13:42:30 +0000 Subject: [PATCH 13/13] =?UTF-8?q?chore(changeset):=20the=20Clause-?= =?UTF-8?q?=E2=91=A1=20line=20carries=20its=20arm,=20yes=20(narrowing)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The contract review on PR #13043 (record 6268625896): a diff that widens one surface and narrows another reads `Clause-②: yes (narrowing)`, the fleet reader's spelling (clause2-line.mjs). The two-direction lists are unchanged. Claude-Session: https://claude.ai/code/session_0188TsgPV8kQXfuRuKmkj2ks Co-authored-by: Claude --- .changeset/12971-objectstack-pin-main.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/12971-objectstack-pin-main.md b/.changeset/12971-objectstack-pin-main.md index 86f69f803a..5a6b580865 100644 --- a/.changeset/12971-objectstack-pin-main.md +++ b/.changeset/12971-objectstack-pin-main.md @@ -10,7 +10,7 @@ Build `@objectstack/*` from objectstack `main` `f4755a68a7` (objectui#12971). `.objectstack-sha` moves from `2c9bf9430a`, the commit `@objectstack/spec` `18.0.0-next.3` was released from, to `f4755a68a7`, a commit on objectstack `main` after the `18.0.0-next.5` release, so its packages read `18.0.0-next.5`. The console and the runner bundle `@objectstack/*` built from it. No package's `@objectstack/*` range changes. -Clause-②: yes +Clause-②: yes (narrowing) The pin moves `@object-ui/types`' accept sets both ways: keys the spec added arrive by reference and widen them, and checks the spec added narrow them. Both are listed below.