diff --git a/.changeset/liveness-ledger-reaudit-16362.md b/.changeset/liveness-ledger-reaudit-16362.md new file mode 100644 index 0000000000..d2d122e1fc --- /dev/null +++ b/.changeset/liveness-ledger-reaudit-16362.md @@ -0,0 +1,12 @@ +--- +"@objectstack/spec": patch +--- + +Liveness ledger: four verdicts re-derived and corrected ahead of the author-warning flip. + +The ledger's `dead` and `live-elsewhere` verdicts are about to start warning downstream authors, so each row was re-measured against a pinned tree — objectstack `5d55afec4d`, objectui `a472b071` — with a firing positive control on the same instrument and corpus before any zero was read as a reading. + +- **`validation.label` / `.description` / `.tags`: `dead` → `live`.** The 2026-08-10 sweep upheld `dead` on *reachability*, not on the read: `ValidationPreview` genuinely rendered all three, but the only route that mounted it was the standalone `validation` resource door, and ADR-0088 had retired that kind — so on the governed path (a rule embedded in its object) the preview was never handed a draft. That note named its own falsifier, and it has since landed: the standalone door is gone, and `EmbeddedItemEditor` now resolves `getMetadataPreview(editAs)` and mounts the preview on the live draft, with the embedded anchor binding `editAs: 'validation'`. Under the ruling that a designer preview rendering a key to a human is a runtime consumer, these three display keys are live. They remain docs-shaped and are still not author-warned. +- **`view` `list.tabs`: `live` → `dead`.** The previous note was wrong in both directions at once. It credited objectui's `TabBar` with reading `icon`/`visible`/`pinned`/`filter` — true of the component, but **nothing mounts it**: every `TabBar` render site in the whole renderer tree is its own definition or one of its two test files, and `ListView` never reads `tabs` off the view schema, so authoring `list.tabs` draws no tab bar. And it called `tabs[].order` a dead sub-surface while `getVisibleTabs` sorts on exactly that key. The two author-time readers that do walk the key (a field-reference lint and the metadata diagnostics) check `tabs[].filter[].field` for reference integrity and deliver none of the key's declared effect — validated-then-ignored is accept/reject, which this ledger has always kept separate from liveness. + +No published surface moves: these are ledger JSON rows plus the generated count table, with no export, key, or accept-set change. The `list.tabs` re-grade does mean an author who writes tabs on a list view will be told the key is inert — which it is, and was. diff --git a/packages/spec/liveness/state-counts.md b/packages/spec/liveness/state-counts.md index 3095afc96c..85b774d338 100644 --- a/packages/spec/liveness/state-counts.md +++ b/packages/spec/liveness/state-counts.md @@ -39,7 +39,7 @@ for both corollaries. | `skill` | 16 | 0 | 0 | 1 | 0 | 17 | | `dataset` | 27 | 0 | 0 | 0 | 0 | 27 | | `page` | 23 | 0 | 0 | 0 | 1 | 24 | -| `view` | 79 | 0 | 0 | 9 | 0 | 88 | +| `view` | 78 | 0 | 0 | 10 | 0 | 88 | | `report` | 21 | 0 | 0 | 0 | 0 | 21 | | `dashboard` | 34 | 0 | 0 | 8 | 0 | 42 | | `webhook` | 19 | 0 | 0 | 0 | 0 | 19 | @@ -53,7 +53,7 @@ for both corollaries. | `mapping` | 14 | 0 | 0 | 0 | 0 | 14 | | `seed` | 12 | 0 | 0 | 0 | 0 | 12 | | `translation` | 23 | 0 | 0 | 0 | 2 | 25 | -| `validation` | 15 | 0 | 0 | 3 | 0 | 18 | +| `validation` | 18 | 0 | 0 | 0 | 0 | 18 | | `api` | 25 | 0 | 0 | 1 | 2 | 28 | | `capability` | 12 | 0 | 0 | 0 | 0 | 12 | | `qa` | 4 | 0 | 0 | 5 | 0 | 9 | @@ -63,4 +63,4 @@ for both corollaries. | `batch_endpoints` | 5 | 0 | 0 | 2 | 0 | 7 | | `route_generation` | 0 | 0 | 0 | 4 | 0 | 4 | | `realtime_subscription` | 0 | 0 | 0 | 6 | 0 | 6 | -| **total** | **846** | **5** | **1** | **94** | **12** | **958** | +| **total** | **848** | **5** | **1** | **92** | **12** | **958** | diff --git a/packages/spec/liveness/validation.json b/packages/spec/liveness/validation.json index 640943c682..c98e4de8d7 100644 --- a/packages/spec/liveness/validation.json +++ b/packages/spec/liveness/validation.json @@ -9,16 +9,20 @@ "note": "names the rule in violation logs and the broken-rule skip warning. 2026-08-28: RE-ANCHORED (#13003) and REPOINTED — `:665` and `:676` had BOTH rotted into the same ADR-0124 docblock above `isReadonlyWhenLocked`, ~1,180 lines above the evaluator. Nine of this file's ten citations pointed into the 640-710 band, which today is that docblock and a `readonlyWhen` helper: the whole ledger had drifted as ONE block when the module grew its conditional-field section, and every pointer stayed IN RANGE, so no check could see any of it. Re-closed by hand against 8cb96ec41." }, "label": { - "status": "dead", + "status": "live", + "verifiedAt": "2026-09-07", "evidenceScope": "cross-repo", - "verifiedAt": "2026-08-10", - "note": "governance/editor metadata, declared deliberately (the schema header says so): surfaced in rule listings, never evaluated on the write path. Docs-shaped, KEPT, not authorWarn'd — the hook.label precedent. VERDICT RE-TESTED AND UPHELD 2026-08-10 (#7427) under the maintainer ruling that a designer preview rendering a key to a human is a runtime consumer (2026-08-10, #7131; README, 'Designer previews count as consumers'). This is the sweep's sharpest case and the reason the README's REACHABILITY clause is not decoration: the render is real and the read point is unreachable on the governed path. THE MEASUREMENT, at objectui @e9ab52f9: ValidationPreview exists, is registered for `validation` (previews/index.ts:45), reads this key at ValidationPreview.tsx:101 with the rule `name` as fallback and renders it as the preview card's title at ValidationPreview.tsx:131. Under the ruling that would settle a display key — except that the type that resolves the preview no longer exists here. The STANDALONE `validation` kind was retired 2026-08-02 (#4509, ADR-0088), as this file's own `_note` records at length; it is absent from both METADATA_TYPE_SCHEMAS and UNREGISTERED_KIND_SCHEMAS in packages/spec/src/kernel/metadata-type-schemas.ts. Rules live where they are evaluated, embedded as `object.validations`, and objectui routes an embedded item to EmbeddedItemEditor (anchors.ts:79 `editAs: 'validation'`, MetadataDetailDrawer.tsx:129), which renders a SchemaForm — an authoring form, never ResourceEditPage's preview tab. So on the ONE path the framework evaluates, this preview is never handed a draft. objectui does still register a standalone `validation` resource with a create affordance (anchors.ts:347-366) whose route WOULD mount the preview, but granting `live` on the strength of a door ADR-0088 closed is the 'shipped false signpost' this ledger exists to catch — the same reasoning that deleted the readReplicas pill. Filed as objectui#4132; if that lands as 'wire ValidationPreview into the embedded editor', this row re-grades to live and should." + "evidence": "objectui: packages/app-shell/src/views/metadata-admin/previews/ValidationPreview.tsx#ValidationPreview @a472b071 — read off the draft with the rule name as fallback, rendered as the preview card title.", + "producer": "objectui: packages/app-shell/src/views/metadata-admin/previews/index.ts#registerBuiltinPreviews @a472b071 registers ValidationPreview for the `validation` type; objectui: packages/app-shell/src/views/metadata-admin/EmbeddedItemEditor.tsx#EmbeddedItemEditor resolves it through getMetadataPreview(editAs) and hands it the live draft; objectui: packages/app-shell/src/views/metadata-admin/anchors.ts#registerBuiltinAnchors binds the embedded rule to it with editAs set to `validation`. That chain IS the surface that resolves the preview — the half a read-point citation alone never proves.", + "note": "Governance / editor metadata, declared deliberately (the schema header says so): surfaced in rule listings, never evaluated on the write path. Docs-shaped and KEPT, and still NOT authorWarn-ed — pure display annotation must not warn (the job.label / translation.label precedent), and ADR-0033 exempts it from enforce-or-remove either way. LIVE under the maintainer ruling that a designer preview rendering a key to a human IS a runtime consumer (2026-08-10, #7131; README, \"Designer previews count as consumers\"), which settles a DISPLAY key outright: being shown to a human is the whole of the claimed effect, so no second layer is being stood in for. RE-DERIVED 2026-09-07 (#16362, ledger audit ahead of the #16094 authorWarn flip) — verdict FLIPPED dead to live, on the re-open condition the 2026-08-10 note stated for itself. That note upheld `dead` at objectui @e9ab52f9 on REACHABILITY, not on the read: ValidationPreview genuinely read and rendered the key, but the only route that mounted it was the standalone `validation` resource door, and ADR-0088 / #4509 had retired that kind, so on the governed (embedded `object.validations`) path the preview was never handed a draft. That note closed by naming its own falsifier — \"Filed as objectui#4132; if that lands as 'wire ValidationPreview into the embedded editor', this row re-grades to live and should.\" objectui#4132 HAS landed, and it did both halves. (1) The standalone door is gone: anchors.ts now records that there is no standalone Validations group and no create affordance, and that this file registered that door until objectui#4132 removed it. (2) The preview is wired into the embedded editor instead — EmbeddedItemEditor resolves getMetadataPreview(editAs) and mounts the result above the form with draft set to the live authored value, and the `__object_validation` anchor sets editAs to `validation` — so a rule edited where the framework actually evaluates it (embedded in its object) now renders through ValidationPreview. The read point that never ran, runs. Measured at objectui @a472b071 with a firing control on every leg: the preview-registration grep that returns zero for hook / qa / manifest / realtime_subscription returns one for validation, and the sibling PermissionPreview only COUNTS its rowLevelSecurity array and descends no further — which is why permission.rowLevelSecurity.label / .description / .tags stay dead on this same instrument." }, "description": { - "status": "dead", + "status": "live", + "verifiedAt": "2026-09-07", "evidenceScope": "cross-repo", - "verifiedAt": "2026-08-10", - "note": "same as `label` — governance annotation, deliberately kept. Re-tested and upheld with `label` 2026-08-10 (#7427): at objectui @e9ab52f9 ValidationPreview.tsx:102 reads it and :136 renders it beneath the title, but the read point is unreachable on the governed (embedded) path — see `label` for the full closure and objectui#4132." + "evidence": "objectui: packages/app-shell/src/views/metadata-admin/previews/ValidationPreview.tsx#ValidationPreview @a472b071 — read off the draft and rendered beneath the title, guarded so an empty description renders nothing.", + "producer": "objectui: packages/app-shell/src/views/metadata-admin/previews/index.ts#registerBuiltinPreviews @a472b071 registers ValidationPreview for the `validation` type; objectui: packages/app-shell/src/views/metadata-admin/EmbeddedItemEditor.tsx#EmbeddedItemEditor resolves it through getMetadataPreview(editAs) and hands it the live draft; objectui: packages/app-shell/src/views/metadata-admin/anchors.ts#registerBuiltinAnchors binds the embedded rule to it with editAs set to `validation`. That chain IS the surface that resolves the preview — the half a read-point citation alone never proves.", + "note": "Same as `label` — governance annotation, deliberately kept, docs-shaped, not authorWarn-ed. RE-DERIVED 2026-09-07 (#16362, ledger audit ahead of the #16094 authorWarn flip) — verdict FLIPPED dead to live, on the re-open condition the 2026-08-10 note stated for itself. That note upheld `dead` at objectui @e9ab52f9 on REACHABILITY, not on the read: ValidationPreview genuinely read and rendered the key, but the only route that mounted it was the standalone `validation` resource door, and ADR-0088 / #4509 had retired that kind, so on the governed (embedded `object.validations`) path the preview was never handed a draft. That note closed by naming its own falsifier — \"Filed as objectui#4132; if that lands as 'wire ValidationPreview into the embedded editor', this row re-grades to live and should.\" objectui#4132 HAS landed, and it did both halves. (1) The standalone door is gone: anchors.ts now records that there is no standalone Validations group and no create affordance, and that this file registered that door until objectui#4132 removed it. (2) The preview is wired into the embedded editor instead — EmbeddedItemEditor resolves getMetadataPreview(editAs) and mounts the result above the form with draft set to the live authored value, and the `__object_validation` anchor sets editAs to `validation` — so a rule edited where the framework actually evaluates it (embedded in its object) now renders through ValidationPreview. The read point that never ran, runs. Measured at objectui @a472b071 with a firing control on every leg: the preview-registration grep that returns zero for hook / qa / manifest / realtime_subscription returns one for validation, and the sibling PermissionPreview only COUNTS its rowLevelSecurity array and descends no further — which is why permission.rowLevelSecurity.label / .description / .tags stay dead on this same instrument." }, "active": { "status": "live", @@ -39,10 +43,12 @@ "note": "stable low-number-first sort of the evaluation order. 2026-08-28: RE-ANCHORED (#13003) and REPOINTED — `:657` had rotted onto a blank line of that docblock (see `name`). Re-closed by hand against 8cb96ec41." }, "tags": { - "status": "dead", + "status": "live", + "verifiedAt": "2026-09-07", "evidenceScope": "cross-repo", - "verifiedAt": "2026-08-10", - "note": "categorization for reporting/management — governance metadata like label/description, deliberately kept. Re-tested and upheld with `label` 2026-08-10 (#7427): at objectui @e9ab52f9 ValidationPreview.tsx:110 reads the array and :167-175 renders one chip per tag, so unlike `permission.rowLevelSecurity.tags` (which the permission preview only COUNTS) the values do reach a rendering — but through the same unreachable read point as `label`, so the verdict does not move. Note also that the declared effect here is annotation, not filtering: the describe is 'Categorization tags' and the schema header calls all three keys 'governance / editor metadata … they carry authoring intent, not enforcement'. That matters, because a tags key whose describe PROMISES filtering is behavioural and a chip render would not settle it either way — `qa.scenarios.tags` is that other case, and it is not this one." + "evidence": "objectui: packages/app-shell/src/views/metadata-admin/previews/ValidationPreview.tsx#ValidationPreview @a472b071 — reads the array and renders one chip per tag.", + "producer": "objectui: packages/app-shell/src/views/metadata-admin/previews/index.ts#registerBuiltinPreviews @a472b071 registers ValidationPreview for the `validation` type; objectui: packages/app-shell/src/views/metadata-admin/EmbeddedItemEditor.tsx#EmbeddedItemEditor resolves it through getMetadataPreview(editAs) and hands it the live draft; objectui: packages/app-shell/src/views/metadata-admin/anchors.ts#registerBuiltinAnchors binds the embedded rule to it with editAs set to `validation`. That chain IS the surface that resolves the preview — the half a read-point citation alone never proves.", + "note": "Categorization for reporting / management — governance metadata like label and description, deliberately kept. The declared effect here is ANNOTATION, not filtering: the describe reads \"Categorization tags\" and the schema header calls all three keys governance / editor metadata carrying authoring intent, not enforcement. That distinction is load-bearing and survives this re-grade — a tags key whose describe PROMISES filtering is behavioural, and a chip render would not settle it in either direction. `qa.scenarios.tags` is that other case and stays dead: its describe promises filtering, and `os test` ships three flags (--url, --token, --fail-on-empty), none of which selects scenarios. RE-DERIVED 2026-09-07 (#16362, ledger audit ahead of the #16094 authorWarn flip) — verdict FLIPPED dead to live, on the re-open condition the 2026-08-10 note stated for itself. That note upheld `dead` at objectui @e9ab52f9 on REACHABILITY, not on the read: ValidationPreview genuinely read and rendered the key, but the only route that mounted it was the standalone `validation` resource door, and ADR-0088 / #4509 had retired that kind, so on the governed (embedded `object.validations`) path the preview was never handed a draft. That note closed by naming its own falsifier — \"Filed as objectui#4132; if that lands as 'wire ValidationPreview into the embedded editor', this row re-grades to live and should.\" objectui#4132 HAS landed, and it did both halves. (1) The standalone door is gone: anchors.ts now records that there is no standalone Validations group and no create affordance, and that this file registered that door until objectui#4132 removed it. (2) The preview is wired into the embedded editor instead — EmbeddedItemEditor resolves getMetadataPreview(editAs) and mounts the result above the form with draft set to the live authored value, and the `__object_validation` anchor sets editAs to `validation` — so a rule edited where the framework actually evaluates it (embedded in its object) now renders through ValidationPreview. The read point that never ran, runs. Measured at objectui @a472b071 with a firing control on every leg: the preview-registration grep that returns zero for hook / qa / manifest / realtime_subscription returns one for validation, and the sibling PermissionPreview only COUNTS its rowLevelSecurity array and descends no further — which is why permission.rowLevelSecurity.label / .description / .tags stay dead on this same instrument." }, "severity": { "status": "live", diff --git a/packages/spec/liveness/view.json b/packages/spec/liveness/view.json index 5a24ad282a..e30c9edff3 100644 --- a/packages/spec/liveness/view.json +++ b/packages/spec/liveness/view.json @@ -211,8 +211,10 @@ "note": "objectui: allowedVisualizations gates the view-type switcher (audit L15); showDescription gates ListView.tsx:1728." }, "tabs": { - "status": "live", - "note": "objectui: TabBar.tsx — icon/visible/pinned/filter wired (audit L15). Sub-key tabs[].order is NOT used for sorting (audit L20) — dead sub-surface." + "status": "dead", + "verifiedAt": "2026-09-07", + "evidenceScope": "cross-repo", + "note": "RE-DERIVED 2026-09-07 (#16362, decision batch #60 option A — the ledger audit that precedes the #16094 authorWarn flip). VERDICT FLIPPED live to dead, and the note this replaces was wrong in BOTH directions at once, which is why the row was worth re-opening. It read: \"objectui: TabBar.tsx — icon/visible/pinned/filter wired (audit L15). Sub-key tabs[].order is NOT used for sorting (audit L20) — dead sub-surface.\" (a) The OVERSTATEMENT, and the reason the row moves: TabBar reads those sub-keys, but NOTHING MOUNTS TabBar. Measured at objectui @a472b071: every ` (a.order ?? 0) - (b.order ?? 0))`. The old note called it a dead sub-surface. Both halves of one sentence were false in opposite directions, which is the two-direction rot the README warns a ledger entry accumulates. CORROBORATION, independent of this measurement: this repo already says so in code — packages/cli/src/utils/i18n-extract.ts scopes its tab-label extractor to a page's `interfaceConfig.userFilters.tabs` and states \"`ListViewSchema.tabs` has no reader in either repo\", deliberately emitting no scaffolding keys for this one. THE hotcrm PREMISE IS UPHELD, NOT CONTRADICTED: hotcrm#1307's `test/view-tab-label-inert.test.ts` asserts the object-view switcher never reads `list.tabs`, and the switcher is plugin-view/src/ViewTabBar.tsx, which takes a `views: ViewTabItem[]` prop (saved views) and reads no `tabs` key at all. So nothing needs filing against that test. (That hotcrm reading is INHERITED from the card and #16094, not re-measured — hotcrm is out of this seat's repo scope; what IS measured here is the objectui switcher it describes.) WHY NOT `live` ON THE TWO AUTHOR-TIME READERS: packages/lint/src/validate-list-view-field-refs.ts#checkTabs and packages/metadata-protocol/src/metadata-diagnostics.ts both walk `tabs[].filter[].field` for reference integrity, and metadata-protocol normalizes filter operators inside it. None of them delivers the key's declared effect (\"Tab definitions for multi-tab view interface\"). That is the route_generation precedent verbatim — an enum validated at the door and then ignored is accept/reject, a different question from liveness — and it is the opposite of dashboard.widgets[].suppressWarnings, whose declared effect IS the lint read. The spec's own ObjectUserFiltersSchema already refuses `tabs` on object views with the prescription \"an object view's tab bar is its saved-view switcher (ViewTabBar)\"; this row now says the same thing about the list slot. ENFORCE-OR-REMOVE (ADR-0049) is a follow-up decision, not this card: the enforce route mounts TabBar and threads `list.tabs` into it, the remove route retires the key and its ViewTabSchema carrier on this slot. Not authorWarn-ed here — the authorWarn field is #16094's." }, "addRecord": { "status": "live",