Skip to content

Commit 3a27208

Browse files
fix(lint)!: refuse a stored sort on a sortable: false field, on list views and every stored page sort (#30084)
<!-- claude-projects-attribution: {"github_login":"os-support-ai"} --> _Requested by **Yibo Wang** · [project thread](https://claude.ai/code/project/chan_01BVUyyPie8gHwoPM18iABwB?thread=cmsg_01BVUyyPie8gHwoPM18iABwBGAgbDVW8xmM2xwwkx5q3JU)_ Fixes #30023 ## 维护者速读 - 改了什么:`validate-sortable-fields` 不再自己判断「虚拟类型」,改为读数据接口列表门所用的同一个可排序投影 `resolveObjectSortability`,所以字段写了 `sortable: false` 时,列表视图的 `sort` 报 `sort-field-unsortable`(error);同时把规则扩展到页面上所有会打到列表门的已存排序(区块自身 `sort`、元素 `dataSource.sort`、相关列表 `parentDataSource.sort`、列表页 `interfaceConfig.sort`、应用页 `record.sort`),并让 page 写入门也跑这条规则。 - 为什么改:#30021 之后列表门对这种排序答 400 `INVALID_SORT`,但 `os validate` 和发布门照样放行,于是视图首次加载起每次都 400;页面上的排序此前完全不判可排序性(公式字段也一样)。 - 风险与回滚:接受集收窄(BREAKING,Metadata-protocol narrowed,`@objectstack/lint` 和 `@objectstack/spec` minor):带这种排序的视图或页面在下次 validate / 保存时被拒(422),已存的照常加载。仓内语料没有任何 `sortable: false`,示例栈实测 0 条新发现。回滚即 revert 本 PR。 - 先看:`packages/lint/src/validate-sortable-fields.ts` 的 `unsortableFinding`、`validatePageSorts`、`PAGE_BLOCK_SORT_OBJECT_PROP`;`reference-integrity-suite.ts` 的 `page` 跨入。 - 两分钟验证:`pnpm --filter @objectstack/metadata-protocol exec vitest run src/protocol.runtime-authoring-gate.test.ts -t 30023`(先建 lint),预期 7 个用例全过:视图和 4 个页面槽位被拒在各自路径,对照(无键、`true`、公式字段保留自己的判定)照常。 - 需要你做的:无,席位落地。 Clause-②: yes (narrowing) — `sort-field-unsortable` (error) now also fires on a sort naming a field whose author declared `sortable: false`, on the list-view rungs it already walked and on every stored page sort it did not walk before (a block's own `sort`, every element `dataSource.sort`, a related list's `parentDataSource.sort`, a list page's `interfaceConfig.sort`, an app page's `record.sort`, where a `formula` sort is now refused too), so `os validate` / `os build` / `os lint` and the `page` and `view` publish doors refuse metadata they used to accept. The widening half: `@objectstack/lint` exports `indexObjectSortability` and the `SortabilityFields` type, and `checkSortDeclaration` takes an optional trailing `sortability` index. Metadata-protocol: narrowed Skills-docs: none — `skills/**` names no `sortable` field key and no page or view `sort` rule; `content/docs/**` already teaches `sortable: false` as "do not allow sorting by this field". The prescription ships in the finding's fix line, `os explain sort-field-unsortable` and the upgrade-guide entry. ## What changes - **One projection, two reasons** (`packages/lint/src/validate-sortable-fields.ts`). The virtuality check no longer calls `isVirtualSearchField` itself. It reads the projection `resolveObjectSortability` (`@objectstack/spec/api`) builds from the authored object, the resolver the list door (`assertSortFieldsExist`) refuses by. A `sortable: false` entry with `reason: 'virtual-type'` keeps the existing message byte for byte. One with `reason: 'author-declared'` reports `sort-field-unsortable` at `error` with the door's clause: `list-view sort orders by "body", a field on object "help_ticket" that declares `sortable: false`, so every load answers 400 INVALID_SORT`. The fix line is `Sort by another field, or remove `sortable: false` from "body" to make it sortable`. Only the literal `false` counts. A formula field that also declares `sortable: false` keeps its virtual verdict, because the projection does. - **Grading.** `error`, the level the #9257 precedent (`formula`) publishes at. The door answers both reasons with the same `400 INVALID_SORT` on the view's first fetch. - **The exported core stays compatible.** `checkSortDeclaration` takes an optional trailing `sortability` index (`indexObjectSortability`, exported). If a caller omits it, the projection comes from the type-only slice, so the caller gets the pre-change answers (virtual only). This is the posture the `unprovisionedAnchors` parameter already has. Every in-repo caller passes it. - **Every stored page sort is walked** (`validatePageSorts`), for the projection's verdict only: - each component's `dataSource.sort`, bound to `dataSource.object`; - a `record:related_list`'s `properties.parentDataSource.sort`, bound to its own `object`; - the `properties.sort` of each block that declares one, bound to `dataSource.object` and then the block's object prop. The `PAGE_BLOCK_SORT_OBJECT_PROP` table is pinned against `ComponentPropsMap`: | Block | Object prop | | --- | --- | | `list-view` | `data.object` | | `record:related_list` | `objectName` | | `record:line_items` | `childObject` | | `object-grid`, `object-calendar`, `object-gantt`, `object-map`, `object-timeline` | `objectName` | - a list page's `interfaceConfig.sort`, bound to `source` and then the page `object`; - an app page's `record.sort`, bound to `record.object`. `validate-page-field-bindings` still owns existence and provenance on these positions, as `page-field-unknown` / `page-field-unprovisioned`. This rule adds only the question that rule does not ask, so no name is reported twice. - **The page door** (`reference-integrity-suite.ts`, `authoring-rules.ts`). `validateSortableFields` declares `page`, and the suite entry's `runtimeTypes` gains `page`. A page write reaches exactly this one member: no other member declares `page`. The member resolves only against `stack.objects`, which the per-write page snapshot carries. That is the #9313 reason, one write type over. The page dispatch pin (`runtime-gate.page-visibility-predicate-writes.test.ts`) lists `validateReferenceIntegrity`. - **`os explain sort-field-unsortable`** (`rule-explanations.ts`) gains the author-declared paragraph and the page surfaces. - **Upgrade-guide entry** `18.field-sortable-false-sort-refused`: `surface` and `acceptanceCriteria` now list every stored surface above (delta review 6625831334 ③). The `reason` sentence "Lint does not yet judge a view `sort`…" is replaced. It now says that `os validate` and the publish door refuse each surface. - **Changeset:** `@objectstack/lint` and `@objectstack/spec` are both `minor`, with `Metadata-protocol: narrowed`, the BREAKING banner, and Before / Now / Not changed / The remedy. The ADR-0087 marker is `not-required (already-registered field-sortable-false-sort-refused)`, which cites the existing entry. A **Supersedes, in the same release** paragraph corrects #29896's unreleased note "Lint does not yet judge these at authoring." Before writing it I checked that npm `@objectstack/spec@18.3.0` (published 2026-11-03 15:15Z) does not carry `field-sortable-false-sort-refused`. ## Why #30021 (`140d8ce8`) makes the list door refuse a sort that names a `sortable: false` field. The lint rule keyed only on `isVirtualSearchField`, so `os validate` and the view door both passed such a view. On a page, none of the stored sorts was judged for sortability at all. The rule walked only the five list-view rungs, and its module note left page sorts to `walkPageComponents`' territory, where only existence was asked. The view then broke on every load, traced to nothing. ## Readings - **Surfaces before this PR:** - The rule walked `objects[].listViews.*.sort`, `views[].list.sort`, `views[].listViews.*.sort`, the flattened overlay `views[].sort` and the record `views[].config.sort`, all for the virtual verdict only. - It walked no page surface. - The suite did not dispatch on `page` writes. `runtimeAuthoringRulesFor('page')` listed no `validateReferenceIntegrity`. - **Surfaces the delta review missed, found by enumerating every `sort:` key under `packages/spec/src/**/*.zod.ts` and by the new drift pin:** - `record:line_items` `sort`; - the page `list-view` node's own `sort` (`ListViewPageProps` spreads `ListViewSchema`); - the related list's `parentDataSource.sort`. The drift pin first went red naming `list-view`, which the hand list had missed. - **App page `record.sort` reaches the door.** `ui/packages/app-shell/src/views/PageView.tsx#appPageRecordBinding` mounts it through `ElementDataSourceGate` with `sort: true` (objectui#12931). Its `liveness/page.json` row still says `planned`, which is stale. That is noted below and not changed here. - **Corpus.** No shipped object declares `sortable: false`: `grep -rn "sortable: false"` over `examples/`, `packages/platform-objects/src` and `packages/plugins` finds nothing. `validateSortableFields` over `examples/app-crm` (6 objects, 1 page), `app-todo` and `app-multi-package` gives 0 findings. `examples/app-showcase` (24 objects, 29 pages): 0 findings. Non-vacuity probe: with every authored field set to `sortable: false` in memory, the same run fires 3 findings, 2 of them on pages (`pages[14].interfaceConfig.sort[0]`, `pages[17].interfaceConfig.sort[0]`), so the page walk reaches the shipped corpus. ## Tests - `packages/lint/src/validate-sortable-fields.test.ts` (+16): - **The author-declared verdict:** exact message and fix, path, and `error` level. It fires on the legacy string form, on `-field`, and on the overlay and record view shapes. - **Controls:** no key, `true`, and a formula field with `sortable: false`, which keeps the virtual message. - **Projection identity:** the rule's index deep-equals `resolveObjectSortability(object).fields`. - **The exported core's optional parameter:** absent, it answers only the virtual verdict; present, it answers both. - **Every page slot is refused at its path:** related list `sort`, its `dataSource.sort` and `parentDataSource.sort`, `object-grid`, `record:line_items`, `list-view`, an element `dataSource.sort`, `interfaceConfig.sort` and `record.sort`. - **Binding precedence:** `dataSource.object` wins over the block prop. A list page with no `source` binds to the page `object`. - **A formula sort on a page is refused.** - **Page controls:** no key, `true`, an unknown name, a dotted path, `created_at`, another package's object and a block with no `sort` prop are all not reported. Neither is a `kind: 'react'` page's cached regions. - **`PAGE_BLOCK_SORT_OBJECT_PROP` ↔ `ComponentPropsMap`:** every row with a live `sort` key, each with a live object prop. The tombstone detector is pinned non-vacuous on `element:record_picker.sort`. - **The real publish route** (`packages/metadata-protocol/src/protocol.runtime-authoring-gate.test.ts`, a new `describe` on the existing stub-engine harness, so no double ledger moves; +7): - `PUT` view with `sort: body` gives 422 `INVALID_METADATA` with `sort-field-unsortable` at `views[0].sort[0]`, carrying the door's clause, and stores nothing. - A page sorting by `body` at a `record:related_list` `sort`, an element `dataSource.sort`, a list page's `interfaceConfig.sort` and an app page's `record.sort` gives 422 at `pages[0]…` slot paths, and stores nothing. - Controls: `subject` (no key) and `priority` (`sortable: true`) save on the view and on all four page slots. `score` (formula) is refused with its own virtual message on the view and on a page. ## Verification Readings are at `90989939` on base `c23501b2`, unless marked otherwise. Head `c745679c` adds only the `index.ts` export of `indexObjectSortability` / `SortabilityFields` and the matching changeset clause. For that head: - lint `tsc`, `check:test-typecheck` and the four touched lint test files (90 tests, including `rule-id-barrel-exports`) were rerun. - `check:dts-closure`, `check:lean-entry-closure`, `check:published-files`, `check:undeclared-dep-imports`, `check:api-surface`, `check-changeset-no-major`, `check-empty-changeset` and `check-adr-0087-registration` were rerun, all exit 0. - The `--commands` derivation is unchanged: the same 82. - **Builds.** A full `turbo run build --filter='!@objectstack/docs' --concurrency=2` ran under the verify lock: 119 tasks, 0 failed, 11m16s on a shared box. - **Package suites.** - `@objectstack/lint` `test`: 193 files, 7988 tests passed. `typecheck`: 0. - `@objectstack/spec` `test`: 811 files, 24387 tests passed. `typecheck`: 0. - `@objectstack/metadata-protocol` `test`: 312 files, 22354 tests passed, 26 skipped. `typecheck`: 0. - `pnpm lint` (repo eslint): 0. - **Derived gates.** `dispatch-gates --commands` derived 82, and all 82 ran with exit 0. `dispatch-gates --ran` reports 82 run, 0 NOT-MEASURED, 0 UNRUN; the record is `/mnt/project-files/issue-30023/gates-ran.list`. - `check-plugin-teardown-shape --self-test` first exited 3 because this shallow clone could not reach its pinned fixture. After `git fetch --unshallow origin main` it exited 0, and 48 cases passed. - `check-adr-0087-registration --base origin/main`: `not-required (already-registered)` accepted. - `check-changeset-no-major` with this body as the event: LEVEL AXIS `yes (narrowing)` + `narrowed`, and no moved package is graded `patch`. - `test:repo` was not run locally. It belongs to CI (Test Core). - **Ablation A**, at the author-declared verdict. I changed `unsortableFinding`'s guard to also return for `reason === 'author-declared'`, rebuilt lint and reran both files: - `validate-sortable-fields.test.ts`: `Tests 7 failed | 57 passed (64)`. The 7 are the author-declared and page-slot cases. Every control, and the formula page case, stayed green. - The route pins: `Tests 5 failed | 2 passed`. The view and the 4 page slots went red; the 2 controls stayed green. - Restored: the blob equals HEAD. - **Ablation B**, at the page-door crossing. I dropped `'page'` from `validateSortableFields`' member `runtimeTypes`: - The lint unit file stayed green: `64 passed`. - The route pins went red, `Tests 5 failed | 2 passed`: the 4 page slots and the virtual page control. The view refusal and the save control stayed green. - Restored: the blob equals HEAD. ## Acceptance notes - **Not walked, by design:** a `kind: 'react'` page's JSX props (`validate-react-page-props`' territory, unchanged), dashboard widget `sortBy` and report `order[].by` (dataset names, not object fields; as before). - **Existence on page sorts stays advisory.** An unknown name in a related list's `sort` reaches the same door and answers 400, yet `page-field-unknown` reports it at `warning`. That is a pre-existing severity call in `validate-page-field-bindings`, and this PR leaves it unchanged. Reported to the seat; not filed here. - **Object door not crossed.** An object write carrying both `sortable: false` on a field and a built-in `listViews.*.sort` on it is judged by `os validate`, and by the view door for view items, but not by the object publish door. `validateSortableFields` does not declare `object`, and `reference-integrity-suite.ts` records that crossing as its own adjudication (#15254's note). Reported to the seat. - **Stale liveness row.** `liveness/page.json` `record` still says `planned`, while `ui/…/PageView.tsx` reads the binding (objectui#12931). Not changed here. 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_01WGufzgUAaThh7rNSXWuzXR <!-- signed: domain:server#6 · os-support-ai · session_01WGufzgUAaThh7rNSXWuzXR --> --------- Co-authored-by: Claude <noreply@anthropic.com>
1 parent 0ce44c9 commit 3a27208

10 files changed

Lines changed: 710 additions & 44 deletions
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
---
2+
'@objectstack/lint': minor
3+
'@objectstack/spec': minor
4+
---
5+
6+
fix(lint)!: a stored sort naming a field that declares `sortable: false` is refused by `os validate` and at publish, judged by the same sortability projection the Data API list door refuses it by — on a list view and on every stored page sort (#30023)
7+
8+
Clause-②: yes (narrowing) — `sort-field-unsortable` (error) now also fires on a sort naming a field whose author declared `sortable: false`, on the list-view rungs it already walked and on every stored page sort it did not walk before (a block's own `sort`, every element `dataSource.sort`, a related list's `parentDataSource.sort`, a list page's `interfaceConfig.sort`, an app page's `record.sort`, where a `formula` sort is now refused too), so `os validate` / `os build` / `os lint` and the `page` and `view` publish doors refuse metadata they used to accept. The widening half: `@objectstack/lint` exports `indexObjectSortability` and the `SortabilityFields` type, and `checkSortDeclaration` takes an optional trailing `sortability` index.
9+
Metadata-protocol: narrowed
10+
Skills-docs: none — `skills/**` names no `sortable` field key and no page or view `sort` rule; `content/docs/**` already teaches `sortable: false` as "do not allow sorting by this field". The prescription ships in the finding's fix line, `os explain sort-field-unsortable` and the upgrade-guide entry.
11+
12+
<!-- adr-0087: not-required (already-registered field-sortable-false-sort-refused) the entry already prescribes this change: it names the stored sorts this rule now judges and, from this release, names `os validate` and the publish door as where an affected view or page surfaces; its surface and acceptance criteria are widened here to every stored page sort -->
13+
14+
**BREAKING** accept-set narrowing at authoring (`@objectstack/lint`): a stored sort the Data API list door refuses is refused before it is stored.
15+
16+
- **Before.** A list view whose `sort` named a field marked `sortable: false` passed `os validate` and the `PUT /api/v1/meta/view` door, then answered `400 INVALID_SORT` on its first fetch and on every fetch after it. No page sort was judged for sortability at all: a `record:related_list`, `record:line_items`, `list-view` or `object-*` block sorting by such a field (or by a `formula` field), an element `dataSource.sort`, a related list's `parentDataSource.sort`, a list page's `interfaceConfig.sort` and an app page's `record.sort` all saved green and failed at read.
17+
- **Now.** `validateSortableFields` judges each of those positions by `resolveObjectSortability`, the projection the list door refuses by, and reports `sort-field-unsortable` at `error` with the door's own clause ("a field on object X that declares `sortable: false`") at the slot's path. The reference-integrity suite now runs on a `page` write for this one member, so the Studio, REST `/meta` and MCP page doors give the same refusal (422). Only the literal `false` counts: a field with no `sortable` key, or `sortable: true`, sorts as before. A `formula` field also marked `sortable: false` keeps its virtual-field verdict. Existence on page sorts stays `page-field-unknown`.
18+
- **Not changed.** A stored view or page already carrying such a sort keeps loading and serving; only its next save is judged, and its first fetch still answers 400 as it did since the list door started refusing it.
19+
20+
**The remedy.** Sort by another field, or remove `sortable: false` from the field to make it sortable.
21+
22+
**Supersedes, in the same release.** The `@objectstack/spec` / `@objectstack/metadata-protocol` / `@objectstack/mcp` note for #29896 says "Lint does not yet judge these at authoring." From this release it does: `os validate` and the publish doors refuse every stored sort that note lists, and the stored page sorts it did not list.

‎packages/lint/src/authoring-rules.ts‎

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1249,8 +1249,13 @@ export const AUTHORING_RULES: readonly AuthoringRule[] = [
12491249
// tier 1 («the parsers load NEVER») from a standing fact into a red. The
12501250
// measurement that named their bridge named `validateStackExpressions`, a
12511251
// CEL-only rule, for exactly this reason.
1252+
// [#30023] `page` joins, NARROW by the same mechanism: a page write reaches
1253+
// exactly `validateSortableFields`, the one member that declares `page`,
1254+
// so a stored page sort naming a field the list door refuses
1255+
// (`sortable: false`, a `formula`) is refused at publish rather than at
1256+
// its first fetch. Every other member keeps its declaration.
12521257
surfaces: CLI_AND_RUNTIME,
1253-
runtimeTypes: ['flow', 'view', 'object', 'dataset', 'report'],
1258+
runtimeTypes: ['flow', 'view', 'object', 'dataset', 'report', 'page'],
12541259
run: (stack, ctx) => validateReferenceIntegrity(stack, ctx),
12551260
},
12561261
// ADR-0078 / #5068 — the SDUI component-props gate. `PageComponent.properties`

‎packages/lint/src/index.ts‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -521,16 +521,21 @@ export type {
521521
// ingress, `assertOrderByIsMaterializable` #7095 in the engine); this is the
522522
// authoring-time half, which is what makes the refusal traceable back to the
523523
// declaration that caused it.
524+
// [#30023] `indexObjectSortability` builds the optional trailing argument of
525+
// `checkSortDeclaration` that answers the author-declared verdict
526+
// (`sortable: false`), so an out-of-repo caller of the core can pass it.
524527
export {
525528
validateSortableFields,
526529
checkSortDeclaration,
530+
indexObjectSortability,
527531
SORT_FIELD_UNKNOWN,
528532
SORT_FIELD_UNSORTABLE,
529533
SORT_FIELD_UNPROVISIONED,
530534
} from './validate-sortable-fields.js';
531535
export type {
532536
SortableFieldFinding,
533537
SortableFieldSeverity,
538+
SortabilityFields,
534539
} from './validate-sortable-fields.js';
535540

536541
// [#14107] The rest of the list view's field surface — the two rules above own

‎packages/lint/src/reference-integrity-suite.ts‎

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -282,7 +282,16 @@ export const REFERENCE_INTEGRITY_RULES: readonly ReferenceIntegrityRule[] = [
282282
// `assertSortFieldsExist` (#6994) and `assertOrderByIsMaterializable` (#7095)
283283
// both answer `400 INVALID_SORT` — and a view's sort is its FIRST fetch, so
284284
// the refusal is the whole view, on every load, traced to nothing.
285-
{ name: 'validateSortableFields', runtimeTypes: ['flow', 'view'], run: validateSortableFields },
285+
//
286+
// [#30023] `page` joins: since the projection's `author-declared` verdict
287+
// the member also walks every stored PAGE sort (element `dataSource.sort`, a
288+
// block's own `sort`, `interfaceConfig.sort`, `record.sort`) and judges it
289+
// by the sortability projection alone. It resolves only against
290+
// `stack.objects`, which the per-write page snapshot carries, so it has no
291+
// missing-collection false-positive channel — the #9313 reason, one write
292+
// type over. It is the only member that declares `page`, so a page write
293+
// dispatches nothing else from this suite.
294+
{ name: 'validateSortableFields', runtimeTypes: ['flow', 'view', 'page'], run: validateSortableFields },
286295
// [#14107] The REST of the same list view's field surface. The two members
287296
// above own `sort` and `searchableFields`; every OTHER field-naming position
288297
// on a list view — `columns`, filter keys, `grouping`, `rowColor`,

‎packages/lint/src/rule-explanations.ts‎

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2479,14 +2479,21 @@ const SORT_FIELD_UNKNOWN_EXPLANATION: RuleExplanation = {
24792479

24802480
const SORT_FIELD_UNSORTABLE_EXPLANATION: RuleExplanation = {
24812481
rule: 'sort-field-unsortable',
2482-
covers: 'why a formula field cannot be sorted by',
2482+
covers: 'why a formula or `sortable: false` field cannot sort',
24832483
paragraphs: [
24842484
VIRTUAL_FIELD_STORAGE,
24852485
'Measured before the runtime refused it: an ORDER BY over a formula returned \'asc\' and \'desc\' ' +
24862486
'in byte-identical row order, carrying the very values it was asked to order by, unordered, ' +
24872487
'under a success. Both runtime doors now refuse it with `400 INVALID_SORT` — the REST ingress ' +
24882488
'(`assertSortFieldsExist`) and the engine (`assertOrderByIsMaterializable`) — so the declaration ' +
24892489
'breaks the view\'s first fetch, and every fetch after it.',
2490+
'A stored field whose author declared `sortable: false` is refused the same way at the REST ingress ' +
2491+
'(`400 INVALID_SORT`, "a field that declares `sortable: false`"), though a column stands behind it: ' +
2492+
'the key says what the platform offers, so the list header and the Sort picker do not offer it and ' +
2493+
'the Data API does not perform it. Both verdicts are the served sortability projection\'s ' +
2494+
'`sortable: false`, which this rule reads, so it and the door agree. A list view\'s sort and every ' +
2495+
'stored page sort (a block\'s `sort` or `dataSource.sort`, a list page\'s `interfaceConfig.sort`, an ' +
2496+
'app page\'s `record.sort`) are judged. Sort by another field, or remove `sortable: false`.',
24902497
LIST_VIEW_FIELD_SKIPS,
24912498
],
24922499
};

‎packages/lint/src/runtime-gate.page-visibility-predicate-writes.test.ts‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,9 @@ describe('#24491 — the page door gives the build\'s visibility-predicate verdi
138138
// slots (warnings only); first because it is the registry's first rule.
139139
'validateStackExpressions',
140140
'validatePresetComparands',
141+
// #30023 — the reference-integrity suite, for its one `page` member
142+
// (`validateSortableFields`: a stored page sort the list door refuses).
143+
'validateReferenceIntegrity',
141144
'validateComponentProps',
142145
'validateComponentTypes',
143146
'validatePrintPageBlocks',

0 commit comments

Comments
 (0)