diff --git a/.changeset/23434-component-read-points-part-3.md b/.changeset/23434-component-read-points-part-3.md
new file mode 100644
index 00000000000..44e5bc119af
--- /dev/null
+++ b/.changeset/23434-component-read-points-part-3.md
@@ -0,0 +1,13 @@
+---
+'@objectstack/spec': patch
+---
+
+Component-member read points, part 3 of 3, plus the two held-back moves and the other citation spellings: `packages/spec/src` no longer ties a live read point to an objectui commit or to the console pin.
+
+Clause-②: no
+
+- **Component-member tests and the other group-C files.** `component.test.ts`, the `component-*.pin.test.ts` family, the record-block tests, `expression-bindable-text-keys.zod.ts`, `page.zod.ts` and `inline-grid-column-carriers.test.ts` now point at `liveness/page.json`, row `regions`. The evidence list there is the same one parts 1 and 2 carry. `content/docs/references/ui/expression-bindable-text-keys.mdx` is regenerated from the shortened comment.
+- **The two held-back moves.** The `measures.format` record in `src/ui/dataset.zod.ts` moves into `liveness/dataset.json`, row `measures.format`. The `enable.apiMethods` record in `api-methods-batch-conformance.test.ts` moves into `liveness/object.json`, row `enable.apiMethods`.
+- **Other spellings.** Live read points written as `objectui SHA … File.tsx:NNN`, or sha-less as "at the `.objectui-sha` pin", move into the note of their row in `field.json`, `action.json`, `app.json`, `dashboard.json`, `view.json` or `page.json`, each as `objectui @SHA FILE#SYMBOL`.
+- **Unchanged on purpose.** Retirement history stays where it is: the ADR-0087 conversion entries, the v18 migration entries and the retirement pins. A citation with no matching ledger row also stays, and is listed on the pull request.
+- No schema, type, export, default, accept or refuse change. No `.describe()` text changed.
diff --git a/content/docs/references/ui/expression-bindable-text-keys.mdx b/content/docs/references/ui/expression-bindable-text-keys.mdx
index 1cc31b33366..b5210c6ae19 100644
--- a/content/docs/references/ui/expression-bindable-text-keys.mdx
+++ b/content/docs/references/ui/expression-bindable-text-keys.mdx
@@ -51,16 +51,15 @@ renderer happens to read.
## Why these rows (measured, not inferred)
Rows are a RECORD of what each component renderer already reads back from
-the node's top level, measured at the `.objectui-sha` pin `82a9417`
-(re-verified identical at objectui `origin/main` `6c68b13` on
-2026-08-18) — declaring a key a renderer does not read back would recreate
+the node's top level (read points recorded in `liveness/page.json`, row
+`regions`) — declaring a key a renderer does not read back would recreate
the evaluated-but-blank half of the objectui#4795 table:
- | type | renderer read points (top level, within the closed set) |
- |-------------|----------------------------------------------------------|
- | `statistic` | `schema.label`, `schema.value`, `schema.description` (`data-display/statistic.tsx`) |
- | `card` | `schema.title`, `schema.description` (`layout/card.tsx`) |
- | `button` | `schema.label` (`form/button.tsx`) |
+ | type | renderer reads (top level, within the closed set) |
+ |-------------|---------------------------------------------------|
+ | `statistic` | `schema.label`, `schema.value`, `schema.description` |
+ | `card` | `schema.title`, `schema.description` |
+ | `button` | `schema.label` |
These are the measured motivating cases from objectui#4795 (dashboard
workhorses). Other registered renderers also read keys from this closed set
@@ -69,7 +68,7 @@ at the top level (`alert`/`empty`/`dialog` `title`+`description`, `badge`
declared yet: form-control `value` is interactive state rather than display
text, and each row is an accept-surface widening that should arrive with its
own measurement, not ride this one (startup scope discipline). `text` reads
-back `schema.content || schema.value` (`basic/text.tsx`) — unlike the rows
+back `schema.content || schema.value` (the same ledger entry) — unlike the rows
above, its omission is not merely unmeasured: `value` there is a fallback
spelling for the same slot `content` already evaluates (see `content` NOT a
member, above), not a second read point, so a `text: ['value']` row would
diff --git a/packages/spec/liveness/action.json b/packages/spec/liveness/action.json
index a8189c08bbe..b9f265a2934 100644
--- a/packages/spec/liveness/action.json
+++ b/packages/spec/liveness/action.json
@@ -48,7 +48,7 @@
"verifiedAt": "2026-09-08",
"evidenceScope": "in-repo",
"evidence": "packages/runtime/src/action-execution.ts#isDeclarativeUpdateAction (the executor's own discriminator — a bare `action?.operation === DECLARATIVE_UPDATE_OPERATION`, deliberately with no `type` clause so data at rest whose `type` contradicts its `operation` is still routed by `operation`); packages/runtime/src/domains/actions.ts#handleActionsRequest (the REST `/actions` door: the branch runs ahead of the `type` switch and ahead of the trusted-mode plumbing, and hands off to `executeDeclarativeUpdateAction`); packages/runtime/src/action-execution.ts#invokeBusinessAction (the MCP `run_action` door takes the same branch into the same executor — one implementation, two doors); packages/runtime/src/action-execution.ts#isHeadlessInvokableAction (asked FIRST, so a declarative update is listed as invokable although it carries neither `target` nor `body`); packages/runtime/src/action-execution.ts#headlessActionTypeError (asked FIRST, so the key suppresses the `type` prescription that would otherwise be wrong for it); packages/runtime/src/action-execution.ts#summarizeAction (the MCP listing face projects the declared `operation` and forces `requiresRecord`); packages/spec/src/ui/action.zod.ts#refuseDeclarativeUpdateContradictions (authoring-time: every executor-binding key beside `operation: 'update'` is refused at its own path, and `patch` without it); packages/spec/src/stack.zod.ts#collectGlobalUpdateActionErrors (defineStack refuses a standalone `operation: 'update'` action with no `objectName`)",
- "note": "The discriminator of the declarative single-record field write — one member, `'update'`; `'delete'`/`'custom'` are refused with the reason. FLIPPED `planned` -> `live` 2026-09-08 (#15080) on the runtime half #15079 (PR #15448, merged 2026-09-04): the key now decides dispatch at both server doors, and it is read BEFORE `type` at every one of them — contract point 1 of the executor contract PR #15077 pinned here, and a rule about ORDER, not merely a new branch. Declared by the #14092 maintainer ruling (2026-09-01): the row-level counterpart of a list view's `bulkActionDefs` `operation: 'update'`, spelled with the same words. The EXECUTOR CONTRACT is now honoured in tree rather than promised: the write is a single data-plane update of the CURRENT record executed AS THE CALLER under `wiring.ec` and never `buildActionExecutionContext` (the #14010 `runAs: 'user'` direction), so object/row/field permissions, hooks and validations fire as for a user edit and a caller who cannot read the row is refused (the class commit f19475c0a closed); `patch` merges UNDER the collected `params`; `undoable` captures the prior values of exactly the fields written; an action with no current record is a located 400, never a silent no-op. Pinned end-to-end in packages/runtime/src/action-declarative-update.test.ts, one describe per contract point plus a reverse pin that a handler-less `type: 'script'` action WITHOUT `operation` is unchanged. `evidenceScope: in-repo` is exact and deliberate: this verdict rests on the framework-side readers alone. The console half (objectui#7551) is a SECOND reader and the flip did not wait for it — objectui's `ActionRunner` still dispatches on `type` — so a console-side forward/undo pointer is a later widening of this row's scope, not a precondition of its verdict."
+ "note": "The discriminator of the declarative single-record field write — one member, `'update'`; `'delete'`/`'custom'` are refused with the reason. FLIPPED `planned` -> `live` 2026-09-08 (#15080) on the runtime half #15079 (PR #15448, merged 2026-09-04): the key now decides dispatch at both server doors, and it is read BEFORE `type` at every one of them — contract point 1 of the executor contract PR #15077 pinned here, and a rule about ORDER, not merely a new branch. Declared by the #14092 maintainer ruling (2026-09-01): the row-level counterpart of a list view's `bulkActionDefs` `operation: 'update'`, spelled with the same words. The EXECUTOR CONTRACT is now honoured in tree rather than promised: the write is a single data-plane update of the CURRENT record executed AS THE CALLER under `wiring.ec` and never `buildActionExecutionContext` (the #14010 `runAs: 'user'` direction), so object/row/field permissions, hooks and validations fire as for a user edit and a caller who cannot read the row is refused (the class commit f19475c0a closed); `patch` merges UNDER the collected `params`; `undoable` captures the prior values of exactly the fields written; an action with no current record is a located 400, never a silent no-op. Pinned end-to-end in packages/runtime/src/action-declarative-update.test.ts, one describe per contract point plus a reverse pin that a handler-less `type: 'script'` action WITHOUT `operation` is unchanged. `evidenceScope: in-repo` is exact and deliberate: this verdict rests on the framework-side readers alone. The console half (objectui#7551) is a SECOND reader and the flip did not wait for it — objectui's `ActionRunner` still dispatches on `type` — so a console-side forward/undo pointer is a later widening of this row's scope, not a precondition of its verdict. The console's runner reads `operation` before any executor (packages/spec/src/ui/action-declarative-update.ts; moved out of spec source, #23434): objectui @b9814b334 packages/core/src/actions/ActionRunner.ts#execute (isUpdateOperationAction) posts the write through its registered `script` dispatch and runs no executor of its own, whatever executor the action or row names; byte-identical at objectui main 524136e."
},
"patch": {
"status": "live",
@@ -68,7 +68,7 @@
"status": "live",
"verifiedAt": "2026-08-28",
"evidence": "packages/runtime/src/action-execution.ts#dispatchFlowAction (type:'flow' server dispatch — automation.execute(action.target, …) runs inside it, after flowIsUnknown rejects an unrecognized flow name by that same value); packages/runtime/src/action-execution.ts#headlessActionTypeError (names the target the client-dispatched types go to instead)",
- "note": "URL/script/flow/endpoint + ${param}/${ctx} interpolation. 2026-08-25: REPOINTED — the evidence cited packages/runtime/src/http-dispatcher.ts, which has 0 occurrences of `target`; the action consumer was extracted into domains/actions.ts + action-execution.ts and http-dispatcher.ts now only delegates. The file still existed and the citation carried no line, so nothing in the gate could see it. 2026-08-28: RE-ANCHORED (#12516) — the 08-25 repoint wrote line numbers (:725/:718/:472) and all three drifted IN RANGE within a day (the lines now hold the FlowActionRefusal brand block and disabledActionRefusal's docblock); the citation now anchors the consuming symbols, which move with the consumer."
+ "note": "URL/script/flow/endpoint + ${param}/${ctx} interpolation. 2026-08-25: REPOINTED — the evidence cited packages/runtime/src/http-dispatcher.ts, which has 0 occurrences of `target`; the action consumer was extracted into domains/actions.ts + action-execution.ts and http-dispatcher.ts now only delegates. The file still existed and the citation carried no line, so nothing in the gate could see it. 2026-08-28: RE-ANCHORED (#12516) — the 08-25 repoint wrote line numbers (:725/:718/:472) and all three drifted IN RANGE within a day (the lines now hold the FlowActionRefusal brand block and disabledActionRefusal's docblock); the citation now anchors the consuming symbols, which move with the consumer. The url-target scheme set's runner half (packages/spec/src/ui/navigation-target.ts and its pin action-url-target-scheme-set.test.ts; moved out of spec source, #23434): objectui @7578323 packages/core/src/actions/navigationTarget.ts#classifyNavigationTarget, which the action runner and the entitlement CTA both call; the runner's own pinned cases, mirrored by the spec test, are objectui @7578323 packages/core/src/actions/__tests__/navigationTarget.mailto-12191.test.ts."
},
"body": {
"status": "live",
diff --git a/packages/spec/liveness/app.json b/packages/spec/liveness/app.json
index 93e0bb8f9a9..d59304eafba 100644
--- a/packages/spec/liveness/app.json
+++ b/packages/spec/liveness/app.json
@@ -160,7 +160,7 @@
"status": "live",
"verifiedAt": "2026-08-01",
"evidence": "objectui @940ba24: packages/layout/src/NavigationRenderer.tsx:294-296, :418",
- "note": "target precedence recordId → filters → viewName; also keys the view-label i18n lookup."
+ "note": "target precedence recordId → filters → viewName; also keys the view-label i18n lookup. With no `viewName` (packages/spec/src/ui/app.zod.ts, ObjectNavItemSchema; moved out of spec source, #23434): the entry links to the bare object route, where objectui @b9814b334 packages/app-shell/src/views/ObjectView.tsx#activeViewId opens `defaultViewId || views[0]`, the view objectui @b9814b334 packages/app-shell/src/views/ObjectView.tsx#buildViewTabs marks default, and the `all` tab that function adds only for an object with no list view (#21973); first read at objectui @0abd4f9f8769 (the same two symbols), re-read 2026-10-15."
},
"recordId": {
"status": "live",
diff --git a/packages/spec/liveness/dashboard.json b/packages/spec/liveness/dashboard.json
index a12e1ffb848..46f33a6218b 100644
--- a/packages/spec/liveness/dashboard.json
+++ b/packages/spec/liveness/dashboard.json
@@ -221,7 +221,7 @@
"status": "live",
"verifiedAt": "2026-08-03",
"evidence": "objectui @91757a7: packages/plugin-dashboard/src/DashboardRenderer.tsx:439 — spread into every component schema; objectui: packages/plugin-dashboard/src/DatasetWidget.tsx:190-191 — declared query keys lowered into the DatasetSelection",
- "note": "the renderer-extras bag; its four DECLARED keys (dateGranularity / sortBy / sortOrder / limit, framework#3588) reach the analytics query, the rest pass through to the renderer."
+ "note": "the renderer-extras bag; its four DECLARED keys (dateGranularity / sortBy / sortOrder / limit, framework#3588) reach the analytics query, the rest pass through to the renderer. The #20960 census (packages/spec/src/ui/dashboard.zod.ts; moved out of spec source, #23434): on the dataset-bound path objectui main @5262f7dd packages/plugin-dashboard/src/DatasetWidget.tsx#DatasetWidget reads the declared query keys (`dateGranularity`, `sortBy`, `sortOrder`, `limit`) and the metric tile's `description` (#resolvedSubCaption) and nothing else of the bag; none of the keys this repo's examples wrote (`format`, `currency`, `color`, `suffix`, `showLegend`, `horizontal`, `showDataLabels`) is read there, only the legacy inline arm spreads the bag, and each was removed from its producer."
},
"filterBindings": {
"status": "live",
diff --git a/packages/spec/liveness/dataset.json b/packages/spec/liveness/dataset.json
index f48c30aecd0..a3f13ec585a 100644
--- a/packages/spec/liveness/dataset.json
+++ b/packages/spec/liveness/dataset.json
@@ -106,7 +106,7 @@
"format": {
"status": "live",
"evidence": "packages/services/service-analytics/src/dataset-compiler.ts#compileDataset (`if (typeof m.format === 'string') metric.format = m.format`); packages/services/service-analytics/src/analytics-service.ts#AnalyticsService (`queryDataset`: `if (f.format == null && m.format) f.format = m.format` — enriched onto the result field for the renderer)",
- "note": "compiled into Cube metric + enriched onto result fields for the renderer. 2026-08-28: RE-ANCHORED (commit 9ee2dcfbd) and REPOINTED — `analytics-service.ts:480` had rotted onto a docblock sentence about driver selection. Re-closed by hand against c459da6bc; DATED for the first time (this file carried no `verifiedAt` anywhere, which the review accepting that re-anchoring sorts as OLDEST).",
+ "note": "compiled into Cube metric + enriched onto result fields for the renderer. 2026-08-28: RE-ANCHORED (commit 9ee2dcfbd) and REPOINTED — `analytics-service.ts:480` had rotted onto a docblock sentence about driver selection. Re-closed by hand against c459da6bc; DATED for the first time (this file carried no `verifiedAt` anywhere, which the review accepting that re-anchoring sorts as OLDEST). Renderer read points for the date-valued measure (packages/spec/src/ui/dataset.zod.ts; moved out of spec source, #23434), re-read at objectui @b9814b334 on 2026-10-14: objectui @b9814b334 packages/core/src/utils/dataset-format.ts#formatMeasure routes a non-numeric value through objectui @b9814b334 packages/core/src/utils/dataset-format.ts#formatMeasureDate, whose date-only arm threads `format` into the STYLE parameter of objectui @b9814b334 packages/core/src/utils/date-display.ts#formatDate (its `relative` branch falls back to the absolute form beyond ±7 days, stripping the style through objectui @b9814b334 packages/core/src/utils/date-display.ts#absoluteFallbackOptions), while its datetime arm answers `relative` with objectui @b9814b334 packages/core/src/utils/date-display.ts#formatRelativeDate, `short` with objectui @b9814b334 packages/core/src/utils/date-display.ts#formatDateTime (`style: 'compact'`) and everything else — a date pattern included — with the bare `formatDateTime(v, { locale })`. Until objectui#8352 a datetime value ignored `format`; the pattern-grammar gap stays documented rather than closed (objectui#7178 ruled A).",
"verifiedAt": "2026-08-28"
},
"currency": {
diff --git a/packages/spec/liveness/field.json b/packages/spec/liveness/field.json
index 9a99832bb76..1a13c967199 100644
--- a/packages/spec/liveness/field.json
+++ b/packages/spec/liveness/field.json
@@ -54,7 +54,7 @@
},
"options": {
"status": "live",
- "note": "select options {label,value,description,color,default} — renderers + validation. `description` joined 2026-08-31 (objectui#6153, inheriting the objectui#6140 ruling frame): objectui LookupField searches it on authored static options (LookupField.tsx:526) and recordToOption produces it for fetched options. `icon` is NOT an option key (withdrawn from the object.form options repeater under ADR-0049, #13671; pinned by packages/spec/src/data/field-rows-option-description.test.ts). Read points moved out of spec source (#23434), measured at objectui @d8ec8d6d4f011b11c8eb1e6dbd364ef206711391 and on objectui main with the same answer: objectui @d8ec8d6d4f01 packages/fields/src/index.tsx#SelectCellRenderer (its `renderOne` badge/dot branch reads `option?.label` and `option?.color` off a `SelectOptionMetadata[]`, never `option?.icon`); no field-option render path reads `icon`; the one `opt.icon` read in that tree is the config-panel `ConfigField` vocabulary (a `React.ReactNode` an authored option cannot reach)."
+ "note": "select options {label,value,description,color,default} — renderers + validation. `description` joined 2026-08-31 (objectui#6153, inheriting the objectui#6140 ruling frame): objectui LookupField searches it on authored static options (LookupField.tsx:526) and recordToOption produces it for fetched options. `icon` is NOT an option key (withdrawn from the object.form options repeater under ADR-0049, #13671; pinned by packages/spec/src/data/field-rows-option-description.test.ts). Read points moved out of spec source (#23434), measured at objectui @d8ec8d6d4f011b11c8eb1e6dbd364ef206711391 and on objectui main with the same answer: objectui @d8ec8d6d4f01 packages/fields/src/index.tsx#SelectCellRenderer (its `renderOne` badge/dot branch reads `option?.label` and `option?.color` off a `SelectOptionMetadata[]`, never `option?.icon`); no field-option render path reads `icon`; the one `opt.icon` read in that tree is the config-panel `ConfigField` vocabulary (a `React.ReactNode` an authored option cannot reach). No per-option `disabled` on the object-field pipeline (packages/spec/src/shared/editability-boundary.ts, the SelectOptionSchema prescription; moved out of spec source, #23434): measured on objectui main @aca27fa, packages/fields/src/widgets/SelectField.tsx#SingleSelectField calls the root `disabled` the single authority and packages/fields/src/widgets/RadioField.tsx#hostGroupProps reads only `props.disabled`; the per-option `disabled` that exists is the SDUI family's own vocabulary, objectui @aca27fa packages/components/src/renderers/form/select.tsx#SelectRenderer."
},
"picklist": {
"status": "live",
@@ -292,7 +292,7 @@
},
"lookupColumns": {
"status": "live",
- "note": "objectui RecordPickerDialog — record-picker table columns; renderer auto-derives from the referenced object when omitted (reads lookupColumns || lookup_columns)."
+ "note": "objectui RecordPickerDialog — record-picker table columns; renderer auto-derives from the referenced object when omitted (reads lookupColumns || lookup_columns). The lookup keys' snake_case twins (the docblock above `displayField` in packages/spec/src/data/field.zod.ts, for all seven lookup keys; moved out of spec source, #23434): of the seven, only `lookupColumns`, `lookupPageSize` and `allowCreate` are read as `SNAKE ?? CAMEL`, at objectui @ed971e8 packages/fields/src/widgets/LookupField.tsx#lookupColumns, #lookupPageSize and #explicitAllowCreate (all inside LookupField); `displayField`, `descriptionField`, `lookupFilters` and `dependsOn` are read camelCase-only there; claim dated 2026-09-09."
},
"lookupPageSize": {
"status": "live",
@@ -325,7 +325,7 @@
"verifiedAt": "2026-09-27",
"evidenceScope": "cross-repo",
"evidence": "objectui: packages/i18n/src/currency.ts:60 reads field.currencyConfig.defaultCurrency ONLY when currencyConfig.currencyMode is 'fixed' — the second step of resolveFieldCurrency's precedence chain; a 'dynamic' config, or one naming no mode, skips it for the tenant default localization.currency; objectui: packages/fields/src/widgets/CurrencyField.tsx:55 calls resolveFieldCurrency and applies the resolved code at :91 through formatAmount, which passes it to Intl.NumberFormat via formatDisplayNumber — measured objectui @25c7d584",
- "note": "RE-CITED 2026-09-27 (#20126): since objectui#10461 the reader takes defaultCurrency only under currencyMode 'fixed', and the chain no longer cites the date/datetime-semantics ADR, which never names currency; line pointers moved with it (currency.ts :32 → :60, CurrencyField.tsx :45/:51 → :55/:91). Verdict unchanged: LIVE. RE-CITED 2026-08-10 (#7133/#7142): the old pointer 'packages/fields/src/index.tsx:469' now lands in formatRelativeDays, a date-phrase helper with no currency involvement — the resolver moved to @object-ui/i18n and packages/fields/src/currency.ts:14 only re-exports it, which is why the old line drifted onto unrelated code rather than disappearing. Verdict unchanged: LIVE, and now cited at both the reader that consumes the key and the widget that applies the resolved currency."
+ "note": "RE-CITED 2026-09-27 (#20126): since objectui#10461 the reader takes defaultCurrency only under currencyMode 'fixed', and the chain no longer cites the date/datetime-semantics ADR, which never names currency; line pointers moved with it (currency.ts :32 → :60, CurrencyField.tsx :45/:51 → :55/:91). Verdict unchanged: LIVE. RE-CITED 2026-08-10 (#7133/#7142): the old pointer 'packages/fields/src/index.tsx:469' now lands in formatRelativeDays, a date-phrase helper with no currency involvement — the resolver moved to @object-ui/i18n and packages/fields/src/currency.ts:14 only re-exports it, which is why the old line drifted onto unrelated code rather than disappearing. Verdict unchanged: LIVE, and now cited at both the reader that consumes the key and the widget that applies the resolved currency. The removed `currencyConfig.precision` (#19992; packages/spec/src/data/field.zod.ts; moved out of spec source, #23434): the widget's one width is the currency's ISO 4217 minor unit, objectui @b9814b334 packages/fields/src/widgets/CurrencyField.tsx#CurrencyField through objectui @b9814b334 packages/fields/src/widgets/number-format.ts#currencyDisplayWidth over objectui @b9814b334 packages/fields/src/currency.ts#currencyFractionDigits, and no objectui code reads `currencyConfig.precision`; re-read 2026-10-15, first cited sha-less (the source then named `currencyFractionDigits(currency)` as the widget's own line)."
},
"dimensions": {
"status": "live",
@@ -456,7 +456,7 @@
"verifiedAt": "2026-09-20",
"evidenceScope": "cross-repo",
"evidence": "objectui: packages/app-shell/src/utils/deriveRelatedLists.ts#deriveRelatedLists:276 puts the authored value on the derived descriptor as `filter`, gated by the same file's #isDeclaredFilter predicate — the declared-vs-absent discrimination its relatedListTitle / relatedListColumns siblings do, with no alias accepted and no shape coerced; objectui: packages/app-shell/src/views/RecordDetailView.tsx#synthParts:2079 destructures that descriptor key as `declaredFilter` (:2041) and writes it onto the synthesized `record:related_list` node, the same `filter` slot the component-level input already lowers, so RelatedList AND-composes it with { [referenceField]: parentId } and the tab strip's count probe composes the same pair — measured objectui @53ded82bf7, which is this repo's `.objectui-sha` pin, so both pointers were read AT THE PIN this repo builds against rather than on objectui main",
- "note": "[#8704] Contract-first spec half (maintainer ruling 2026-08-15, 「接受全部建议。」 item 3): the declarative default filter the auto-derived related list AND-composes with { [referenceField]: parentId }, badge-count parity included — both clauses normative in the key's describe()/JSDoc and pinned in field.test.ts. Reuses FilterConditionSchema, so the #8793 bare-preset schema door judges it at parse (pinned at this position) and the engine FILTER doors (#8296 formula refusal etc.) judge the composed query at run time. Seeded `planned` + authorWarn per enforce-or-mark, the app.navigation runAction (#4848) shape rather than the useGrouping one, and that seeding wrote its own flip condition: 「Flip to `live` (and drop authorWarn) with a deriveRelatedLists/RecordDetailView evidence pointer when objectui#4664 lands.」 **FLIPPED `planned` → `live` 2026-09-20 (#19187), and the condition was re-measured rather than relayed**: objectui#4664 landed as objectui d796c8dde (objectui PR #6946, 2026-08-31) and `git merge-base --is-ancestor d796c8dde 53ded82bf7` exits 0, so the consumer is inside the console this repo pins — the #10068 discipline (read both pointers at the pin, never at objectui main) one row over. What the flip drops is not bookkeeping: the authorHint it carried told an author 「the auto-derived related list does not apply this filter yet」 about a key the pinned console applies, and `packages/lint`'s ledger-driven advisory repeated that sentence at every compile, steering authors off a working key. The sentence is recorded rather than deleted because it was TRUE from #8704 until the pin absorbed d796c8dde — a `planned` row falsifies by its consumer landing, which is the one direction no citation check can see (the pointer never rots; there was no pointer)."
+ "note": "[#8704] Contract-first spec half (maintainer ruling 2026-08-15, 「接受全部建议。」 item 3): the declarative default filter the auto-derived related list AND-composes with { [referenceField]: parentId }, badge-count parity included — both clauses normative in the key's describe()/JSDoc and pinned in field.test.ts. Reuses FilterConditionSchema, so the #8793 bare-preset schema door judges it at parse (pinned at this position) and the engine FILTER doors (#8296 formula refusal etc.) judge the composed query at run time. Seeded `planned` + authorWarn per enforce-or-mark, the app.navigation runAction (#4848) shape rather than the useGrouping one, and that seeding wrote its own flip condition: 「Flip to `live` (and drop authorWarn) with a deriveRelatedLists/RecordDetailView evidence pointer when objectui#4664 lands.」 **FLIPPED `planned` → `live` 2026-09-20 (#19187), and the condition was re-measured rather than relayed**: objectui#4664 landed as objectui d796c8dde (objectui PR #6946, 2026-08-31) and `git merge-base --is-ancestor d796c8dde 53ded82bf7` exits 0, so the consumer is inside the console this repo pins — the #10068 discipline (read both pointers at the pin, never at objectui main) one row over. What the flip drops is not bookkeeping: the authorHint it carried told an author 「the auto-derived related list does not apply this filter yet」 about a key the pinned console applies, and `packages/lint`'s ledger-driven advisory repeated that sentence at every compile, steering authors off a working key. The sentence is recorded rather than deleted because it was TRUE from #8704 until the pin absorbed d796c8dde — a `planned` row falsifies by its consumer landing, which is the one direction no citation check can see (the pointer never rots; there was no pointer). The form hint's face today (packages/spec/src/data/field.form.ts; moved out of spec source, #23434): objectui @b9814b334 packages/app-shell/src/views/metadata-admin/SchemaForm.tsx#resolveFieldFace lands the `filter-condition` hint on `{ kind: 'raw-json', hint }`, past both structural fallbacks, because objectui @b9814b334 packages/app-shell/src/views/metadata-admin/widgets.tsx#WIDGETS registers no `filter-condition`; re-read 2026-10-15, first cited sha-less."
},
"trackHistory": {
"status": "live",
diff --git a/packages/spec/liveness/object.json b/packages/spec/liveness/object.json
index 2af77c3aa36..0c63f12041b 100644
--- a/packages/spec/liveness/object.json
+++ b/packages/spec/liveness/object.json
@@ -189,7 +189,7 @@
"apiMethods": {
"status": "live",
"evidence": "packages/spec/src/data/api-derivation.ts, packages/rest/src/rest-server.ts, packages/runtime/src/api-exposure.ts",
- "note": "three-state whitelist over the six primitives (get/list/create/update/delete/bulk): undefined = unrestricted, [] = deny-all (fully closed), subset = the derived closure; a present-but-non-array value fails CLOSED (#3545). resolveEffectiveApiMethods (the single derivation table) is consumed by the REST gate (405 outside the effective set) and the runtime dispatcher gate. Since #3543 the enum IS the six primitives; the legacy 8 values (upsert/aggregate/history/search/restore/purge/import/export) are DERIVED effective operations (ApiOperation vocabulary) — a stored legacy value is stripped at parse (stripLegacyApiMethods, canonicalize-and-warn, permanent tolerance)."
+ "note": "three-state whitelist over the six primitives (get/list/create/update/delete/bulk): undefined = unrestricted, [] = deny-all (fully closed), subset = the derived closure; a present-but-non-array value fails CLOSED (#3545). resolveEffectiveApiMethods (the single derivation table) is consumed by the REST gate (405 outside the effective set) and the runtime dispatcher gate. Since #3543 the enum IS the six primitives; the legacy 8 values (upsert/aggregate/history/search/restore/purge/import/export) are DERIVED effective operations (ApiOperation vocabulary) — a stored legacy value is stripped at parse (stripLegacyApiMethods, canonicalize-and-warn, permanent tolerance). Read points for the `sys_api_key` single-record-write exemption pinned in packages/spec/src/data/api-methods-batch-conformance.test.ts (moved out of spec source, #23434), re-read at objectui @b9814b334 (2026-10-14): objectui @b9814b334 packages/plugin-grid/src/ObjectGrid.tsx#selectionMode — with neither `selection` nor `selectable` authored, multi-select is enabled only by objectui @b9814b334 packages/plugin-grid/src/ObjectGrid.tsx#hasBulkActions, and the one implicit bulk action, bulk-delete, is gated on the resolved delete affordance (objectui @b9814b334 packages/plugin-grid/src/ObjectGrid.tsx#rowDeleteVerdict); a list-item action named in `bulkActions` is promoted to `operation: 'custom'` + `actionDef` and dispatched through objectui @b9814b334 packages/plugin-grid/src/ObjectGrid.tsx#dispatchBulkAction; objectui @b9814b334 packages/plugin-grid/src/hooks/useBulkExecutor.ts#useBulkExecutor — a promoted custom def fans out per row through the action runner, and only an `update`/`delete` bulk def reaches the data-plane `bulk` primitive."
},
"trackHistory": {
"status": "live",
diff --git a/packages/spec/liveness/page.json b/packages/spec/liveness/page.json
index b960a0e5c9a..955126178f1 100644
--- a/packages/spec/liveness/page.json
+++ b/packages/spec/liveness/page.json
@@ -54,7 +54,7 @@
"verifiedAt": "2026-08-10",
"evidenceScope": "cross-repo",
"evidence": "objectui: packages/components/src/renderers/layout/page.tsx:290 branches on schema.regions, :197-204 resolves the named slots (header/sidebar/main/aside/footer) and appends the remainder below main at :211, and :157 flattens their components for the JSX-source path — measured objectui @11c1e71e",
- "note": "region → component tree rendering (header/main/sidebar/footer). RE-CITED 2026-08-10 (#7133/#7142): same split-citation pruning as `template` — at objectui @11c1e71e the containers.tsx half names `regions` only in a comment (:798, 'page:section — thin wrapper used inside regions'). Verdict unchanged: LIVE. Component-level liveness stays unclassified (undrilled container, #4956); one component key carries a verdict OUTSIDE this file: `components[].responsive` is a retiredKey tombstone (#11027, ADR-0049 D2 — dead on a two-repo measurement; see the file _note)."
+ "note": "region → component tree rendering (header/main/sidebar/footer). RE-CITED 2026-08-10 (#7133/#7142): same split-citation pruning as `template` — at objectui @11c1e71e the containers.tsx half names `regions` only in a comment (:798, 'page:section — thin wrapper used inside regions'). Verdict unchanged: LIVE. Component-level liveness stays unclassified (undrilled container, #4956); one component key carries a verdict OUTSIDE this file: `components[].responsive` is a retiredKey tombstone (#11027, ADR-0049 D2 — dead on a two-repo measurement; see the file _note). COMPONENT-MEMBER READ POINTS (moved out of packages/spec/src, #23434; ruling 6165388570 letter C, Q1 A as the seat read it): an EVIDENCE LIST only — no verdict is asserted, so component-level liveness stays unclassified as above. Each entry names the ComponentPropsMap row and member it reads, then its read points in the spelling `objectui @SHA FILE#SYMBOL` (the SHA is the objectui tree the point was last read in; a pin hop moves nothing here, and a renamed or deleted symbol is the event that re-measures it). Inside one entry, a letter defined at its head abbreviates a repeated file: with `P = objectui @SHA FILE`, `P#a P#b` reads `objectui @SHA FILE#a`, `objectui @SHA FILE#b`. Entries, in source order: [1] page:header (H = objectui @b9814b334 packages/components/src/renderers/layout/containers.tsx#PageHeaderRenderer): title (`schema?.title ?? schema?.properties?.title`), the refused `icon` (resolved only per header action) and `breadcrumb` (an empty slot), `actions` (resolvedHeaderActions then headerActionPlan), recordChrome (`=== false` on either carrier, branching the header), showStar and showCopyId (the record chip), maxVisible and mobileMaxVisible (`?? 3` / `?? 1`), all in H; re-read 2026-10-15, first cited sha-less; [2] page:tabs (T = objectui @b9814b334 packages/components/src/renderers/layout/containers.tsx#PageTabsRenderer): tabStyle (`schema?.properties?.type || schema?.tabStyle || 'line'`), alwaysShowStrip (`schema?.alwaysShowStrip === true || schema?.properties?.alwaysShowStrip === true`), items[].value (`it.value`, falling back to `tab-${idx}`; the refused `key` is the designer's `page:tabs.items.itemFields` input in objectui @b9814b334 packages/app-shell/src/views/metadata-admin/previews/block-config.ts#BLOCK_CONFIG), all in T; the retired props key `type` (the reason for the rename): left unhoisted by objectui @b9814b334 packages/react/src/SchemaRenderer.tsx#HOIST_PROTECTED_KEYS, and skipped as a base prop by objectui @b9814b334 packages/sdui-parser/src/validate.ts#BASE_PROPS; re-read 2026-10-15, first cited sha-less; [3] page:tabs items[].icon (C = objectui @b9814b334 packages/components/src/renderers/layout/containers.tsx): C#triggerClass (`LazyIcon` inside the TabsTrigger) in C#PageTabsRenderer; published by its registration's `items` input; vocabulary objectui @b9814b334 packages/components/src/lib/lazy-icon.tsx#getLazyIcon; [4] page:tabs items[].visibleWhen (the tab-item evaluator: `data` is the row, bare fields spread flat, ambient roots after it): objectui @1fb1ced36243 packages/components/src/renderers/layout/containers.tsx#isItemVisible (its ExpressionEvaluator) in PageTabsRenderer; [5] record:details / record:highlights / record:related_list / record:quick_actions .requiredPermissions (RECORD_BLOCK_REQUIRED_PERMISSIONS_DESCRIPTION; R = objectui @b9814b334 packages/plugin-detail/src/renderers/, P = objectui @b9814b334 packages/permissions/src/): the gate `perms.hasCapabilities(required)` and the notice in R record-details.tsx#RecordDetailsBody, R record-highlights.tsx#highlightsAllowed (RecordHighlightsBody), R record-related-list.tsx#RecordRelatedListBody, R record-quick-actions.tsx#RecordQuickActionsBody; earlier withholding: no record R record-details.tsx#RecordDetailsBody, no object and the related read gate R record-related-list.tsx#RecordRelatedListBody; a gated highlights registers no fields R record-highlights.tsx#RecordHighlightsBody (useRegisterHighlightFields); ALL OF THEM and fail-open on unreported P MePermissionsProvider.tsx#hasCapabilities; fail-open P PermissionProvider.tsx#ALL_CAPABILITIES and P usePermissions.ts#NO_PROVIDER_PERMISSIONS; the binding wrapper (objectui#12294) objectui @b9814b334 packages/plugin-detail/src/renderers/recordBinding.tsx#recordBindingBlock; [6] record:details sections[].headerColor (closed enum, #12126): the six class literals of objectui @b9814b334 packages/plugin-detail/src/headerColor.ts#headerColorClass (objectui#6294, merged 2026-08-25); re-read 2026-10-15, first cited sha-less; [7] record:details sections[] hideEmpty, collapsible, showBorder and the #11661 trio (renderer defaults measured; the trio at objectui @190fbd01): objectui @190fbd01 packages/plugin-detail/src/renderers/record-details.tsx#RecordDetailsRenderer and objectui @190fbd01 packages/plugin-detail/src/DetailSection.tsx#DetailSection (`hideEmpty ?? true`; the undeclared `s.title ?? s.label` limb); [8] record:related_list.parentDataSource (the name): the sibling record blocks' binding read objectui @f0532d8a packages/plugin-detail/src/renderers/recordBinding.tsx#recordBindingBlock (`isElementDataSourceConfig(schema.dataSource)`), measured on objectui main; [9] record:details sections[].count (read since objectui c08c9332a, objectui#12192): objectui @b9814b334 packages/plugin-detail/src/renderers/record-details.tsx#countField (inside filteredSections; fills every `{{ count }}` hole); [10] record:related_list.parentDataSource (PLANNED): the objectui measurement is the file _note's (objectui @f0532d8a, the record context read in RecordRelatedListBody); no new evidence here; [11] record:activity guidance `items` / `loading` (host feed slot; R = objectui @89cad75d5570 packages/plugin-detail/src/renderers/): R record-activity.tsx#hostItems and R record-activity.tsx#loading in RecordActivityRenderer; record:chatter / record:discussion `feed` reads neither, R record-chatter.tsx#RecordChatterRenderer; [12] record:chatter.position (vocabulary bottom / right / left, #8762): objectui @665661ab0932 packages/plugin-detail/src/RecordChatterPanel.tsx#position (`right`/`left` dock vs `bottom` in-flow); the designer's CHATTER_INPUTS and the merge fallback in objectui @665661ab0932 packages/plugin-detail/src/renderers/record-chatter.tsx#RecordChatterRenderer; [13] record:reference_rail (RecordReferenceRailProps): objectui @b9814b334 packages/plugin-detail/src/renderers/record-reference-rail.tsx#RecordReferenceRailRenderer ( an entry `icon` is unread, `title` a raw React child); the synthesizer emitting `icon` objectui @b9814b334 packages/plugin-detail/src/synth/buildDefaultPageSchema.ts#buildDefaultPageSchema; re-read 2026-10-15, first cited sha-less; [14] record:alert, record:quick_actions, record:history: objectui @b9814b334 packages/plugin-detail/src/renderers/record-alert.tsx#RecordAlertRenderer, objectui @b9814b334 packages/plugin-detail/src/renderers/record-quick-actions.tsx#RecordQuickActionsRenderer, objectui @b9814b334 packages/plugin-detail/src/renderers/record-history.tsx#RecordHistoryRenderer and objectui @b9814b334 packages/plugin-detail/src/HistoryTimeline.tsx#HistoryTimeline (each renderer's ACTUAL reads, against its registration's declared inputs); re-read 2026-10-15, first cited sha-less; [15] record:line_items (RecordLineItemsProps; L = objectui @31971ff1e28f packages/plugin-form/src/LineItemsPanel.tsx): registered as `line_items` (namespace `record`) in objectui @31971ff1e28f packages/plugin-form/src/index.tsx with its mapping objectui @31971ff1e28f packages/plugin-form/src/index.tsx#RECORD_LINE_ITEMS_DATA_SOURCE; the fifteen `schema.KEY` reads in L#LineItemsPanel (childObject L#heldReloadRef; parentObject L#parentObject; parentId, recordId L#parentId; amountField, totalField L#parentPatch; filter L#scopeFilter; limit L#message; columns L#gridField (applyColumnPermissions)); the gate objectui @31971ff1e28f packages/react/src/element-data-source/ElementDataSourceGate.tsx#useElementDataSourceSchema; read set unchanged at objectui main d59f11c0d3dc; [16] record:line_items guidance (addLabel, sortField, onRowExpand not handed to the grid): objectui @9dfaca654311 packages/plugin-form/src/LineItemsPanel.tsx#gridField; [17] record:approvals (RecordApprovalsProps, EMPTY key set; A = objectui @47b1f0bb71 packages/app-shell/src/views/): registered as `approvals` (namespace `record`) in A record-approvals-renderer.tsx#RecordApprovalsRenderer; approvals A record-approvals-renderer.tsx#hostApprovals, threaded by A RecordDetailView.tsx#RecordDetailView and emitted by objectui @47b1f0bb71 packages/plugin-detail/src/synth/buildDefaultPageSchema.ts#buildDefaultPageSchema; currentUserId falls back in A RecordApprovalsPanel.tsx#isSubmitter; Studio page create seeds without options in A metadata-admin/anchors.ts#synth; [18] page:accordion items[].value (refused): objectui @b9814b334 packages/components/src/renderers/layout/containers.tsx#PageAccordionRenderer overwrites it with `panel-${idx}`; the designer input `page:accordion.items.itemFields` in objectui @b9814b334 packages/app-shell/src/views/metadata-admin/previews/block-config.ts#BLOCK_CONFIG (objectui#7973); re-read 2026-10-15, first cited sha-less; [19] page:accordion items[].icon (C = objectui @b9814b334 packages/components/src/renderers/layout/containers.tsx): C#commonChildren (`LazyIcon` in the AccordionTrigger) inside C#PageAccordionRenderer; published by its `accordion` registration's `items` input; vocabulary objectui @b9814b334 packages/components/src/lib/lazy-icon.tsx#getLazyIcon; [20] page:accordion.variant: objectui @b9814b334 packages/components/src/renderers/layout/containers.tsx#PageAccordionRenderer (`schema?.variant ?? schema?.properties?.variant ?? 'flush'`); re-read 2026-10-15, first cited sha-less; [21] element:text.variant retired `heading` / `subheading`: objectui @89cad75d55 packages/components/src/renderers/basic/elements.tsx#VARIANT_TAG; [22] element:button.icon (B = objectui @b9814b334 packages/components/src/renderers/form/button.tsx, R = objectui @b9814b334 packages/components/src/renderers/action/resolve-icon.ts): B#Icon (resolveIcon) and its render on either side of the label in B#ButtonRenderer; R#resolveIcon R#describeIconLookup R#toPascalCase R#iconNameMap R#recordIconName (the vocabulary: the generated objectui @b9814b334 packages/components/src/lib/lucide-record-icon-names.ts#LUCIDE_RECORD_ICON_NAME_TABLE); contrast objectui @b9814b334 packages/components/src/lib/lazy-icon.tsx#getLazyIcon; no `icon` in the registration's inputs inside B#ButtonRenderer (objectui#9910 added the `children` slot input); history: the read point moved files on the hop onto objectui 9602dc820, and the registration ranges were first wrong-since-written at objectui a472b0716; [23] action:* rows, the effective executor and the runner's reads (R = objectui @b9814b334 packages/core/src/actions/ActionRunner.ts, first read at objectui @1fb1ced36243 with every anchor at the same symbols; A = objectui @b9814b334 packages/components/src/renderers/action/): executor resolution R#execute (`action.type || action.actionType || action.name`); forwarded executor A action-button.tsx#forwarded, A action-icon.tsx#forwarded (`type: schema.actionType`), A action-group.tsx#paramsPayload, A action-menu.tsx#paramsPayload (`type: action.type`); the name leg documented in A action-button.tsx#forwarded; built-in executors and the `navigation` alias R#ActionRunner (`builtinExecutors`), url navigation executeUrl / executeNavigation / navigateTo in R#ActionRunner; no console host handler under `url` / `navigation`: objectui @b9814b334 packages/app-shell/src/console/ConsoleShell.tsx, packages/app-shell/src/hooks/useConsoleActionRuntime.tsx, packages/app-shell/src/console/AppContent.tsx, packages/app-shell/src/hooks/useObjectActions.ts; onSuccess R#handlePostExecution R#readOnSuccessNavigation; operation read before any executor R#execute (isUpdateOperationAction), forwarded A action-button.tsx#forwarded; patch merged only when a plain object (executeUpdateOperation in R#ActionRunner); unchanged at objectui main 866763bd and 72594f29; [24] section 4b, the action:* quartet and element:* lists (shared reads; A = objectui @b9814b334 packages/components/src/renderers/action/): publication objectui @b9814b334 packages/core/src/registry/public-blocks.ts#PUBLIC_BLOCKS; `autoTrigger` \"NOT persisted metadata\" in the header of A auto-trigger.ts#useAutoTriggerOnce; the Button primitive vocabulary objectui @b9814b334 packages/components/src/ui/button.tsx#buttonVariants; `objectName` forwarded by A action-button.tsx#forwarded and A action-icon.tsx#forwarded, and per member by A action-group.tsx#paramsPayload and A action-menu.tsx#paramsPayload; history: objectui#11168 slices 1-2, objectui#11212 (fail-closed `visible`), objectui#11182 (host `disabled` verdict), objectui#11344 (`outcomeMessages`), objectui#11638 (member `properties.params` read retired), objectui#11839 (disabled reason), objectui#11880 (repeater binding), objectui#12085 (repeater publishes only the binding); [25] action:button (ActionButtonPropsSchema; B = objectui @b9814b334 packages/components/src/renderers/action/action-button.tsx; the retired gate's quoted first line `type: schema.actionType,` holds at B#forwarded): name B#isVisible (diagnostic label) B#forwarded; label B#button (React child) B#isVisible B#forwarded; icon B#Icon (resolveIcon); actionType B#forwarded (`type`); variant, size B#variant and its `size` twin; visible B#isVisible B#ActionButtonRenderer (hasDeclaredVisibilityGate); disabled B#isDisabled B#button; params B#staticValues (withUndoBaseline) and objectui @b9814b334 packages/components/src/renderers/action/static-params.ts#readStaticParamValues; the forwarded set B#forwarded (outcomeMessages forwarded since objectui#11344, left unpublished in the registration's inputs inside B#ActionButtonRenderer); undo baseline B#withUndoBaseline; [26] action:icon (ActionIconPropsSchema; I = objectui @b9814b334 packages/components/src/renderers/action/action-icon.tsx; the retired gate's quoted first line `type: schema.actionType,` holds at I#forwarded): size not read I#size (fixed `'icon'`); the forward I#forwarded (no undoable / recordIdField; outcomeMessages since objectui#11344); label I#isVisible I#forwarded I#button (aria-label, initial letter, DisabledReasonTrigger heading) I#ActionIconRenderer (tooltip); visible I#isVisible I#ActionIconRenderer; disabled I#isDisabledPred I#button; variant I#variant; params I#staticValues (readStaticParamValues); [27] action:group / action:menu members (actionContainerMember; G = objectui @2e818d0b51ec packages/components/src/renderers/action/action-group.tsx, M = objectui @2e818d0b51ec packages/components/src/renderers/action/action-menu.tsx, P = objectui @2e818d0b51ec packages/components/src/renderers/action/static-params.ts): drawn G#InlineActionButton G#DropdownActionItem M#ActionMenuItem; visible G#useMemberVisible M#useMenuActionVisible; size (group only) G#btnSize; tags G#showSeparator; locations G#actions (actionRendersAt); forwarded G#staticValues M#staticValues (the forward block); object params forwarded on `api` and dropped, with a development-build warning only, for every other `type` P#readActionEntryParamValues (first cited at objectui @0abd4f9f8, same symbol); refused: properties.params P#readMemberStaticParamValues, className G#handleClick, autoTrigger M#ActionAutoTrigger (useAutoTriggerOnce), onClick G#handleExecute M#handleExecute; the array forward (the retired gate's quoted first line `const paramsPayload: ActionDef = Array.isArray(action.params)`) objectui @b9814b334 packages/components/src/renderers/action/action-group.tsx#paramsPayload and objectui @b9814b334 packages/components/src/renderers/action/action-menu.tsx#paramsPayload, other values objectui @b9814b334 packages/components/src/renderers/action/static-params.ts#readActionEntryParamValues; the fork measured at objectui @ab1879721595, files byte-identical at objectui main 2abec3a96; [28] action:group (ActionGroupPropsSchema; G = objectui @b9814b334 packages/components/src/renderers/action/action-group.tsx): actions G#declaredActions G#actions (actionRendersAt) G#useMemberVisible G#paramsPayload; display G#display; label, icon, variant, size G#TriggerIcon (the trigger; size raw to inline members) G#btnSize; visible G#isVisible; the host `disabled` verdict (objectui#11182) G#ActionGroupRenderer; group `name` unread (the comment above G#ActionGroupRenderer, objectui#11168); the registration's inputs inside G#ActionGroupRenderer; [29] action:menu (ActionMenuPropsSchema; M = objectui @b9814b334 packages/components/src/renderers/action/action-menu.tsx): actions M#ActionMenuRenderer M#ActionMenuItem M#ActionAutoTrigger M#paramsPayload; label, icon, variant, size, visible and the host `disabled` verdict (objectui#11182) M#ActionMenuRenderer; the registration's inputs inside M#ActionMenuRenderer (objectui#11168 slice 1); [30] element:definition-list (ElementDefinitionListPropsSchema; L = objectui @b9814b334 packages/components/src/renderers/basic/data-list.tsx; the retired gate's quoted first line `const props = readProps<{` holds at L#props): items, columns (`=== 2`), inline, term, description L#DefinitionListRenderer (an item's `description` shown through L#toText: a string or number as text, an object as JSON; first cited at objectui @89cad75d55); the registration's number enum and optional `items` (objectui#11168 slice 2) at its `definition-list` registration in L; the designer's number control objectui @b9814b334 packages/app-shell/src/views/metadata-admin/previews/block-config.ts#BLOCK_CONFIG; [31] element:repeater (ElementRepeaterPropsSchema; L = objectui @b9814b334 packages/components/src/renderers/basic/data-list.tsx; the quoted first line `const props = readProps<{` holds at L#props in L#RepeaterRenderer): object, filter, sort, limit, emptyText, divided, titleField, fields L#RepeaterRenderer; the binding L#dataBinding (useElementDataSource, objectui#11880, aaba8655a); resolved filter tokens L#filterScope; delivery objectui @b9814b334 packages/data-objectstack/src/index.ts#ObjectStackAdapter (translateFilterArray arm) and objectui @b9814b334 packages/data-objectstack/src/index.ts#serializeOrderBy; the registration wrapped by elementDataSourceBlock publishes no `object` input since objectui#12085 (ce991bd70); the registration's `object` required flag read at objectui @20c6d351a; [32] object-grid.aggregations[] (GridAggregationSchema): objectui @89cad75d55 packages/plugin-grid/src/ObjectGrid.tsx#groupHeaders (useGroupedData) and objectui @89cad75d55 packages/plugin-grid/src/ObjectGrid.tsx#serverGroupSource (useServerGroupHeaders); the grid's own function vocabulary objectui @89cad75d55 packages/plugin-grid/src/useGroupedData.ts#AggregationType (unchanged at objectui @b9814b334); [33] object-grid (ObjectGridPropsSchema, per key; E = objectui @eb7f586b packages/plugin-grid/src/ObjectGrid.tsx): columns, fields E#schemaFields; filter E#schemaFilterSource (toFilterNode); defaultFilters E#cols (legacy fallback); sort E#schemaSort; defaultSort E#cols; pagination, pageSize, showPagination E#lastFindParamsRef E#schemaPageSize E#paginationEnabled; searchableFields, showSearch E#trimmedSearch E#searchEnabled; rowHeight E#ObjectGrid (resolveRowHeightMode); grouping, aggregations E#grouping E#groupValueFormatter; rowColor E#getRowClassName; conditionalFormatting E#predicateFields E#rules; selection, selectable E#ObjectGrid; rowActions E#rowActionsList; batchActions, bulkActions E#declaredBulkActions; bulkActionDefs E#legacyBulkNames; navigation E#navigation; editable, singleClickEdit, resizable, resizableColumns, reorderableColumns E#dataTableSchema; frozenColumns E#effectiveFrozenColumns; showColumnTypeIcons E#fieldMeta; exportOptions, operations E#declared; label, title E#fileNameFor E#dataTableSchema; data, staticData E#getDataConfig; [#20694] description objectui @db11afd4967c packages/plugin-grid/src/ObjectGrid.tsx#resolvedDescription (drawn as `gridDescription`); emptyState objectui @db11afd4967c packages/plugin-grid/src/ObjectGrid.tsx#authoredEmptyState (DataEmptyState in renderedGridContent); keyboardNavigation 0 read points at objectui @db11afd4967c, 15 hit lines at objectui @ab1879721595 and at objectui @b9814b334 against 3 then 4 for the control `schema.editable` (the fourth objectui @b9814b334 packages/plugin-grid/src/ObjectGrid.tsx#carriesConcurrencyToken); [34] object-grid.description, object-grid.emptyState (B = objectui @b9814b334 packages/plugin-grid/src/ObjectGrid.tsx): description objectui @db11afd4967c packages/plugin-grid/src/ObjectGrid.tsx#resolvedDescription; emptyState title/message B#authoredEmptyTitle (resolveInlineI18nLabel, objectui#11227 carried by 6158e4c93; raw at objectui @89cad75d5570) drawn in B#renderedGridContent, link (objectui#12270, b434f5f47) B#renderedGridContent (EmptyStateLink); [35] object-grid.columns (ListViewSchema.shape.columns; A = objectui @ab1879721595 packages/plugin-grid/src/ObjectGrid.tsx): A#normalizeColumns (first-entry dispatch) A#cols A#fieldName (resolvesToDataColumn); the retired `colOverride?.options` read: A#groupValueFormatter A#rawOptions (objectui b0bf413, objectui#11544); the footer summary's off-contract column keys objectui @ab1879721595 packages/plugin-grid/src/useColumnSummary.ts#columnHints; [36] object-grid.fields (O = objectui @89cad75d55 packages/plugin-grid/src/ObjectGrid.tsx): O#schemaFields O#fieldsToShow O#generateColumns; the host hand-off projection O#getSelectFields; [37] object-grid.filter: objectui @53ded82b packages/plugin-grid/src/ObjectGrid.tsx#ObjectGrid (toFilterNode before `$filter`); [38] object-grid.sort (S = objectui @53ded82b packages/plugin-grid/src/ObjectGrid.tsx): S#schemaSort S#cols (the fetch path's string arm and array arm) S#declaredSort (parseSchemaSort, `TableSortItem[]`); the registration's array input objectui @53ded82b packages/plugin-grid/src/index.tsx (`{ name: 'sort', type: 'array' }`); [39] object-grid.defaultSort (REMOVED, tombstone; D = objectui @190fbd01d packages/plugin-grid/src/ObjectGrid.tsx): D#cols (`$orderby` fallback) and D#declaredSort (`[schema.defaultSort]`); [40] object-grid.pagination (D = objectui @d18322415 packages/plugin-grid/src/ObjectGrid.tsx): pageSize D#lastFindParamsRef D#schemaPageSize D#pageSize; pageSizeOptions D#dataTableSchema; presence D#paginationEnabled; the registry input objectui @d18322415 packages/plugin-grid/src/index.tsx (`pagination`, type object); [41] object-grid members read at objectui @89cad75d55 (O = objectui @89cad75d55 packages/plugin-grid/src/ObjectGrid.tsx): rowHeight O#resolveRowHeightMode; aggregations O#groupHeaders (useGroupedData) O#serverGroupSource (useServerGroupHeaders); conditionalFormatting O#getRowStyle (resolveConditionalFormatting); rowColor O#getRowClassName (useRowColor); selection and selectable O#ObjectGrid (the selection-mode branch) O#dataTableSchema (`selectable`), read by objectui @89cad75d55 packages/components/src/renderers/complex/data-table.tsx#resolveSelectionMode; rowActions O#rowActionsDeclared; bulkActions, batchActions O#declaredBulkActions (`batchActions ?? bulkActions`); bulkActionDefs O#legacyBulkNames (resolveBulkActions); [42] object-grid.navigation: objectui @89cad75d55 packages/plugin-grid/src/ObjectGrid.tsx#navigation (useNavigationOverlay); [43] object-grid.keyboardNavigation (built by objectui 154075ab1, objectui#11068; declared ahead of its reader, which read nothing at objectui @db11afd4967c): objectui @b9814b334 packages/plugin-grid/src/ObjectGrid.tsx#dataTableSchema (`schema.keyboardNavigation ?? inlineEditable`) with objectui @b9814b334 packages/plugin-grid/src/ObjectGrid.tsx#inlineEditable; objectui @b9814b334 packages/components/src/renderers/complex/data-table.tsx#DataTableRenderer (default false, `role=\"grid\"`, the roving tabIndex), objectui @b9814b334 packages/components/src/renderers/complex/data-table.tsx#navigationTarget and objectui @b9814b334 packages/components/src/renderers/complex/data-table.tsx#handleCellKeyDown; [44] object-grid.resizableColumns (REMOVED, tombstone): objectui @89cad75d55 packages/plugin-grid/src/ObjectGrid.tsx#dataTableSchema (`schema.resizable ?? schema.resizableColumns ?? true`); [45] object-grid.operations (GridOperationsSchema; O = objectui @89cad75d55 packages/plugin-grid/src/ObjectGrid.tsx): create O#dataTableSchema (showAddRow); update, delete O#wantDeleteAction; export O#handleExport O#dataTableSchema (exportable) O#exportEnabled; a declared block replaces the default O#explicitOperations; [46] object-grid.data: the registry input objectui @b9814b334 packages/plugin-grid/src/index.tsx#GRID_QUERY_INPUTS (`{ name: 'data', type: 'object' }`, held by gridDataInputContract.test.ts); re-read 2026-10-15, first cited sha-less; [47] object-metric.aggregate (ObjectMetricAggregateSchema; M = objectui @89cad75d55 packages/plugin-dashboard/src/ObjectMetricWidget.tsx): field, function M#computeOne; function also M#fieldUnitApplies (answersInFieldUnit) M#inferredFormat (min/max width); groupBy M#computeOne (objectAggregateSpecQuery; floored at `'_all'`) typed on M#ObjectMetricWidgetProps (`ChartAggregate['groupBy']`); objectui's unit-rule pin ObjectMetricWidget.countNotCurrency-10356.test.tsx mounts one tile per AggregationFunction member; [48] object-metric.trend (ObjectMetricTrendSchema; W = objectui @89cad75d55 packages/plugin-dashboard/src/): drawn in W MetricWidget.tsx#MetricWidget (`{value}%`, direction arrow), caption W MetricWidget.tsx#localizedTrendLabel (pickLocalized); declared on W MetricWidget.tsx#MetricWidgetProps, mirrored on W ObjectMetricWidget.tsx#ObjectMetricWidgetProps; replaced by a derived trend in W ObjectMetricWidget.tsx#effectiveTrend; [49] object-metric.drillDown (ObjectMetricDrillDownSchema; A = objectui @ab1879721595): enabled A packages/plugin-dashboard/src/ObjectMetricWidget.tsx#drillEnabled (isDrillEnabled); title A packages/plugin-dashboard/src/ObjectMetricWidget.tsx#drawerTitle (resolveDrillTitle against an empty event); target, columns, maxRows A packages/plugin-dashboard/src/ObjectMetricWidget.tsx#drillDrawer (DrillDownDrawer); `filter` / `mode` refused as objectui's own A packages/types/src/data-display.ts#ObjectMetricDrillDownConfig refuses them; measured writers, objectui's drill-down member pins A packages/plugin-dashboard/src/__tests__/objectMetricDrillDownMembers-8071.test.tsx and A packages/plugin-dashboard/src/__tests__/ObjectMetricWidget.drillRoutedToSharedDrawer-8970.test.tsx; [50] object-metric.drillDown.report (R = objectui @2e818d0b51ec packages/plugin-dashboard/src/): handed verbatim in R ObjectMetricWidget.tsx#drillDrawer; drawn when R DrillDownDrawer.tsx#isDatasetBoundReport holds (R DrillDownDrawer.tsx#isReportDrill), joining the metric filter into `runtimeFilter` (R DrillDownDrawer.tsx#body); typed `SpecReportInput` in objectui @2e818d0b51ec packages/types/src/data-display.ts; the fork measured at objectui @ab1879721595, both files byte-identical at objectui main 2abec3a96; [51] object-metric.compareTo (ObjectMetricCompareToSchema; A = objectui @ab1879721595): A packages/plugin-dashboard/src/ObjectMetricWidget.tsx#comparisonFilter (second aggregate over shiftFilterByCompareTo) and A packages/plugin-dashboard/src/ObjectMetricWidget.tsx#derivedTrend (compareToTrendLabelKey); both dispatch on `kind === 'previousYear'` in A packages/core/src/utils/compare-to.ts#shiftFilterByCompareTo and A packages/core/src/utils/compare-to.ts#compareToTrendLabelKey; `dimension` \"deliberately never read on this path\" in that module's header; [52] object-metric (ObjectMetricPropsSchema): objectui @eb7f586b packages/plugin-dashboard/src/ObjectMetricWidget.tsx#ObjectMetricWidgetProps (the complete destructured read set); [53] object-metric.icon (B = objectui @b9814b334 packages/plugin-dashboard/src/): published by B index.tsx#ObjectMetricBlock (`{ name: 'icon', type: 'string' }`); destructured and forwarded by B ObjectMetricWidget.tsx#ObjectMetricWidget; resolved and drawn by B MetricWidget.tsx#MetricWidget (getLazyIcon, guarded on a string); vocabulary objectui @b9814b334 packages/components/src/lib/lazy-icon.tsx#getLazyIcon; not B MetricCard.tsx (off this key's path); [54] object-metric.filter: the analytics wire lowering objectui @53ded82b packages/data-objectstack/src/index.ts#lowerAnalyticsFilterForWire (objectui#7754); before it the adapter at objectui @a472b07 posted an array verbatim (a 400, #15828); [55] object-kanban.columns[] lane (ObjectKanbanLaneSchema; K = objectui @89cad75d55 packages/plugin-kanban/src/): id K index.tsx#bucketCardsIntoColumns; title K ObjectKanban.tsx#localizeColumn; cards K index.tsx#bucketCardsIntoColumns (kept ahead of the bucketed records); limit K KanbanImpl.tsx#isLimitExceeded; className K KanbanImpl.tsx#KanbanColumnView; collapsed K KanbanImpl.tsx#isColumnCollapsed; [56] object-kanban (ObjectKanbanPropsSchema; E = objectui @eb7f586b packages/plugin-kanban/src/ObjectKanban.tsx): columns E#effectiveColumns; filter E#fetchData (`$filter`); data E#boundData; cardTitle, titleField E#explicitTitleField; cardFields E#explicitCardFields; swimlaneField, grouping E#effectiveSwimlaneField; coverImageField, conditionalFormatting via objectui @eb7f586b packages/plugin-kanban/src/index.tsx#KanbanRenderer (the spread of the authored bag); limit objectui @b9814b334 packages/plugin-kanban/src/ObjectKanban.tsx#query (`$top: resolveRowLimit(schema.limit, DEFAULT_KANBAN_FETCH_BATCH_SIZE)`), first re-read at objectui @87af769e9 where `$top: schema.limit ?? DEFAULT_KANBAN_LIMIT` had become resolveRowLimit; [57] object-kanban.columns (the first-entry dispatch): objectui @89cad75d55 packages/plugin-kanban/src/ObjectKanban.tsx#effectiveColumns (string arm only without `groupBy`); [58] object-kanban.filter: objectui @53ded82b packages/plugin-kanban/src/ObjectKanban.tsx#ObjectKanban (`$filter: schema.filter`, verbatim, lowered by ObjectStackAdapter.convertQueryParams through translateFilterArray); [59] object-kanban.limit (B = objectui @b9814b334): query B packages/plugin-kanban/src/ObjectKanban.tsx#query (`$top: resolveRowLimit(schema.limit, DEFAULT_KANBAN_FETCH_BATCH_SIZE)`) with B packages/plugin-kanban/src/ObjectKanban.tsx#DEFAULT_KANBAN_FETCH_BATCH_SIZE and the resolved filter B packages/plugin-kanban/src/ObjectKanban.tsx#filterScope; mapping B packages/plugin-kanban/src/index.tsx#OBJECT_KANBAN_DATA_SOURCE (`limit: 'limit'`); type B packages/types/src/objectql.ts#ObjectKanbanSchema (`limit?: number`); docs B content/docs/plugins/plugin-kanban.mdx (`limit: 250` snippet and Properties row); precedence B packages/react/src/element-data-source/ElementDataSourceGate.tsx#useElementDataSourceSchema (binding cap over this key; a view's pagination.pageSize only when unset) and B packages/react/src/element-data-source/ElementDataSourceGate.tsx#isUsableRowLimit; the saved-view fallback B packages/core/src/data-scope/element-data-source.ts#savedViewRawLimit; first re-read at objectui @87af769e9 2026-09-20; [60] object-master-detail-form (ObjectMasterDetailFormPropsSchema): objectui @eb7f586b packages/plugin-form/src/MasterDetailForm.tsx#MasterDetailForm; auto-derivation objectui @eb7f586b packages/plugin-form/src/deriveMasterDetail.ts; the `formType` pair objectui's MasterDetailFormSchema declares; [61] object-kanban.quickAdd (RETIRED, tombstone; K = objectui @b9814b334 packages/plugin-kanban/src/): K index.tsx#KanbanRenderer passes `quickAdd` / `onQuickAdd` (the host-mounted React component); gated on both in K KanbanImpl.tsx#KanbanColumnView; K KanbanBoardCore.tsx#KanbanBoardCoreProps reads neither off `schema` (objectui#11234); K ObjectKanban.tsx#ObjectKanban names `quickAdd` and `onQuickAdd` 2 times each (both in comments) against 11 for `onCardClick` (method: occurrences in that file, re-counted 2026-10-15); no `kanban-ui` registration at that sha (objectui#8257; the name survives only in tests and the changelog); through objectui @db11afd49 the board's spread forwarded the key; [62] object-kanban.conditionalFormatting (A = objectui @ab1879721595): A packages/plugin-kanban/src/KanbanBoardCore.tsx#processedColumns hands it to the board; A packages/plugin-kanban/src/KanbanImpl.tsx#getCardStyles evaluates it through A packages/core/src/evaluator/listConditional.ts#resolveConditionalFormatting, the evaluator of A packages/plugin-grid/src/ObjectGrid.tsx#getRowStyle; objectui's declaration A packages/types/src/zod/objectql.zod.ts#KanbanConditionalFormattingRuleSchema and A packages/types/src/objectql.ts#KanbanConditionalFormattingRule (objectui#11522, landed by objectui#11532 c73cdb5695); the stored-dialect arms in A packages/plugin-kanban/src/KanbanImpl.tsx#getCardStyles; blank-predicate fallback A packages/core/src/evaluator/listConditional.ts#evalRowPredicate; the four reader files byte-identical at objectui main 2e818d0b51; the writer census also read objectui at main; [63] object-kanban.navigation (K = objectui @b9814b334 packages/plugin-kanban/src/ObjectKanban.tsx): K#navConfig (`schema.navigation ?? { mode: 'drawer' }`) K#navigation (useNavigationOverlay) K#boardView (card click) K#renderRecordOverlay (NavigationOverlay); first re-derived at objectui @87af769e9, where the `(schema as any)` cast was still spelled; [64] object-calendar flat field keys (OBJECT_CALENDAR_FLAT_FIELD_GUIDANCE): objectui @b9814b334 packages/plugin-calendar/src/ObjectCalendar.tsx#getCalendarConfig (the backward-compat flat fallback); re-read 2026-10-15, first cited sha-less; [65] object-calendar (ObjectCalendarPropsSchema; C = objectui @eb7f586b packages/plugin-calendar/src/ObjectCalendar.tsx): calendar C#getCalendarConfig; defaultView C#schemaDefaultView; locale, loading via the registry shell objectui @eb7f586b packages/plugin-calendar/src/index.tsx; [66] object-calendar.calendar (CalendarConfigSchema by reference; C = objectui @89cad75d55 packages/plugin-calendar/src/ObjectCalendar.tsx): C#getCalendarConfig returns the block; its five bindings read in C#queryFilter, C#handleEventDropDefault and C#submitQuickCreate; [67] object-calendar.filter: objectui @53ded82b packages/plugin-calendar/src/ObjectCalendar.tsx#fetchData (`$filter: schema.filter`, verbatim); [68] object-tree.navigation: objectui @89cad75d55 packages/plugin-tree/src/ObjectTree.tsx#navigation (useNavigationOverlay); [69] object-calendar.sort: objectui @53ded82b packages/plugin-calendar/src/ObjectCalendar.tsx#fetchData (`$orderby: convertSortToQueryParams(schema.sort)`), whose sink objectui @53ded82b packages/core/src/utils/sort-query.ts#convertSortToQueryParams still lowered the string clause there; no `sort` input on objectui @53ded82b packages/plugin-calendar/src/index.tsx; [70] object-timeline flat config keys (OBJECT_TIMELINE_FLAT_CONFIG_GUIDANCE): the backward-compat flat rung (with the `dateField` alias) in objectui @b9814b334 packages/plugin-timeline/src/ObjectTimeline.tsx#startDateField and its siblings; emitted by objectui @b9814b334 packages/plugin-list/src/ListView.tsx#viewComponentSchema (`case 'timeline'`); re-read 2026-10-15, first cited sha-less; [71] object-calendar.navigation (C = objectui @b9814b334 packages/plugin-calendar/src/ObjectCalendar.tsx): C#navConfig (`schema.navigation ?? { mode: 'drawer' }`) C#navigation (useNavigationOverlay) C#calendarView (event click) C#renderRecordOverlay (NavigationOverlay); [72] object-timeline.mapping (ObjectTimelineMappingSchema; A = objectui @ab1879721595 packages/plugin-timeline/src/ObjectTimeline.tsx; unchanged at objectui main 94985a92ba): title A#titleField; date A#startDateField; description A#descField; variant A#variantField; declared on A#ObjectTimelineProps (`mapping`) and A#TimelineMappingSchema; [73] object-timeline.items[] arms (R = objectui @2e818d0b51ec packages/plugin-timeline/src/renderer.tsx; unchanged at objectui main 2abec3a96): gantt bar startDate / endDate R#dimensions R#calculateDateRange, variant and title in R#TimelineRenderer (the bar and its tooltip); feed entry time R#dateLabel and title, description, variant, icon, content (renderChildren), className in R#TimelineRenderer; gantt row label R#TimelineRenderer (TimelineGanttLabel), items R#classifyGanttRows; vocabulary objectui @2e818d0b51ec packages/types/src/data-display.ts#TimelineItemVariant; element shape and refinement objectui @2e818d0b51ec packages/types/src/zod/data-display.zod.ts#TimelineItemSchema and objectui @2e818d0b51ec packages/types/src/zod/data-display.zod.ts#timelineItemsFitVariant; [74] object-form.layout retired values `inline` / `grid` (OBJECT_FORM_LAYOUT_RETIRED; P = objectui @f8a9d0fb0 packages/plugin-form/src/): folded to 'vertical' in P ObjectForm.tsx#SimpleObjectForm; only 'vertical' / 'horizontal' passed through by P ObjectForm.tsx#drawerLayout, ObjectForm.tsx#modalLayout, DrawerForm.tsx#formLayout, ModalForm.tsx#formLayout; 'vertical' hard-coded in P TabbedForm.tsx#TabbedForm, SplitForm.tsx#panes, WizardForm.tsx#WizardForm; [75] object-form.mobile (ObjectFormMobileSchema; F = objectui @89cad75d55 packages/plugin-form/src/ObjectForm.tsx): F#mobileOpts (the flat arm); stickyActions F#formSchema; stepper, stepperMinFields, stepperFieldsPerStep F#stepperMode; fullscreenLongText F#fieldsWithMobile; the `data-mobile-form` marker in F#SimpleObjectForm; [76] object-form.fields and object-master-detail-form.fields (formFieldNameList): objectui @ab1879721595 packages/plugin-form/src/MasterDetailForm.tsx#parentSchema (hands `fields` over verbatim), read by objectui @ab1879721595 packages/plugin-form/src/ObjectForm.tsx#fieldsToShow and objectui @ab1879721595 packages/plugin-form/src/flatFields.ts#buildFlatFields (a stored `{ name }` entry drawn by name; any other object entry warned by warnUnresolvedTopLevelField); unchanged at objectui main 94985a92ba; the retired inline field entry an author was taught by objectui @ab1879721595 skills/objectui/guides/page-builder.md (its object-form example; first cited sha-less); [77] object-form.customFields[] `grid` widget keys (minRows, maxRows, allowAdd, allowDelete, allowReorder, totalField, addLabel, sortField; W = objectui @9dfaca654311 packages/fields/src/widgets/GridField.tsx): declared on objectui @9dfaca654311 packages/types/src/field-types.ts#GridFieldMetadata, carried by objectui @9dfaca654311 packages/types/src/form.ts#FormField, mirrored in objectui @9dfaca654311 packages/types/src/zod/form.zod.ts#FormFieldSchema; read W#cfg W#allowAdd W#removeRow (minRows) W#totalField W#showTotal W#emit (sortField) W#GridFieldBody (maxRows, allowReorder, addLabel); objectui#11610 (merge 2abec3a96c) camelCased them; the parent-field `totalField` hand-off objectui @9dfaca654311 packages/plugin-form/src/LineItemsPanel.tsx#gridField and objectui @9dfaca654311 packages/plugin-form/src/MasterDetailForm.tsx#MasterDetailLines; the writer shape (one `grid` field carrying all eight camelCase keys) objectui @9dfaca654311 examples/schema-catalog/src/schemas/fields-grid/line-items-grid.json; [78] object-form.customFields[] retired snake_case `grid` keys (OBJECT_FORM_GRID_WIDGET_SNAKE_KEYS): objectui @9dfaca654311 packages/types/src/field-types.ts#GRID_FIELD_RETIRED_KEYS; refused by objectui @9dfaca654311 packages/fields/src/widgets/GridField.tsx#GridField, tombstoned on objectui @9dfaca654311 packages/types/src/field-types.ts#GridFieldMetadata and objectui @9dfaca654311 packages/types/src/form.ts#FormField, named in objectui @9dfaca654311 packages/types/src/zod/form.zod.ts#FormFieldSchema (retiredGridFieldKey); [79] object-form.customFields[].validation: objectui @2e818d0b51ec packages/components/src/renderers/form/form.tsx#rules (inside renderFormField: minLength/maxLength/min/max spread as `{ value, message }`, `required` read only as a message string); objectui's declaration objectui @2e818d0b51ec packages/types/src/form.ts#FieldValidationRules; [80] object-timeline.navigation: objectui @b9814b334 packages/plugin-timeline/src/ObjectTimeline.tsx#navigation (useNavigationOverlay) and objectui @b9814b334 packages/plugin-timeline/src/ObjectTimeline.tsx#effectiveSchema (entry click, overlay); re-read 2026-10-15, first cited sha-less, when the read still spelled `(schema as any).navigation`; [81] object-form.customFields[].options[] (buildObjectFormRuntimeOption; F = objectui @2e818d0b51ec packages/components/src/renderers/form/form.tsx): label, value F#BuiltinSelectControl and objectui @2e818d0b51ec packages/core/src/evaluator/optionRules.ts#optionDisplayLabel (the four option widgets); visibleWhen F#cascade (resolveCascadingOptions; each widget's useCascadingOptions); description objectui @2e818d0b51ec packages/fields/src/widgets/LookupField.tsx#filteredOptions; `value` a runtime value: F#BuiltinSelectControl (matchOptionValue), objectui @2e818d0b51ec packages/types/src/zod/form.zod.ts#SelectOptionSchema (deliberate divergence comment), objectui @2e818d0b51ec packages/plugin-designer/src/ObjectManager.tsx#formSchema (writes `{ label, value }` pairs); unchanged at objectui main fd060f076; [82] object-form.customFields[] and the inline section entry (buildObjectFormRuntimeField; F = objectui @2e818d0b51ec packages/components/src/renderers/form/form.tsx, W = objectui @2e818d0b51ec packages/fields/src/widgets/): merge objectui @2e818d0b51ec packages/plugin-form/src/customFieldsMerge.ts#mergeCustomFields from objectui @2e818d0b51ec packages/plugin-form/src/ObjectForm.tsx#generateField; carrier F#builtinBranchHasNoControl (`field.field || field`); field row F#renderFormField (name, label, description, type, required, disabled, readonly, hidden, colSpan via F#colSpanClass), widget F#resolvedType, validation F#rules, the three `*When` rules F#ruleState, placeholder and inputType F#builtinBranchHasNoControl, options and dependsOn F#cascade, multiple F#resolvedType; layout objectui @2e818d0b51ec packages/plugin-form/src/autoLayout.ts#resolveColSpan (span, colSpan) and objectui @2e818d0b51ec packages/plugin-form/src/fieldGroups.ts#deriveFieldGroupSections (group); widgets W TextAreaField.tsx#rows, FileField.tsx#multiple (accept, multiple), VectorField.tsx#dimensions, LookupField.tsx#referenceTo, NumberField.tsx#NumberField (min, max), F#renderFieldComponent (minLength, maxLength), FormulaField.tsx#returnType, SummaryField.tsx#summaryType, GridField.tsx#allColumns (columns); read and refused: visibleOn F#ruleState, condition F#legacyConditionCel, id F#fieldKey; a measured writer, the object-manager create / edit dialog (a `formType: 'modal'` block): objectui @b9814b334 packages/plugin-designer/src/ObjectManager.tsx#formSchema (first cited sha-less); [83] object-form / object-master-detail-form sections[].fields[] `{ field }` entry (buildObjectFormSectionFieldEntry): objectui @2e818d0b51ec packages/plugin-form/src/sectionFields.ts#resolveSectionEntry (names an object field by `field`, every other key overrides its generated definition; label/placeholder/helpText copied as they stand); [84] object-form / object-master-detail-form sections[] (buildObjectFormSection; F = objectui @2e818d0b51ec packages/plugin-form/src/ObjectForm.tsx): handed over verbatim by objectui @2e818d0b51ec packages/plugin-form/src/MasterDetailForm.tsx#parentSchema; name, label F#sectionCtx (heading) F#inertPredicateSections (per-formType maps); collapsible, collapsed F#collapse (resolveSectionCollapse); visibleWhen F#sectionCtx (divider-row predicate); columns F#secCols F#clampCol (a NUMBER only); pane objectui @2e818d0b51ec packages/plugin-form/src/SplitForm.tsx#paneOf; the inline runtime field drawn as it stands in objectui @2e818d0b51ec packages/plugin-form/src/sectionFields.ts#resolveSectionEntry; objectui's own declaration objectui @2e818d0b51ec packages/types/src/objectql.ts#ObjectFormSection; [85] object-form (ObjectFormPropsSchema: the UNION of `schema.*` reads of the simple form and the sub-forms it forwards the bag into): objectui @eb7f586b packages/plugin-form/src/ObjectForm.tsx#ObjectForm, with TabbedForm, WizardForm, SplitForm, DrawerForm, ModalForm under objectui @eb7f586b packages/plugin-form/src/; `layout` `inline` / `grid` folded to `vertical` there while the registry inputs and the designer palette offered them; [86] object-form.fields (the `{ name }` entry retired from the authoring faces by objectui#11550): a census of objectui @ab1879721595 found it written only by fixtures probing the stored read and the refusal; [87] object-form.customFields: objectui @2e818d0b51ec packages/plugin-form/src/customFieldsMerge.ts#mergeCustomFields (merged over the generated fields); at objectui @2e818d0b51ec the open runtime field spelled the eight `grid` widget keys in snake_case, camelCased by objectui#11610 (carried at objectui @9dfaca654311); [88] object-form.contentLayout: objectui @89cad75d55 packages/plugin-form/src/ModalForm.tsx#renderContent (`schema.contentLayout === 'tabbed' && groups.length > 1`), declared on objectui @89cad75d55 packages/plugin-form/src/ModalForm.tsx#ModalFormSchema; [89] object-form.submitBehavior: objectui @89cad75d55 packages/plugin-form/src/ObjectForm.tsx#handleSubmit and objectui @89cad75d55 packages/plugin-form/src/WizardForm.tsx#handleStepSubmit (switch on `kind`), redirect `url` judged by objectui @89cad75d55 packages/plugin-form/src/submitRedirect.ts#resolveSubmitRedirect (FormViewSchema.safeParse); [90] object-form.navigateOnSuccess: objectui @89cad75d55 packages/plugin-form/src/successBehavior.ts#resolveSuccessNavigate, called from objectui @89cad75d55 packages/plugin-form/src/ObjectForm.tsx#handleSubmit and objectui @89cad75d55 packages/plugin-form/src/WizardForm.tsx#handleStepSubmit; a refused value reported on the success toast in objectui @89cad75d55 packages/plugin-form/src/ObjectForm.tsx#handleSubmit; [91] object-master-detail-form.details[] (the eleven entry keys): objectui @31971ff1e28f packages/plugin-form/src/MasterDetailForm.tsx#MasterDetailDetailConfig and every `d.KEY` read in objectui @31971ff1e28f packages/plugin-form/src/MasterDetailForm.tsx#MasterDetailLines; re-read at objectui @89cad75d5570 for #21589; [92] object-master-detail-form.details[].sortField (REMOVED, tombstone): objectui @89cad75d5570 packages/plugin-form/src/MasterDetailForm.tsx#MasterDetailDetailConfig (no `sortField` member), derived by objectui @89cad75d5570 packages/plugin-form/src/deriveMasterDetail.ts#deriveDetail (SORT_FIELD_NAMES) and handed to the grid as `sort_field` in objectui @89cad75d5570 packages/plugin-form/src/MasterDetailForm.tsx#MasterDetailLines; at objectui @9dfaca654311 the same hand-off spells `sortField` (objectui#11610) from objectui @9dfaca654311 packages/plugin-form/src/deriveMasterDetail.ts#deriveDetail; an entry the renderer does not resolve loads no child schema (objectui @9dfaca654311 packages/plugin-form/src/MasterDetailForm.tsx#entries); [93] object-master-detail-form.sections, .fields: objectui @2e818d0b51ec packages/plugin-form/src/MasterDetailForm.tsx#parentSchema (handed to the parent object-form verbatim); [94] object-map flat config keys (OBJECT_MAP_FLAT_CONFIG_GUIDANCE): objectui @b9814b334 packages/plugin-map/src/ObjectMap.tsx#getMapConfig (branch 2) and objectui @b9814b334 packages/plugin-map/src/ObjectMap.tsx#warnOnShadowedFlatMapKeys and objectui @b9814b334 packages/plugin-map/src/ObjectMap.tsx#FLAT_MAP_CONFIG_KEYS; emitted by objectui @b9814b334 packages/plugin-view/src/ObjectView.tsx#ObjectView and objectui @b9814b334 packages/plugin-list/src/ListView.tsx#viewComponentSchema (`case 'map'`); re-read 2026-10-15, first cited sha-less at the then pin; [95] object-map (ObjectMapPropsSchema, per key; P = objectui @b9814b334 packages/plugin-map/src/ObjectMap.tsx, C = objectui @b9814b334 packages/core/src/utils/record-source.ts, I = objectui @b9814b334 packages/plugin-map/src/index.tsx): data P#getDataConfig C#resolveRecordSourceConfig (rung 1; the deleted array head and its carriers are recorded in the docblock above P#FLAT_MAP_CONFIG_KEYS); staticData C#resolveRecordSourceConfig (rung 2); objectName C#resolveRecordSourceConfig (rung 3) P#navigation P#warnOnLegacyFilterMapConfig P#warnOnTopLevelStyleUrl P#warnOnShadowedFlatMapKeys (cache keys) P#recordSourceObjectName (useSettledSchema); filter P#queryFilter P#fetchData (`$filter` on both fetches); sort P#fetchData (convertSortToQueryParams); map P#getMapConfig (branch 1; validates against ObjectMapConfigSchema) I#ObjectMapRenderer (its registration's `map` input); mapStyle P#getMapConfig (`schema.mapStyle || schema.map?.style`) I#ObjectMapRenderer; navigation P#navigation I#ObjectMapRenderer; enableClustering P#clusteredData I#ObjectMapRenderer; measured and not declared: style P#warnOnTopLevelStyleUrl (read only to say it is not a map style); [96] object-map.filter: objectui @b9814b334 packages/plugin-map/src/ObjectMap.tsx#queryFilter (useResolvedFilter) and objectui @b9814b334 packages/plugin-map/src/ObjectMap.tsx#fetchData (`$filter` on the inline and the object fetch); the registration's `filter` input objectui @b9814b334 packages/plugin-map/src/index.tsx#ObjectMapRenderer; [97] object-map.sort: objectui @b9814b334 packages/plugin-map/src/ObjectMap.tsx#fetchData (convertSortToQueryParams to `$orderby`, both fetches); the registration's array-form `sort` input (objectui#8220) objectui @b9814b334 packages/plugin-map/src/index.tsx#ObjectMapRenderer; [98] object-map.navigation: objectui @89cad75d55 packages/plugin-map/src/ObjectMap.tsx#navigation (hands `schema.navigation` to useNavigationOverlay) and objectui @89cad75d55 packages/react/src/hooks/useNavigationOverlay.ts#useNavigationOverlay (`navigation?.mode ?? 'page'`); [99] object-gantt flat config keys (OBJECT_GANTT_FLAT_CONFIG_GUIDANCE): objectui @b9814b334 packages/plugin-gantt/src/ObjectGantt.tsx#FLAT_GANTT_CONFIG_KEYS and objectui @b9814b334 packages/plugin-gantt/src/ObjectGantt.tsx#getGanttConfig (branch 2 reads them; a present `gantt` block is taken whole and the flat keys beside it named as ignored); re-read 2026-10-15, first cited sha-less at the then pin; [100] object-gantt.markers (objectGanttMarker): G = objectui @ab1879721595 packages/plugin-gantt/src/GanttView.tsx: objectui @ab1879721595 packages/plugin-gantt/src/ObjectGantt.tsx#ganttView (hands `schema.markers` to GanttView verbatim); date G#markers (time-zone re-base) G#resolvedMarkers (axis mapping, drops unparsable or out-of-range dates); color G#resolvedMarkers (`m.color || 'hsl(var(--primary))'`); drawn in G#GanttView and in G#buildExportSvg; the declaration taken: objectui @ab1879721595 packages/types/src/objectql.ts#ObjectGanttSchema and objectui @ab1879721595 packages/types/src/zod/objectql.zod.ts#ObjectGanttSchema (`markers`); unchanged at objectui main 94985a92ba; [101] object-gantt (ObjectGanttPropsSchema, per key; P = objectui @b9814b334 packages/plugin-gantt/src/ObjectGantt.tsx, C = objectui @b9814b334 packages/core/src/utils/record-source.ts): data P#rawDataConfig C#resolveRecordSourceConfig (rung 1); staticData C#resolveRecordSourceConfig (rung 2); objectName (rung 3) P#persistLayoutKey P#navigation; filter P#queryFilter P#reload (`$filter`); sort P#reload (convertSortToQueryParams to `$orderby`); gantt P#getGanttConfig (branch 1, validated against the spec's GanttConfigSchema) and objectui @b9814b334 packages/plugin-gantt/src/index.tsx#ObjectGanttRenderer (its registration's `gantt` object input); navigation P#navConfig P#navigation; label P#ganttView (resolveInlineI18nLabel, export file-name chain); skipWeekends, holidays P#workingCalendar; persistLayout, viewName P#persistLayoutKey; markers, criticalPath, showBaselines, readOnly, mobileReadOnly P#ganttView, readOnly also P#renderRecordOverlay; measured and not declared: title (absent from the P#ganttView export-name chain), row cap (P#reload spreads nonGridRowCeilingQuery, marked not authorable), search and searchableFields P#searchTerm P#reload (host-generated by objectui @b9814b334 packages/plugin-list/src/ListView.tsx#viewComponentSchema, its `case 'gantt'` arm); [102] object-gantt.navigation: objectui @89cad75d55 packages/plugin-gantt/src/ObjectGantt.tsx#navConfig (`schema.navigation ?? { mode: 'drawer' }`) and objectui @89cad75d55 packages/plugin-gantt/src/ObjectGantt.tsx#navigation (useNavigationOverlay); [103] object-tree flat config keys (OBJECT_TREE_FLAT_CONFIG_GUIDANCE: parentField, labelField, titleField, fields, defaultExpandedDepth): objectui @b9814b334 packages/plugin-tree/src/ObjectTree.tsx#getTreeConfig (reads the flat spellings ahead of the `tree` block; the `schema.titleField` rung's retirement is recorded in its docblock above `fieldKey`, objectui#8841), objectui @b9814b334 packages/plugin-list/src/ListView.tsx#viewComponentSchema (its `case 'tree'` arm emits parentField, `labelField: treeCfg.labelField || 'name'`, fields, defaultExpandedDepth and no titleField since objectui 3fd862510), objectui @b9814b334 packages/plugin-tree/src/index.tsx#treeInputs (`{ name: 'tree', type: 'object' }`, no flat input); [104] object-tree (ObjectTreePropsSchema, per key; P = objectui @b9814b334 packages/plugin-tree/src/ObjectTree.tsx, C = objectui @b9814b334 packages/core/src/utils/record-source.ts): data P#dataConfig (resolveRecordSourceConfig with the `view-data` arm) and C#resolveRecordSourceConfig (rung 1, authoredDataIsOnTheDeclaredArm); staticData C#resolveRecordSourceConfig (rung 2); objectName (rung 3) P#headerObjectName P#navigation P#renderRecordOverlay (each behind resolveRecordSourceObjectName) P#parentField (detectParentField); filter P#queryFilter (useResolvedFilter) P#fetchData (`$filter` on the object fetch and on the inline ValueDataSource query); tree P#getTreeConfig and objectui @b9814b334 packages/plugin-tree/src/index.tsx#treeInputs; navigation P#navigation (useNavigationOverlay); host-prop `data` (not the authored key) P#passed; measured and not declared: sort (no `$orderby` in P#fetchData), row cap (P#fetchData spreads nonGridRowCeilingQuery); [105] object-tree.objectName (optional because no ElementDataSourceGate wiring): objectui @b9814b334 packages/plugin-tree/src/index.tsx#ObjectTreeRenderer has 0 occurrences of `ElementDataSourceGate` (re-counted 2026-10-15), against controls objectui @b9814b334 packages/plugin-gantt/src/index.tsx#ObjectGanttRenderer, packages/plugin-grid/src/index.tsx, packages/plugin-calendar/src/index.tsx (3 each) and packages/plugin-map/src/index.tsx#ObjectMapRenderer (4); method: occurrences of the identifier in each `src/index.tsx`; [106] object-timeline (ObjectTimelinePropsSchema, per key; P = objectui @b9814b334 packages/plugin-timeline/src/ObjectTimeline.tsx, R = objectui @b9814b334 packages/plugin-timeline/src/renderer.tsx, I = objectui @b9814b334 packages/plugin-timeline/src/index.tsx): objectName P#ObjectTimeline (fetch gate) P#useSettledSchema P#fetchesForItself P#invalidationNonce P#fetchData P#handleRefresh P#effectiveItems P#navigation; timeline P#timelineConfig; filter P#queryFilter P#filterKey P#fetchData; sort P#sortKey P#fetchData (convertSortToQueryParams); limit P#fetchData (resolveRowLimit) P#DEFAULT_TIMELINE_LIMIT P#describeRefusedRowLimit; items P#hasInlineItems P#fetchesForItself P#effectiveItems P#hasAuthoredItems; data P#hasInlineData P#fetchesForItself P#rawData; descriptionField P#descField; mapping P#titleField P#startDateField P#descField P#variantField; variant P#hasAuthoredItems (the `timeline-unsupported-variant` refusal, objectui#6655) and I#OBJECT_TIMELINE_INPUTS; navigation P#navigation P#effectiveSchema; dateFormat, rowLabel, minDate, maxDate R#TimelineRenderer (rowLabel and minDate/maxDate in its gantt branch, R#findUnusableGanttDate) off P#effectiveSchema; measured and not declared: bind P#boundData (useDataScope), className P#effectiveSchema; [107] object-timeline.data (read off React props, not `schema`; the prop channel is SchemaRenderer's `properties.*` hoist, objectui @b9814b334 packages/react/src/SchemaRenderer.tsx#SchemaRenderer, with `object-timeline` absent from objectui @b9814b334 packages/core/src/utils/record-source.ts#RECORD_SOURCE_DATA_ARM_BY_TYPE): objectui @b9814b334 packages/plugin-timeline/src/ObjectTimeline.tsx#hasInlineData (loading seed), objectui @b9814b334 packages/plugin-timeline/src/ObjectTimeline.tsx#fetchesForItself (the query skip the fetch effect reads), objectui @b9814b334 packages/plugin-timeline/src/ObjectTimeline.tsx#rawData (row source `(props as any).data || boundData || fetchedData`), objectui @b9814b334 packages/plugin-timeline/src/ObjectTimeline.tsx#effectiveItems (the `timeline` field bindings a fetched row takes); [108] object-timeline.items: objectui @2e818d0b51ec packages/types/src/data-display.ts#TimelineFeedItem and objectui @2e818d0b51ec packages/types/src/data-display.ts#TimelineGanttItem (the declared authored entry, ruled on objectui#6356), handed to the rail verbatim at objectui @2e818d0b51ec packages/plugin-timeline/src/ObjectTimeline.tsx#effectiveItems (`if (schema.items) return schema.items`); [109] record:reference_rail, record:alert, record:quick_actions, record:history, record:line_items (rows): key sets measured from the renderers' read points; the per-key read points are recorded under each props schema below; [110] record:approval_decision (row, EMPTY key set): objectui @d03b022 packages/app-shell/src/views/approval-decision/ApprovalDecisionPanel.tsx#ApprovalDecisionRenderer (landed in objectui a368ccb, module-internal at d03b022; discards `schema`, draws from the record context); [111] record:attachments (row, EMPTY key set): objectui @47b1f0bb71 packages/app-shell/src/views/record-attachments-renderer.tsx#RecordAttachmentsRenderer (registered as `attachments` in the `record` namespace; discards `schema`); [112] cloud-connection:panel, marketplace:installed-list (rows, EMPTY key sets): objectui @b9814b334 packages/app-shell/src/console/cloud-connection/CloudConnectionPanel.tsx#CloudConnectionPanel and objectui @b9814b334 packages/app-shell/src/console/marketplace/InstalledListWidget.tsx#InstalledList (each registration is `() => `; re-read 2026-10-15, first measured sha-less at the then pin); [113] mcp:connect-agent (row, EMPTY key set): objectui @b9814b334 packages/app-shell/src/console/connect/ConnectAgentWidget.tsx#ConnectAgent (registration `() => `; re-read 2026-10-15, first measured sha-less at the then pin); [114] element:definition-list, element:repeater (rows: the three-part string-arm evidence): objectui @b9814b334 packages/components/src/renderers/basic/data-list.tsx#DefinitionListRenderer and objectui @b9814b334 packages/components/src/renderers/basic/data-list.tsx#RepeaterRenderer (both registered in the `element` namespace), objectui @b9814b334 packages/core/src/registry/public-blocks.ts#PUBLIC_BLOCKS (publication), objectui @b9814b334 packages/app-shell/src/views/metadata-admin/previews/block-types.ts#BLOCK_TYPE_META (palette), objectui @b9814b334 packages/app-shell/src/views/metadata-admin/previews/block-config.ts#BLOCK_CONFIG (each block's inspector); [115] action:button, action:group, action:menu, action:icon (rows): objectui @b9814b334 packages/core/src/registry/public-blocks.ts#PUBLIC_BLOCKS (the four `action:*` members), registered under objectui packages/components/src/renderers/action/ in the `action` namespace; [116] object-map, object-gantt, object-tree (row key sets; per-key read points under each props schema): objectui @b9814b334 packages/plugin-map/src/index.tsx#ObjectMapRenderer, objectui @b9814b334 packages/plugin-map/src/ObjectMap.tsx#ObjectMap, objectui @b9814b334 packages/plugin-gantt/src/index.tsx#ObjectGanttRenderer, objectui @b9814b334 packages/plugin-gantt/src/ObjectGantt.tsx#ObjectGantt, objectui @b9814b334 packages/plugin-tree/src/index.tsx#ObjectTreeRenderer, objectui @b9814b334 packages/plugin-tree/src/ObjectTree.tsx#ObjectTree; [117] object-timeline (row key set; per-key read points under ObjectTimelinePropsSchema): objectui @b9814b334 packages/plugin-timeline/src/index.tsx#ObjectTimelineRenderer (the `object-timeline` and `timeline` registrations), objectui @b9814b334 packages/plugin-timeline/src/ObjectTimeline.tsx#ObjectTimeline, objectui @b9814b334 packages/plugin-timeline/src/renderer.tsx#TimelineRenderer; [118] EXPRESSION_BINDABLE_TEXT_KEYS_BY_COMPONENT rows statistic, card, button (the top-level text keys each renderer reads back; R = objectui @82a9417 packages/components/src/renderers/, re-verified identical at objectui 6c68b13 on 2026-08-18): statistic `label`, `value`, `description` R data-display/statistic.tsx#StatisticRenderer; card `title`, `description` R layout/card.tsx#CardRenderer; button `label` R form/button.tsx#ButtonRenderer; the deliberate `text` omission, `schema.content || schema.value`, at its `text` registration in R basic/text.tsx; [119] PageComponent.dataSource, the PLANNED API binding (ElementApiDataSourceSchema; its record is this file's `_note`; R = objectui @7578323a544e packages/core/src/): `read.url`'s refusal of a `./` path, measured against the console's `apiBase` promotion of a root-relative `/api/…` path only, R actions/ActionRunner.ts#navigateTo; `read.method` GET alone because every read (find, findOne, aggregate) sends an explicit `method: 'GET'`, R adapters/ApiDataSource.ts#ApiDataSource; no renderer reads the binding yet, the hook admitting only a string `object`, R data-scope/element-data-source.ts#isElementDataSourceConfig; [120] PageComponent.visibleWhen (the component-level evaluator's roots): the ambient scope (`current_user`, `user`, `ctx.user`, `os.user`, `features`, nothing else) objectui @1fb1ced36243 packages/app-shell/src/providers/ExpressionProvider.tsx#buildExpressionScope; composed with `record` (only when the page has a row) and `page` by objectui @1fb1ced36243 packages/react/src/SchemaRenderer.tsx#configEvaluationScope; no `data` root (objectui#9308) in objectui @1fb1ced36243 packages/react/src/SchemaRenderer.tsx#evaluatedSchema; the files identical at objectui main f228d710; the `page:tabs` item-level evaluator is the `page:tabs items[].visibleWhen` entry;"
},
"assignedProfiles": {
"status": "dead",
@@ -67,7 +67,7 @@
},
"interfaceConfig": {
"status": "live",
- "note": "the entire Airtable-parity list surface (source/columns/filterBy/appearance/userFilters/userActions/addRecord/buttons/recordAction/...) — objectui app-shell/src/views/InterfaceListPage.tsx + PageView.tsx. Verified in browser during the dogfood (grid+kanban+filters). [#23005] This blanket `live` verdict covers `interfaceConfig.emptyState` too: the list page's own empty state, the list view's EmptyStateSchema by reference. It was declared ahead of its renderer, contract first, with the `[PLANNED — not yet rendered]` marker on its describe; the renderer half, objectstack-ai/objectui#12270 (objectui b434f5f47), is inside the console pin from objectui b9814b334, and the marker is dropped. Measured there: InterfaceListPage hands ListView `cfg.emptyState ?? view.emptyState` (InterfaceListPage.tsx:509), so the page's own empty state wins over the source view's. `page/interfaceConfig` is a recorded undrilled container (undrilled-containers.baseline.json), so the walk reads no row for the member."
+ "note": "the entire Airtable-parity list surface (source/columns/filterBy/appearance/userFilters/userActions/addRecord/buttons/recordAction/...) — objectui app-shell/src/views/InterfaceListPage.tsx + PageView.tsx. Verified in browser during the dogfood (grid+kanban+filters). [#23005] This blanket `live` verdict covers `interfaceConfig.emptyState` too: the list page's own empty state, the list view's EmptyStateSchema by reference. It was declared ahead of its renderer, contract first, with the `[PLANNED — not yet rendered]` marker on its describe; the renderer half, objectstack-ai/objectui#12270 (objectui b434f5f47), is inside the console pin from objectui b9814b334, and the marker is dropped. Measured there: InterfaceListPage hands ListView `cfg.emptyState ?? view.emptyState` (InterfaceListPage.tsx:509), so the page's own empty state wins over the source view's. `page/interfaceConfig` is a recorded undrilled container (undrilled-containers.baseline.json), so the walk reads no row for the member. The reading before objectui#12270 (first cited by the Studio-form omit row for `interfaceConfig.emptyState` in packages/spec/src/system/metadata-form-zod-reconciliation.test.ts, which #23568 removed once the renderer half shipped; recorded here by #23434): objectui @7af0ab3 packages/app-shell/src/views/InterfaceListPage.tsx#schema handed ListView the source view's `emptyState` only; at objectui @b9814b334 the same symbol hands `cfg.emptyState ?? view.emptyState`."
},
"aria": {
"status": "live",
diff --git a/packages/spec/liveness/view.json b/packages/spec/liveness/view.json
index eb03dbffb36..0db4d586190 100644
--- a/packages/spec/liveness/view.json
+++ b/packages/spec/liveness/view.json
@@ -92,7 +92,7 @@
},
"kanban": {
"status": "live",
- "note": "objectui: KanbanImpl.tsx:682 — field-by-field wired (audit L16)."
+ "note": "objectui: KanbanImpl.tsx:682 — field-by-field wired (audit L16). What `groupByField` names, on kanban, gantt and timeline alike (packages/spec/src/ui/view.zod.ts, the padded-spelling refusal; moved out of spec source, #23434): a lookup BY THAT NAME on data the server answers under the unpadded name, at objectui @dda8f3815 packages/plugin-list/src/ListView.tsx#laneField (`groupByField || groupField || detectStatusField(objectDef)`, inside #viewComponentSchema; cards bucketed by `card[laneField]`), objectui @dda8f3815 packages/plugin-gantt/src/ObjectGantt.tsx#groupByAccessor (splits on `.` and walks the record) and objectui @dda8f3815 packages/plugin-timeline/src/ObjectTimeline.tsx#effectiveItems (`item[groupByField]`)."
},
"calendar": {
"status": "live",
@@ -186,7 +186,7 @@
"bulkActionDefs": {
"status": "live",
"evidence": "packages/spec/src/ui/bulk-action.zod.ts",
- "note": "objectui: ListView.tsx:1343 forwards rich defs to ObjectGrid (BulkActionDialog). Dispatch: useBulkExecutor.ts run() — per-record fan-out by default; execution:'aggregate' defs go through the ONE-call bulkCall branch injecting params._selectedIds (ObjectGrid.runBulkActionAggregate, objectui#3139). Verified objectui@4bf612c. #4457 gave the def a SHAPE (it was z.record(z.any())): the entry schema is BulkActionDefSchema, strict, and it refuses the combinations that parse but the executor never reads — so this row's liveness now covers the keys inside a def, not just the array."
+ "note": "objectui: ListView.tsx:1343 forwards rich defs to ObjectGrid (BulkActionDialog). Dispatch: useBulkExecutor.ts run() — per-record fan-out by default; execution:'aggregate' defs go through the ONE-call bulkCall branch injecting params._selectedIds (ObjectGrid.runBulkActionAggregate, objectui#3139). Verified objectui@4bf612c. #4457 gave the def a SHAPE (it was z.record(z.any())): the entry schema is BulkActionDefSchema, strict, and it refuses the combinations that parse but the executor never reads — so this row's liveness now covers the keys inside a def, not just the array. A PROMOTED def's field-backed params (packages/spec/src/ui/bulk-action.zod.ts; moved out of spec source, #23434): resolved when the dialog opens by objectui main @dca25aff2 packages/plugin-grid/src/resolveBulkActions.ts#resolvePromotedBulkParams through `resolveActionParams` (objectui 29b99490), then renamed onto the bulk vocabulary by the same file's #toBulkParam, which carries the field's type, translated label, options, required, description, placeholder, defaultValue, multiple, `dependsOn`, `accept` and `maxSize` (plus a reference-bearing field's reference and display field) and drops the lookup settings."
},
"virtualScroll": {
"status": "dead",
@@ -215,7 +215,7 @@
},
"appearance": {
"status": "live",
- "note": "objectui: allowedVisualizations gates the view-type switcher (audit L15); showDescription gates ListView.tsx:1728."
+ "note": "objectui: allowedVisualizations gates the view-type switcher (audit L15); showDescription gates ListView.tsx:1728. objectui's authoring mirror runs none of the spec's object-level checks on this block (packages/spec/src/ui/object-refinement-check-exports.test.ts; moved out of spec source, #23434): objectui @a472b07167a3 packages/types/src/zod/objectql.zod.ts#ListViewSchema extends `specFieldsExcept(SpecListViewSchema.shape, …)`, which carries the fields and drops every check attached to the object (the source counted six such sites at that pin); unchanged at objectui @53ded82bf7a4."
},
"tabs": {
"status": "dead",
@@ -238,7 +238,7 @@
"emptyState": {
"status": "live",
"evidence": "packages/cli/src/utils/i18n-extract.ts",
- "note": "objectui: ListView empty-state panel (audit L15); CLI i18n extract emits _views..emptyState keys (spec CHANGELOG). [#23004] This blanket `live` verdict covers `emptyState.link` too. It was declared ahead of its renderer, contract first, with the `[PLANNED — not yet rendered]` marker on its describe; the renderer half, objectstack-ai/objectui#12270 (objectui b434f5f47), is inside the console pin from objectui b9814b334, and the marker is dropped. Measured there: ListView hands ListEmptyState the `link` (ListView.tsx:5716), drawn through the shared EmptyStateLink in the grid and gallery empty branch, and ObjectGrid draws it in its authored empty state (ObjectGrid.tsx:6897-6899). `view/list.emptyState` is a recorded undrilled container (undrilled-containers.baseline.json), so the walk reads no row for the member."
+ "note": "objectui: ListView empty-state panel (audit L15); CLI i18n extract emits _views..emptyState keys (spec CHANGELOG). [#23004] This blanket `live` verdict covers `emptyState.link` too. It was declared ahead of its renderer, contract first, with the `[PLANNED — not yet rendered]` marker on its describe; the renderer half, objectstack-ai/objectui#12270 (objectui b434f5f47), is inside the console pin from objectui b9814b334, and the marker is dropped. Measured there: ListView hands ListEmptyState the `link` (ListView.tsx:5716), drawn through the shared EmptyStateLink in the grid and gallery empty branch, and ObjectGrid draws it in its authored empty state (ObjectGrid.tsx:6897-6899). `view/list.emptyState` is a recorded undrilled container (undrilled-containers.baseline.json), so the walk reads no row for the member. The `link`'s draw site beside the add-record action (packages/spec/src/ui/view.zod.ts, EmptyStateSchema; moved out of spec source, #23434): objectui @b9814b334 packages/plugin-list/src/ListEmptyState.tsx#addRecordAction, inside #ListEmptyState."
},
"aria": {
"status": "live",
diff --git a/packages/spec/src/data/api-methods-batch-conformance.test.ts b/packages/spec/src/data/api-methods-batch-conformance.test.ts
index 1b000ecc38e..41eda68572f 100644
--- a/packages/spec/src/data/api-methods-batch-conformance.test.ts
+++ b/packages/spec/src/data/api-methods-batch-conformance.test.ts
@@ -60,228 +60,8 @@ const SINGLE_RECORD_WRITE_ONLY: Record = {
// one column: the `revoke_api_key` / `restore_api_key` row actions PATCH
// `revoked` on ONE key. The multi-select surface this rule protects does not
// exist for API keys, and the shape a future one would take does not need
- // `bulk` either — both read off objectui `b9814b334`
- // (re-read there 2026-10-14:
- // in `packages/plugin-grid`, on the hop off `1fb1ced36`, `ObjectGrid.tsx`
- // changed again (327 insertions, 80 deletions: objectui#12292's per-row
- // If-Match saves, objectui#12303's save feedback, objectui#12030's spec 18
- // contract and objectui#12270's empty-state link), none of it inside the
- // selection block, which only MOVED by +48: `ObjectGrid.tsx:5045-5072` here
- // (`4997-5024` at `1fb1ced36`), still hashing to
- // `c88443302d40c2db739ddb235470bafa29056e2e` (hash-object of the block),
- // re-READ with the same reading below. No hunk sits beside that reading: the
- // `delete` verdict line MOVED `:1793` -> `:1873` and the promoted def's
- // params `:5181-5200` -> `:5229-5248` (called at `:5216` -> `:5264`), each
- // byte-identical. `hooks/useBulkExecutor.ts` is byte-identical to `1fb1ced36`
- // and its `:298-303` still hashes to
- // `01083348330f10a201cdf1078b4c21c236402b6a`. At `1fb1ced36`, re-read there
- // 2026-10-12:
- // every objectui file this record cites is byte-identical across the hop from
- // `7578323a5` (`git diff --quiet`), so every anchor held unmoved. At
- // `7578323a5`, re-read there 2026-10-12:
- // every objectui file this record cites is byte-identical across the hop from
- // `9646e2ed2` (`git diff --quiet`), so every anchor held unmoved. At
- // `9646e2ed2`, re-read there 2026-10-12:
- // every objectui file this record cites is byte-identical across the hop from
- // `088e0f705` (`git diff --quiet`), so every anchor held unmoved. At
- // `088e0f705`, re-read there 2026-10-12:
- // every objectui file this record cites is byte-identical across the hop from
- // `e5311165a` (`git diff --quiet`), so every anchor held unmoved. At
- // `e5311165a`, re-read there 2026-10-12:
- // in `packages/plugin-grid`, on the hop off `499799502`, `ObjectGrid.tsx`
- // changed again (27 insertions, 11 deletions: objectui#12110's authored
- // column label and objectui#12143's grouped-pager button names), none of it
- // inside the selection block, which only MOVED by +16:
- // `ObjectGrid.tsx:4997-5024` here (`4981-5008` at `499799502`), still hashing to
- // `c88443302d40c2db739ddb235470bafa29056e2e` (hash-object of the block),
- // re-READ with the same reading below. No hunk sits beside that reading: the
- // `delete` verdict line MOVED `:1787` -> `:1793` and the promoted def's params
- // `:5165-5184` -> `:5181-5200` (called at `:5200` -> `:5216`), each
- // byte-identical. `hooks/useBulkExecutor.ts` is byte-identical to `499799502`
- // and its `:298-303` still hashes to
- // `01083348330f10a201cdf1078b4c21c236402b6a`. At
- // `499799502`, re-read there 2026-10-11:
- // in `packages/plugin-grid`, on the hop off `0df67f237`, `ObjectGrid.tsx`
- // changed again (89 insertions, 44 deletions: objectui#12081 item 3's
- // whole-set footer and objectui#12082 leg A), none of it inside the
- // selection block, which only MOVED by +84: `ObjectGrid.tsx:4981-5008` here
- // (`4897-4924` at `0df67f237`), still hashing to
- // `c88443302d40c2db739ddb235470bafa29056e2e` (hash-object of the block),
- // re-READ with the same reading below. Two hunks sit beside that reading and
- // were re-READ as well: objectui#12081 item 3 moved the `bulkFanoutParams`
- // and `resolvedTotalMatching` declarations, their code byte-identical, above
- // the footer's hook; and objectui#12082 now also withholds a bulk `update`
- // def unless the edit verdict (`rowEditVerdict`) allows it, which narrows the
- // declared defs and adds no implicit one. The `delete` verdict line MOVED
- // `:1786` -> `:1787` and the promoted def's params `:5097-5116` ->
- // `:5165-5184` (called at `:5132` -> `:5200`), each byte-identical.
- // `hooks/useBulkExecutor.ts` is byte-identical to `0df67f237` and its
- // `:298-303` still hashes to `01083348330f10a201cdf1078b4c21c236402b6a`. At
- // `0df67f237`, re-read there 2026-10-11:
- // in `packages/plugin-grid`, on the hop off `20c6d351a`, `ObjectGrid.tsx`
- // changed again (82 insertions, 32 deletions: objectui#12082's
- // affordance-to-grant map, objectui#12103's per-column write grant and
- // objectui#12105's promoted bulk-action params), none of it inside the
- // selection block, which only MOVED by +29: `ObjectGrid.tsx:4897-4924` here
- // (`4868-4895` at `20c6d351a`), still hashing to
- // `c88443302d40c2db739ddb235470bafa29056e2e` (hash-object of the block),
- // re-READ with the same reading below. Two hunks touch that reading and were
- // re-READ as well: the `delete` verdict the implicit bulk-delete is gated on
- // now comes from `resolveAffordance('rowDelete', …)` (`:1786`), which still
- // asks the managed-object policy and the object's effective API operations,
- // with the caller's delete grant beside them; and a promoted def's params
- // now resolve when its dialog opens (`:5097-5116`, called at `:5132`), its
- // rows still fanned out through `useBulkExecutor`. `hooks/useBulkExecutor.ts`
- // is byte-identical to `20c6d351a` and its `:298-303` still hashes to
- // `01083348330f10a201cdf1078b4c21c236402b6a`. At `20c6d351a`, re-read there
- // 2026-10-10:
- // every objectui file this record cites is byte-identical across the hop
- // from `47b1f0bb7` (`git diff --quiet`), so every anchor held unmoved:
- // `ObjectGrid.tsx:4868-4895` still hashes to
- // `c88443302d40c2db739ddb235470bafa29056e2e` and
- // `hooks/useBulkExecutor.ts:298-303` to
- // `01083348330f10a201cdf1078b4c21c236402b6a`. At `47b1f0bb7`, re-read there
- // 2026-10-09:
- // in `packages/plugin-grid`, on the hop off `f0268ad78`, `ObjectGrid.tsx`
- // changed again (19 insertions, 11 deletions: objectui#11865 slice m,
- // objectui `2063f7a96`: one import line, and the grouped pager's
- // rows-per-page picker drawn with the shared `Select`), none of it inside the
- // selection block and no hunk naming a bulk action, a delete affordance or
- // `operations`, so the block only MOVED by +1: `ObjectGrid.tsx:4868-4895`
- // here (`4867-4894` at `f0268ad78`), still hashing to
- // `c88443302d40c2db739ddb235470bafa29056e2e` (hash-object of the block),
- // re-READ with the same reading below; `hooks/useBulkExecutor.ts` is
- // byte-identical to `f0268ad78` and its `:298-303` still hashes to
- // `01083348330f10a201cdf1078b4c21c236402b6a`. At `f0268ad78`, re-read there
- // 2026-10-09:
- // in `packages/plugin-grid`, on the hop off `a58626c88`, `ObjectGrid.tsx`
- // changed again (85 insertions, 27 deletions: objectui#11880 item 5's grid
- // filter hand-off, objectui#6152 rounds 7 and 10, objectui#11817's link cell,
- // objectui#11809's option order and objectui#11689's boolean face), none of
- // it inside the selection block and no hunk naming a bulk action, a delete
- // affordance or `operations`, so the block only MOVED by +54:
- // `ObjectGrid.tsx:4867-4894` here (`4813-4840` at `a58626c88`), still hashing
- // to `c88443302d40c2db739ddb235470bafa29056e2e` (hash-object of the block),
- // re-READ with the same reading below; `hooks/useBulkExecutor.ts` is
- // byte-identical to `a58626c88` and its `:298-303` still hashes to
- // `01083348330f10a201cdf1078b4c21c236402b6a`. At `a58626c88`, re-read there
- // 2026-10-06:
- // every objectui file this record cites is byte-identical across the hop from
- // `0abd4f9f8` (`git diff --quiet`), so every anchor held unmoved.
- // At `0abd4f9f8`, re-read there 2026-10-05:
- // every objectui file this record cites is byte-identical across the hop from
- // `9dfaca654` (`git diff --quiet`), so every anchor held unmoved.
- // At `9dfaca654`, `packages/plugin-grid`; re-measured at
- // that pin, 2026-10-05: on the hop off `2e818d0b5`, `ObjectGrid.tsx` changed
- // in three type docblocks only (9 insertions, 6 deletions: objectui#8347
- // re-wording its `BaseSchema` index-signature notes in the past tense), all
- // above the selection block, which only MOVED by +3:
- // `ObjectGrid.tsx:4813-4840` here (`4810-4837` at `2e818d0b5`), still
- // hashing to `c88443302d40c2db739ddb235470bafa29056e2e` (hash-object of the
- // block), re-READ with the same reading below; `hooks/useBulkExecutor.ts` is
- // byte-identical to `2e818d0b5` and its `:298-303` still hashes to
- // `01083348330f10a201cdf1078b4c21c236402b6a`. At `2e818d0b5`, 2026-10-04:
- // `ObjectGrid.tsx` and `hooks/useBulkExecutor.ts` are
- // byte-identical across the hop off `ab1879721` (`git diff --quiet`), so
- // every anchor held unmoved. Re-measured at `ab1879721`, 2026-10-03. On the
- // hop off `89cad75d5`, `ObjectGrid.tsx` changed
- // again (74 insertions, 11 deletions: objectui#11544's group-header labels
- // read from the object field's `options` only, objectui#11475's percent
- // storage `max` copied onto the cell's field meta on three paths and one
- // import edited in place, above the selection block; objectui#11068's
- // `keyboardNavigation`, objectui#11475's mobile-card percent face and
- // objectui#11227's resolved empty-state labels, below it), none of it inside
- // the selection block, which only MOVED by +19: `ObjectGrid.tsx:4810-4837`
- // here (`4791-4818` at `89cad75d5`), still hashing to
- // `c88443302d40c2db739ddb235470bafa29056e2e` (hash-object of the block),
- // re-READ with the same reading below; `hooks/useBulkExecutor.ts` is
- // byte-identical to `89cad75d5` and its `:298-303` still hashes to
- // `01083348330f10a201cdf1078b4c21c236402b6a`. At `89cad75d5`, 2026-10-02:
- // on the hop off `31971ff1e`, `ObjectGrid.tsx` changed
- // again (42 insertions, 17 deletions: objectui#11322's built-in bulk-delete
- // gate asking `partitionRowsByPredicate` directly and objectui#11254's
- // mobile-card percent width, plus their two import lines, each edited in
- // place), every hunk either a same-length import edit or below the
- // selection block, which did NOT move: `ObjectGrid.tsx:4791-4818` there as at
- // `31971ff1e`, still hashing to `c88443302d40c2db739ddb235470bafa29056e2e`
- // (hash-object of the block), re-READ with the same reading below;
- // `hooks/useBulkExecutor.ts` is byte-identical to `31971ff1e` and its
- // `:298-303` still hashes to `01083348330f10a201cdf1078b4c21c236402b6a`.
- // At `31971ff1e`, 2026-10-01: on the hop off `e420df310`, `ObjectGrid.tsx` changed
- // again (41 insertions, 1 deletion: objectui#10689's re-read on a harvested
- // query input), every hunk above the selection block, which only MOVED by
- // +40: `ObjectGrid.tsx:4791-4818` there (`4751-4778` at `e420df310`), still
- // hashing to `c88443302d40c2db739ddb235470bafa29056e2e` (hash-object of the
- // block), re-READ with the same reading below; `hooks/useBulkExecutor.ts` is
- // byte-identical to `e420df310` and its `:298-303` still hashes to
- // `01083348330f10a201cdf1078b4c21c236402b6a`. At `e420df310`, 2026-09-30:
- // on the hop off `db11afd49`, `ObjectGrid.tsx` changed
- // again (164 insertions, 48 deletions: objectui#9853's display page size,
- // objectui#11021's searched grouped grid, objectui#9547's `onNavigate` prop,
- // objectui#7297's `{record_id}` filter values and objectui#11070's
- // `reference` spelling among them), none of it inside the selection block,
- // which only MOVED by +114: `ObjectGrid.tsx:4751-4778` there (`4637-4664` at
- // `db11afd49`), still hashing to
- // `c88443302d40c2db739ddb235470bafa29056e2e` (hash-object of the block),
- // re-READ with the same reading below; `hooks/useBulkExecutor.ts` is
- // byte-identical to `db11afd49` and its `:298-303` still hashes to
- // `01083348330f10a201cdf1078b4c21c236402b6a`. At `db11afd49`, 2026-09-29:
- // on the hop off `dd3f7e1be`, `ObjectGrid.tsx` changed
- // again (105 insertions, 16 deletions: objectui#11068's grid keys,
- // objectui#11105's server-grouped column-name fix, objectui#10993's title
- // locale map among them), none of it inside the selection block, which only
- // MOVED by +32: `ObjectGrid.tsx:4637-4664` here (`4605-4632` at
- // `dd3f7e1be`), still hashing to
- // `c88443302d40c2db739ddb235470bafa29056e2e` (hash-object of the block),
- // re-READ with the same reading below; `hooks/useBulkExecutor.ts` is
- // byte-identical to `dd3f7e1be` and its `:298-303` still hashes to
- // `01083348330f10a201cdf1078b4c21c236402b6a`. Previously measured at
- // `89cad75d5`, `31971ff1e`, `e420df310`, `db11afd49`, `dd3f7e1be`, `f8a9d0fb0`, `62597c588`,
- // `87af769e9`, `53ded82bf`, `a472b0716`, `00d3f09c5`, `67dadd602`, before
- // that at `d8ec8d6d4`, `9602dc820`, `190fbd01d`, `9a3daf8d3`, originally at
- // `6314e87f2`. On the hop off `f8a9d0fb0`, `ObjectGrid.tsx` changed hard
- // (745 insertions, 161 deletions: objectui#7189's server-side grid grouping
- // and objectui#10881's grouped-grid refusal among them), none of it inside
- // the selection block, which only MOVED: `ObjectGrid.tsx:4605-4632` then
- // (`4032-4059` at `f8a9d0fb0`), still hashing to
- // `c88443302d40c2db739ddb235470bafa29056e2e`, re-READ with the same reading
- // below — the one edit in the surrounding selection-mode region (from its
- // `Determine selection mode` comment to `singleSelection`) is a comment tag
- // (`[#3720]` -> `[objectstack#3720]`). On the hop off
- // `62597c588`, `ObjectGrid.tsx` changed too (18 insertions, 5 deletions:
- // objectui#10083's `rowActionsDeclared` row-menu signal and objectui#9909's
- // currency display locale), none of it inside the selection block, which
- // only MOVED then as well (`4024-4051` to `4032-4059`), re-READ with the
- // same reading. `ObjectGrid.tsx` changed across the move off
- // `87af769e9` too (119 insertions, 9 deletions), and THAT time the selection block's CONTENT
- // moved, not only its position: objectui#10218 (`62597c588` itself)
- // rewrote the `selection` arm to "presence enables; an explicit off wins",
- // so an authored `selection` object with no `type` now selects
- // (`DEFAULT_SELECTION_TYPE`, `'multiple'`) where it used to fall through.
- // The block was `ObjectGrid.tsx:4024-4051` at `62597c588` — `3940-3955` at `87af769e9`,
- // `3538-3553` at `53ded82bf` — and no longer hashes to the
- // `6133933199230670e29d8c7f51c558d86a0af1d2` the previous three hops
- // recorded (`c88443302d40c2db739ddb235470bafa29056e2e` now). Re-READ, the
- // arm this record relies on is unchanged: with neither `selection` nor
- // `selectable` authored, multi-select is still enabled only by
- // `hasBulkActions`, and the rewritten arm is reachable only by a view that
- // declares `selection` — which none of these four does. The earlier hop off
- // `00d3f09c5` is the one that caught the previous record's OWN grid anchor as
- // wrong rather than merely shifted: `3790-3805` there is
- // `runBulkActionAggregate` and says nothing about selection. That is the
- // class commit d1ba685ec gates, and the reason a citation refresh re-READS instead of moving
- // numbers — arithmetic on a wrong anchor produces a fresh-looking span still
- // describing the wrong function. The second claim,
- // `hooks/useBulkExecutor.ts:298-303`, sits in a file that is byte-identical
- // to `f8a9d0fb0`, to `62597c588` and to `87af769e9` on the last three hops
- // (`git diff --quiet`; it last changed on the hop off `53ded82bf`, 36
- // insertions, 22 deletions, when it was re-READ rather than carried on file
- // identity): the six lines hash to
- // `01083348330f10a201cdf1078b4c21c236402b6a` at every one of those pins and
- // still end on
- // `label = 'bulk delete'`, the line the `284-288` span cited nine
- // pins ago stopped short of, truncating the second of the two branches it
- // names (byte-identity is never taken as proof an anchor is right):
+ // `bulk` either — both read off the console renderer (the read points are
+ // recorded in `packages/spec/liveness/object.json`, row `enable.apiMethods`):
//
// · No checkbox column is rendered. None of the object's four list views
// declares `bulkActions` / `bulkActionDefs` / `selection`, and `ObjectGrid`
diff --git a/packages/spec/src/data/field.form.ts b/packages/spec/src/data/field.form.ts
index 2892cb941bf..6843367fefe 100644
--- a/packages/spec/src/data/field.form.ts
+++ b/packages/spec/src/data/field.form.ts
@@ -212,8 +212,9 @@ export const fieldForm = defineForm({
// already uses it one section down for `summaryOperations.filter`, the
// sibling FilterConditionSchema key.
//
- // ⚠ What the hint renders as TODAY, measured at the pinned
- // `.objectui-sha`, is the announced raw-JSON editor carrying the hint —
+ // ⚠ What the hint renders as TODAY (read points recorded in
+ // `liveness/field.json`, row `relatedListFilter`) is the announced
+ // raw-JSON editor carrying the hint —
// ⛔ NOT a criteria builder. The renderer that consumes this registry is
// the metadata-admin `SchemaForm`, whose own `WIDGETS` map registers no
// `filter-condition` (the `FilterConditionField` of that name lives in
diff --git a/packages/spec/src/data/field.zod.ts b/packages/spec/src/data/field.zod.ts
index 7a7eafb0c41..47e43cb54cf 100644
--- a/packages/spec/src/data/field.zod.ts
+++ b/packages/spec/src/data/field.zod.ts
@@ -453,11 +453,11 @@ const CURRENCY_DECIMAL_PLACES_ARE_THE_CURRENCYS =
* #19910 — 「a currency's decimal places are the currency's, not a setting」):
* `precision` was a declared, validated key that no renderer or runtime ever
* read. objectui's `CurrencyField` derives the width from the currency's ISO
- * 4217 minor unit (`currencyFractionDigits(currency)`, the same line at the
- * `.objectui-sha` pin and at objectui `main`), and no code read the key at all —
- * measured with a lit control (`currencyConfig.currencyMode` IS read) over
- * objectstack `packages/**` + `examples/**`, objectui at the pin and at `main`,
- * and cloud `main`. Its only reader was
+ * 4217 minor unit (read points recorded in `liveness/field.json`, row
+ * `currencyConfig`), and no code read the key at all — measured with a lit
+ * control (`currencyConfig.currencyMode` IS read) over objectstack
+ * `packages/**` + `examples/**`, objectui (the console's tree and `main`) and
+ * cloud `main`. Its only reader was
* its own ISO 4217 contradiction check (#7918), which policed a width nothing
* applied; that check, the `.overwrite()` that baked a default `2` into parse
* output (#11423), and the `decimals` / `scale` → `precision` aliases all left
@@ -1710,9 +1710,9 @@ export const FieldSchema = lazySchema(() => {
* this schema declares — the camelCase key is the authored one in every
* case.
*
- * Claim dated to objectui ed971e8, re-measured 2026-09-09. It is a reading
- * of a pinned foreign tree and no gate here re-checks it: when the console
- * pin moves, this paragraph is what goes stale.
+ * The read points, dated, are recorded in `liveness/field.json`, row
+ * `lookupColumns`. It is a reading of a foreign tree and no gate here
+ * re-checks it.
*/
displayField: z.string().optional().describe("Field shown as each candidate's label in the picker/popover (defaults to the referenced object's name/title)."),
descriptionField: z.string().optional().describe('Secondary field shown under the label in the quick-select popover.'),
diff --git a/packages/spec/src/inline-grid-column-carriers.test.ts b/packages/spec/src/inline-grid-column-carriers.test.ts
index 3d22da0a749..8672d4dbc7b 100644
--- a/packages/spec/src/inline-grid-column-carriers.test.ts
+++ b/packages/spec/src/inline-grid-column-carriers.test.ts
@@ -426,8 +426,8 @@ describe('the `field` → `name` respelling is a chain step on the form-view car
const MASTER_DETAIL_PROPS = ComponentPropsMap['object-master-detail-form'];
/**
- * Every key objectui's `MasterDetailForm` reads off a detail entry (the
- * `.objectui-sha` pin `31971ff1e28f`, re-read at `89cad75d5570`). `sortField`
+ * Every key objectui's `MasterDetailForm` reads off a detail entry (read
+ * points recorded in `liveness/page.json`, row `regions`). `sortField`
* is not one of them: the renderer derives the line-position field from the
* child object, and the key is a tombstone (#21589,
* `ui/master-detail-detail-sort-field-retirement.test.ts`).
@@ -621,7 +621,7 @@ describe('defineStack judges an identity-only detail column by the type it rende
*/
const LINE_ITEMS_PROPS = ComponentPropsMap['record:line_items'];
-/** Every key objectui's `LineItemsPanel` reads off its schema (the `.objectui-sha` pin `31971ff1e28f`). */
+/** Every key objectui's `LineItemsPanel` reads off its schema (read points recorded in `liveness/page.json`, row `regions`). */
const FULL_LINE_ITEMS = {
childObject: 'crm_invoice_line',
relationshipField: 'invoice',
diff --git a/packages/spec/src/kernel/functional-completeness.ts b/packages/spec/src/kernel/functional-completeness.ts
index 62672664d58..8fe58366ad7 100644
--- a/packages/spec/src/kernel/functional-completeness.ts
+++ b/packages/spec/src/kernel/functional-completeness.ts
@@ -287,8 +287,8 @@ export function checkFieldCompleteness(def: unknown): CompletenessFinding[] {
* "Calendar configuration required" refusal screen, which names
* `startDateField` as the key to declare (objectui#8170 corrected that
* screen's second clause: `titleField` is NOT required). ⚠️ The screen's
- * copy is LOCALISED at the pin: objectui#10101 (objectui `afb228418`), which
- * the pin now contains, routes it through `tt('calendar.configRequired', …)`
+ * copy is LOCALISED: objectui#10101 (objectui `afb228418`), which the
+ * console this repo ships contains, routes it through `tt('calendar.configRequired', …)`
* (in `ObjectCalendar`), whose default and the `en` pack both
* read "Calendar configuration required. Please specify startDateField, …",
* while a non-English locale renders its own pack's words for the same
@@ -307,8 +307,8 @@ export function checkFieldCompleteness(def: unknown): CompletenessFinding[] {
* `case 'gantt'` spreads `startDateField` / `endDateField` / `titleField`
* only when the view DECLARED them — the `'start_date'` / `'end_date'`
* floors were deleted by objectui#7070 (landing commit objectui
- * `5f4514f7b`, which the arm's comment cites in the issue's place at this
- * pin: objectui `fec3b1a8b` re-cited objectui#7070 because it answers
+ * `5f4514f7b`, which the arm's comment cites in the issue's place on that
+ * console: objectui `fec3b1a8b` re-cited objectui#7070 because it answers
* 404), and the `'progress'` /
* `'dependencies'` floors by objectui#7499 (OMITTED, not refused: an absent
* progress or dependency binding is a legitimate state). ② `ObjectGantt`'s
@@ -324,7 +324,7 @@ export function checkFieldCompleteness(def: unknown): CompletenessFinding[] {
* through `resolveTimelineDateBinding` and spreads it only when one was
* declared — the `startDateField || 'created_at'` floor was deleted by
* objectui#7070 step ③ (landing commit objectui `04a67b9dc`, which the
- * arm's comment cites in the issue's place at this pin), on the ruling
+ * arm's comment cites in the issue's place on that console), on the ruling
* 日期轴永不虚构 (a date axis is never
* fabricated) — while its `titleField: dateBinding.titleField || 'name'`
* line is kept on purpose (a title is not an axis). ② `ObjectTimeline`'s
diff --git a/packages/spec/src/shared/editability-boundary.ts b/packages/spec/src/shared/editability-boundary.ts
index d4d6618d76b..8031a64e19e 100644
--- a/packages/spec/src/shared/editability-boundary.ts
+++ b/packages/spec/src/shared/editability-boundary.ts
@@ -21,14 +21,13 @@
* ruling now, on a **re-measured** version of the ruling's own premise rather
* than by analogy — the premise that carries it is "no editability semantics
* exist here to enforce", and for an option that is a fact about the renderer,
- * not an argument. Measured on objectui `origin/main` @ `aca27fa`: the
- * object-field pipeline these options actually feed has **zero** per-option
- * `disabled` consumers — `packages/fields/src/widgets/SelectField.tsx:161`
- * calls the root-level `disabled` "the single authority" in its own comment,
- * and `RadioField.tsx:124` reads only `props.disabled`. A shown-but-unselectable
- * option does exist in objectui's **SDUI** family
- * (`packages/components/src/renderers/form/select.tsx:62`), but on that
- * package's own select-option vocabulary in `packages/types` — a different
+ * not an argument. Measured on objectui `main` (read points recorded in
+ * `liveness/field.json`, row `options`): the object-field pipeline these
+ * options actually feed has **zero** per-option `disabled` consumers — the
+ * select widget calls the root-level `disabled` "the single authority" in its
+ * own comment, and the radio widget reads only `props.disabled`. A
+ * shown-but-unselectable option does exist in objectui's **SDUI** family
+ * select renderer, but on that package's own select-option vocabulary in `packages/types` — a different
* shape from this one, so it makes no key here enforced.
*
* The prescription it gets is NOT the siblings' text, because the siblings'
diff --git a/packages/spec/src/system/i18n-resolver.ts b/packages/spec/src/system/i18n-resolver.ts
index 247d364fd82..2e8baa02561 100644
--- a/packages/spec/src/system/i18n-resolver.ts
+++ b/packages/spec/src/system/i18n-resolver.ts
@@ -4281,8 +4281,9 @@ function lookupFlowScreenFieldCopy(
* client-side route always had. Under maintainer ruling A on #22507 a client
* overlay never touches a server-rendered slot. Its one caller, objectui's
* `FlowRunner` `localizeScreen`, stops overlaying the heading in that ruling's
- * consumer half, and this function retires once the `.objectui-sha` pin
- * carries that change (the pinned console still imports it).
+ * consumer half, and this function retires once the console this repo ships
+ * carries that change (it still imports it: read point recorded in
+ * `liveness/translation.json`, row `flows.screens`).
*/
export function resolveFlowScreenTitle(
bundle: TranslationBundle | undefined,
diff --git a/packages/spec/src/ui/action-declarative-update.ts b/packages/spec/src/ui/action-declarative-update.ts
index 3508c7554d6..29522057ef7 100644
--- a/packages/spec/src/ui/action-declarative-update.ts
+++ b/packages/spec/src/ui/action-declarative-update.ts
@@ -13,9 +13,8 @@ import { onSuccessBesideUpdateOperationRefusal } from './action-on-success-execu
* the rows' half is pinned in `component-action-row-declarative-update.test.ts`.
*
* Both runtimes read `operation` before the executor. The console's action
- * runner (`ActionRunner.execute`, `core/src/actions/ActionRunner.ts:1384-1388`
- * at the `.objectui-sha` pin `b9814b334`, byte-identical at objectui `main`
- * `524136e`) posts the write through its registered `script` dispatch and runs
+ * runner (`ActionRunner.execute`; read point recorded in `liveness/action.json`,
+ * row `operation`) posts the write through its registered `script` dispatch and runs
* no executor of its own, whatever executor the action or row names. The
* platform action route treats an action carrying `operation: 'update'` as the
* write "whatever `type` says" (`isDeclarativeUpdateAction`,
diff --git a/packages/spec/src/ui/action-url-target-scheme-set.test.ts b/packages/spec/src/ui/action-url-target-scheme-set.test.ts
index 7fcbe9c012a..b839a16dcc8 100644
--- a/packages/spec/src/ui/action-url-target-scheme-set.test.ts
+++ b/packages/spec/src/ui/action-url-target-scheme-set.test.ts
@@ -179,9 +179,8 @@ describe("an admitted `type: 'url'` target parses unchanged", () => {
// ===========================================================================
describe("the door answers the runner's pinned cases the same way", () => {
- // The cases objectui pins for `classifyNavigationTarget`
- // (`packages/core/src/actions/__tests__/navigationTarget.mailto-12191.test.ts`
- // at objectui 7578323). A literal target the runner opens must parse here,
+ // The cases objectui pins for `classifyNavigationTarget` (recorded in
+ // `liveness/action.json`, row `target`). A literal target the runner opens must parse here,
// and one it refuses must be refused here — a wider door publishes a target
// that fails at the click, a narrower one refuses a target that works.
it.each([
diff --git a/packages/spec/src/ui/app.zod.ts b/packages/spec/src/ui/app.zod.ts
index 05e1e68ce2b..6e21d3b1cff 100644
--- a/packages/spec/src/ui/app.zod.ts
+++ b/packages/spec/src/ui/app.zod.ts
@@ -430,8 +430,8 @@ export const ObjectNavItemSchema = lazySchema(() => strictObject(navItemSurface(
type: z.literal('object'),
objectName: z.string().describe('Target object name'),
/**
- * The rule this sentence states is the console's, read at the objectui commit
- * `.objectui-sha` pins: an entry with no `viewName` links to the bare object
+ * The rule this sentence states is the console's (read points recorded in
+ * `liveness/app.json`, row `navigation.viewName`): an entry with no `viewName` links to the bare object
* route, where `ObjectView` opens `defaultViewId || views[0]` — the view
* `buildViewTabs` marks `isDefault` (the default `list`), else the first
* declared list view. Its `all` tab is the fallback `buildViewTabs` adds only
diff --git a/packages/spec/src/ui/bulk-action.zod.ts b/packages/spec/src/ui/bulk-action.zod.ts
index 2e798a0be29..e3af9316d2e 100644
--- a/packages/spec/src/ui/bulk-action.zod.ts
+++ b/packages/spec/src/ui/bulk-action.zod.ts
@@ -155,7 +155,8 @@ export type BulkActionExecution = z.input;
* dialog opens, through the single-record dialog's own resolver (objectui
* `29b99490`: plugin-grid's `resolvePromotedBulkParams` calls
* `resolveActionParams` from `@object-ui/fields`, then renames the result onto
- * the bulk vocabulary). Measured on objectui `main` `dca25aff2`, that route
+ * the bulk vocabulary). Measured on objectui `main` (read points recorded in
+ * `liveness/view.json`, row `list.bulkActionDefs`), that route
* carries the field's `type`, translated `label`, `options`, `required`,
* `description` (as the help text), `placeholder`, `defaultValue`, `multiple`,
* `accept` and `maxSize`, plus a reference-bearing field's `reference`,
diff --git a/packages/spec/src/ui/component-action-element-rows-20371.test.ts b/packages/spec/src/ui/component-action-element-rows-20371.test.ts
index d8d867a3f9a..0a5bfcbd3e7 100644
--- a/packages/spec/src/ui/component-action-element-rows-20371.test.ts
+++ b/packages/spec/src/ui/component-action-element-rows-20371.test.ts
@@ -8,9 +8,9 @@
// (outside every namespace the enum populates) and the two `element:*` lists
// were refused as `component-type-unknown` (inside the reserved `element:`
// namespace with neither an enum member nor a row). Each row is strict from
-// birth, with its key set measured from the renderer's read points at the
-// `.objectui-sha` pin — the per-key citations live in `component.zod.ts`,
-// section 4b. The key sets are asserted WHOLE, as #18305's were: a row derived
+// birth, with its key set measured from the renderer's read points (recorded
+// in `liveness/page.json`, row `regions`; the rows sit in `component.zod.ts`
+// section 4b). The key sets are asserted WHOLE, as #18305's were: a row derived
// from read points is a claim about a complete set, and only an equality holds
// a later addition to having been measured too.
diff --git a/packages/spec/src/ui/component-action-member-params-array-only.pin.test.ts b/packages/spec/src/ui/component-action-member-params-array-only.pin.test.ts
index 1be3f9a731f..a6514321666 100644
--- a/packages/spec/src/ui/component-action-member-params-array-only.pin.test.ts
+++ b/packages/spec/src/ui/component-action-member-params-array-only.pin.test.ts
@@ -11,9 +11,10 @@
* The member declared `params` as `z.unknown()`. Both containers forward an
* array as the input list, forward any other value only for a `type: 'api'`
* member (its request payload), and drop it for every other `type`, with a
- * development-build warning only (objectui `static-params.ts:172-182` at the
- * `.objectui-sha` pin `0abd4f9f8`). So an object `params` on a `navigate_edit`
- * member passed the component-props gate and then reached no action.
+ * development-build warning only (read points recorded in
+ * `liveness/page.json`, row `regions`). So an object `params` on a
+ * `navigate_edit` member passed the component-props gate and then reached no
+ * action.
*
* ## What is pinned, and why each half
*
diff --git a/packages/spec/src/ui/component-action-row-effective-executor.test.ts b/packages/spec/src/ui/component-action-row-effective-executor.test.ts
index 63bc4966713..09ed1d87e92 100644
--- a/packages/spec/src/ui/component-action-row-effective-executor.test.ts
+++ b/packages/spec/src/ui/component-action-row-effective-executor.test.ts
@@ -6,8 +6,8 @@
* console's action runner will RUN, not only against the executor key.
*
* The runner dispatches on `action.type || action.actionType || action.name`
- * (objectui `core/src/actions/ActionRunner.ts:1265` at the `.objectui-sha`
- * pin), and every row forwards its executor key as `type` beside its `name`.
+ * (read points recorded in `liveness/page.json`, row `regions`), and every row
+ * forwards its executor key as `type` beside its `name`.
* So a row with no executor key whose `name` is `url` or `navigation` runs the
* url navigator — and its `target` is judged by the one url-target grammar
* (`navigation-target.ts`), whichever key spelled the executor. ⛔ `name` is
diff --git a/packages/spec/src/ui/component-element-navigation-17987.test.ts b/packages/spec/src/ui/component-element-navigation-17987.test.ts
index 02b980002e6..3e9f2b89ace 100644
--- a/packages/spec/src/ui/component-element-navigation-17987.test.ts
+++ b/packages/spec/src/ui/component-element-navigation-17987.test.ts
@@ -202,7 +202,7 @@ describe('the VIEW-level carrier is untouched', () => {
describe('the `object-timeline` row judges the block in BOTH directions', () => {
const TIMELINE = ComponentPropsMap['object-timeline'];
- it('accepts the key set measured from the renderer at the `.objectui-sha` pin', () => {
+ it('accepts the key set measured from the renderer read points (`liveness/page.json`, row `regions`)', () => {
const r = TIMELINE.safeParse({
objectName: 'task',
timeline: { startDateField: 'start_at', endDateField: 'end_at', titleField: 'subject', colorField: 'status' },
@@ -237,8 +237,8 @@ describe('the `object-timeline` row judges the block in BOTH directions', () =>
* The contract review's BLOCKING finding, pinned so the row cannot lose the
* key again.
*
- * `data` is read off REACT PROPS (`ObjectTimeline.tsx:171`, `:247`,
- * `:256`), not off `schema`, and an authored `properties.data` reaches that
+ * `data` is read off REACT PROPS (read points recorded in
+ * `liveness/page.json`, row `regions`), not off `schema`, and an authored `properties.data` reaches that
* channel through `SchemaRenderer`'s hoist-and-spread. The first cut of this
* row measured `schema.*` read points only, so it declared fourteen keys and
* refused this one BY NAME — reproducing this card's own defect sentence on
diff --git a/packages/spec/src/ui/component-form-custom-fields-sections-typed.pin.test.ts b/packages/spec/src/ui/component-form-custom-fields-sections-typed.pin.test.ts
index 1180ebbbf33..9dc8682b7ba 100644
--- a/packages/spec/src/ui/component-form-custom-fields-sections-typed.pin.test.ts
+++ b/packages/spec/src/ui/component-form-custom-fields-sections-typed.pin.test.ts
@@ -34,8 +34,8 @@
* one runtime field `customFields` takes.
* - §4 THE REGISTRATION: the ADR-0087 D3 entries step 18 carries.
* - §5 THE GRID WIDGET'S CAMELCASE KEYS (#21768): objectstack-ai/objectui#11610
- * renamed the `grid` widget's eight field-level keys to camelCase, and the
- * `.objectui-sha` pin `9dfaca654311` carries it, so the runtime field declares
+ * renamed the `grid` widget's eight field-level keys to camelCase (read
+ * points recorded in `liveness/page.json`, row `regions`), so the runtime field declares
* `minRows`, `maxRows`, `allowAdd`, `allowDelete`, `allowReorder`,
* `totalField`, `addLabel` and `sortField` with the widget's value types. The
* writer shape parses (§1); each snake_case spelling is refused by name with
@@ -212,9 +212,9 @@ describe('§1 each member accepts every shape a measured writer authors', () =>
{ name: 'rest', label: 'Rest', columns: 1, pane: 'secondary', fields: ['note'] },
],
}],
- // §5 — objectui `examples/schema-catalog/src/schemas/fields-grid/line-items-grid.json` at the
- // `.objectui-sha` pin `9dfaca654311`: the one `fields[]` entry, a `grid` field carrying all eight
- // camelCase keys, the shape objectui's grid-field guide (`content/docs/fields/grid.mdx`) teaches.
+ // §5 — objectui's schema-catalog grid example (recorded in `liveness/page.json`, row `regions`):
+ // the one `fields[]` entry, a `grid` field carrying all eight camelCase keys, the shape objectui's
+ // grid-field guide (`content/docs/fields/grid.mdx`) teaches.
['the grid widget\'s camelCase keys on an inline grid field', 'object-form', {
customFields: [{
name: 'line_items', label: 'Line Items', type: 'grid',
@@ -249,8 +249,8 @@ describe('§1 each member accepts every shape a measured writer authors', () =>
});
}
- // objectui `plugin-designer/src/ObjectManager.tsx` (about `:239`-`:247` at the `.objectui-sha` pin):
- // the registered `object-manager` component's create / edit dialog, a `formType: 'modal'` block.
+ // objectui's registered `object-manager` component's create / edit dialog, a `formType: 'modal'`
+ // block (recorded in `liveness/page.json`, row `regions`).
// Its two select members build their options from the file's own constants, each entry
// `{ label: v, value: v }`; the labels it draws through `t(...)` are written out as strings here.
it('object-form: parses the shipped object-manager dialog\'s inline fields byte-identical', () => {
@@ -494,8 +494,8 @@ describe('§4 each narrowing is registered as the ADR-0087 D3 entry step 18 carr
// ───────────────────────────────────────────────────────────────────────────
describe('§5 the grid widget\'s eight field-level keys, camelCase since objectui renamed them', () => {
- // The rename, as objectui's `GRID_FIELD_RETIRED_KEYS` pairs it (`types/src/field-types.ts:1159` at the
- // `.objectui-sha` pin `9dfaca654311`), with each key's value type as `GridFieldMetadata` declares it.
+ // The rename, as objectui's `GRID_FIELD_RETIRED_KEYS` pairs it (read points recorded in
+ // `liveness/page.json`, row `regions`), with each key's value type as `GridFieldMetadata` declares it.
const GRID_KEYS = [
['min_rows', 'minRows', 1, 'one'],
['max_rows', 'maxRows', 10, '10'],
@@ -556,7 +556,7 @@ describe('§5 the grid widget\'s eight field-level keys, camelCase since objectu
// Two keys spelled alike across siblings with opposite meanings is how a writer goes wrong: the grid's
// `totalField` names the CHILD column it sums, the child-collection blocks' names the PARENT field the
// sum is saved to (their child column is `amountField`, which their renderers hand the grid AS its
- // `totalField` — `LineItemsPanel.tsx:710`, `MasterDetailForm.tsx:876` at the pin).
+ // `totalField` — read points recorded in `liveness/page.json`, row `regions`).
it('`totalField` on the inline grid field is the CHILD column summed, the opposite of the same spelling on the child-collection blocks', () => {
const description = (schema: unknown) => (schema as { description?: string }).description ?? '';
const grid = description(runtimeField().shape.totalField);
diff --git a/packages/spec/src/ui/component-form-family-typed-members.pin.test.ts b/packages/spec/src/ui/component-form-family-typed-members.pin.test.ts
index e9335236667..d07fb7297cd 100644
--- a/packages/spec/src/ui/component-form-family-typed-members.pin.test.ts
+++ b/packages/spec/src/ui/component-form-family-typed-members.pin.test.ts
@@ -16,8 +16,8 @@
*
* ## The defect this file closes
*
- * Each of the four is read with one shape (measured at the `.objectui-sha` pin
- * `89cad75d55`; the read points are in the members' docblocks), and the row
+ * Each of the four is read with one shape (read points recorded in
+ * `liveness/page.json`, row `regions`), and the row
* declared them `z.unknown()`. So a `submitBehavior` whose `kind` the form does
* not know, a `contentLayout: 'tabs'`, a numeric `navigateOnSuccess` and a
* misspelled `mobile` member all passed the component-props gate, and the form
diff --git a/packages/spec/src/ui/component-list-family-typed-members.pin.test.ts b/packages/spec/src/ui/component-list-family-typed-members.pin.test.ts
index 9e3f9f0b59f..03782a36784 100644
--- a/packages/spec/src/ui/component-list-family-typed-members.pin.test.ts
+++ b/packages/spec/src/ui/component-list-family-typed-members.pin.test.ts
@@ -5,17 +5,17 @@
* typed: `object-grid` `columns`, `fields`, `selection`, `selectable`,
* `rowActions`, `bulkActions` and `batchActions`, `object-kanban` `columns`,
* and `object-calendar` `calendar`. Stage 2 typed eight and held `object-grid`
- * `columns`, because at the `.objectui-sha` pin `89cad75d55` the grid's group
- * headers drew a column's `options`, which the list view's column entry does
- * not declare. objectui `b0bf413` (objectstack-ai/objectui#11544) retired that
- * read: at the `.objectui-sha` pin `ab1879721595` the group-header labels come
- * from the object field's `options` only, so stage 5 types `columns` too.
+ * `columns`, because the grid's group headers then drew a column's `options`,
+ * which the list view's column entry does not declare. objectui `b0bf413`
+ * (objectstack-ai/objectui#11544) retired that read: the group-header labels
+ * now come from the object field's `options` only, so stage 5 types `columns`
+ * too (read points recorded in `liveness/page.json`, row `regions`).
*
* ## The defect this file closes
*
- * Each renderer reads these members with one shape (measured at the
- * `.objectui-sha` pin `89cad75d55`; the read points are in the members'
- * docblocks), and each row declared them `z.unknown()`. So a grid column keyed
+ * Each renderer reads these members with one shape (read points recorded in
+ * `liveness/page.json`, row `regions`), and each row declared them
+ * `z.unknown()`. So a grid column keyed
* `accessorKey`, an object entry in the grid's `fields`, a `{ name }` entry in
* `bulkActions`, a kanban lane list mixing objects and strings and a calendar
* block with no `startDateField` all passed the component-props gate, and the
diff --git a/packages/spec/src/ui/component-metric-family-typed-members.pin.test.ts b/packages/spec/src/ui/component-metric-family-typed-members.pin.test.ts
index fa5f8b6556d..f00c666b4da 100644
--- a/packages/spec/src/ui/component-metric-family-typed-members.pin.test.ts
+++ b/packages/spec/src/ui/component-metric-family-typed-members.pin.test.ts
@@ -14,10 +14,9 @@
*
* ## The defect this file closes
*
- * Each member is read with one shape (measured at the `.objectui-sha` pin
- * `89cad75d55` for `aggregate` / `trend`, and at the `.objectui-sha` pin
- * `ab1879721595` for `drillDown` / `compareTo`; the read points are in the
- * schemas' docblocks), and the row declared them `z.unknown()`. So
+ * Each member is read with one shape (read points recorded in
+ * `liveness/page.json`, row `regions`), and the row declared them
+ * `z.unknown()`. So
* `aggregate: 'count'`, a function the engine does not have, `groupby` for
* `groupBy`, a bare `trend: 'up'`, a `trend` with no `value`, a drill `filter`
* and a comparison `dimension` all passed the component-props gate, and the
@@ -101,8 +100,7 @@ describe('§1 each member accepts every shape a measured writer authors', () =>
['a trend with a locale-map caption', {
trend: { value: 12, direction: 'up', label: { en: 'Revenue records', 'zh-CN': '收入记录' } },
}],
- // objectui's drill-down member pins (`plugin-dashboard/src/__tests__/objectMetricDrillDownMembers-8071.test.tsx`,
- // `ObjectMetricWidget.drillRoutedToSharedDrawer-8970.test.tsx`) at the `.objectui-sha` pin `ab1879721595`.
+ // objectui's drill-down member pins (recorded in `liveness/page.json`, row `regions`).
['an empty drill-down block (on)', { drillDown: {} }],
['a drill-down switched off', { drillDown: { enabled: false } }],
['a drill-down with every list member', {
diff --git a/packages/spec/src/ui/component-object-grid-declared-keys.pin.test.ts b/packages/spec/src/ui/component-object-grid-declared-keys.pin.test.ts
index 693b89f5aac..cd53cd9f86b 100644
--- a/packages/spec/src/ui/component-object-grid-declared-keys.pin.test.ts
+++ b/packages/spec/src/ui/component-object-grid-declared-keys.pin.test.ts
@@ -8,9 +8,9 @@
* ## The gap this file closes
*
* `ComponentPropsMap['object-grid']` is a strict shape derived from the
- * renderer's own read points, and it lagged the renderer: at the
- * `.objectui-sha` pin the grid reads `schema.description` and
- * `schema.emptyState`, while this row refused both by name. A metadata author
+ * renderer's own read points, and it lagged the renderer: the grid reads
+ * `schema.description` and `schema.emptyState` (read points recorded in
+ * `liveness/page.json`, row `regions`), while this row refused both by name. A metadata author
* validating against the row had a key the renderer honours reported as
* unknown, and objectui's registry could not list it either (its parity test
* refuses an input the spec does not accept).
diff --git a/packages/spec/src/ui/component-object-grid-typed-members.pin.test.ts b/packages/spec/src/ui/component-object-grid-typed-members.pin.test.ts
index 7f666cff9ec..47c124a13af 100644
--- a/packages/spec/src/ui/component-object-grid-typed-members.pin.test.ts
+++ b/packages/spec/src/ui/component-object-grid-typed-members.pin.test.ts
@@ -10,8 +10,8 @@
* `rowHeight`, `aggregations`, `conditionalFormatting`, `rowColor`,
* `navigation` and `operations` were `z.unknown()`, and `bulkActionDefs` an
* array of it, while objectui's `ObjectGrid` reads each with one shape
- * (measured at the `.objectui-sha` pin `89cad75d55`; the read points are in
- * the row's docblock). So `rowHeight: 42` passed every door and rendered as a
+ * (read points recorded in `liveness/page.json`, row `regions`). So
+ * `rowHeight: 42` passed every door and rendered as a
* compact grid, and every other off-shape value was substituted or dropped
* with no report. `resizableColumns` was the second spelling of `resizable`,
* read only when `resizable` was absent.
@@ -203,8 +203,8 @@ describe('§3 the members hold the list view\'s own schemas, and the measured vo
it('aggregations[].type is AggregationFunction, whose members are exactly the six functions the grid computes', () => {
const type = shape().aggregations.unwrap().element.shape.type;
expect(type._zod.def).toBe(AggregationFunction._zod.def);
- // The grid's own vocabulary at the pin (`AggregationType` in
- // `plugin-grid/src/useGroupedData.ts`). A member added to the query AST's
+ // The grid's own vocabulary (`AggregationType`, recorded in
+ // `liveness/page.json`, row `regions`). A member added to the query AST's
// enum widens this door past the grid's reader; this line reds first.
expect([...AggregationFunction.options].sort()).toEqual(['avg', 'count', 'count_distinct', 'max', 'min', 'sum']);
});
diff --git a/packages/spec/src/ui/component-objectui-held-typed-members.pin.test.ts b/packages/spec/src/ui/component-objectui-held-typed-members.pin.test.ts
index 0337f2f4f27..e396ac0a091 100644
--- a/packages/spec/src/ui/component-objectui-held-typed-members.pin.test.ts
+++ b/packages/spec/src/ui/component-objectui-held-typed-members.pin.test.ts
@@ -14,9 +14,9 @@
*
* ## The defect this file closes
*
- * Each member is read with one shape (measured at the `.objectui-sha` pin
- * `ab1879721595`, unchanged at objectui `main` `94985a92ba`; the read points
- * are in the schemas' docblocks), and the rows declared them `z.unknown()`. So
+ * Each member is read with one shape (read points recorded in
+ * `liveness/page.json`, row `regions`), and the rows declared them
+ * `z.unknown()`. So
* a marker with no `date`, a numeric `date`, a misspelled marker member, a
* `mapping` written as a bare field name or keyed `titleField`, and a form
* `fields` entry written `{ name }` or `{ field }` all passed the
@@ -149,7 +149,7 @@ describe('§2 an off-shape value is refused with the code and the path', () => {
// objectui `plugin-form/src/__tests__/objectFormFieldsMembers-8071.test.tsx:140` — the warn probe.
['a `{ field }` field entry', 'object-form', { fields: [{ field: 'note' }] }, 'invalid_type', 'fields.0'],
['a numeric field entry', 'object-form', { fields: [5] }, 'invalid_type', 'fields.0'],
- // objectui's page-builder guide at `.objectui-sha` (respelled on objectui `main`).
+ // objectui's page-builder guide (recorded in `liveness/page.json`, row `regions`).
['the guide\'s retired inline field', 'object-form', {
fields: [{ name: 'name', label: 'Name', type: 'text', required: true }, 'email'],
}, 'invalid_type', 'fields.0'],
diff --git a/packages/spec/src/ui/component-props-unknown-members.pin.test.ts b/packages/spec/src/ui/component-props-unknown-members.pin.test.ts
index 4a077bd23c7..6ceac58f24a 100644
--- a/packages/spec/src/ui/component-props-unknown-members.pin.test.ts
+++ b/packages/spec/src/ui/component-props-unknown-members.pin.test.ts
@@ -65,7 +65,7 @@
*
* ## The STAGED reason is debt, not a verdict — and the debt is paid
*
- * A `staged` member WAS read with a fixed shape at the `.objectui-sha` pin, its
+ * A `staged` member WAS read with a fixed shape by its renderer, its
* reader cited on its line, and typing it was a later stage of #21464's
* close-out (the census found more than one reviewable PR's worth), each stage
* preceded by its own census of authored writers. The ledger could only lose
@@ -191,7 +191,7 @@ type Reason =
*/
| { readonly kind: 'opaque'; readonly ruling: string; readonly why: string }
/**
- * Read with a fixed shape at the pin (`reader`); typing it is a named later
+ * Read with a fixed shape by a renderer (`reader`); typing it is a named later
* stage. A `fork` line also names the viable shapes no ruling has chosen
* between (`shapes`).
*/
@@ -232,9 +232,8 @@ const SLOT: Reason = { kind: 'slot' };
const RUNNER: Reason = { kind: 'runner' };
/**
- * `ObjectUI` source paths are at the `.objectui-sha` pin `89cad75d55`, except
- * the S-final stage's line (the timeline entry's `content`), read at the
- * `.objectui-sha` pin `2e818d0b51ec`.
+ * The objectui read points a line's reason rests on are recorded in
+ * `liveness/page.json`, row `regions`.
*/
const LEDGER = new Map();
const on = (types: readonly string[], paths: readonly string[], reason: Reason): void => {
@@ -300,7 +299,7 @@ on(['object-grid'], ['bulkActionDefs[].patch{}', 'bulkActionDefs[].params[].defa
on(['action:button', 'action:icon'], ['patch{}'], RECORDS);
on(['action:group', 'action:menu'], ['actions[].patch{}'], RECORDS);
// A static board's card is a record row: `id` and `title` are typed, the rest
-// is the row's own values (`plugin-kanban/src/index.tsx:155`, kept verbatim).
+// is the row's own values (the kanban's lane bucketing keeps them verbatim).
on(['object-kanban'], ['columns[].cards[].*'], RECORDS);
on(['object-grid'], ['bulkActionDefs[].params[].options[].*'], BULK_OPTION_ENTRY);
on(['object-form'], ['customFields[].summaryOperations.filter{}'], FILTER_CONDITION);
@@ -313,7 +312,7 @@ on(['object-metric'], ['drillDown.report.runtimeFilter{}', 'drillDown.report.blo
// The rest, one line each.
on(['element:definition-list'], ['items[].description'], {
kind: 'any-value',
- why: 'shown as-is — a string or number as text, an object as JSON (`components/src/renderers/basic/data-list.tsx:68`, `toText`)',
+ why: 'shown as-is — a string or number as text, an object as JSON (the definition list\'s `toText`)',
});
on(['object-grid'], ['pagination.*'], {
kind: 'open-bag',
@@ -321,8 +320,8 @@ on(['object-grid'], ['pagination.*'], {
});
// Held opaque by a ruling. A timeline feed entry's `content` is child schema
-// nodes the entry draws below its description (`plugin-timeline/src/renderer.tsx:1659`,
-// `:1716`, `renderChildren`); the ruling on the decision card #21704's fork 4
+// nodes the entry draws below its description (through `renderChildren`); the
+// ruling on the decision card #21704's fork 4
// (letter B) keeps it unjudged on this row rather than making it a slot
// position the page walks visit, until a writer appears — the census found
// none.
@@ -351,8 +350,8 @@ describe('§1 every `z.unknown()` member across ComponentPropsMap is typed, or l
expect(
unlisted,
'A `z.unknown()` member with no recorded reason. A member a renderer reads with a fixed shape is TYPED '
- + '(by reference where a schema already declares it, otherwise to the renderer\'s read at the '
- + '`.objectui-sha` pin); a member handed verbatim to a runner keeps `z.unknown()` with that reason in its '
+ + '(by reference where a schema already declares it, otherwise to the renderer\'s read point, recorded in '
+ + '`liveness/page.json` row `regions`); a member handed verbatim to a runner keeps `z.unknown()` with that reason in its '
+ '`.describe()` and a `runner` line here.',
).toEqual([]);
});
@@ -396,7 +395,7 @@ describe('§2 each recorded reason holds', () => {
expect(silent).toEqual([]);
});
- it('a `staged` member names a declared stage and a reader at the pin', () => {
+ it('a `staged` member names a declared stage and a reader', () => {
for (const [key, reason] of entries) {
if (reason.kind !== 'staged') continue;
expect(Object.keys(STAGES), key).toContain(reason.stage);
diff --git a/packages/spec/src/ui/component-record-approvals-attachments-22537.test.ts b/packages/spec/src/ui/component-record-approvals-attachments-22537.test.ts
index 6a9b2e8c2ce..e149813e4d9 100644
--- a/packages/spec/src/ui/component-record-approvals-attachments-22537.test.ts
+++ b/packages/spec/src/ui/component-record-approvals-attachments-22537.test.ts
@@ -10,7 +10,8 @@
* `enable.files` object.
*
* Both are declared now, each with a strict row measured from its renderer's
- * read points at the `.objectui-sha` pin. Both rows accept no key:
+ * read points (recorded in `liveness/page.json`, row `regions`). Both rows
+ * accept no key:
* `record:attachments` reads no props at all, and `record:approvals` reads
* only the host's runtime channel (`approvals`, `currentUserId`), which the row
* refuses with a prescription instead of declaring. The authoring rule ids
diff --git a/packages/spec/src/ui/component-record-block-field-security.test.ts b/packages/spec/src/ui/component-record-block-field-security.test.ts
index 8d58934c2ce..2be4c2fd5a3 100644
--- a/packages/spec/src/ui/component-record-block-field-security.test.ts
+++ b/packages/spec/src/ui/component-record-block-field-security.test.ts
@@ -11,7 +11,8 @@
//
// The card declared the field-security PAIR first and held the third key until
// its semantics were ruled (#19186 ruling B: an ADR-0066 capability set) and the
-// renderers read it that way at the pin. Every pin below is an ACCEPT pin: a
+// renderers read it that way (read points recorded in `liveness/page.json`, row
+// `regions`). Every pin below is an ACCEPT pin: a
// full `safeParse` success is the assertion (not merely "no
// `unrecognized_keys`"), because the value arm is part of what is being
// declared, and a key-only assertion would stay green over a declaration that
diff --git a/packages/spec/src/ui/component-record-blocks.test.ts b/packages/spec/src/ui/component-record-blocks.test.ts
index 1770ee8cc0b..729c240d33a 100644
--- a/packages/spec/src/ui/component-record-blocks.test.ts
+++ b/packages/spec/src/ui/component-record-blocks.test.ts
@@ -6,10 +6,9 @@
// renderer + enum/palette presence + no row = the #5068 gate's dispatch skips
// the props bag and every authored key rides through in silence).
//
-// The key sets are measured from the renderers' read points at the
-// `.objectui-sha` pin (`record-alert.tsx`, `record-quick-actions.tsx`,
-// `record-history.tsx` + `HistoryTimeline.tsx`, `record-chatter.tsx`), NOT
-// from the registrations' declared-input lists — and the divergences between
+// The key sets are measured from the renderers' read points (recorded in
+// `liveness/page.json`, row `regions`), NOT from the registrations'
+// declared-input lists — and the divergences between
// the two are the interesting pins below: quick_actions' `aria` (read under a
// spelling the shared ARIA shape refuses), its `actions` (host channel),
// history's `entries`/`loading` (host channel), and alert's `icon` (READ here,
@@ -332,9 +331,10 @@ describe('ComponentPropsMap["record:activity"] — the host feed slot is named,
});
it('the `record:chatter` / `record:discussion` `feed` (the same object) refuses both keys and says nothing reads them there', () => {
- // At the `.objectui-sha` pin the chatter renderer reads its rows and its
- // loading flag off the discussion context and never reads `feed.items` /
- // `feed.loading`, so the mount-true clause is the one asserted here.
+ // The chatter renderer reads its rows and its loading flag off the
+ // discussion context and never reads `feed.items` / `feed.loading` (read
+ // points recorded in `liveness/page.json`, row `regions`), so the
+ // mount-true clause is the one asserted here.
for (const type of ['record:chatter', 'record:discussion'] as const) {
for (const key of ['items', 'loading'] as const) {
const result = ComponentPropsMap[type].safeParse({ feed: { [key]: key === 'items' ? [] : true } });
diff --git a/packages/spec/src/ui/component-reference-rail.test.ts b/packages/spec/src/ui/component-reference-rail.test.ts
index 18687f82e4f..250e2778e5b 100644
--- a/packages/spec/src/ui/component-reference-rail.test.ts
+++ b/packages/spec/src/ui/component-reference-rail.test.ts
@@ -11,8 +11,8 @@
// reproduced here as pins in both directions: the planted bogus key refused,
// the real shape accepted byte-identically.
//
-// The key set is measured from the renderer's read points at the
-// `.objectui-sha` pin (`record-reference-rail.tsx`), NOT from its TS interface
+// The key set is measured from the renderer's read points (recorded in
+// `liveness/page.json`, row `regions`), NOT from its TS interface
// — `icon` is in the interface and emitted by the page synthesizer but read by
// no render path, so it is a guidance refusal here, not a declared key.
diff --git a/packages/spec/src/ui/component-report-items-action-members-typed.pin.test.ts b/packages/spec/src/ui/component-report-items-action-members-typed.pin.test.ts
index b76f367626c..0b8d2024ead 100644
--- a/packages/spec/src/ui/component-report-items-action-members-typed.pin.test.ts
+++ b/packages/spec/src/ui/component-report-items-action-members-typed.pin.test.ts
@@ -19,9 +19,8 @@
*
* ## The defect this file closes
*
- * Each member is read with a fixed shape (measured at the `.objectui-sha` pin
- * `2e818d0b51ec`, unchanged at objectui `main` `2abec3a96`; the read points are
- * in the schemas' docblocks), and the rows declared them `z.unknown()` /
+ * Each member is read with a fixed shape (read points recorded in
+ * `liveness/page.json`, row `regions`), and the rows declared them `z.unknown()` /
* open records. So a drill report with no `dataset` or a bare report name, a
* gantt row on a feed timeline (or a feed entry with no `title`), and an
* action member keyed `actionType`, `endpoint` or a misspelling all passed the
@@ -430,9 +429,9 @@ describe('§3 each shape is the declaration the ruling names', () => {
// ───────────────────────────────────────────────────────────────────────────
/**
- * objectui `plugin-dashboard/src/DrillDownDrawer.tsx:92-99` at the
- * `.objectui-sha` pin `2e818d0b51ec`, restated: the drawer draws a drill report
- * as a report exactly when it holds, and lists the records otherwise. The
+ * objectui's drill drawer predicate (`isDatasetBoundReport`, recorded in
+ * `liveness/page.json`, row `regions`), restated: the drawer draws a drill
+ * report as a report exactly when it holds, and lists the records otherwise. The
* drawer reads the value as written — a page component's `properties` is
* never parsed on the way.
*/
diff --git a/packages/spec/src/ui/component.test.ts b/packages/spec/src/ui/component.test.ts
index 153642daeca..b1a0234b1b0 100644
--- a/packages/spec/src/ui/component.test.ts
+++ b/packages/spec/src/ui/component.test.ts
@@ -81,7 +81,8 @@ describe('PageHeaderProps', () => {
});
// #6776 — the three record-chrome switches objectui's header renderer has always
-// read (`containers.tsx:979-981`) and `PageHeaderProps` never declared. Until
+// read (read points recorded in `liveness/page.json`, row `regions`) and
+// `PageHeaderProps` never declared. Until
// this declaration objectui's published manifest called them legal while
// `validateComponentProps` (#5068) called them undeclared — two platform
// authorities disagreeing about one key (#5435), with the renderer siding with
@@ -229,9 +230,9 @@ describe('PageTabsProps', () => {
// rather than being stripped in silence (the retiredKey contract). The reason
// the concept had to change spelling at all is structural, not aesthetic: a
// props key named `type` collides with the page component's own dispatch key,
-// which is why objectui's `SchemaRenderer.tsx:253,264` refuses to hoist
-// `properties.type` and why `sdui-parser`'s `BASE_PROPS` (`validate.ts:20-30`)
-// skips it before any validation runs.
+// which is why objectui's `SchemaRenderer` refuses to hoist `properties.type`
+// and why `sdui-parser`'s `BASE_PROPS` skips it before any validation runs
+// (read points recorded in `liveness/page.json`, row `regions`).
describe('PageTabsProps tabStyle — renamed from `type`, which collides with the component `type`', () => {
it('accepts the three declared styles under the new key', () => {
for (const tabStyle of ['line', 'card', 'pill'] as const) {
@@ -256,8 +257,8 @@ describe('PageTabsProps tabStyle — renamed from `type`, which collides with th
});
});
-// #6776 — `page:accordion.variant`, read at objectui `containers.tsx:734` and
-// visible on screen (`flush` draws the divider, `card` leaves the border to the
+// #6776 — `page:accordion.variant`, read by objectui's accordion renderer (read
+// points recorded in `liveness/page.json`, row `regions`) and visible on screen (`flush` draws the divider, `card` leaves the border to the
// panel's own content), declared nowhere until now.
describe('PageAccordionProps variant — declared because the accordion renderer reads it', () => {
const accordion = ComponentPropsMap['page:accordion'];
@@ -283,115 +284,10 @@ describe('PageAccordionProps variant — declared because the accordion renderer
// #9881 — the accept-pin for `page:accordion` items[].icon, a key a liveness
// sweep once read as declared-but-unenforced. It has a live cross-repo consumer:
// objectui's `PageAccordionRenderer` renders `{item.icon && }` inside the `AccordionTrigger`
-// (`packages/components/src/renderers/layout/containers.tsx:1173-1179`), and the
-// same file's `ComponentRegistry.register('accordion', …)` publishes the key to
-// the Studio block designer at `:1222` (the `items` input, documented as
-// `[{ label, icon?, collapsed?, children }]`). Measured at objectui `b9814b334`, re-read there 2026-10-14:
-// every objectui file this record cites is byte-identical across the hop from
-// `1fb1ced36` (`git diff --quiet`), so every anchor held unmoved. At
-// `1fb1ced36`, re-read there 2026-10-12:
-// every objectui file this record cites is byte-identical across the hop from
-// `7578323a5` (`git diff --quiet`), so every anchor held unmoved. At
-// `7578323a5`, re-read there 2026-10-12:
-// every objectui file this record cites is byte-identical across the hop from
-// `9646e2ed2` (`git diff --quiet`), so every anchor held unmoved. At
-// `9646e2ed2`, re-read there 2026-10-12:
-// every objectui file this record cites is byte-identical across the hop from
-// `088e0f705` (`git diff --quiet`), so every anchor held unmoved. At
-// `088e0f705`, re-read there 2026-10-12:
-// every objectui file this record cites is byte-identical across the hop from
-// `e5311165a` (`git diff --quiet`), so every anchor held unmoved. At
-// `e5311165a`, re-read there 2026-10-12:
-// every objectui file this record cites is byte-identical across the hop from
-// `499799502` (`git diff --quiet`), so every anchor held unmoved. At
-// `499799502`, re-read there 2026-10-11:
-// every objectui file this record cites is byte-identical across the hop from
-// `0df67f237` (`git diff --quiet`), so every anchor held unmoved. At
-// `0df67f237`, re-read there 2026-10-11:
-// every objectui file this record cites is byte-identical across the hop from
-// `20c6d351a` (`git diff --quiet`), so every anchor held unmoved. At
-// `20c6d351a`, re-read there 2026-10-10:
-// every objectui file this record cites is byte-identical across the hop from
-// `47b1f0bb7` (`git diff --quiet`), so every anchor held unmoved. At
-// `47b1f0bb7`, re-read there 2026-10-09:
-// every objectui file this record cites is byte-identical across the hop from
-// `f0268ad78` (`git diff --quiet`), so every anchor held unmoved. At
-// `f0268ad78`, re-read there 2026-10-09:
-// `containers.tsx` changed across the hop from `a58626c88` (+92/-6,
-// objectui#11811: a record action disabled by its predicate says why, in the
-// `page:header` renderer), every hunk at `:1512` or below, so both anchors were
-// re-READ in place and NEITHER moved, each byte-identical. At `a58626c88`,
-// re-read there 2026-10-06:
-// every objectui file this record cites is byte-identical across the hop from
-// `0abd4f9f8` (`git diff --quiet`), so every anchor held unmoved.
-// At `0abd4f9f8`, re-read there 2026-10-05:
-// every objectui file this record cites is byte-identical across the hop from
-// `9dfaca654` (`git diff --quiet`), so every anchor held unmoved.
-// At `9dfaca654`. Re-derived at that pin
-// 2026-10-05: `containers.tsx` changed across the hop from `2e818d0b5` (89
-// insertions, 0 deletions: objectui#11619's record picture in the record
-// chrome — three import lines at the top of the file, and the
-// `recordPictureUrl` helpers and the `page:header` picture read below both
-// anchors), so both anchors were re-READ rather than carried, and BOTH MOVED
-// down three lines with their text byte-identical: the icon block
-// `1170-1176` -> `1173-1179`, still inside `PageAccordionRenderer`'s
-// `AccordionTrigger`, and the input `1219` -> `1222`, still inside the
-// `register('accordion', …)` inputs. At `2e818d0b5`, re-derived there
-// 2026-10-04: every objectui file this record cites is byte-identical across
-// the hop from `ab1879721` (`git diff --quiet`), so every anchor held unmoved.
-// At `ab1879721`, re-derived there 2026-10-03: `containers.tsx` changed
-// across the hop from `89cad75d5` (23
-// insertions, 27 deletions: objectui#11445's i18next count family for the
-// `page:tabs` count badge, and objectui#11438 dropping the `page:header`
-// registration's inert `breadcrumb` input), so both anchors were re-READ rather
-// than carried, and BOTH MOVED up one line with their text byte-identical (the
-// tab-count translation table above them lost a net line): the icon block
-// `1171-1177` -> `1170-1176`, still inside `PageAccordionRenderer`'s
-// `AccordionTrigger`, and the input `1220` -> `1219`, still inside the
-// `register('accordion', …)` inputs. At `89cad75d5`, re-derived at that pin
-// 2026-10-02: `containers.tsx` is byte-identical across the hop from
-// `31971ff1e` (`git diff --quiet`), and both anchors were re-READ in place and
-// still say what this block says: the icon block `1171-1177`, inside
-// `PageAccordionRenderer`'s `AccordionTrigger`, and the input `1220`, inside
-// the `register('accordion', …)` inputs. At `31971ff1e`, re-derived at that pin
-// 2026-10-01: `containers.tsx` is byte-identical across the hop from
-// `e420df310` (`git diff --quiet`), and both anchors were re-READ in place and
-// still say what this block says: the icon block `1171-1177`, inside
-// `PageAccordionRenderer`'s `AccordionTrigger`, and the input `1220`, inside
-// the `register('accordion', …)` inputs. At `e420df310`, re-derived at that pin
-// 2026-09-30: `containers.tsx` changed again across the hop from `db11afd49` (40
-// insertions, 26 deletions: objectui#11166's `page:header` breadcrumb slot and
-// objectui#11212's fail-closed permission gates), every hunk of it at `:1286`
-// or below, so both anchors were re-READ in place and NEITHER moved, each
-// byte-identical: the icon block `1171-1177`, still inside
-// `PageAccordionRenderer`'s `AccordionTrigger`, and the input `1220`, still
-// inside the `register('accordion', …)` inputs. At `db11afd49`, re-derived at
-// that pin 2026-09-29: `containers.tsx` changed again across the hop from `dd3f7e1be` (46
-// insertions, 6 deletions: objectui `0ecaa7dbb`'s block-level nested `aria` bags
-// and comment re-citations), so both anchors were re-READ rather than carried,
-// and BOTH MOVED with their text byte-identical, the icon block by 32 and the
-// registration input by 34: `1139-1145` -> `1171-1177`, `1186` -> `1220`. At
-// `dd3f7e1be`, re-derived at that pin
-// 2026-09-28: `containers.tsx` changed again across the hop from `f8a9d0fb0`
-// (120 insertions, 63 deletions; the 70 net lines above both anchors are
-// objectui `3261e6479`'s one `titleFormat` interpolator for the record title
-// and an import line from objectui `f5178a272`; the rest lands below both,
-// objectui `1dae95a41`'s two re-cited `page:header` comments among it), so
-// both anchors were re-READ
-// rather than carried — and both MOVED with their text byte-identical: the
-// icon block `1069-1075` -> `1139-1145`, still inside `PageAccordionRenderer`'s
-// `AccordionTrigger`, and the input `1116` -> `1186`, still inside the
-// `register('accordion', …)` inputs. At `f8a9d0fb0` (2026-09-24, off
-// `62597c588`: 36 insertions, 7 deletions, objectui `ba0b61a60`, an import
-// line and the `page:header` title) NEITHER had moved, each byte-identical to
-// its `62597c588` and `87af769e9` text. The hop onto `62597c588` (74
-// insertions, 16 deletions, objectui `4c6f549ef`) read the same. (The hop before, off `53ded82bf`,
-// moved them from `919-925` and `966` and rewrote the input LINE — it now
-// declares `of: 'object'`, carries a longer description and no `label` —
-// while the member list this pin cites stayed unchanged.) Identity preserves a
-// wrong anchor as faithfully as a right one, which is why neither was carried
-// (commit d1ba685ec).
+// name={item.icon} …/>}` inside the `AccordionTrigger`, and the same file's
+// `accordion` registration publishes the key to the Studio block designer (the
+// `items` input, documented as `[{ label, icon?, collapsed?, children }]`)
+// (read points recorded in `liveness/page.json`, row `regions`).
//
// #9397 spent a full dispatch cycle re-deriving that read point from scratch
// after the sweep proposed retiring the key. This block plus the `.describe()`
@@ -469,110 +365,10 @@ describe('PageTabsProps items[].value / items[].count — declared because the t
// #9881 accordion key: same file, same renderer, same `LazyIcon` slot, and the
// same bare declaration a liveness sweep reads as declared-but-unenforced.
// objectui's `PageTabsRenderer` renders `{item.icon && }` inside the `TabsTrigger`
-// (`packages/components/src/renderers/layout/containers.tsx:948-954`), and the
-// same file's `ComponentRegistry.register('tabs', …)` publishes the key to the
-// Studio block designer at `:1007` (the `items` input, documented as
-// `[{ label, value?, icon?, count?, visibleWhen?, children }]`). Measured at
-// objectui `b9814b334`, re-read there 2026-10-14:
-// every objectui file this record cites is byte-identical across the hop from
-// `1fb1ced36` (`git diff --quiet`), so every anchor held unmoved. At
-// `1fb1ced36`, re-read there 2026-10-12:
-// every objectui file this record cites is byte-identical across the hop from
-// `7578323a5` (`git diff --quiet`), so every anchor held unmoved. At
-// `7578323a5`, re-read there 2026-10-12:
-// every objectui file this record cites is byte-identical across the hop from
-// `9646e2ed2` (`git diff --quiet`), so every anchor held unmoved. At
-// `9646e2ed2`, re-read there 2026-10-12:
-// every objectui file this record cites is byte-identical across the hop from
-// `088e0f705` (`git diff --quiet`), so every anchor held unmoved. At
-// `088e0f705`, re-read there 2026-10-12:
-// every objectui file this record cites is byte-identical across the hop from
-// `e5311165a` (`git diff --quiet`), so every anchor held unmoved. At
-// `e5311165a`, re-read there 2026-10-12:
-// every objectui file this record cites is byte-identical across the hop from
-// `499799502` (`git diff --quiet`), so every anchor held unmoved. At
-// `499799502`, re-read there 2026-10-11:
-// every objectui file this record cites is byte-identical across the hop from
-// `0df67f237` (`git diff --quiet`), so every anchor held unmoved. At
-// `0df67f237`, re-read there 2026-10-11:
-// every objectui file this record cites is byte-identical across the hop from
-// `20c6d351a` (`git diff --quiet`), so every anchor held unmoved. At
-// `20c6d351a`, re-read there 2026-10-10:
-// every objectui file this record cites is byte-identical across the hop from
-// `47b1f0bb7` (`git diff --quiet`), so every anchor held unmoved. At
-// `47b1f0bb7`, re-read there 2026-10-09:
-// every objectui file this record cites is byte-identical across the hop from
-// `f0268ad78` (`git diff --quiet`), so every anchor held unmoved. At
-// `f0268ad78`, re-read there 2026-10-09:
-// `containers.tsx` changed across the hop from `a58626c88` (+92/-6,
-// objectui#11811: a record action disabled by its predicate says why, in the
-// `page:header` renderer), every hunk at `:1512` or below, so both anchors were
-// re-READ in place and NEITHER moved, each byte-identical. At `a58626c88`,
-// re-read there 2026-10-06:
-// every objectui file this record cites is byte-identical across the hop from
-// `0abd4f9f8` (`git diff --quiet`), so every anchor held unmoved.
-// At `0abd4f9f8`, re-read there 2026-10-05:
-// every objectui file this record cites is byte-identical across the hop from
-// `9dfaca654` (`git diff --quiet`), so every anchor held unmoved.
-// At `9dfaca654`. Re-derived at
-// that pin 2026-10-05: `containers.tsx` changed across the hop from
-// `2e818d0b5` (89 insertions, 0 deletions: objectui#11619's record picture in
-// the record chrome — three import lines at the top of the file, and the
-// `recordPictureUrl` helpers and the `page:header` picture read below both
-// anchors), so both anchors were re-READ rather than carried, and BOTH MOVED
-// down three lines with their text byte-identical: the icon block `945-951`
-// -> `948-954`, still inside `PageTabsRenderer`'s `TabsTrigger`, and the
-// input `1004` -> `1007`, still inside the `register('tabs', …)` inputs. At
-// `2e818d0b5`, re-derived there 2026-10-04: every objectui file this record cites is byte-identical
-// across the hop from `ab1879721` (`git diff --quiet`), so every anchor held
-// unmoved. At `ab1879721`, re-derived there 2026-10-03: `containers.tsx`
-// changed across the hop from `89cad75d5`
-// (23 insertions, 27 deletions: objectui#11445's i18next count family, which
-// rewrote the tab-count translation table above both anchors and the count
-// badge's `aria-label` between them, and objectui#11438 dropping the
-// `page:header` registration's inert `breadcrumb` input below them), so both
-// anchors were re-READ rather than carried, and BOTH MOVED up one line with
-// their text byte-identical: the icon block `946-952` -> `945-951`, still
-// inside `PageTabsRenderer`'s `TabsTrigger`, and the input `1005` -> `1004`,
-// still inside the `register('tabs', …)` inputs. At `89cad75d5`, re-derived at
-// that pin 2026-10-02: `containers.tsx` is byte-identical across the hop from
-// `31971ff1e` (`git diff --quiet`), and both anchors were re-READ in place and
-// still say what this block says: the icon block `946-952`, inside
-// `PageTabsRenderer`'s `TabsTrigger`, and the input `1005`, inside the
-// `register('tabs', …)` inputs. At `31971ff1e`, re-derived at that pin
-// 2026-10-01: `containers.tsx` is byte-identical across the hop from
-// `e420df310` (`git diff --quiet`), and both anchors were re-READ in place and
-// still say what this block says: the icon block `946-952`, inside
-// `PageTabsRenderer`'s `TabsTrigger`, and the input `1005`, inside the
-// `register('tabs', …)` inputs. At `e420df310`, re-derived at that pin
-// 2026-09-30: `containers.tsx` changed again across the hop from
-// `db11afd49` (40 insertions, 26 deletions: objectui#11166's `page:header`
-// breadcrumb slot and objectui#11212's fail-closed permission gates), every hunk
-// of it at `:1286` or below, so both anchors were re-READ in place and NEITHER
-// moved, each byte-identical: the icon block `946-952`, still inside
-// `PageTabsRenderer`'s `TabsTrigger`, and the input `1005`, still inside the
-// `register('tabs', …)` inputs. At `db11afd49`, re-derived at
-// that pin 2026-09-29: `containers.tsx` changed again across the hop from
-// `dd3f7e1be` (46 insertions, 6 deletions: objectui `0ecaa7dbb`'s block-level
-// nested `aria` bags and comment re-citations), so both anchors were re-READ
-// rather than carried, and BOTH MOVED with their text byte-identical, the net +23
-// all landing above them: `923-929` -> `946-952`, `982` -> `1005`. At
-// `dd3f7e1be`, re-derived
-// at that pin 2026-09-28: `containers.tsx` changed again across the hop from
-// `f8a9d0fb0` (120 insertions, 63 deletions, 70 net lines above both anchors:
-// objectui `3261e6479`'s `titleFormat` interpolator and an import line), so
-// both anchors were re-READ rather than carried — and both MOVED with their
-// text byte-identical: the icon block `853-859` -> `923-929`, still inside
-// `PageTabsRenderer`'s `TabsTrigger`, and the input `912` -> `982`, still
-// inside the `register('tabs', …)` inputs. At `f8a9d0fb0` (2026-09-24, off
-// `62597c588`: 36 insertions, 7 deletions, objectui `ba0b61a60`) NEITHER had
-// moved, each byte-identical to its `62597c588` and `87af769e9` text; the hop
-// onto `62597c588` (74 insertions, 16 deletions, objectui `4c6f549ef`) read
-// the same. (The hop before, off `53ded82bf`, moved them from
-// `730-736` and `789` and rewrote the input LINE — `of: 'object'`, a longer
-// description, no `label` — while the member list this pin cites stayed
-// unchanged.) Never inferred (commit d1ba685ec).
+// name={item.icon} …/>}` inside the `TabsTrigger`, and the same file's
+// `tabs` registration publishes the key to the Studio block designer (the
+// `items` input, documented as `[{ label, value?, icon?, count?, visibleWhen?,
+// children }]`) (read points recorded in `liveness/page.json`, row `regions`).
//
// #9397 spent a full dispatch cycle re-deriving the accordion's read point
// after the sweep proposed retiring it. This block plus the `.describe()` it
@@ -900,10 +696,9 @@ describe('RecordDetailsProps', () => {
// #11661 — three more section keys in exactly the pre-#11289 position
// (honoured by the renderer, refused by this shape), declared under the
- // inherited ruling. Measured at the `.objectui-sha` pin (`190fbd01`):
- // `defaultCollapsed` at `DetailSection.tsx:139`
- // (`useState(section.defaultCollapsed ?? false)`), `icon` at
- // `DetailSection.tsx:516/546`, `description` at `DetailSection.tsx:520/557`.
+ // inherited ruling. Measured on the section renderer (read points recorded in `liveness/page.json`, row `regions`):
+ // `defaultCollapsed` (`useState(section.defaultCollapsed ?? false)`), `icon`
+ // and `description`.
it('preserves `defaultCollapsed` / `icon` / `description` verbatim', () => {
const result = RecordDetailsProps.parse({
sections: [{
@@ -962,7 +757,7 @@ describe('RecordDetailsProps', () => {
});
it('still refuses `title`, deliberately withheld as a second spelling of `label`', () => {
- // Honoured by the renderer at the pin, and OUT of the accept set on
+ // Honoured by the renderer, and OUT of the accept set on
// purpose: `title` is a second spelling of the heading slot `label`
// declares (the `page:card` `body`-vs-`children` shape, which #5775
// converged rather than declared) and is held for a maintainer ruling.
@@ -1681,8 +1476,8 @@ describe('ComponentPropsMap', () => {
// #11575 — the two `@objectstack/cloud-connection` console widgets. Rows
// exist so the #5068 gate's dispatch reaches them; the accepted key set is
- // EMPTY, measured from the renderers' read points at the `.objectui-sha`
- // pin (both registrations discard the schema node — `() => `).
+ // EMPTY, measured from the renderers' read points (both registrations
+ // discard the schema node — `() => `; read points recorded in `liveness/page.json`, row `regions`).
describe('plugin console widgets', () => {
it('declares rows for cloud-connection:panel and marketplace:installed-list', () => {
expect(ComponentPropsMap['cloud-connection:panel']).toBeDefined();
@@ -1720,9 +1515,9 @@ describe('ComponentPropsMap', () => {
// third instance over. Row exists so the #5068 gate's dispatch reaches it
// (and so the mcp canonical-envelope gate's door 3 reads its bag instead of
// carrying a standing exemption); the accepted key set is EMPTY, measured
- // from the renderer's read points at the `.objectui-sha` pin (the
- // registration discards the schema node — `() => ` — and
- // the component function takes no parameters).
+ // from the renderer's read points (the registration discards the schema
+ // node — `() => ` — and the component function takes no
+ // parameters; read points recorded in `liveness/page.json`, row `regions`).
describe('mcp console widget', () => {
it('declares a row for mcp:connect-agent', () => {
expect(ComponentPropsMap['mcp:connect-agent']).toBeDefined();
@@ -2490,15 +2285,14 @@ describe('the seven `object-*` `filter` doors — one filter orthography platfor
r.success ? [] : r.error!.issues.filter((i) => i.path.join('.') === path);
it.each(OBJECT_DOORS)('%s accepts a ViewFilterRule[] filter and echoes it — the acceptance criterion', (type) => {
- // Measured at the objectui pin `53ded82b` before the declarations moved:
+ // Measured before the declarations moved (read points recorded in `liveness/page.json`, row `regions`):
// grid lowers the rule array through `toFilterNode`; kanban and calendar
// hand it verbatim to `$filter`, where `convertQueryParams` lowers it; the
// metric's aggregate path lowers it through `translateFilterArray` and
// `parseFilterAST` before `POST /analytics/query` (objectui#7754 — the
- // door the family was sequenced behind, #15828 / the pin bump commit 30b099078). Re-measured at
- // the same pin for the three #18305 doors: `ObjectMap.tsx:742`,
- // `ObjectGantt.tsx:738` and `ObjectTree.tsx:474` each hand `schema.filter`
- // verbatim to `$filter`, the kanban/calendar shape.
+ // door the family was sequenced behind, #15828 / the pin bump commit 30b099078). Re-measured
+ // for the three #18305 doors: the map, gantt and tree renderers each hand
+ // `schema.filter` verbatim to `$filter`, the kanban/calendar shape.
const r = door(type).safeParse({ objectName: 'showcase_task', filter: RULES });
expect(r.success).toBe(true);
expect(r.data!.filter).toEqual(RULES);
@@ -2561,18 +2355,15 @@ describe('the seven `object-*` `filter` doors — one filter orthography platfor
describe('the four `object-*` `sort` doors — one sort orthography, the array', () => {
// `object-map` and `object-gantt` joined at #18305: both hand `schema.sort`
// to the SAME shared sink the grid and the calendar do
- // (`convertSortToQueryParams`, `core/src/utils/sort-query.ts`) —
- // `ObjectMap.tsx:743`, `ObjectGantt.tsx:739` at the pin `53ded82b`.
- // `object-tree` is deliberately NOT here: its fetch (`ObjectTree.tsx:473-484`)
- // carries `$filter`, `$top` and `$expand` and no `$orderby` at all, so its row
+ // (`convertSortToQueryParams`; read points recorded in `liveness/page.json`, row `regions`).
+ // `object-tree` is deliberately NOT here: its fetch carries `$filter`, `$top` and `$expand` and no `$orderby` at all, so its row
// declares no `sort` — a door with no read site is what this family refuses to
// publish.
const SORT_DOORS = ['object-grid', 'object-calendar', 'object-map', 'object-gantt'] as const;
const ARRAY_FORM = [{ field: 'created_at', order: 'desc' }];
/**
- * The legacy OData-ish clause `convertSortToQueryParams` honours at the
- * objectui pin `53ded82b` (`core/src/utils/sort-query.ts:66-70`) and that
- * `ObjectGrid.tsx:1845-1846` puts on `$orderby` verbatim. Retired by the
+ * The legacy OData-ish clause `convertSortToQueryParams` honoured when this
+ * was measured, and that the grid put on `$orderby` verbatim (read points recorded in `liveness/page.json`, row `regions`). Retired by the
* ruling; refused here.
*/
const STRING_FORM = 'created_at desc';
@@ -2957,7 +2748,8 @@ describe('RecordChatterProps', () => {
it("should accept exactly the renderer's position vocabulary", () => {
// `RecordChatterPanel` branches on right/left (docked) vs bottom
- // (in-flow) — measured at objectui pin 665661ab0932. One vocabulary.
+ // (in-flow) (read points recorded in `liveness/page.json`, row
+ // `regions`). One vocabulary.
const positions = ['bottom', 'right', 'left'] as const;
positions.forEach(position => {
const result = RecordChatterProps.parse({ position });
@@ -3534,186 +3326,17 @@ describe('object-* block props schemas — declared, so the props gate has a sch
// #16503 — the spec half of objectui#8172 (decision batch #68, 2026-09-07,
// option A: the contract declares the capability that already ships, is
-// documented and is in use). Measured at objectui `b9814b334` (re-read there 2026-10-14:
-// `plugin-kanban/src/types.ts`, `ObjectKanban.tsx` and `plugin-kanban.mdx` are
-// byte-identical across the hop from `1fb1ced36` (`git diff --quiet`), so the
-// default `:100`, the `$top` read `:764`, the `limit` row and the `limit: 250`
-// snippet did not move; `plugin-kanban/src/index.tsx` changed only below the
-// mapping (+2/-2, objectui#12030, objectui `c5406c201`: a comment re-cited to
-// `18.0.0-next.0`), which did not move from `488-492`; and `objectql.ts`
-// (+15/-27, the same commit) changed only above the member, which MOVED `4838`
-// -> `4826` byte-identical, still inside `ObjectKanbanSchema`. At `1fb1ced36`,
-// re-read there 2026-10-12:
-// every objectui file this record cites is byte-identical across the hop from
-// `7578323a5` (`git diff --quiet`), so every anchor held unmoved. At
-// `7578323a5`, re-read there 2026-10-12:
-// every objectui file this record cites is byte-identical across the hop from
-// `9646e2ed2` (`git diff --quiet`), so every anchor held unmoved. At
-// `9646e2ed2`, re-read there 2026-10-12:
-// every objectui file this record cites is byte-identical across the hop from
-// `088e0f705` (`git diff --quiet`), so every anchor held unmoved. At
-// `088e0f705`, re-read there 2026-10-12:
-// every objectui file this record cites is byte-identical across the hop from
-// `e5311165a` (`git diff --quiet`), so every anchor held unmoved. At
-// `e5311165a`, re-read there 2026-10-12:
-// every objectui file this record cites is byte-identical across the hop from
-// `499799502` (`git diff --quiet`), so every anchor held unmoved. At
-// `499799502`, re-read there 2026-10-11:
-// every objectui file this record cites is byte-identical across the hop from
-// `0df67f237` (`git diff --quiet`), so every anchor held unmoved. At
-// `0df67f237`, re-read there 2026-10-11:
-// `plugin-kanban/src/index.tsx`, `plugin-kanban/src/types.ts` and
-// `objectql.ts` are byte-identical across the hop from `20c6d351a` (`git diff
-// --quiet`), so the mapping `488-492` and the member `4838` did not move;
-// `ObjectKanban.tsx` changed (+21/-1, objectui#12082, objectui `5af42dbbd`:
-// the card move reads the affordance-to-grant map), two import lines above
-// `:98` and every other hunk below the fetch, so the default MOVED `:98` ->
-// `:100` and the `$top` read `:762` -> `:764`, both byte-identical; and
-// `plugin-kanban.mdx` changed in its drag-and-drop feature bullet only
-// (+5/-1, the same commit), above the `limit` row and the `limit: 250`
-// snippet, neither of which changed. At `20c6d351a`, re-read there
-// 2026-10-10:
-// every objectui file this record cites is byte-identical across the hop from
-// `47b1f0bb7` (`git diff --quiet`) except `objectql.ts` (+14/-13, comments
-// only: objectui#12063, objectui `c7b30bd66`, and objectui#6152 round 15,
-// objectui `025341692`, re-word the `object-chart` legacy-axis docblocks),
-// whose every hunk is below the member, at `:5441` or later, so the member
-// `4838` did not move and is byte-identical, still inside
-// `ObjectKanbanSchema`; the `$top` read `:762`, the default `:98`, the `limit`
-// row, the `limit: 250` snippet and the mapping `488-492` held unmoved. At
-// `47b1f0bb7`, re-read there 2026-10-09:
-// every objectui file this record cites is byte-identical across the hop from
-// `f0268ad78` (`git diff --quiet`), so every anchor held unmoved. At
-// `f0268ad78`, re-read there 2026-10-09:
-// `ObjectKanban.tsx`, `plugin-kanban/src/types.ts` and `plugin-kanban.mdx` are
-// byte-identical to `a58626c88` (`git diff --quiet`), so the `$top` read
-// `:762`, the default `:98`, the `limit` row and the `limit: 250` snippet did
-// not move or change; `plugin-kanban/src/index.tsx` changed only below the
-// mapping (+3/-3: a comment re-cited to 17.7.0, and objectui#6152 round 8's
-// `filter` input description), which did not move from `488-492`; and
-// `objectql.ts` (+218/-125: objectui#6152 rounds 7 to 12, objectui#11880 item 5
-// and the 17.7.0 moves) MOVED the member `4754` -> `4838` byte-identical, still
-// inside `ObjectKanbanSchema`. At `a58626c88`, re-read there 2026-10-06:
-// `ObjectKanban.tsx` changed (+65/-2, objectui#11629: each column header totals
-// the view's `summarizeField`), which MOVED the `$top` read `752` -> `762` and
-// the default `:97` -> `:98`, both byte-identical; `plugin-kanban.mdx` gained
-// one feature bullet above the `limit` row and the `limit: 250` snippet,
-// neither of which changed; and `plugin-kanban/src/index.tsx`,
-// `plugin-kanban/src/types.ts` and `objectql.ts` are byte-identical (`git diff
-// --quiet`), so `488-492` and `4754` did not move.
-// At `0abd4f9f8`, re-read there 2026-10-05:
-// every objectui file this record cites is byte-identical across the hop from
-// `9dfaca654` (`git diff --quiet`), so every anchor held unmoved.
-// At `9dfaca654`; re-measured there 2026-10-05 —
-// `plugin-kanban/src/types.ts` and `plugin-kanban.mdx` are byte-identical to
-// `2e818d0b5` (`git diff --quiet`), so `types.ts` still declares no `limit`
-// and the mdx still teaches `limit: 250` with its Properties row; the other
-// three files changed, so their anchors were re-READ, and each held or MOVED
-// with its text byte-identical. `ObjectKanban.tsx` (+35/-5, objectui#8347)
-// edited its type import in place (`:10`) and, below `:97` and above the
-// fetch, added a private `GateBoundKanbanSchema` read type, a re-worded
-// docblock and a widened `schema` binding, so the constant did not move and
-// the query line MOVED `722` -> `752`; `plugin-kanban/src/index.tsx` (+34/-3) gained one
-// docblock line above the mapping (objectui#8347) and objectui#11605's
-// `requiresObject` gate and non-required `objectName` input below it, so
-// `OBJECT_KANBAN_DATA_SOURCE` MOVED `487-491` -> `488-492`, still mapping
-// `limit: 'limit'`; `objectql.ts` (+85/-45: objectui#11615's section-entry
-// arm, objectui#11266's `InlineGridColumn` columns and objectui#8347 among
-// them) MOVED the member `4720` -> `4754`, still inside
-// `ObjectKanbanSchema`. At `2e818d0b5`, re-measured there 2026-10-04 —
-// `plugin-kanban/src/types.ts`, `ObjectKanban.tsx` and
-// `plugin-kanban/src/index.tsx` are byte-identical to `ab1879721`
-// (`git diff --quiet`), so `types.ts` still declares no `limit` and `:722` /
-// `:97` / `487-491` did not move; `plugin-kanban.mdx` gained a `grouping`
-// Properties row below the `limit` row (objectui#11216) and still teaches
-// `limit: 250`; `objectql.ts` changed only below the member (objectui#11216's
-// `grouping` declaration on `ObjectKanbanSchema`), so `:4720` did not move.
-// At `ab1879721`, re-measured there 2026-10-03 —
-// `plugin-kanban/src/types.ts`, `ObjectKanban.tsx` and `plugin-kanban.mdx` are
-// byte-identical to `89cad75d5` (`git diff --quiet`), so `types.ts` still
-// declares no `limit`, `:722` / `:97` did not move and were re-read in place,
-// and the mdx still teaches `limit: 250` with its Properties row; `index.tsx`
-// changed only below the mapping (objectui#11438's 17.6.0 re-citation in the
-// `ObjectKanbanRenderer` docblock and objectui#11522's `{ condition, style }`
-// description on the `conditionalFormatting` input), so `487-491` did not
-// move and still maps `limit: 'limit'`; `objectql.ts` MOVED the member `4661`
-// -> `4720` byte-identical, still inside `ObjectKanbanSchema` (the 59 lines
-// are declarations the range changed above it: the spec `{ condition, style }`
-// rule types of objectui#11533 / objectui#11522, `ObjectGridSchema`'s
-// `keyboardNavigation` of objectui#11068 and its 17.6.0 members of
-// objectui#11438 among them). At `89cad75d5`, re-measured there 2026-10-02 —
-// `plugin-kanban/src/types.ts` and `ObjectKanban.tsx` are byte-identical to
-// `31971ff1e` (`git diff --quiet`), so `types.ts` still declares no `limit`
-// and `:722` / `:97` did not move and were re-read in place; `index.tsx`
-// changed only in the `ObjectKanbanRenderer` docblock and the `navigation`
-// input's description (objectui#11293's record-navigator `page` mode), at
-// `:626` and below, so the mapping did not move from `487-491`; `objectql.ts`
-// MOVED the member `4588` -> `4661` byte-identical, still inside
-// `ObjectKanbanSchema` (the 73 lines are declarations eight objectui commits
-// of the range added above it); and `plugin-kanban.mdx` rewrote its
-// `navigation` Properties row and gained a `swimlaneField` row, both below the
-// `limit` row, which is byte-identical, and still teaches `limit: 250`. At
-// `31971ff1e`, re-measured there 2026-10-01 —
-// `plugin-kanban/src/types.ts` is byte-identical to `e420df310` and still
-// declares no `limit`; `ObjectKanban.tsx` changed only in the comment above
-// its `navigation` read (objectui#8652), below both anchors, so `:722` and
-// `:97` did not move; `index.tsx` changed below the mapping (objectui#8652's
-// `navigation` input), which did not move from `487-491`; `objectql.ts`
-// MOVED the member `4430` -> `4588` byte-identical, still inside
-// `ObjectKanbanSchema`; and `plugin-kanban.mdx` gained a `navigation`
-// Properties row below the `limit` row and still teaches `limit: 250`. At
-// `e420df310`, re-measured there 2026-09-30 —
-// `plugin-kanban/src/types.ts` is byte-identical to `db11afd49` and still
-// declares no `limit`; the other four files changed, so their anchors were
-// re-READ. `ObjectKanban.tsx` changed at BOTH anchors: objectui#9853 renamed
-// the default `DEFAULT_KANBAN_LIMIT` to `DEFAULT_KANBAN_FETCH_BATCH_SIZE`
-// (still 100, now documented as the board's fetch batch, not a page size) and
-// objectui#11234 moved the board into an internal `KanbanBoardCore`, so the
-// query line now reads `$top: resolveRowLimit(schema.limit,
-// DEFAULT_KANBAN_FETCH_BATCH_SIZE)` and moved `712` -> `722`, and the constant
-// `:88` -> `:97` — same cap, same default, a renamed name. `index.tsx` lost
-// the Quick Add plumbing above the mapping (objectui#8285, objectui#11234), so
-// `OBJECT_KANBAN_DATA_SOURCE` MOVED `506-510` -> `487-491` byte-identical;
-// `objectql.ts` MOVED the member `4302` -> `4430` byte-identical, still inside
-// `ObjectKanbanSchema`; `plugin-kanban.mdx` still teaches `limit: 250` and its
-// Properties row. At `db11afd49`, re-measured there 2026-09-29 —
-// `plugin-kanban.mdx`, `plugin-kanban/src/types.ts` and
-// `plugin-kanban/src/index.tsx` are byte-identical to `dd3f7e1be`;
-// `ObjectKanban.tsx` changed in one comment line (`:1367`), so `:712` and `:88`
-// did not move; `objectql.ts` gained declarations above the member, which is
-// still inside `ObjectKanbanSchema`, and MOVED `4139` -> `4302` with its text
-// byte-identical. At `dd3f7e1be`, re-measured there 2026-09-28 —
-// `plugin-kanban.mdx` is byte-identical to `f8a9d0fb0`; the other four files
-// changed, so their anchors were re-READ, and every one MOVED with its text
-// byte-identical: `ObjectKanban.tsx` gained three imports and, above the
-// fetch, objectui#10666's resolved `$filter` and objectui#10572's
-// invalidation re-read (`687` -> `712`, `:85` -> `:88`; its comments also
-// re-cite objectui#8307 as `5591f03bd`, objectui `1dae95a41`, one line for
-// one); `index.tsx` changed
-// above the mapping in exports and docblocks only (objectui#10582's
-// `ColumnWidthConfig`, objectui#8522's `useColumnWidths`), net one line up
-// (`507-511` -> `506-510`); `objectql.ts` grew above the member, which is
-// still inside `ObjectKanbanSchema` (`3832` -> `4139`); and `types.ts` only
-// dropped the same `ColumnWidthConfig` re-export and still declares no
-// `limit`. At `f8a9d0fb0` (2026-09-24) `types.ts` and `plugin-kanban.mdx`
-// were byte-identical to `62597c588`, `676` -> `687` and `:84` -> `:85` moved
-// with their text byte-identical, the mapping gained `sort: true` beside the
-// `limit` it cites (objectui#10068, `447-450` -> `507-511`), and the
-// `limit?: number` member moved `3735` -> `3832`. All five files were
-// byte-identical across the hop onto `62597c588`, and were last re-READ at
-// `87af769e9` 2026-09-20, the hop that moved every anchor and renamed one
-// face outright): `plugin-kanban/src/ObjectKanban.tsx:762`
-// queries `$top: resolveRowLimit(schema.limit, DEFAULT_KANBAN_FETCH_BATCH_SIZE)`
-// (100, `:98`; the bare `??` became `resolveRowLimit` in objectui#9925, which drops
-// and reports a cap the contract refuses),
-// `plugin-kanban/src/index.tsx:488-492` maps `limit: 'limit'` in
-// `OBJECT_KANBAN_DATA_SOURCE`, ⚠️ `KanbanSchema` is RETIRED at this pin and
-// `plugin-kanban/src/types.ts` declares the member no more — the published
-// twin is `ObjectKanbanSchema`, declaring `limit?: number` at
-// `packages/types/src/objectql.ts:4826` — and `content/docs/plugins/plugin-kanban.mdx`
-// teaches `limit: 250` with a Properties row. The strict map refused the key by
-// name — the same `unrecognized_keys` verdict as the `bogusProp` control — so an
-// author following the published docs wrote a node the save gate rejected.
+// documented and is in use). Read points recorded in `liveness/page.json`, row
+// `regions`: the board queries `$top: resolveRowLimit(schema.limit,
+// DEFAULT_KANBAN_FETCH_BATCH_SIZE)` (100; the bare `??` became
+// `resolveRowLimit` in objectui#9925, which drops and reports a cap the
+// contract refuses), the registration maps `limit: 'limit'` in
+// `OBJECT_KANBAN_DATA_SOURCE`, ⚠️ `KanbanSchema` is RETIRED and the published
+// twin is `ObjectKanbanSchema`, declaring `limit?: number` — and objectui's
+// kanban plugin guide teaches `limit: 250` with a Properties row. The strict
+// map refused the key by name — the same `unrecognized_keys` verdict as the
+// `bogusProp` control — so an author following the published docs wrote a node
+// the save gate rejected.
describe('ObjectKanbanPropsSchema limit — the row cap four objectui faces already implement', () => {
const kanban = ComponentPropsMap['object-kanban'];
@@ -3771,133 +3394,14 @@ describe('ObjectKanbanPropsSchema limit — the row cap four objectui faces alre
// named the React-host `kanban-ui` block as where it stays, and objectui has
// since retired that block, objectui#8257). Unlike `limit` above — a key four
// objectui faces already implemented, so the spec was the half that was wrong
-// — `quickAdd` was FORWARDED and never read: at objectui `b9814b334` (re-read there 2026-10-14:
-// every objectui file this record cites is byte-identical across the hop from
-// `1fb1ced36` (`git diff --quiet`), so every anchor held unmoved. At
-// `1fb1ced36`, re-read there 2026-10-12:
-// every objectui file this record cites is byte-identical across the hop from
-// `7578323a5` (`git diff --quiet`), so every anchor held unmoved. At
-// `7578323a5`, re-read there 2026-10-12:
-// every objectui file this record cites is byte-identical across the hop from
-// `9646e2ed2` (`git diff --quiet`), so every anchor held unmoved. At
-// `9646e2ed2`, re-read there 2026-10-12:
-// every objectui file this record cites is byte-identical across the hop from
-// `088e0f705` (`git diff --quiet`), so every anchor held unmoved. At
-// `088e0f705`, re-read there 2026-10-12:
-// every objectui file this record cites is byte-identical across the hop from
-// `e5311165a` (`git diff --quiet`), so every anchor held unmoved. At
-// `e5311165a`, re-read there 2026-10-12:
-// every objectui file this record cites is byte-identical across the hop from
-// `499799502` (`git diff --quiet`), so every anchor held unmoved. At
-// `499799502`, re-read there 2026-10-11:
-// every objectui file this record cites is byte-identical across the hop from
-// `0df67f237` (`git diff --quiet`), so every anchor held unmoved. At
-// `0df67f237`, re-read there 2026-10-11:
-// all three files changed across the hop from `20c6d351a` for one commit,
-// objectui#12082 (objectui `5af42dbbd`: a card is draggable only for a caller
-// the `kanbanCardMove` row of the affordance-to-grant map allows), no hunk on
-// a cited line, so every anchor MOVED with its line byte-identical:
-// `KanbanBoardCore.tsx` (+9/-0) `:78` -> `:85` and `:111-112` -> `:120-121`,
-// `ObjectKanban.tsx` (+21/-1) the spread `:1731` -> `:1751`, and
-// `KanbanImpl.tsx` (+30/-7) the gate `:671` / `:684` -> `:688` / `:701`, still
-// reading `quickAdd && onQuickAdd`; and the counts re-read the same, 2 / 2 /
-// 11. At `20c6d351a`, re-read there 2026-10-10:
-// `KanbanBoardCore.tsx` and `ObjectKanban.tsx` are byte-identical across the
-// hop from `47b1f0bb7` (`git diff --quiet`), so `:78`, `:111-112` and the
-// spread `:1731` did not move, and the counts re-read the same, 2 / 2 / 11;
-// `KanbanImpl.tsx` changed (+9/-6, objectui#6349 batch 7, objectui
-// `c0c0a0d56`: its rule type spelled `KanbanConditionalFormattingRule` by that
-// name, three lines of comment added above the props), so the gate MOVED
-// `:668` / `:681` -> `:671` / `:684`, both lines byte-identical and still
-// reading `quickAdd && onQuickAdd`. At `47b1f0bb7`, re-read there 2026-10-09:
-// `KanbanBoardCore.tsx`, `ObjectKanban.tsx` and `KanbanImpl.tsx` are
-// byte-identical across the hop from `f0268ad78` (`git diff --quiet`), so
-// `:78`, `:111-112`, the spread `:1731` and the gate `:668` / `:681` did not
-// move, and the counts re-read the same, 2 / 2 / 11. At `f0268ad78`, re-read
-// there 2026-10-09:
-// `KanbanBoardCore.tsx`, `ObjectKanban.tsx` and `KanbanImpl.tsx` are
-// byte-identical across the hop from `a58626c88` (`git diff --quiet`), so
-// `:78`, `:111-112`, the spread `:1731` and the gate `:668` / `:681` did not
-// move, and the counts re-read the same, 2 / 2 / 11. At `a58626c88`, re-read
-// there 2026-10-06:
-// `KanbanBoardCore.tsx` is byte-identical (`git diff --quiet`), so `:78` and
-// `:111-112` did not move; `ObjectKanban.tsx` (+65/-2) and `KanbanImpl.tsx`
-// (+48/-1) changed for objectui#11629 (each column header totals the view's
-// `summarizeField`), and every anchor in them MOVED with its line
-// byte-identical: the spread `1669` -> `1731`, still the `schema` bag handed to
-// `KanbanBoardCore`, and the gate `624` -> `668` and `637` -> `681`; and the
-// counts re-read the same, 2 / 2 / 11.
-// At `0abd4f9f8`, re-read there 2026-10-05:
-// every objectui file this record cites is byte-identical across the hop from
-// `9dfaca654` (`git diff --quiet`), so every anchor held unmoved.
-// At `9dfaca654`; re-measured there 2026-10-05 —
-// `KanbanBoardCore.tsx` and `KanbanImpl.tsx` are byte-identical to `2e818d0b5`
-// (`git diff --quiet`), so `:78`, `:111-112`, `:624` and `:637` did not move;
-// `ObjectKanban.tsx` changed above the spread (+35/-5, objectui#8347's private
-// `GateBoundKanbanSchema` read type and widened `schema` binding), which MOVED
-// `1639` -> `1669` with its line byte-identical, still the `schema` bag handed
-// to `KanbanBoardCore`; and the counts re-read the same, 2 / 2 / 11. At
-// `2e818d0b5`, re-measured there 2026-10-04 —
-// every objectui file this record cites is byte-identical across the hop from
-// `ab1879721` (`git diff --quiet`), so every anchor held unmoved. At
-// `ab1879721`, re-measured there 2026-10-03 —
-// `KanbanBoardCore.tsx` and `ObjectKanban.tsx` are byte-identical to
-// `89cad75d5` (`git diff --quiet`), so `:78`, `:111-112` and the spread
-// `:1639` did not move and were re-read in place, and the counts re-read the
-// same, 2 / 2 / 11; `KanbanImpl.tsx` changed only in two comments above the
-// gate (objectui#11522: card formatting is the spec `{ condition, style }`
-// rule alone, +8/-5), so both gate lines MOVED by 3 byte-identical, `621` ->
-// `624` and `634` -> `637`, and still read `quickAdd && onQuickAdd`. At
-// `89cad75d5`, re-measured there 2026-10-02 —
-// `KanbanImpl.tsx`, `KanbanBoardCore.tsx` and `ObjectKanban.tsx` are
-// byte-identical to `31971ff1e` (`git diff --quiet`), so `:621`, `:634`,
-// `:78`, `:111-112` and the spread `:1639` did not move and were re-read in
-// place, and the counts re-read the same, 2 / 2 / 11. At `31971ff1e`,
-// re-measured there 2026-10-01 —
-// `KanbanImpl.tsx` and `KanbanBoardCore.tsx` are byte-identical to
-// `e420df310`, so `:621`, `:634`, `:78` and `:111-112` did not move and were
-// re-read in place; `ObjectKanban.tsx` changed only in the comment above its
-// `navigation` read (objectui#8652), above the spread, which MOVED `1641` ->
-// `1639` with its line byte-identical; and the counts re-read the same, 2 /
-// 2 / 11. At `e420df310`, re-measured there 2026-09-30 —
-// `KanbanImpl.tsx` is byte-identical to `db11afd49`, so `:621` and `:634` did
-// not move and were re-read in place; `ObjectKanban.tsx` changed, carrying
-// objectui's own half of this retirement: objectui#8285 stopped forwarding
-// `quickAdd`, and objectui#11234 retired `onQuickAdd` and mounts an internal
-// `KanbanBoardCore` where it mounted `KanbanRenderer`. So the spread MOVED
-// `1614` -> `1641` with its line byte-identical, but it now feeds
-// `KanbanBoardCore`, which reads neither key off `schema` and takes the pair
-// only as explicit props (`KanbanBoardCore.tsx:78`, `:111-112`) that
-// `ObjectKanban` never passes. ⚠️ The 0 / 0 / 11 counts did NOT re-read the
-// same: `ObjectKanban.tsx` now spells `quickAdd` 2 times and `onQuickAdd` 2
-// times, all four inside the two objectui#11234 comments that record the cut,
-// so it still names neither half in code, against 11 for `onCardClick`. At
-// `db11afd49`, re-measured there 2026-09-29 —
-// `KanbanImpl.tsx` is byte-identical to `dd3f7e1be` and `ObjectKanban.tsx`
-// changed in one comment line (`:1367`), so `:1614`, `:621` and `:634` did not
-// move and were re-read in place, and the 0 / 0 / 11 counts re-read the same. At
-// `dd3f7e1be`, re-measured there 2026-09-28 —
-// `KanbanImpl.tsx` changed in three comment lines only (objectui `1dae95a41`
-// re-citing objectui#8307 as `5591f03bd`, one line for one), so `:621` /
-// `:634` did not move and re-read the same, and `ObjectKanban.tsx` changed
-// above the spread (objectui#10666's resolved `$filter`, objectui#10572's
-// invalidation re-read, objectui#10663's error clear), which MOVED `1578` ->
-// `1614` with its text byte-identical, still the `schema` bag handed to
-// `KanbanRenderer` — the same re-citation touched the comment on the line
-// below it, not the spread; at `f8a9d0fb0` (2026-09-24) it
-// had MOVED `1563` -> `1578` the same way (objectui#10068's `$orderby`); both
-// files were byte-identical across the hop onto `62597c588`, and every anchor
-// was re-READ at `87af769e9` 2026-09-20) `ObjectKanban.tsx:1731`
-// spreads the
-// authored bag into `KanbanBoardCore` (into `KanbanRenderer` until
-// objectui#11234, which reads the pair off it no more) and `KanbanImpl` gates the affordance on
-// `quickAdd && onQuickAdd` (`KanbanImpl.tsx:671`, `:684` — the file is spelled
-// here because those two ranges are NOT in `ObjectKanban.tsx`), while
-// `onQuickAdd` is a
-// host-supplied FUNCTION no producer puts on an `object-kanban` node
-// (`ObjectKanban.tsx` names neither half in code: 0 each re-counted at this pin
-// outside the two comments that record objectui's cut, 2 each with them,
-// against 11 for the sibling `onCardClick` in the same file).
+// — `quickAdd` was FORWARDED and never read (read points recorded in
+// `liveness/page.json`, row `regions`): the board spreads the authored bag into
+// `KanbanBoardCore` (into `KanbanRenderer` until objectui#11234, which reads
+// the pair off it no more), `KanbanImpl` gates the affordance on
+// `quickAdd && onQuickAdd`, and `onQuickAdd` is a host-supplied FUNCTION no
+// producer puts on an `object-kanban` node (`ObjectKanban` names neither half
+// in code: 0 each outside the two comments that record objectui's cut, 2 each
+// with them, against 11 for the sibling `onCardClick` in the same file).
describe('ObjectKanbanPropsSchema quickAdd is retired', () => {
const kanban = ComponentPropsMap['object-kanban'];
@@ -3991,131 +3495,27 @@ describe('ObjectKanbanPropsSchema quickAdd is retired', () => {
// that sent #9397 on a full dispatch cycle re-deriving the accordion read point.
// #9881 and commit 60e0f900a recorded the accordion and tab items; these two close the set.
//
-// The button record re-measured at objectui `b9814b334`, re-read there 2026-10-14:
-// every objectui file this record cites is byte-identical across the hop from
-// `1fb1ced36` (`git diff --quiet`), so every anchor held unmoved. At
-// `1fb1ced36`, re-read there 2026-10-12:
-// every objectui file this record cites is byte-identical across the hop from
-// `7578323a5` (`git diff --quiet`), so every anchor held unmoved. At
-// `7578323a5`, re-read there 2026-10-12:
-// every objectui file this record cites is byte-identical across the hop from
-// `9646e2ed2` (`git diff --quiet`), so every anchor held unmoved. At
-// `9646e2ed2`, re-read there 2026-10-12:
-// every objectui file this record cites is byte-identical across the hop from
-// `088e0f705` (`git diff --quiet`), so every anchor held unmoved. At
-// `088e0f705`, re-read there 2026-10-12:
-// every objectui file this record cites is byte-identical across the hop from
-// `e5311165a` (`git diff --quiet`), so every anchor held unmoved. At
-// `e5311165a`, re-read there 2026-10-12:
-// every objectui file this record cites is byte-identical across the hop from
-// `499799502` (`git diff --quiet`), so every anchor held unmoved. At
-// `499799502`, re-read there 2026-10-11:
-// every objectui file this record cites is byte-identical across the hop from
-// `0df67f237` (`git diff --quiet`), so every anchor held unmoved. At
-// `0df67f237`, re-read there 2026-10-11:
-// every objectui file this record cites is byte-identical across the hop from
-// `20c6d351a` (`git diff --quiet`), so every anchor held unmoved. At
-// `20c6d351a`, re-read there 2026-10-10:
-// every objectui file this record cites is byte-identical across the hop from
-// `47b1f0bb7` (`git diff --quiet`), so every anchor held unmoved. At
-// `47b1f0bb7`, re-read there 2026-10-09:
-// every objectui file this record cites is byte-identical across the hop from
-// `f0268ad78` (`git diff --quiet`), so every anchor held unmoved. At
-// `f0268ad78`, re-read there 2026-10-09:
-// every objectui file this record cites is byte-identical across the hop from
-// `a58626c88` (`git diff --quiet`), so every anchor held unmoved. At
-// `a58626c88`, re-read there 2026-10-06:
-// every objectui file this record cites is byte-identical across the hop from
-// `0abd4f9f8` (`git diff --quiet`), so every anchor held unmoved.
-// At `0abd4f9f8`, re-read there 2026-10-05:
-// every objectui file this record cites is byte-identical across the hop from
-// `9dfaca654` (`git diff --quiet`), so every anchor held unmoved.
-// At `9dfaca654`, re-derived there 2026-10-05: every objectui
-// file this record cites (`button.tsx` read as both the `renderers/form`
-// registration and the `ui` primitive) is byte-identical to `2e818d0b5`
-// (`git diff --quiet`), so every anchor below holds unmoved. At `2e818d0b5`,
-// re-derived there 2026-10-04: every objectui
-// file this record cites is byte-identical to `ab1879721` (`git diff --quiet`),
-// so every anchor below holds unmoved. At `ab1879721`, re-derived there
-// 2026-10-03: `button.tsx`,
-// `lazy-icon.tsx`, `resolve-icon.ts` and the generated
-// `lucide-record-icon-names.ts` are byte-identical to `89cad75d5`
-// (`git diff --quiet`), so every anchor below holds unmoved and was re-read in
-// place. At `89cad75d5`, 2026-10-02: `button.tsx`,
-// `lazy-icon.tsx`, `resolve-icon.ts` and the generated
-// `lucide-record-icon-names.ts` are byte-identical to `31971ff1e`
-// (`git diff --quiet`), so every anchor below holds unmoved and was re-read in
-// place. At `31971ff1e`, 2026-10-01: `button.tsx`,
-// `lazy-icon.tsx`, `resolve-icon.ts` and the generated
-// `lucide-record-icon-names.ts` are byte-identical to `e420df310`
-// (`git diff --quiet`), so every anchor below holds unmoved and was re-read in
-// place. At `e420df310`, 2026-09-30: `button.tsx`,
-// `lazy-icon.tsx`, `resolve-icon.ts` and the generated
-// `lucide-record-icon-names.ts` are byte-identical to `db11afd49`, so every
-// anchor below holds unmoved and was re-read in place. At `db11afd49`,
-// 2026-09-29: `button.tsx`,
-// `lazy-icon.tsx` and `resolve-icon.ts` are byte-identical to `dd3f7e1be`, so
-// every anchor below holds unmoved. At `dd3f7e1be`, 2026-09-28: `button.tsx` and
-// `lazy-icon.tsx` are byte-identical to `f8a9d0fb0` (`git diff --quiet`), so
-// the `:43` / `:72` / `:74` anchors below hold by identity, and
-// `resolve-icon.ts` changed (42 insertions, 17 deletions, objectui
-// `fb336df01`: lucide-react 1.31.0 -> 1.43.0), so its anchors were re-READ:
-// `toPascalCase` `:153-158` and the rename map `:143-145` did not move, and
-// `describeIconLookup` `302-305` -> `327-330` and `resolveIcon` `322-328` ->
-// `347-353` MOVED byte-identical. What changed in the file sits past the
-// name lookup — the lazily loaded module's path data is now read from
-// `__iconData.node` before `__iconNode`, the `IconNode` type is narrowed with
-// `NonNullable`, and the `lucideClassNames` docblock was rewritten over
-// unchanged code — so the SPELLINGS an author may write resolve exactly as
-// before. The VOCABULARY moved with the bump, in the generated table
-// `recordIconName` decodes (`lib/lucide-record-icon-names.ts`, 1781 -> 1818
-// entries): 38 names in and one out, `Trash2`, so `trash-2` now resolves to
-// `null` and draws nothing, like any unknown name. At `f8a9d0fb0`
-// (2026-09-24) `resolve-icon.ts` and `lazy-icon.tsx` were byte-identical to `62597c588`
-// and `87af769e9`, and `button.tsx` changed only inside its registration's
-// input list (objectui#9910 added a `children` slot input, no `icon` one), so
-// the button anchors did not move; all three files were byte-identical across
-// the hop onto `62597c588`. The hop before that,
-// onto `87af769e9` (re-derived 2026-09-20), moved both files in this chain —
-// `resolve-icon.ts` +203/-7 and `button.tsx` +6/-11 against `53ded82bf` — so
-// no anchor below was carried there and every one was re-READ (commit d1ba685ec). ⚠️ `resolveIcon` itself was rewritten: its tail no
-// longer indexes `lucide-react`'s `icons` record, it asks `recordIconName`
-// for the kebab-case name and hands the pair to `lazyIconComponent`, so the
-// glyph arrives lazily. What an author may write did not change with it. The
-// earlier hop
-// onto `00d3f09c5` was the one that changed this record's SUBSTANCE and not
-// merely its line numbers: `resolve-icon.ts` was restructured (110
-// insertions), so `resolveIcon` no longer PascalCases and maps inline — it
-// delegates to the `describeIconLookup` seam (now `:327-330`), and the tokeniser
-// splits on hyphen, underscore AND whitespace (`/[-_\s]+/`), where this record
-// used to say "splits on `-` only". That sentence was true when written and
-// was false by then, which is exactly why a citation refresh re-READS instead
-// of moving numbers (commit d1ba685ec).
-// The one move that changed the button READ POINT and not merely its line
-// numbers was the one onto `9602dc820`: objectui#5993 deleted `button.tsx`'s
-// file-local `toPascalCase` + `iconNameMap` + `icons` index and routed the
-// button through the SHARED `resolveIcon` that every `action:*` site already
-// used, so the resolution anchor hops into `renderers/action/resolve-icon.ts`.
-// What an author sees did not move with it: an unknown name still resolves to
-// `null` and draws nothing, which is still the `LazyIcon` contrast the third
-// test below pins. The moves before that were line-number drift only — #10137
-// moved the pin while the #9881 / commit 60e0f900a records still cited `82a94170c`, commit d1ba685ec re-measured
-// those four onto `9a3daf8d3`, and `button.tsx` was byte-identical at
-// `9a3daf8d3` and `190fbd01d`.
+// The button record's read points are recorded in `liveness/page.json`, row
+// `regions`. The one move that changed the button READ POINT and not merely its
+// line numbers was objectui#5993: it deleted the button's file-local
+// `toPascalCase` + `iconNameMap` + `icons` index and routed the button through
+// the SHARED `resolveIcon` that every `action:*` site already used. What an
+// author sees did not move with it: an unknown name still resolves to `null`
+// and draws nothing, which is still the `LazyIcon` contrast the third test
+// below pins. The resolver's tokeniser splits on hyphen, underscore AND
+// whitespace (`/[-_\s]+/`); it asks `recordIconName` for the kebab-case name
+// and hands the pair to `lazyIconComponent`, so the glyph arrives lazily.
describe('ElementButtonPropsSchema icon liveness', () => {
const button = ComponentPropsMap['element:button'];
it('accepts an icon on a button — the value objectui resolves through the lucide `icons` map', () => {
- // objectui `packages/components/src/renderers/form/button.tsx:43` hands the
- // name to the shared `resolveIcon`
- // (`packages/components/src/renderers/action/resolve-icon.ts:347-353`),
- // which delegates to `describeIconLookup` (`:327-330`): that PascalCases
- // through `toPascalCase` (`:153-158`, splitting on hyphen, underscore or
- // whitespace) and applies the one-entry rename map (`:143-145`) before the
- // lookup, which at this pin runs through `recordIconName` +
- // `lazyIconComponent` rather than indexing `icons` from `lucide-react`
- // directly; `button.tsx:72` / `:74`
- // draw it either side of the label per `iconPosition`.
+ // The button renderer hands the name to the shared `resolveIcon`, which
+ // delegates to `describeIconLookup`: that PascalCases through
+ // `toPascalCase` (splitting on hyphen, underscore or whitespace) and
+ // applies the one-entry rename map before the lookup, which runs through
+ // `recordIconName` + `lazyIconComponent` rather than indexing `icons` from
+ // `lucide-react` directly; the renderer draws it either side of the label
+ // per `iconPosition`.
const result = button.safeParse({ label: 'Save', icon: 'arrow-right' });
expect(result.success).toBe(true);
const parsed = (result.success ? result.data : undefined) as { icon?: string } | undefined;
@@ -4156,14 +3556,10 @@ describe('ObjectMetricPropsSchema icon liveness', () => {
const metric = ComponentPropsMap['object-metric'];
it('accepts an icon on the metric tile — the value objectui resolves via getLazyIcon', () => {
- // objectui `plugin-dashboard/src/index.tsx:299` publishes the input
- // (this read `:161` until the `a472b0716` re-measure: wrong since written,
- // not shifted — that line is a sentence in the registry shell's docblock,
- // not the `object-metric` registration's `icon` input, and the file is
- // byte-identical at both pins, so only a re-READ could find it);
- // `ObjectMetricWidget.tsx:142` destructures it and forwards it at `:474` to
- // `MetricWidget`, which resolves it at `MetricWidget.tsx:312-321` and draws
- // it at `:373-382` in the `colorVariant`-tinted square.
+ // The `object-metric` registration publishes the input; `ObjectMetricWidget`
+ // destructures it and forwards it to `MetricWidget`, which resolves it and
+ // draws it in the `colorVariant`-tinted square (read points recorded in
+ // `liveness/page.json`, row `regions`).
const result = metric.safeParse({ objectName: 'task', icon: 'circle-alert' });
expect(result.success).toBe(true);
const parsed = (result.success ? result.data : undefined) as { icon?: string } | undefined;
@@ -4194,148 +3590,8 @@ describe('ObjectMetricPropsSchema icon liveness', () => {
// 「8348 以协议为准」 (batch #83, 2026-09-08) and batch #136 item 3 (Q1-C).
//
// The acceptance the card names, pinned: each row's KEY SET is the one the
-// renderer's read points support at objectui `b9814b334` (re-read there 2026-10-14:
-// every objectui file this record cites is byte-identical across the hop from
-// `1fb1ced36` (`git diff --quiet`), so every anchor held unmoved. At
-// `1fb1ced36`, re-read there 2026-10-12:
-// every objectui file this record cites is byte-identical across the hop from
-// `7578323a5` (`git diff --quiet`), so every anchor held unmoved. At
-// `7578323a5`, re-read there 2026-10-12:
-// every objectui file this record cites is byte-identical across the hop from
-// `9646e2ed2` (`git diff --quiet`), so every anchor held unmoved. At
-// `9646e2ed2`, re-read there 2026-10-12:
-// every objectui file this record cites is byte-identical across the hop from
-// `088e0f705` (`git diff --quiet`), so every anchor held unmoved. At
-// `088e0f705`, re-read there 2026-10-12:
-// every objectui file this record cites is byte-identical across the hop from
-// `e5311165a` (`git diff --quiet`), so every anchor held unmoved. At
-// `e5311165a`, re-read there 2026-10-12:
-// every objectui file this record cites is byte-identical across the hop from
-// `499799502` (`git diff --quiet`), so every anchor held unmoved. At
-// `499799502`, re-read there 2026-10-11:
-// `ObjectTree.tsx`, `ObjectMap.tsx` and `record-source.ts` are byte-identical
-// across the hop from `0df67f237` (`git diff --quiet`), so every anchor in them
-// held unmoved; `ObjectGantt.tsx` +27/-4 changed for objectui#12082 (objectui
-// `752504520`: the chart's in-chart writes read the affordance-to-grant map,
-// so a bar's drag, its links and the row Delete are handlers withheld from a
-// caller without the grant), no hunk on a `schema.*` read, and the set of
-// `schema.*` keys it reads is the same at both pins (49 names). At
-// `0df67f237`, re-read there 2026-10-11:
-// every objectui file this record cites is byte-identical across the hop from
-// `20c6d351a` (`git diff --quiet`), so every anchor held unmoved. At
-// `20c6d351a`, re-read there 2026-10-10:
-// every objectui file this record cites is byte-identical across the hop from
-// `47b1f0bb7` (`git diff --quiet`), so every anchor held unmoved. At
-// `47b1f0bb7`, re-read there 2026-10-09:
-// every objectui file this record cites is byte-identical across the hop from
-// `f0268ad78` (`git diff --quiet`), so every anchor held unmoved. At
-// `f0268ad78`, re-read there 2026-10-09:
-// `ObjectGantt.tsx`, `ObjectTree.tsx` and `record-source.ts` are byte-identical
-// across the hop off `a58626c88` (`git diff --quiet`), so every anchor in them
-// held unmoved, the tree's three reads at `:714`, `:945` and `:1135`;
-// `ObjectMap.tsx` +85/-4 changed for objectui#11819 (without WebGL2 the map
-// lists its records instead of crashing), none of it on a read, and the set of
-// `schema.*` keys each renderer reads is the same at both pins. At `a58626c88`,
-// re-read there 2026-10-06:
-// `ObjectMap.tsx`, `ObjectGantt.tsx` and `record-source.ts` are byte-identical
-// across the hop off `0abd4f9f8` (`git diff --quiet`), so every anchor in them
-// held unmoved; `ObjectTree.tsx` +81/-3 changed for objectui#11686 (a tree cell
-// draws the same field face a list cell does), none of it on a cited line, so
-// the tree's rung-1 call `resolveRecordSourceConfig(schema, 'view-data')` MOVED
-// `:637` -> `:714`, its shorthand read `(rest as any).data` `:868` -> `:945`
-// and its `schema.navigation` read `:1057` -> `:1135`, each byte-identical, and
-// the set of `schema.*` keys each renderer reads is the same at both pins.
-// At `0abd4f9f8`, re-read there 2026-10-05:
-// every objectui file this record cites is byte-identical across the hop from
-// `9dfaca654` (`git diff --quiet`), so every anchor held unmoved.
-// At `9dfaca654`; re-measured there 2026-10-05 —
-// `ObjectMap.tsx` and `record-source.ts` are byte-identical across the hop off
-// `2e818d0b5` (`git diff --quiet`), so every anchor in them held unmoved;
-// `ObjectTree.tsx` +8/-5 and `ObjectGantt.tsx` +4/-3 changed in docblocks only
-// (objectui#8347 putting `BaseSchema`'s index signature in the past tense), so
-// the tree's rung-1 call `resolveRecordSourceConfig(schema, 'view-data')`
-// MOVED `:634` -> `:637`, its shorthand read `(rest as any).data` `:865` ->
-// `:868` and its `schema.navigation` read `:1054` -> `:1057`, each
-// byte-identical, and the set of `schema.*` keys each renderer reads is the
-// same at both pins. At `2e818d0b5`, re-measured there 2026-10-04 —
-// `ObjectMap.tsx`, `ObjectTree.tsx`, `ObjectGantt.tsx` and `record-source.ts`
-// are byte-identical across the hop off `ab1879721` (`git diff --quiet`), so
-// every anchor in them held unmoved. At `ab1879721`, re-measured there
-// 2026-10-03 —
-// `ObjectMap.tsx`, `ObjectTree.tsx` and `record-source.ts` are byte-identical
-// across the hop off `89cad75d5` (`git diff --quiet`), so every anchor in them
-// held unmoved; `ObjectGantt.tsx` +8/-0 gained one import line and, in the
-// tooltip's `percent` row, a `percentCellScale(def)` argument scaling at the
-// field definition's declared storage (objectui#11475) — a field-definition
-// read, not a node key — so the set of `schema.*` keys each renderer reads is
-// the same at both pins. At `89cad75d5`, 2026-10-02 — all four
-// cited files changed on the hop off `31971ff1e`, so each was re-READ, and
-// the set of `schema.*` keys each renderer reads is the same at both pins.
-// `ObjectMap.tsx` +11/-4: the shadowed-flat-key warning reads `schema[key]`
-// typed instead of through a cast (objectui#11355), and the declared `map`
-// block's return path now takes the same `style` as every other path,
-// `mapStyle` first, then `map.style` (objectui#11168 slice 3) — the two keys
-// it reads are unchanged, and the `style` line MOVED `400` -> `407`
-// byte-identical. `ObjectGantt.tsx` +47/-10: the same typed shadowed-key read
-// (objectui#11355) and the tooltip's number and percent rows taking their
-// width from the field definition's `scale` through `resolveFieldScale`
-// (objectui#11254) — a field-definition read, not a node key.
-// `ObjectTree.tsx` +8/-17: the `navigation` read lost its cast
-// (`(schema as any).navigation` `:1063` -> `schema.navigation` `:1054`,
-// objectui#11168 slice 3 declaring it), the same key; the rung-1 call
-// `resolveRecordSourceConfig(schema, 'view-data')` `:634` and the shorthand
-// read `(rest as any).data` `:865` did not move. ⚠️ `record-source.ts`
-// +4/-5 no longer lists FOUR tree tags as `view-data`: objectui `990a2d616`
-// (objectui#10859 batch 8) retired the bare `tree` / `view:tree` node types,
-// so the arm table keeps `object-tree` and `plugin-tree:object-tree` only,
-// still `view-data`. The in-test notes below stay dated to the pins they
-// name. At `31971ff1e`, 2026-10-01 — `ObjectMap.tsx`, `ObjectGantt.tsx`,
-// `ObjectTree.tsx` and `record-source.ts` were byte-identical across the hop
-// off `e420df310` (`git diff --quiet`), so every anchor held unmoved and the
-// set of `schema.*` keys each renderer reads was the one recorded at
-// `e420df310`. At `e420df310`, 2026-09-30 — all
-// three renderers changed on the hop off `db11afd49`, `ObjectMap.tsx` in one docblock
-// only, `ObjectGantt.tsx` +85/-26 (objectui#11141's inclusive date-only end,
-// objectui#8348, objectui#11070) and `ObjectTree.tsx` +29/-26, and the set of
-// `schema.*` keys each reads is the same at both pins. ⚠️ One read changed
-// CONTENT, in the direction of this row: objectui#8348 (objectui `846cec0ef`)
-// moved the tree's rung-1 call from `resolveRecordSourceConfig(schema,
-// 'undeclared')` to `'view-data'` (`ObjectTree.tsx:632` -> `:634`), the arm its
-// siblings pass, and `record-source.ts` now lists the four tree tags as
-// `view-data`; and the shorthand read `(rest as any).data ?? schema.data`
-// became `(rest as any).data` (`:862` -> `:865`), so the renderer no longer
-// honours an authored bare array at all. The in-test notes below that say the
-// tree's arm is `'undeclared'` and WIDER than this row are the `87af769e9`
-// reading they are dated to; at this pin the renderer and the row agree. At
-// `db11afd49`, 2026-09-29 — `ObjectMap.tsx`
-// is byte-identical to `dd3f7e1be`, `ObjectTree.tsx` changed in one comment line
-// and `ObjectGantt.tsx` in its date-only DST handling and citations, and the set
-// of `schema.*` keys each reads is the same at both pins. At `dd3f7e1be`,
-// 2026-09-28: all three
-// renderers changed on this hop, `ObjectMap.tsx` +193/-72, `ObjectGantt.tsx`
-// +285/-56 and `ObjectTree.tsx` +136/-30, so each was re-READ: no declared key
-// set moved. The set of `schema.*` keys the code reads is the same at both
-// pins in all three files; what changed is how reads are MADE — each now
-// resolves its own `filter` through `useResolvedFilter` before the fetch
-// (objectui#10666) and re-reads on the data-invalidation bus — while the
-// tree's fetch still carries no `$orderby`, so `sort` stays off its row, and
-// `record-source.ts` lost only the retired bare `map` / `view:map` arm entries
-// (objectui#10393). At `f8a9d0fb0` (2026-09-24) the map's `ObjectMap.tsx` was
-// byte-identical to `62597c588`, and the gantt and tree renderers changed and
-// were re-READ with no declared key set moving (the gantt's new
-// host-generated `search` / `searchableFields` reads, objectui#10250, stay
-// undeclared and are recorded in its header; the tree's `filter.tree` stash
-// read was deleted, objectui#9549). At `62597c588`
-// the gantt and tree renderers were byte-identical to `87af769e9`, and the
-// map's `ObjectMap.tsx` had changed only in a docblock and a dev-warning
-// string (objectui `2252653d0`), so its anchors MOVED with their cited text
-// byte-identical and no key set moved. They were re-READ at `87af769e9`
-// 2026-09-22 — all three renderers moved hard on the hop from `53ded82bf`,
-// so NO anchor in this block was carried and every one was re-derived. Four
-// changed CONTENT rather than position and say so where they are cited: the
-// map's array-shorthand head, the tree's record-source ARM, the cast on the
-// tree's `schema.data` read, and the tree's `titleField` rung), and
-// `Object.keys(ComponentPropsMap)` lists the three. The key sets are asserted
+// renderer's read points support (recorded in `liveness/page.json`, row
+// `regions`), and `Object.keys(ComponentPropsMap)` lists the three.
// WHOLE rather than by spot-check — a row derived from read points is a claim
// about a complete set, and only an equality can hold a later addition to
// having been measured too.
@@ -4351,29 +3607,24 @@ describe('object-map / object-gantt / object-tree — key sets derived from the
};
it('object-map declares exactly its measured read set', () => {
- // ObjectMap.tsx @ 87af769e9: data (:183 — `getDataConfig` is now that one
- // `resolveRecordSourceConfig(schema, 'view-data')` statement; the
- // array-shorthand head that used to open it is GONE, and the docblock at
- // :168-176 records that an authored array now reaches this renderer only
- // through the React props channel), staticData / objectName (the shared
- // ladder's rungs 2 and 3, record-source.ts :296 and :303), filter (:814
- // and :895 — the inline and the object fetch), sort (:815 and :896), map
- // (:382), mapStyle (:377), navigation (:1042), enableClustering (:1058).
+ // One key per read point: data (the shared ladder's rung 1 — the
+ // array-shorthand head that used to open `getDataConfig` is GONE, so an
+ // authored array reaches this renderer only through the React props
+ // channel), staticData / objectName (rungs 2 and 3), filter and sort (the
+ // inline and the object fetch), map, mapStyle, navigation,
+ // enableClustering (read points recorded in `liveness/page.json`, row
+ // `regions`).
expect(keysOf('object-map')).toEqual([
'data', 'enableClustering', 'filter', 'map', 'mapStyle', 'navigation', 'objectName', 'sort', 'staticData',
]);
});
it('object-gantt declares exactly its measured read set', () => {
- // ObjectGantt.tsx @ 87af769e9: the ladder (:613), filter (:844), sort
- // (:845), gantt (:501-503), navigation (:1615), label (:2181 — the
- // `resolveI18nLabel` call in the export-file-name chain; the retired
- // reading :1849 was the COMMENT above that chain even at its own pin, and
- // at this one is a BLANK line two above an unrelated callback's comment),
- // skipWeekends (:1333), holidays (:1334), persistLayout (:1485),
- // viewName (:1487), markers (:2136),
- // criticalPath (:2139), showBaselines (:2142), readOnly (:1985 and
- // :2143), mobileReadOnly (:2144).
+ // One key per read point: the ladder, filter, sort, gantt, navigation,
+ // label (the i18n-label call in the export-file-name chain), skipWeekends,
+ // holidays, persistLayout, viewName, markers, criticalPath, showBaselines,
+ // readOnly, mobileReadOnly (read points recorded in `liveness/page.json`,
+ // row `regions`).
expect(keysOf('object-gantt')).toEqual([
'criticalPath', 'data', 'filter', 'gantt', 'holidays', 'label', 'markers', 'mobileReadOnly',
'navigation', 'objectName', 'persistLayout', 'readOnly', 'showBaselines', 'skipWeekends',
@@ -4383,21 +3634,13 @@ describe('object-map / object-gantt / object-tree — key sets derived from the
it('object-tree declares exactly its measured read set — and `data` IS in it', () => {
// The card's open question, answered by measurement rather than by family
- // symmetry: ObjectTree.tsx @ 87af769e9 reaches `schema.data` through
- // `resolveRecordSourceConfig(schema, 'undeclared')` at :582 — rung 1 of
- // the shared ladder, which returns the authored value VERBATIM. That
- // ONE site is the whole support for the object arm, and it is sufficient.
- // ⚠️ The ARM is `'undeclared'` here, not the `'view-data'` its siblings
- // pass, so rung 1 honours any truthy value at the renderer — WIDER than
- // this row, which is the harmless direction: the door below refuses the
- // bare array the renderer would have taken.
- // ⛔ :775 is NOT a second one: `(rest as any).data ?? schema.data` (the
- // cast on `schema` went away with objectui#8655) is gated by
- // `Array.isArray(passed)` on the next line, so it honours only
- // the bare-ARRAY shorthand this row REFUSES (pinned below). objectui#9234
- // left the rung-1 read marked `undeclared` because neither published face
- // carried the key; the protocol row follows the READ POINTS, which is what
- // 「以协议为准」 resolving for this block means.
+ // symmetry: the tree renderer reaches `schema.data` through the shared
+ // ladder's rung 1, which returns the authored value VERBATIM. That ONE
+ // site is the whole support for the object arm, and it is sufficient; the
+ // host-prop `data` beside it is not a second one, it honours only the
+ // bare-ARRAY shorthand this row REFUSES (pinned below). The protocol row
+ // follows the READ POINTS, which is what 「以协议为准」 resolving for this
+ // block means (read points recorded in `liveness/page.json`, row `regions`).
expect(keysOf('object-tree')).toEqual([
'data', 'filter', 'navigation', 'objectName', 'staticData', 'tree',
]);
@@ -4469,19 +3712,17 @@ describe('object-map / object-gantt / object-tree — key sets derived from the
// renderer's flat branch still reads beside `dependenciesField`.
expect(setFor('object-gantt', 'OBJECT_GANTT_FLAT_CONFIG_KEYS'))
.toEqual([...Object.keys(GanttConfigSchema.shape), 'dependencyField'].sort());
- // tree: `TreeConfigSchema`'s shape PLUS `titleField`. ⚠️ Re-READ at
- // 87af769e9 and the read point is GONE, not moved: objectui#8841 deleted
- // the `?? schema.titleField` rung from `getTreeConfig` (now :235-248),
- // and the docblock above it (:197-218) records why — it read the
- // FLATTENED NODE, never the block, and the key is declared on neither
- // face. The key stays in THIS set, and the prescription that names it
+ // tree: `TreeConfigSchema`'s shape PLUS `titleField`. ⚠️ The read point is
+ // GONE, not moved: objectui#8841 deleted the `?? schema.titleField` rung
+ // from `getTreeConfig`, and the docblock above it records why — it read
+ // the FLATTENED NODE, never the block, and the key is declared on neither
+ // face (read points recorded in `liveness/page.json`, row `regions`). The key stays in THIS set, and the prescription that names it
// stays TRUE, on the OTHER half of the sentence: `ListView`'s flatten
- // still resolves `treeCfg.titleField` into `labelField` before emitting
- // (`ListView.tsx:3270` at this pin), so an authored `titleField` is still
- // only ever the block's `labelField`. What died is the renderer's own
- // fallback, not the flatten's. At `20c6d351a` the flatten's rung is gone
- // too (objectui#6152 round 14, objectui `3fd862510`: `ListView.tsx:3985`
- // reads `treeCfg.labelField || 'name'`), so no half reads `titleField`;
+ // resolved `treeCfg.titleField` into `labelField` before emitting, so an
+ // authored `titleField` was only ever the block's `labelField`. What died
+ // first is the renderer's own fallback, not the flatten's. The flatten's
+ // rung is gone too (objectui#6152 round 14, objectui `3fd862510`: it reads
+ // `treeCfg.labelField || 'name'`), so no half reads `titleField`;
// it stays in the set for the prescription it carries, which names
// `tree.labelField` (see `OBJECT_TREE_FLAT_CONFIG_GUIDANCE`).
expect(setFor('object-tree', 'OBJECT_TREE_FLAT_CONFIG_KEYS'))
@@ -4489,7 +3730,7 @@ describe('object-map / object-gantt / object-tree — key sets derived from the
});
it('the config blocks are the spec own schemas where the renderer names one, `z.unknown()` where it does not', () => {
- // gantt: `ObjectGantt.tsx:503` validates the authored block against
+ // gantt: the renderer validates the authored block against
// `GanttConfigSchema` imported from `@objectstack/spec/ui`, so the read
// point names the schema and the door takes it — a misspelling inside the
// block is refused here exactly as the renderer's own safeParse warns.
@@ -4504,7 +3745,7 @@ describe('object-map / object-gantt / object-tree — key sets derived from the
expect(door('object-tree').safeParse({ tree: { labelFeild: 'name' } }).success).toBe(false);
// map: `ListMapConfigSchema` — the ratchet the previous posture deferred,
// taken now that `style` is declared on that block (the key `getMapConfig`
- // reads at `ObjectMap.tsx:377`, `schema.mapStyle || schema.map?.style`). The
+ // reads, `schema.mapStyle || schema.map?.style`). The
// two assertions that used to record the divergence are INVERTED here: the
// list-view face accepts the style URL, and the door accepts it through the
// spec's own schema rather than through an open value.
@@ -4547,7 +3788,8 @@ describe('object-map / object-gantt / object-tree — key sets derived from the
// #19228 — the react tier's own precedence sentence was narrower than the
// guard it names. These pins hold the structural facts the repair rests on,
-// measured first-hand at the objectui pin `87af769e9` on 2026-09-21T06:30-06:40Z.
+// measured first-hand (read points recorded in `liveness/page.json`, row
+// `regions`).
describe('row caps on the object-bound blocks — a bound view fills `limit` only when the authored one is not a usable cap', () => {
const timeline = ComponentPropsMap['object-timeline'];
const kanban = ComponentPropsMap['object-kanban'];
@@ -4555,7 +3797,7 @@ describe('row caps on the object-bound blocks — a bound view fills `limit` onl
it('leaves the ELEMENT-face `limit` undefaulted — the fact that keeps the gate arm alive', () => {
// `ElementDataSourceGate` lowers a bound view's cap into this key only
// when it does not already carry a USABLE one
- // (`ElementDataSourceGate.tsx:316-331`, `!fromView || !isUsableRowLimit`).
+ // (`!fromView || !isUsableRowLimit`).
// An applied default here would make every parsed node carry a usable cap
// and kill that arm outright — the failure #19228 feared, on the schema it
// would actually happen to. ⛔ Do not "fix" a red here by deleting the pin.
@@ -4587,8 +3829,9 @@ describe('row caps on the object-bound blocks — a bound view fills `limit` onl
// · SPEC side — reds. A `.nullable()`, a `0` sentinel, dropping `.int()`
// or adding a `.default()` each fail a specific expect below.
// · GATE side — ⛔ CANNOT red. `usableToTheGate` is a TRANSCRIPTION of
- // `isUsableRowLimit` as it read at objectui pin `87af769e9`, not an
- // import — nothing here resolves into objectui. A rewrite of that
+ // `isUsableRowLimit` as it reads at its recorded read point
+ // (`liveness/page.json`, row `regions`), not an import — nothing here
+ // resolves into objectui. A rewrite of that
// predicate at objectui HEAD leaves this test green. It is re-read on
// a PIN BUMP, by hand, and that is the only thing that refreshes it.
const usableToTheGate = (v: unknown): boolean =>
diff --git a/packages/spec/src/ui/dashboard.test.ts b/packages/spec/src/ui/dashboard.test.ts
index 0f5b4e42343..86f3ef32b5a 100644
--- a/packages/spec/src/ui/dashboard.test.ts
+++ b/packages/spec/src/ui/dashboard.test.ts
@@ -874,9 +874,9 @@ describe('DashboardHeaderAction fields carry an item-level `title`', () => {
* - the sentence being trimmed back to the plural framing.
*
* The renderer half is deliberately NOT pinned here: which chart types consult
- * the forwarded order is objectui's fact, measured against this repo's
- * `.objectui-sha` pin and reported on the issue, not something `packages/spec`
- * can assert.
+ * the forwarded order is objectui's fact, measured against the console this
+ * repo ships and reported on the issue, not something `packages/spec` can
+ * assert.
*/
/** A minimal dataset-bound widget — everything `stageOrder` is not. */
const WIDGET_BASE = {
diff --git a/packages/spec/src/ui/dashboard.zod.ts b/packages/spec/src/ui/dashboard.zod.ts
index aa640707681..17ac776359a 100644
--- a/packages/spec/src/ui/dashboard.zod.ts
+++ b/packages/spec/src/ui/dashboard.zod.ts
@@ -266,8 +266,9 @@ const WIDGET_HISTORY =
* renderer setting. `dataset` is required, so every widget renders through
* objectui's dataset-bound path (`DatasetWidget`), and that path is meant to
* read exactly the five keys declared below. Any other key parses and reaches
- * no renderer. The #20960 census measured that at objectui `main` `5262f7dd`
- * over every key this repo's examples wrote here (`format`, `currency`,
+ * no renderer. The #20960 census measured that on objectui `main` (read points
+ * recorded in `liveness/dashboard.json`, row `widgets.options`) over every key
+ * this repo's examples wrote here (`format`, `currency`,
* `color`, `suffix`, `showLegend`, `horizontal`, `showDataLabels`): none is
* read on that path — only the legacy inline arm, which a widget carrying a
* `dataset` never reaches, spreads the bag into component props — so each was
@@ -690,7 +691,8 @@ const SINGLE_MEASURE_WIDGET_TYPES = ['metric', 'kpi', 'gauge', 'solid-gauge', 'b
* the dataset, not about the widget, and unreachable from this schema — a
* tile naming one measure nobody declared parses exactly as before.
* 5. **objectui's CLIENT-SIDE authoring door**, a `.shape` mirror that runs no
- * object-level check of this schema's: at the `.objectui-sha` pin,
+ * object-level check of this schema's (read point recorded in
+ * `liveness/dashboard.json`, row `widgets`):
* `@object-ui/types` builds its own `DashboardWidgetSchema` from
* `specFieldsExcept(SpecDashboardWidgetSchema.shape, …).extend({…}).strict()`
* and re-attaches none of this file's exported checks. Until it imports and
diff --git a/packages/spec/src/ui/dataset.zod.ts b/packages/spec/src/ui/dataset.zod.ts
index e555259e8d7..f386424e34e 100644
--- a/packages/spec/src/ui/dataset.zod.ts
+++ b/packages/spec/src/ui/dataset.zod.ts
@@ -277,132 +277,16 @@ export const DatasetMeasureSchema = lazySchema(() => strictObject({
* `relative` (`3 days ago` inside a ±7-day window, the absolute form outside
* it) — the same two words `DateCellRenderer` honours from `field.format`.
*
- * ⚠️ The datetime half of that sentence is NEW at the pin below and is the
- * one thing this record's previous revision got wrong the moment the pin
- * moved: until objectui#8352 a DATETIME value ignored `format` altogether,
+ * ⚠️ The datetime half of that sentence is the newer one: until objectui#8352 a DATETIME value ignored `format` altogether,
* and this docblock and the `describe` beneath it both said so.
*
- * Measured at objectui `b9814b334` (re-read there 2026-10-14:
- * every objectui file this record cites is byte-identical across the hop from
- * `1fb1ced36` (`git diff --quiet`), so every anchor held unmoved. At
- * `1fb1ced36`, re-read there 2026-10-12:
- * every objectui file this record cites is byte-identical across the hop from
- * `7578323a5` (`git diff --quiet`), so every anchor held unmoved. At
- * `7578323a5`, re-read there 2026-10-12:
- * every objectui file this record cites is byte-identical across the hop from
- * `9646e2ed2` (`git diff --quiet`), so every anchor held unmoved. At
- * `9646e2ed2`, re-read there 2026-10-12:
- * every objectui file this record cites is byte-identical across the hop from
- * `088e0f705` (`git diff --quiet`), so every anchor held unmoved. At
- * `088e0f705`, re-read there 2026-10-12:
- * every objectui file this record cites is byte-identical across the hop from
- * `e5311165a` (`git diff --quiet`), so every anchor held unmoved. At
- * `e5311165a`, re-read there 2026-10-12:
- * every objectui file this record cites is byte-identical across the hop from
- * `499799502` (`git diff --quiet`), so every anchor held unmoved. At
- * `499799502`, re-read there 2026-10-11:
- * every objectui file this record cites is byte-identical across the hop from
- * `0df67f237` (`git diff --quiet`), so every anchor held unmoved. At
- * `0df67f237`, re-read there 2026-10-11:
- * every objectui file this record cites is byte-identical across the hop from
- * `20c6d351a` (`git diff --quiet`), so every anchor held unmoved. At
- * `20c6d351a`, re-read there 2026-10-10:
- * every objectui file this record cites is byte-identical across the hop from
- * `47b1f0bb7` (`git diff --quiet`), so every anchor held unmoved. At
- * `47b1f0bb7`, re-read there 2026-10-09:
- * every objectui file this record cites is byte-identical across the hop from
- * `f0268ad78` (`git diff --quiet`), so every anchor held unmoved. At
- * `f0268ad78`, re-read there 2026-10-09:
- * `dataset-format.ts` is byte-identical to `a58626c88` (`git diff --quiet`), so
- * `formatMeasureDate` `:240-274`, its datetime arm `:270`-`:272` and its call
- * `:380` held unmoved; `date-display.ts` changed (+152/-16, objectui#11693,
- * objectui `d50f7241b`: an instant renders in the time zone the server answers
- * for the workspace), so `formatDate` `445-480` -> `568-605` was re-READ: it
- * now names an instant's day in that display zone, while its style handling —
- * `short`, `relative`, and the default face for anything else, a date pattern
- * included — reads unchanged, and the ±7-day fallback `399` -> `522` MOVED
- * byte-identical, its day count now taken in the display zone above it. At
- * `a58626c88`, re-read there 2026-10-06:
- * every objectui file this record cites is byte-identical across the hop from
- * `0abd4f9f8` (`git diff --quiet`), so every anchor held unmoved.
- * At `0abd4f9f8`, re-read there 2026-10-05:
- * every objectui file this record cites is byte-identical across the hop from
- * `9dfaca654` (`git diff --quiet`), so every anchor held unmoved.
- * At `9dfaca654`; re-derived at that pin 2026-10-05 — `date-display.ts` and
- * `dataset-format.ts` are byte-identical to `2e818d0b5` (`git diff --quiet`),
- * so every anchor held unmoved. At `2e818d0b5`, re-derived there
- * 2026-10-04 — `date-display.ts` and
- * `dataset-format.ts` are byte-identical to `ab1879721` (`git diff --quiet`),
- * so every anchor held unmoved. At `ab1879721`, re-derived there
- * 2026-10-03 — `date-display.ts` is
- * byte-identical to `89cad75d5`, so `formatDate` `445-480` and the ±7-day
- * fallback `399` held unmoved and were re-READ in place; `dataset-format.ts`
- * changed (+53/-36, objectui#11475: `scalePercent` scales at the storage
- * its caller states, through the spec's `percentScaleOf`, instead of
- * guessing from the value's magnitude), above `formatMeasureDate` in the
- * percent-scaling helpers and below it in `formatMeasure`'s docblock (line
- * for line) and its percent arm, so
- * `formatMeasureDate` `:229-263` -> `:240-274`, its datetime arm `:259`-`:261`
- * -> `:270`-`:272` and its call `:369` -> `:380` MOVED byte-identical,
- * re-READ with the same reading below. At `89cad75d5` (2026-10-02)
- * `dataset-format.ts` and `date-display.ts` were byte-identical to
- * `31971ff1e`, so every anchor below held unmoved and was re-READ in place.
- * At `31971ff1e` (2026-10-01) both
- * files were byte-identical to `e420df310`, so every anchor held unmoved and
- * was re-READ in place. At `e420df310` (2026-09-30)
- * `dataset-format.ts` was byte-identical to `db11afd49`, so `formatMeasureDate` `:229-263`, its call
- * at `:369` and its datetime arm `:259`-`:261` did not move and were re-READ
- * in place, and `date-display.ts` changed (+68/-1, objectui `858eafb4f`,
- * objectui#11141: a header comment naming the new `toDisplayEndDate` /
- * `toInclusiveEndDay` exports, and those two functions added after
- * `toDisplayDate`, above every anchor here), so `formatDate` `378-413` ->
- * `445-480` and the ±7-day fallback `332` -> `399` MOVED byte-identical,
- * re-READ with the same reading below. At `db11afd49` (2026-09-29)
- * `date-display.ts` was
- * byte-identical to `dd3f7e1be` and `dataset-format.ts` changed only in three
- * comment lines (`:529`, `:589`, `:660`, objectui `63ab76112`), all below every
- * anchor here, so `formatDate` `378-413`, the ±7-day fallback `332`,
- * `formatMeasureDate` `:229-263`, its call at `:369` and its datetime arm
- * `:259`-`:261` were re-READ and did not move. At `dd3f7e1be` (2026-09-28)
- * both files changed again on
- * that hop (objectui `544aca24f`, objectui#10301, the date-time half of
- * objectui#10026: `toDisplayDate` now refuses a date-TIME written on a day
- * that does not exist as well, and `dataset-format.ts` rewrote the
- * `ISO_DATETIME_RE` docblock that said such a value still rolls over, four
- * comment lines for four, so nothing below it moved), while the style
- * handling this record cites re-reads unchanged: `formatDate` `355-390` ->
- * `378-413` and the ±7-day fallback `309` -> `332` MOVED byte-identical, and
- * `formatMeasureDate` `:229-263`, its call at `:369` and its datetime arm at
- * `:259`-`:261` did not move. At `f8a9d0fb0` (2026-09-24) both files had
- * moved (objectui `ad694ac3d`, objectui#10026: the shared date path refuses a
- * date-only calendar day that does not exist, with the dash it renders for
- * any unparsable value, and `dataset-format.ts` rewrote
- * `formatMeasureDate`'s comment on that case), while the style handling
- * re-read unchanged: `formatDate` `271-306` -> `355-390` and the ±7-day
- * fallback `225` -> `309` MOVED byte-identical, and `formatMeasureDate` came
- * out one comment line shorter. At `62597c588` (2026-09-23)
- * `dataset-format.ts` was byte-identical to `87af769e9`, and `date-display.ts`
- * had moved (objectui `516583b54`, +77/-4): `formatDate` parses through
- * `toDisplayDate`, so a date-only value renders the calendar day it names in
- * every timezone. At `87af769e9` (2026-09-20) every anchor below MOVED and
- * one of them changed SUBSTANCE, so nothing here was carried there either:
- * `formatMeasureDate`'s datetime arm no longer calls
- * `formatDateTime(v, { locale })` unconditionally, it SELECTS a formatter,
- * because `formatDateTime(value, options?)` has no style parameter to thread
- * into and widening that published signature was refused) in
- * objectui
- * `packages/core/src/utils/dataset-format.ts`: `formatMeasure` routes a
- * non-numeric value through `formatMeasureDate` (`:240-274`, was `:229-263`,
- * `:229-264` and before that `:185-198`) at `:380`,
- * whose date-only arm threads `format` into the STYLE parameter of
- * `formatDate` (`utils/date-display.ts:568-605`, was `:445-480`, `:378-413`, `:355-390`, `:271-306`,
- * `:198-233` and before that `:131-164`, whose `relative` branch falls back to the absolute form
- * beyond ±7 days at `:522`, was `:399`, `:332`, `:309`, `:225`, `:152` and `:117` — the fallback strips the style through
- * `absoluteFallbackOptions`), while its datetime arm answers `relative` with
- * `formatRelativeDate` (`:270`), `short` with
- * `formatDateTime(v, { locale, style: 'compact' })` (`:271`) and everything
- * else — a date PATTERN included — with the bare
- * `formatDateTime(v, { locale })` (`:272`).
+ * Measured on the renderer's shared measure formatter: its date-only arm
+ * threads `format` into the date STYLE parameter (whose `relative` branch
+ * falls back to the absolute form beyond ±7 days), while its datetime arm
+ * answers `relative`, `short` (the compact style) and everything else — a
+ * date PATTERN included — with the bare locale default. The read points are
+ * recorded by symbol in `packages/spec/liveness/dataset.json`, row
+ * `measures.format`.
* Teaching
* the shared path a pattern grammar would change every list cell that reads
* it, so that gap is still DOCUMENTED here rather than closed (objectui#7178
diff --git a/packages/spec/src/ui/expression-bindable-text-keys.zod.ts b/packages/spec/src/ui/expression-bindable-text-keys.zod.ts
index f66ade845fa..b69e07b517f 100644
--- a/packages/spec/src/ui/expression-bindable-text-keys.zod.ts
+++ b/packages/spec/src/ui/expression-bindable-text-keys.zod.ts
@@ -46,16 +46,15 @@
* ## Why these rows (measured, not inferred)
*
* Rows are a RECORD of what each component renderer already reads back from
- * the node's top level, measured at the `.objectui-sha` pin `82a9417`
- * (re-verified identical at objectui `origin/main` `6c68b13` on
- * 2026-08-18) — declaring a key a renderer does not read back would recreate
+ * the node's top level (read points recorded in `liveness/page.json`, row
+ * `regions`) — declaring a key a renderer does not read back would recreate
* the evaluated-but-blank half of the objectui#4795 table:
*
- * | type | renderer read points (top level, within the closed set) |
- * |-------------|----------------------------------------------------------|
- * | `statistic` | `schema.label`, `schema.value`, `schema.description` (`data-display/statistic.tsx`) |
- * | `card` | `schema.title`, `schema.description` (`layout/card.tsx`) |
- * | `button` | `schema.label` (`form/button.tsx`) |
+ * | type | renderer reads (top level, within the closed set) |
+ * |-------------|---------------------------------------------------|
+ * | `statistic` | `schema.label`, `schema.value`, `schema.description` |
+ * | `card` | `schema.title`, `schema.description` |
+ * | `button` | `schema.label` |
*
* These are the measured motivating cases from objectui#4795 (dashboard
* workhorses). Other registered renderers also read keys from this closed set
@@ -64,7 +63,7 @@
* declared yet: form-control `value` is interactive state rather than display
* text, and each row is an accept-surface widening that should arrive with its
* own measurement, not ride this one (startup scope discipline). `text` reads
- * back `schema.content || schema.value` (`basic/text.tsx`) — unlike the rows
+ * back `schema.content || schema.value` (the same ledger entry) — unlike the rows
* above, its omission is not merely unmeasured: `value` there is a fallback
* spelling for the same slot `content` already evaluates (see `content` NOT a
* member, above), not a second read point, so a `text: ['value']` row would
diff --git a/packages/spec/src/ui/list-view-export-options.ts b/packages/spec/src/ui/list-view-export-options.ts
index d46c7deb2f7..e9cfb0e2a64 100644
--- a/packages/spec/src/ui/list-view-export-options.ts
+++ b/packages/spec/src/ui/list-view-export-options.ts
@@ -116,8 +116,8 @@ const exportOptionsUnknownKeyError = strictObjectError({
/**
* Object form of `view.exportOptions` (#8010, maintainer ruling 2026-08-12 —
* option A). The declared key set is exactly what the only renderer reads,
- * measured on objectui `origin/main@878140b` (`ObjectGrid.tsx:1596–1642`):
- * `formats`, `maxRecords`, `includeHeaders`, `fileNamePrefix`, and the
+ * measured on objectui (read points recorded in `liveness/view.json`, row
+ * `list.exportOptions`): `formats`, `maxRecords`, `includeHeaders`, `fileNamePrefix`, and the
* previously UNDECLARED `streaming` opt-out — declared here so no
* undeclared-but-read key survives the fix. Declaring anything more would be
* capability surface with no reader; declaring less recreates the defect.
diff --git a/packages/spec/src/ui/navigation-target.ts b/packages/spec/src/ui/navigation-target.ts
index 4e17e5e83de..f7ce7d8d6bf 100644
--- a/packages/spec/src/ui/navigation-target.ts
+++ b/packages/spec/src/ui/navigation-target.ts
@@ -25,9 +25,9 @@
*
* ## Why the door answers exactly what the runner answers
*
- * The runner's half is objectui's `classifyNavigationTarget`
- * (`packages/core/src/actions/navigationTarget.ts`, read at objectui
- * `7578323`), which both the action runner and the entitlement CTA call. For a
+ * The runner's half is objectui's `classifyNavigationTarget` (read point
+ * recorded in `liveness/action.json`, row `target`), which both the action
+ * runner and the entitlement CTA call. For a
* literal target this function admits exactly what that classifier admits and
* refuses exactly what it refuses. A door wider than the runner is the trap the
* set exists to close: the target publishes clean and fails at click. A door
diff --git a/packages/spec/src/ui/object-refinement-check-exports.test.ts b/packages/spec/src/ui/object-refinement-check-exports.test.ts
index 211b22708d1..2f4ec3d1c0e 100644
--- a/packages/spec/src/ui/object-refinement-check-exports.test.ts
+++ b/packages/spec/src/ui/object-refinement-check-exports.test.ts
@@ -5,9 +5,10 @@
* and each export IS the check its schema runs — the spec half of objectui#7715.
*
* Why: objectui derives its zod mirrors from a spec object's `.shape`
- * (`specFieldsExcept(SpecListViewSchema.shape, …)`, six sites at the pinned
- * `.objectui-sha`). `.shape` carries the FIELDS by reference and drops every
- * check attached to the OBJECT, so at 17.3.0 objectui's authoring door accepted
+ * (`specFieldsExcept(SpecListViewSchema.shape, …)`; read points recorded in
+ * `liveness/view.json`, row `list.appearance`). `.shape` carries the FIELDS by
+ * reference and drops every check attached to the OBJECT, so at 17.3.0
+ * objectui's authoring door accepted
* `appearance.allowedVisualizations: ['calendar']` with no `calendar:` block
* while the spec's publish door refused it. A mirror needs the rule as a
* function it can attach, and that function must be the schema's own — never a
@@ -573,11 +574,10 @@ const MIRRORED: MirroredSchema[] = [
cleanFixtures: [{ field: 'created_at', type: 'date' }],
},
// `dashboard.widgets[]` is mirrored the same way and for the same reason, so
- // the ADR-0049 `stageOrder` type gate belongs in this catalogue: measured at
- // the `.objectui-sha` pin `53ded82bf7a494f54e344e19099dbf00854b8694`,
- // objectui's `packages/types/src/zod/complex.zod.ts` builds its own
- // `DashboardWidgetSchema` from
- // `specFieldsExcept(SpecDashboardWidgetSchema.shape, …)` — a `.shape` spread,
+ // the ADR-0049 `stageOrder` type gate belongs in this catalogue: objectui
+ // builds its own `DashboardWidgetSchema` from
+ // `specFieldsExcept(SpecDashboardWidgetSchema.shape, …)` (read point recorded
+ // in `liveness/dashboard.json`, row `widgets`) — a `.shape` spread,
// which carries the FIELDS and drops every object-level check. That mirror
// re-attaches none of these exports today, which is a live gap recorded on
// the check's own docblock rather than a reason to leave the export
diff --git a/packages/spec/src/ui/page.zod.ts b/packages/spec/src/ui/page.zod.ts
index 1c7b4058a15..df31e4aadbc 100644
--- a/packages/spec/src/ui/page.zod.ts
+++ b/packages/spec/src/ui/page.zod.ts
@@ -317,8 +317,9 @@ export const ElementDataSourceSchema = lazySchema(() => strictObject({
* which that classifier admits for a NAVIGATION, is refused HERE on a
* measurement of the renderer, not by analogy: a read is a `fetch`, and the
* `apiBase` promotion the console applies to a `url` action
- * (`ActionRunner.navigateTo`, measured at objectui `7578323a544e`) prefixes a
- * root-relative `/api/…` path only — a `./` path would resolve against the
+ * (`ActionRunner.navigateTo`; read points recorded in `liveness/page.json`,
+ * row `regions`) prefixes a root-relative `/api/…` path only — a `./` path
+ * would resolve against the
* console route the page is mounted on, on the SPA host, and read the wrong
* thing in the silent direction.
*
@@ -421,7 +422,7 @@ const ELEMENT_API_NO_CREDENTIALS =
* refused with {@link ELEMENT_API_NO_CREDENTIALS}. There is no `write` block:
* a page element READS.
*
- * `method` admits `GET` alone. Measured at objectui `7578323a544e`: the adapter
+ * `method` admits `GET` alone. Measured on the renderer: the adapter
* the ruling names, `@object-ui/core`'s `ApiDataSource`, issues every read —
* `find`, `findOne`, `aggregate` — with an explicit `method: 'GET'` that
* overrides the request config's own, so any other value here would declare a
@@ -429,7 +430,7 @@ const ELEMENT_API_NO_CREDENTIALS =
*
* ## Planned, not yet rendered
*
- * At objectui `7578323a544e` no renderer reads this binding: the page-element
+ * No renderer reads this binding yet: the page-element
* data-source hook (`useElementDataSource`, `@object-ui/react`) admits only a
* binding with a string `object` (`isElementDataSourceConfig`), so an `api`
* binding reaches no block yet. The generic blocks that read it — stat, usage
@@ -642,21 +643,18 @@ export const PageComponentSchema = lazySchema(() => strictObject({
* unavailable — they are NOT promises, and widening the contract to cover
* them is an open question, deliberately not decided here.
*
- * Measured at the `.objectui-sha` pin `1fb1ced36243` (the four files below
- * are identical at objectui `origin/main` `f228d710`):
- * `app-shell/src/providers/ExpressionProvider.tsx:181-190`
- * (`buildExpressionScope`) builds the ambient scope — `current_user`,
- * `user`, `ctx.user`, `os.user`, `features`, and nothing else;
- * `react/src/SchemaRenderer.tsx:665-676` (`configEvaluationScope`) composes
- * this surface's evaluator from it, adding `record` (only when the page has
- * a row) and `page`.
+ * Measured on the renderer (read points recorded in `liveness/page.json`,
+ * row `regions`): `buildExpressionScope` builds the ambient scope —
+ * `current_user`, `user`, `ctx.user`, `os.user`, `features`, and nothing
+ * else; `configEvaluationScope` composes this surface's evaluator from it,
+ * adding `record` (only when the page has a row) and `page`.
*
* ## No `data` root on this surface
*
* The shipping renderer mounts NO `data` root here. objectui#9308 (ruling
* B, 2026-09-13) removed `data` as a runtime expression root:
* `SchemaRenderer` stopped publishing its injected data source under that
- * name (`SchemaRenderer.tsx:1194`), and a data scope reaches a predicate
+ * name, and a data scope reaches a predicate
* only through the predicate-scope channel (`PredicateScopeProvider`),
* whose one shipping feeder, `ExpressionProvider`, publishes no `data`. So a
* `data.*` read here faults, and a faulting `visibleWhen` renders the
@@ -672,7 +670,7 @@ export const PageComponentSchema = lazySchema(() => strictObject({
* ## ⚠️ A `page:tabs` item is a different evaluator
*
* On a `page:tabs` **item-level** `visibleWhen`, a separate evaluator
- * (`components/src/renderers/layout/containers.tsx:642-649`) binds `data` to
+ * (recorded in the same evidence list) binds `data` to
* the record **ROW** and spreads the row's bare fields as well — a binding
* this surface does not have. See that key's own describe in
* `component.zod.ts` rather than assuming either environment carries over.
@@ -925,10 +923,11 @@ export const InterfacePageConfigSchema = lazySchema(() => strictObject({
*
* It was declared ahead of its renderer, with the planned marker on its
* describe. The renderer half, objectstack-ai/objectui#12270 (objectui
- * `b434f5f47`), is inside the console pin from objectui `b9814b334`, so the
- * marker is dropped. Measured there: `InterfaceListPage` hands `ListView`
- * `emptyState: cfg.emptyState ?? view.emptyState` (`InterfaceListPage.tsx:509`),
- * so the page's own empty state wins over its source view's, whole, and the
+ * `b434f5f47`), is inside the console's objectui pin, so the marker is
+ * dropped. Measured there (read point recorded in `liveness/page.json`, row
+ * `interfaceConfig`): `InterfaceListPage` hands `ListView` `emptyState:
+ * cfg.emptyState ?? view.emptyState`, so the page's own empty state wins
+ * over its source view's, whole, and the
* source view's stays the fallback. Where `ListView` draws an empty state at
* all (the `grid` and `gallery` visualizations), that is the one it draws,
* `link` included.
diff --git a/packages/spec/src/ui/view.test.ts b/packages/spec/src/ui/view.test.ts
index cd903dd7611..f21ceedd608 100644
--- a/packages/spec/src/ui/view.test.ts
+++ b/packages/spec/src/ui/view.test.ts
@@ -3931,7 +3931,7 @@ describe('ListViewSchema — retired striped/bordered/virtualScroll (every reade
// 2026-08-12, option A). The spec published a bare format array while the only
// renderer read `exportOptions.formats`, so no declaration was both type-legal
// and functional. The object form declares exactly the five renderer-read keys
-// (measured objectui origin/main@878140b, ObjectGrid.tsx:1596–1642); the
+// (read points recorded in `liveness/view.json`, row `list.exportOptions`); the
// legacy bare array stays accepted and lifts to `{ formats }` at parse.
// `'pdf'` left the enum in the same change (#1301 NOT_PLANNED). The removal
// stands under the 2026-10-08 ruling on #8346 (B′), which re-planned PDF
diff --git a/packages/spec/src/ui/view.zod.ts b/packages/spec/src/ui/view.zod.ts
index 0e18860ffca..8d14dc3c89d 100644
--- a/packages/spec/src/ui/view.zod.ts
+++ b/packages/spec/src/ui/view.zod.ts
@@ -1307,8 +1307,8 @@ function checkGroupingFieldName(raw: string): string | undefined {
* about `grouping.fields[].field` and explicitly not about this axis, so
* quoting its date here would attribute a decision that was never made.
*
- * What the name is used for, measured in the consumer (objectui `dda8f3815`):
- * the kanban board resolves its lane as
+ * What the name is used for, measured in the consumer (read points recorded in
+ * `liveness/view.json`, row `list.kanban`): the kanban board resolves its lane as
* `laneField = groupByField || groupField || detectStatusField(objectDef)`
* and buckets cards by `card[laneField]`; `ObjectGantt`'s `groupByAccessor`
* splits the name on `.` and walks the backing record
@@ -1894,14 +1894,14 @@ const emptyStateLinkSchema = () => strictObject({
* reaches, the `object-grid` page block's, and a list page's own
* `interfaceConfig.emptyState` (`page.zod.ts`, #23005). It was declared ahead
* of its renderer, with the planned marker on its describe. The renderer half,
- * objectstack-ai/objectui#12270 (objectui `b434f5f47`), is inside the console
- * pin from objectui `b9814b334`, so the marker is dropped. Measured there:
- * `ListView` hands `ListEmptyState` the `link` (`ListView.tsx:5716`), which
- * draws it beside the add-record action (`ListEmptyState.tsx:153`) in the
- * empty branch of the `grid` and `gallery` visualizations; `ObjectGrid` draws
- * it in `DataEmptyState`'s action slot (`ObjectGrid.tsx:6897-6899`); and
- * `InterfaceListPage` hands `ListView` the page's own `emptyState` ahead of
- * the source view's (`InterfaceListPage.tsx:509`). Each draws it through the
+ * objectstack-ai/objectui#12270 (objectui `b434f5f47`), is inside the console's
+ * objectui pin, so the marker is dropped. Measured there (read points recorded
+ * in `liveness/view.json`, row `list.emptyState`, and `liveness/page.json`,
+ * row `interfaceConfig`): `ListView` hands `ListEmptyState` the `link`, which
+ * draws it beside the add-record action in the empty branch of the `grid` and
+ * `gallery` visualizations; `ObjectGrid` draws it in `DataEmptyState`'s action
+ * slot; and `InterfaceListPage` hands `ListView` the page's own `emptyState`
+ * ahead of the source view's. Each draws it through the
* one shared `EmptyStateLink` (`@object-ui/components`), which follows it as a
* `type: 'url'` action through the action runner, so a click opens what the
* runner opens for that target.
@@ -2629,10 +2629,10 @@ const LIST_CHART_BINDING_KEYS = ['dataset', 'values'] as const;
* - A declared `chart` block ⇒ nothing here: its own strict schema already
* requires both keys, at `chart.dataset` / `chart.values`.
*
- * What such a view renders is a dead screen either way: at the pin the
- * renderer fabricates a binding nobody wrote (an aggregate over `'name'` /
- * `'value'`); from objectui#6152 round 15 (objectui `0253416`) that floor is
- * retired and `ObjectChart` refuses on screen (`chart-missing-category-axis`).
+ * What such a view renders is a dead screen either way: before objectui#6152
+ * round 15 (objectui `0253416`) the renderer fabricated a binding nobody wrote
+ * (an aggregate over `'name'` / `'value'`); since then that floor is retired
+ * and `ObjectChart` refuses on screen (`chart-missing-category-axis`).
* ⛔ Never fabricate a default here either — only the author knows the dataset.
*
* Reads `type` as the door hands it: the authoring shapes apply the `grid`
@@ -4241,8 +4241,8 @@ function refineFormFieldFeaturesRoot(
// enum-VALUE narrowing: the enum's own error map carries the prescription,
// keyed on `issue.input`, so only a value which used to be legal gets the "was
// removed" message. The twin of `OBJECT_FORM_LAYOUT_RETIRED`
-// (component.zod.ts), which carries the renderer measurement at the
-// `.objectui-sha` pin: every form presentation folds 'grid' and 'inline' to
+// (component.zod.ts), whose renderer measurement is recorded in
+// `liveness/page.json`, row `regions`: every form presentation folds 'grid' and 'inline' to
// 'vertical', and multi-column is `columns`, honoured under every arm. The
// ADR-0087 conversion `form-layout-inline-grid-to-vertical` rewrites both to
// 'vertical' in every form payload a view carries (`form`, `formViews.*`, a