From e5552bfc90bbf3139690b4ba4b2efcadb5f831d4 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 30 Sep 2026 10:27:39 +0000 Subject: [PATCH] chore(spec): the app and view liveness ledgers cite the re-anchoring commit in place of a dead tracker number Sixteen notes in packages/spec/liveness/app.json (10) and view.json (6) dated their 2026-08-28 re-anchoring with a tracker number that now answers 404. Each now names the commit that wrote it, 8f10a79f7 (the closing symbol-anchor batch), the same anchor earlier slices landed for that batch's other ledgers. Note text only: no status, evidence, verifiedAt, producer or evidenceScope leaf changes. Claude-Session: https://claude.ai/code/session_01Sfe5YjBLwB9J3y8fvm2xq1 Co-authored-by: Claude --- ...4-liveness-ledger-provenance-anchors-4a.md | 14 +++++++++++++ packages/spec/liveness/app.json | 20 +++++++++---------- packages/spec/liveness/view.json | 12 +++++------ 3 files changed, 30 insertions(+), 16 deletions(-) create mode 100644 .changeset/20234-liveness-ledger-provenance-anchors-4a.md diff --git a/.changeset/20234-liveness-ledger-provenance-anchors-4a.md b/.changeset/20234-liveness-ledger-provenance-anchors-4a.md new file mode 100644 index 00000000000..752400504c1 --- /dev/null +++ b/.changeset/20234-liveness-ledger-provenance-anchors-4a.md @@ -0,0 +1,14 @@ +--- +'@objectstack/spec': patch +--- + +Notes in the `app` and `view` liveness ledgers that cited a tracker number which no longer resolves now either cite the commit that decided them or say the decision in words + +Clause-②: no + +Sixteen notes in the `app` and `view` ledgers cited a GitHub issue that no longer exists, so a +reader could not tell why a row carries its verdict. Each such note now either names the commit +that made the decision or, where the number alone carried the meaning, says what was decided. +The `liveness/` ledgers ship in this package's tarball, which is why this is a release note at +all. Note text only: no row's status, evidence, proof, producer or date changes, and no schema, +export or runtime behaviour changes. diff --git a/packages/spec/liveness/app.json b/packages/spec/liveness/app.json index 083df78cb02..93e0bb8f9a9 100644 --- a/packages/spec/liveness/app.json +++ b/packages/spec/liveness/app.json @@ -1,26 +1,26 @@ { "type": "app", - "_note": "AppSchema — the navigation shell, the densest hand-authored surface on the platform. Consumers: the REST read layer's filterAppForUser (packages/rest/src/rest-server.ts:2651-2740 — the SERVER-side authority for app/nav permission + capability gating and the ADR-0045 publish gate, which judges `_unpublished` and NOT `hidden` since #4829), the spec i18n translateApp (i18n-resolver.ts:472), and objectui's shell (app-shell UnifiedSidebar/AppSwitcher/AppHeader/ConsoleLayout/ContextSelectors, home HomeAppsStrip, layout NavigationRenderer/AppShell, console RootLandingRedirect/AppManagementPage — each row cites its reader at the sha it was read at). The #4001/#4142 app step already retired seven dead keys as retiredKey tombstones — they stay in the walked shape, so their rows stay here (tombstone rule, orphans.mts). WALK BOUNDARY (#3095 union rule): `navigation` drills into the union's FIRST member (the `object` variant + base keys); the other variants' payload keys sit outside the walk and were verified by hand — dashboardName (NavigationRenderer.tsx:433), pageName (:435-442), url/target (:462), reportName (:460), componentRef (:464,:644), group `expanded` (:856) all live. The one GAP found there is now CLOSED (#4509, objectui @e8bec83): an `action` item's click dispatches through a host-supplied `onAction` prop that no shipped shell passed, so `actionDef.actionName` reached no dispatcher and every such item dead-clicked. objectui's `useNavActionDispatch` (objectui: packages/app-shell/src/hooks/useNavActionDispatch.ts) resolves the name against `action` metadata and dispatches through the console action runtime, and UnifiedSidebar passes it (objectui: packages/app-shell/src/layout/UnifiedSidebar.tsx:473). A shell that still passes no handler now HIDES action items rather than rendering them dead (objectui: packages/layout/src/NavigationRenderer.tsx:971) — the renderer stops manufacturing the trap. Also note that filterAppForUser USED to walk only the top-level `navigation` tree — it never read `item.areas` at all (it returned early when `navigation` was absent), while the client area switcher renders every area. That made area-level `visible` / `requiredPermissions` FAIL-OPEN gates, not merely unread: a \"hidden\" or permission-gated area showed to everyone. Closed in #4722 for the layer that survived the retirement — the server now runs the same filterNav over every `areas[].navigation` — see the `areas.navigation` row below. AREA GATES, 17.0.0 (#4651): both keys REMOVED and their rows DELETED — NavigationAreaSchema is strict, so the keys left the walked shape and retained rows would report ORPHAN. Route B (remove) over route A (enforce) was the maintainer's call: enforcing needs semantics decided first (does filtering an area remove its items everywhere? does the server bind `user` for area CEL?), which the 17.0.0 window could not hold, and a gate that never gated is strictly safer removed than shipped for a whole major. The strict rejection carries the prescription (ui/app.zod.ts AREA_VISIBLE_RETIRED / AREA_REQUIRED_PERMISSIONS_RETIRED) and names the layers that DO enforce. The boundary those prescriptions pointed at — per-item gating inside an area being shell-side only — was the real gap #4651 left behind, and #4722 closed it: item-level `requiredPermissions` / `requiresService` are now stripped server-side inside `areas[]` too, `visible` (CEL) deliberately not. Recorded on `areas.navigation` below. The area-LEVEL keys remain retired; they were not revived. Seeded 2026-08-01 (#4488). CONTEXT SELECTORS, 17.0.0 (#4509): `includeAll` and `placement` rows DELETED — AppContextSelectorSchema is strict, so the keys left the walked shape and retained rows would report ORPHAN. Both were unwarnable (schema defaults materialize at parse, so the lint could not tell authored from supplied), which made removal the only channel that could reach an author. `includeAll` was the sharp one: not unread but deliberately DISOBEYED — selectors are mandatory-scope, and an All row would clear the scope, which on Studio's package selector means listing the platform's own system/cloud kernel packages. STUDIO_APP authored `includeAll: true` against a renderer that ignored it, and that authoring site went with the key. 2026-08-28 (#13003): every `path:NNN` citation in this file was re-anchored to its consuming symbol; nine of the ten were wrong, all of them IN RANGE. Two of this note's own pointers rotted the same way and are corrected here: `filterAppForUser` is a thin delegate today and the gate lives in `packages/rest/src/meta-item-read-gate.ts#filterAppForUserWithReason`, and the spec i18n entry point is `packages/spec/src/system/i18n-resolver.ts#translateApp`. 2026-09-27 (#20146): every row whose evidence cited objectui's `AppSidebar.tsx` — label, description, icon, branding, active, hidden, navigation.id, navigation.visible, areas.id, areas.label, areas.icon, areas.navigation — is REPOINTED to the reader that is actually mounted, file and symbol, no line numbers. AppSidebar was deprecated under objectui#5720 and never mounted (the console renders `UnifiedSidebar`), and objectui PR #10617 (objectui#5817) removed it from objectui main, so it was never evidence of a live reader. CITED SHA: the `.objectui-sha` pin f8a9d0fb, the tree this repo builds against, which is the convention the `navigation.runAction` row states. That pin STILL carries `AppSidebar.tsx` as a barrel export with no mount site, which is why the old pointers kept resolving while proving nothing. Every re-pointed reader was re-read at the pin, and each also reads its key unchanged at objectui main fb91ac9b0, after the removal, so the next pin bump does not strand them. `branding` is now DRILLED: `logo` is `planned` with carrier objectui#10827, and its three siblings stay `live` (see that row).", + "_note": "AppSchema — the navigation shell, the densest hand-authored surface on the platform. Consumers: the REST read layer's filterAppForUser (packages/rest/src/rest-server.ts:2651-2740 — the SERVER-side authority for app/nav permission + capability gating and the ADR-0045 publish gate, which judges `_unpublished` and NOT `hidden` since #4829), the spec i18n translateApp (i18n-resolver.ts:472), and objectui's shell (app-shell UnifiedSidebar/AppSwitcher/AppHeader/ConsoleLayout/ContextSelectors, home HomeAppsStrip, layout NavigationRenderer/AppShell, console RootLandingRedirect/AppManagementPage — each row cites its reader at the sha it was read at). The #4001/#4142 app step already retired seven dead keys as retiredKey tombstones — they stay in the walked shape, so their rows stay here (tombstone rule, orphans.mts). WALK BOUNDARY (#3095 union rule): `navigation` drills into the union's FIRST member (the `object` variant + base keys); the other variants' payload keys sit outside the walk and were verified by hand — dashboardName (NavigationRenderer.tsx:433), pageName (:435-442), url/target (:462), reportName (:460), componentRef (:464,:644), group `expanded` (:856) all live. The one GAP found there is now CLOSED (#4509, objectui @e8bec83): an `action` item's click dispatches through a host-supplied `onAction` prop that no shipped shell passed, so `actionDef.actionName` reached no dispatcher and every such item dead-clicked. objectui's `useNavActionDispatch` (objectui: packages/app-shell/src/hooks/useNavActionDispatch.ts) resolves the name against `action` metadata and dispatches through the console action runtime, and UnifiedSidebar passes it (objectui: packages/app-shell/src/layout/UnifiedSidebar.tsx:473). A shell that still passes no handler now HIDES action items rather than rendering them dead (objectui: packages/layout/src/NavigationRenderer.tsx:971) — the renderer stops manufacturing the trap. Also note that filterAppForUser USED to walk only the top-level `navigation` tree — it never read `item.areas` at all (it returned early when `navigation` was absent), while the client area switcher renders every area. That made area-level `visible` / `requiredPermissions` FAIL-OPEN gates, not merely unread: a \"hidden\" or permission-gated area showed to everyone. Closed in #4722 for the layer that survived the retirement — the server now runs the same filterNav over every `areas[].navigation` — see the `areas.navigation` row below. AREA GATES, 17.0.0 (#4651): both keys REMOVED and their rows DELETED — NavigationAreaSchema is strict, so the keys left the walked shape and retained rows would report ORPHAN. Route B (remove) over route A (enforce) was the maintainer's call: enforcing needs semantics decided first (does filtering an area remove its items everywhere? does the server bind `user` for area CEL?), which the 17.0.0 window could not hold, and a gate that never gated is strictly safer removed than shipped for a whole major. The strict rejection carries the prescription (ui/app.zod.ts AREA_VISIBLE_RETIRED / AREA_REQUIRED_PERMISSIONS_RETIRED) and names the layers that DO enforce. The boundary those prescriptions pointed at — per-item gating inside an area being shell-side only — was the real gap #4651 left behind, and #4722 closed it: item-level `requiredPermissions` / `requiresService` are now stripped server-side inside `areas[]` too, `visible` (CEL) deliberately not. Recorded on `areas.navigation` below. The area-LEVEL keys remain retired; they were not revived. Seeded 2026-08-01 (#4488). CONTEXT SELECTORS, 17.0.0 (#4509): `includeAll` and `placement` rows DELETED — AppContextSelectorSchema is strict, so the keys left the walked shape and retained rows would report ORPHAN. Both were unwarnable (schema defaults materialize at parse, so the lint could not tell authored from supplied), which made removal the only channel that could reach an author. `includeAll` was the sharp one: not unread but deliberately DISOBEYED — selectors are mandatory-scope, and an All row would clear the scope, which on Studio's package selector means listing the platform's own system/cloud kernel packages. STUDIO_APP authored `includeAll: true` against a renderer that ignored it, and that authoring site went with the key. 2026-08-28 (commit 8f10a79f7): every `path:NNN` citation in this file was re-anchored to its consuming symbol; nine of the ten were wrong, all of them IN RANGE. Two of this note's own pointers rotted the same way and are corrected here: `filterAppForUser` is a thin delegate today and the gate lives in `packages/rest/src/meta-item-read-gate.ts#filterAppForUserWithReason`, and the spec i18n entry point is `packages/spec/src/system/i18n-resolver.ts#translateApp`. 2026-09-27 (#20146): every row whose evidence cited objectui's `AppSidebar.tsx` — label, description, icon, branding, active, hidden, navigation.id, navigation.visible, areas.id, areas.label, areas.icon, areas.navigation — is REPOINTED to the reader that is actually mounted, file and symbol, no line numbers. AppSidebar was deprecated under objectui#5720 and never mounted (the console renders `UnifiedSidebar`), and objectui PR #10617 (objectui#5817) removed it from objectui main, so it was never evidence of a live reader. CITED SHA: the `.objectui-sha` pin f8a9d0fb, the tree this repo builds against, which is the convention the `navigation.runAction` row states. That pin STILL carries `AppSidebar.tsx` as a barrel export with no mount site, which is why the old pointers kept resolving while proving nothing. Every re-pointed reader was re-read at the pin, and each also reads its key unchanged at objectui main fb91ac9b0, after the removal, so the next pin bump does not strand them. `branding` is now DRILLED: `logo` is `planned` with carrier objectui#10827, and its three siblings stay `live` (see that row).", "props": { "name": { "status": "live", "verifiedAt": "2026-08-28", "evidence": "packages/spec/src/system/i18n-resolver.ts#translateApp (`const appName = doc.name` — the routing identity is also the translation-bundle key, so every `apps..*` lookup in this file is addressed by it and a renamed app loses its whole bundle at once rather than half of it)", - "note": "routing identity (`/apps/`) and the translation-bundle key (`apps..*`); objectui RootLandingRedirect routes by it. 2026-08-28: RE-ANCHORED (#13003) and REPOINTED — `i18n-resolver.ts:478` had rotted onto `opts?: ResolveOptions`, a PARAMETER in `resolveActionResultDialog`'s signature ~195 lines above the app resolvers. Re-closed by hand against 8cb96ec41." + "note": "routing identity (`/apps/`) and the translation-bundle key (`apps..*`); objectui RootLandingRedirect routes by it. 2026-08-28: RE-ANCHORED (commit 8f10a79f7) and REPOINTED — `i18n-resolver.ts:478` had rotted onto `opts?: ResolveOptions`, a PARAMETER in `resolveActionResultDialog`'s signature ~195 lines above the app resolvers. Re-closed by hand against 8cb96ec41." }, "label": { "status": "live", "verifiedAt": "2026-09-27", "evidenceScope": "cross-repo", "evidence": "packages/spec/src/system/i18n-resolver.ts#lookupAppAttr (reads `apps..label` down the locale chain); packages/spec/src/system/i18n-resolver.ts#translateApp (applies it over the authored value on every /meta app read); objectui @f8a9d0fb: packages/app-shell/src/layout/AppSwitcher.tsx#AppSwitcher (`resolveKeyedI18nLabel(activeApp.label, t)` on the pill, and `app.label` on each switcher row); objectui @f8a9d0fb: packages/app-shell/src/layout/ConsoleLayout.tsx#ConsoleLayout (`appLabel` into `AppHeader`, and the `AppShell` branding title); objectui @f8a9d0fb: packages/app-shell/src/console/home/HomeAppsStrip.tsx#HomeAppsStrip (the launcher tiles)", - "note": "localized on serve by translateApp; rendered by the App Switcher (mounted in `AppHeader`), the console header and the tab title (`ConsoleLayout`), and Home's launcher tiles (`HomeAppsStrip`). 2026-09-27 (#20146): REPOINTED off objectui's `AppSidebar.tsx` — deprecated, never mounted (the console renders `UnifiedSidebar`), and removed from objectui main by objectui PR #10617 — to the mounted reader(s) above, each re-read at the `.objectui-sha` pin f8a9d0fb and unchanged at objectui main fb91ac9b0. localized on serve by translateApp, rendered by the app switcher and shell header. 2026-08-28: RE-ANCHORED (#13003) and REPOINTED — `:481` had rotted onto `if (!spec) return spec;`, a guard on the ACTION result-dialog path. Re-closed by hand against 8cb96ec41." + "note": "localized on serve by translateApp; rendered by the App Switcher (mounted in `AppHeader`), the console header and the tab title (`ConsoleLayout`), and Home's launcher tiles (`HomeAppsStrip`). 2026-09-27 (#20146): REPOINTED off objectui's `AppSidebar.tsx` — deprecated, never mounted (the console renders `UnifiedSidebar`), and removed from objectui main by objectui PR #10617 — to the mounted reader(s) above, each re-read at the `.objectui-sha` pin f8a9d0fb and unchanged at objectui main fb91ac9b0. localized on serve by translateApp, rendered by the app switcher and shell header. 2026-08-28: RE-ANCHORED (commit 8f10a79f7) and REPOINTED — `:481` had rotted onto `if (!spec) return spec;`, a guard on the ACTION result-dialog path. Re-closed by hand against 8cb96ec41." }, "description": { "status": "live", "verifiedAt": "2026-09-27", "evidenceScope": "cross-repo", "evidence": "objectui @f8a9d0fb: apps/console/src/pages/system/AppManagementPage.tsx#AppManagementPage (each row of the `/system/apps` list renders `resolveKeyedI18nLabel(app.description, t)` under the app's title, and `filteredApps` matches the search query against the same resolved text); framework packages/spec/src/system/i18n-resolver.ts#lookupAppAttr (reads `apps..description`); packages/spec/src/system/i18n-resolver.ts#translateApp", - "note": "LIVE, but narrower than this row used to say: the one mounted reader is the admin app list at `/system/apps` (`AppManagementPage`), which shows the localized description under each app's title and searches it; localized by translateApp. The presentation this row used to cite, the description under the active app's title in the sidebar, has NO successor: that was AppSidebar, and it was never mounted. Not a reader: objectui's app-shell `AppCard` also reads `app.description`, but at the pin it is only barrel-exported, with no mount site, which is the same trap AppSidebar was. 2026-09-27 (#20146): REPOINTED off objectui's `AppSidebar.tsx` — deprecated, never mounted (the console renders `UnifiedSidebar`), and removed from objectui main by objectui PR #10617 — to the mounted reader(s) above, each re-read at the `.objectui-sha` pin f8a9d0fb and unchanged at objectui main fb91ac9b0. 2026-08-28: RE-ANCHORED (#13003) and REPOINTED — `:482` had rotted onto the `title` lookup inside `resolveActionResultDialog`; it, `:481` (label) and `:478` (name) were three consecutive lines of ONE unrelated function, which is what a block of pointers looks like after the file above them grows. Re-closed by hand against 8cb96ec41." + "note": "LIVE, but narrower than this row used to say: the one mounted reader is the admin app list at `/system/apps` (`AppManagementPage`), which shows the localized description under each app's title and searches it; localized by translateApp. The presentation this row used to cite, the description under the active app's title in the sidebar, has NO successor: that was AppSidebar, and it was never mounted. Not a reader: objectui's app-shell `AppCard` also reads `app.description`, but at the pin it is only barrel-exported, with no mount site, which is the same trap AppSidebar was. 2026-09-27 (#20146): REPOINTED off objectui's `AppSidebar.tsx` — deprecated, never mounted (the console renders `UnifiedSidebar`), and removed from objectui main by objectui PR #10617 — to the mounted reader(s) above, each re-read at the `.objectui-sha` pin f8a9d0fb and unchanged at objectui main fb91ac9b0. 2026-08-28: RE-ANCHORED (commit 8f10a79f7) and REPOINTED — `:482` had rotted onto the `title` lookup inside `resolveActionResultDialog`; it, `:481` (label) and `:478` (name) were three consecutive lines of ONE unrelated function, which is what a block of pointers looks like after the file above them grows. Re-closed by hand against 8cb96ec41." }, "icon": { "status": "live", @@ -80,7 +80,7 @@ "verifiedAt": "2026-09-27", "evidenceScope": "cross-repo", "evidence": "objectui @f8a9d0fb: packages/app-shell/src/layout/AppSwitcher.tsx#AppSwitcher (`a.hidden !== true` keeps a hidden app out of the switcher list); objectui @f8a9d0fb: packages/app-shell/src/layout/UnifiedSidebar.tsx#UnifiedSidebar (the same filter; its active-app lookup still spans hidden apps, so /apps/account renders); objectui @f8a9d0fb: packages/app-shell/src/utils/appRoute.ts#filterActiveApps (Home's launcher and the `app-launcher` renderer); objectui @f8a9d0fb: packages/app-shell/src/layout/AppHeader.tsx#AppHeader (the avatar menu lists the apps with `hidden === true`, Account excepted because the Profile link already stands for it); packages/platform-objects/src/apps/account.app.ts#ACCOUNT_APP (the canonical author — `hidden: true` under the comment that states why: surface via the avatar dropdown, not the App Switcher)", - "note": "NAVIGATION PRESENTATION ONLY, and re-verified as such at #4829: keep the app out of the App Switcher; the shell surfaces it from the avatar menu (the built-in Account app is the canonical author). It is NOT an access gate — a hidden app stays fully routable and permission-checked for every user, which is its birth contract in app.zod.ts. Between ADR-0045 (2026-06-12) and its 2026-08-09 amendment the REST gate ALSO read this key as \"unpublished\", which erased the Account app from GET /meta/app for every non-builder; that reading now lives on `_unpublished`. The consumer is therefore the client switcher alone. 2026-08-28: RE-ANCHORED (#13003) — the framework pointer was ACCURATE (`account.app.ts:40` is still `hidden: true`), so this leg is the grammar migration and not a repair. What the anchor buys is that it survives the file growing above it, which is exactly how this ledger's sibling citations rotted. Re-closed by hand against 8cb96ec41. 2026-09-27 (#20146): REPOINTED off objectui's `AppSidebar.tsx` — deprecated, never mounted (the console renders `UnifiedSidebar`), and removed from objectui main by objectui PR #10617 — to the mounted reader(s) above, each re-read at the `.objectui-sha` pin f8a9d0fb and unchanged at objectui main fb91ac9b0. The avatar-menu surface this note names is now cited too (`AppHeader`)." + "note": "NAVIGATION PRESENTATION ONLY, and re-verified as such at #4829: keep the app out of the App Switcher; the shell surfaces it from the avatar menu (the built-in Account app is the canonical author). It is NOT an access gate — a hidden app stays fully routable and permission-checked for every user, which is its birth contract in app.zod.ts. Between ADR-0045 (2026-06-12) and its 2026-08-09 amendment the REST gate ALSO read this key as \"unpublished\", which erased the Account app from GET /meta/app for every non-builder; that reading now lives on `_unpublished`. The consumer is therefore the client switcher alone. 2026-08-28: RE-ANCHORED (commit 8f10a79f7) — the framework pointer was ACCURATE (`account.app.ts:40` is still `hidden: true`), so this leg is the grammar migration and not a repair. What the anchor buys is that it survives the file growing above it, which is exactly how this ledger's sibling citations rotted. Re-closed by hand against 8cb96ec41. 2026-09-27 (#20146): REPOINTED off objectui's `AppSidebar.tsx` — deprecated, never mounted (the console renders `UnifiedSidebar`), and removed from objectui main by objectui PR #10617 — to the mounted reader(s) above, each re-read at the `.objectui-sha` pin f8a9d0fb and unchanged at objectui main fb91ac9b0. The avatar-menu surface this note names is now cited too (`AppHeader`)." }, "navigation": { "children": { @@ -95,7 +95,7 @@ "status": "live", "verifiedAt": "2026-08-28", "evidence": "packages/spec/src/system/i18n-resolver.ts#lookupNavLabel (reads `apps..navigation..label` — keyed by the node id, one flat keyspace regardless of tree depth); packages/spec/src/system/i18n-resolver.ts#translateApp (walks the tree and swaps the label in); objectui @940ba24: packages/layout/src/NavigationRenderer.tsx:284-316 (resolveNavItemLabel)", - "note": "rendered everywhere; translateApp swaps in the per-locale label by node id. 2026-08-28: RE-ANCHORED (#13003) and REPOINTED — `:456` had rotted onto `opts?: ResolveOptions` in `lookupActionResultDialogText`'s signature, ~195 lines above `lookupNavLabel`. Re-closed by hand against 8cb96ec41." + "note": "rendered everywhere; translateApp swaps in the per-locale label by node id. 2026-08-28: RE-ANCHORED (commit 8f10a79f7) and REPOINTED — `:456` had rotted onto `opts?: ResolveOptions` in `lookupActionResultDialogText`'s signature, ~195 lines above `lookupNavLabel`. Re-closed by hand against 8cb96ec41." }, "icon": { "status": "live", @@ -131,7 +131,7 @@ "status": "live", "verifiedAt": "2026-09-27", "evidence": "packages/rest/src/meta-item-read-gate.ts#filterNav (the server strips an entry whose `requiredPermissions` are not a subset of the caller's system permissions — from the top-level tree AND, since #4722, from every `areas[].navigation` tree through this same closure); objectui @940ba24: packages/layout/src/NavigationRenderer.tsx:894", - "note": "enforced in BOTH layers: the server strips unsatisfied entries before serving — from the top-level navigation tree AND, since #4722, from every `areas[].navigation` tree through the same filterNav — and the client re-gates per item. 2026-08-28: RE-ANCHORED (#13003) and REPOINTED — `:1844` had rotted onto a bare `try {` inside `computeExecCtx`'s auth-service lookup, ~320 lines above the gate. Re-closed by hand against 8cb96ec41." + "note": "enforced in BOTH layers: the server strips unsatisfied entries before serving — from the top-level navigation tree AND, since #4722, from every `areas[].navigation` tree through the same filterNav — and the client re-gates per item. 2026-08-28: RE-ANCHORED (commit 8f10a79f7) and REPOINTED — `:1844` had rotted onto a bare `try {` inside `computeExecCtx`'s auth-service lookup, ~320 lines above the gate. Re-closed by hand against 8cb96ec41." }, "requiresObject": { "status": "live", @@ -143,7 +143,7 @@ "status": "live", "verifiedAt": "2026-09-27", "evidence": "packages/rest/src/meta-item-read-gate.ts#filterNav (ADR-0057 D10 — an entry naming a service the kernel has not registered is dropped before the tree is served; fail-open when the kernel cannot be probed); objectui @940ba24: packages/layout/src/NavigationRenderer.tsx:900-902", - "note": "ADR-0057 D10 capability gate, server + client. 2026-08-28: RE-ANCHORED (#13003) and REPOINTED — `:1832` had rotted onto `environmentId = await this.resolveRequestEnvironmentId(environmentId, req)` in `computeExecCtx`, its sibling `requiredPermissions` twelve lines below it in the same unrelated block. Re-closed by hand against 8cb96ec41." + "note": "ADR-0057 D10 capability gate, server + client. 2026-08-28: RE-ANCHORED (commit 8f10a79f7) and REPOINTED — `:1832` had rotted onto `environmentId = await this.resolveRequestEnvironmentId(environmentId, req)` in `computeExecCtx`, its sibling `requiredPermissions` twelve lines below it in the same unrelated block. Re-closed by hand against 8cb96ec41." }, "type": { "status": "live", @@ -286,7 +286,7 @@ "status": "live", "verifiedAt": "2026-09-27", "evidence": "packages/rest/src/meta-item-read-gate.ts#filterAppForUserWithReason (`const reqApp = Array.isArray(item.requiredPermissions) ? item.requiredPermissions : []` — an app whose required permissions are not a subset of the caller's is dropped from /meta entirely, and the single-item GET re-checks through this same function)", - "note": "SERVER-enforced: an app whose required permissions are not a subset of the caller's system permissions is dropped from /meta entirely (and the single-item GET re-checks at rest-server.ts:3298). 2026-08-28: RE-ANCHORED (#13003) and REPOINTED — `:1814` had rotted onto the closing `};` of a `booksRequest` literal in an unrelated metadata read, ~340 lines above the gate; the note's own \"single-item GET re-checks at rest-server.ts:3298\" had rotted with it, and that re-check now runs through `filterAppForUserWithReason` from the single-item branch ~2,000 lines further down. Re-closed by hand against 8cb96ec41." + "note": "SERVER-enforced: an app whose required permissions are not a subset of the caller's system permissions is dropped from /meta entirely (and the single-item GET re-checks at rest-server.ts:3298). 2026-08-28: RE-ANCHORED (commit 8f10a79f7) and REPOINTED — `:1814` had rotted onto the closing `};` of a `booksRequest` literal in an unrelated metadata read, ~340 lines above the gate; the note's own \"single-item GET re-checks at rest-server.ts:3298\" had rotted with it, and that re-check now runs through `filterAppForUserWithReason` from the single-item branch ~2,000 lines further down. Re-closed by hand against 8cb96ec41." }, "defaultAgent": { "status": "live", @@ -333,7 +333,7 @@ "status": "live", "verifiedAt": "2026-09-27", "evidence": "packages/rest/src/meta-item-read-gate.ts#filterAppForUserWithReason (`if (item._unpublished === true && !sysPerms.has('studio.access') && !sysPerms.has('setup.access'))` — the ADR-0045 publish gate, which judges THIS key and deliberately not `hidden`); packages/runtime/src/domains/packages.ts#handlePackagesRequest (POST /packages/:id/publish-drafts flips it to `false` — never deletes it, because ADR-0045 §3 keeps publish and unpublish symmetric)", - "note": "MACHINE-MANAGED publish gate (ADR-0045 §3, amended 2026-08-09 / #4829) — never authored: written by the AI additive-materialization path (cloud) and cleared by POST /packages/:id/publish-drafts. SERVER-enforced: filterAppForUser withholds an unpublished app from every metadata response except a builder's (studio/setup access), for direct-URL preview. Declared on AppSchema rather than omitted because the write path validates against that schema (saveMetaItem → 422; Registry.validate('app') → AppSchema.parse), so the flip itself would be unwritable otherwise. Stored pre-amendment rows carrying `hidden: true` are rewritten here by the ADR-0087 conversion `app-hidden-to-unpublished`. 2026-08-28: RE-ANCHORED (#13003) and REPOINTED, both legs — `rest-server.ts:2669` had rotted onto a docblock about a diagnostic view being neither translated nor cached, ~480 lines below the gate, and `packages.ts:245` onto the domain-wide anonymous-deny floor, ~270 lines above the flip. Re-closed by hand against 8cb96ec41." + "note": "MACHINE-MANAGED publish gate (ADR-0045 §3, amended 2026-08-09 / #4829) — never authored: written by the AI additive-materialization path (cloud) and cleared by POST /packages/:id/publish-drafts. SERVER-enforced: filterAppForUser withholds an unpublished app from every metadata response except a builder's (studio/setup access), for direct-URL preview. Declared on AppSchema rather than omitted because the write path validates against that schema (saveMetaItem → 422; Registry.validate('app') → AppSchema.parse), so the flip itself would be unwritable otherwise. Stored pre-amendment rows carrying `hidden: true` are rewritten here by the ADR-0087 conversion `app-hidden-to-unpublished`. 2026-08-28: RE-ANCHORED (commit 8f10a79f7) and REPOINTED, both legs — `rest-server.ts:2669` had rotted onto a docblock about a diagnostic view being neither translated nor cached, ~480 lines below the gate, and `packages.ts:245` onto the domain-wide anonymous-deny floor, ~270 lines above the flip. Re-closed by hand against 8cb96ec41." } } } diff --git a/packages/spec/liveness/view.json b/packages/spec/liveness/view.json index bd9ae6c0202..d6cf52aedb7 100644 --- a/packages/spec/liveness/view.json +++ b/packages/spec/liveness/view.json @@ -1,6 +1,6 @@ { "type": "view", - "_note": "ViewSchema (object view container: list/form/listViews/formViews). Seeded from docs/audits/2026-06-viewschema-property-liveness.md (objectui consumer cross-reference) and re-verified against objectui@fb35e48 (2026-07-16) — several audit-era DEAD findings have since gone LIVE (submitBehavior, sharing.lockedBy, ViewData providers on the list path) and are classified from the current reads, not the stale audit lines. objectui paths cited as 'objectui: ' prose (not resolved against this repo). Sub-sub-key divergences (userActions.buttons, addRecord.mode/formView, tabs[].order) can't be drilled (one level only) — captured in the parent entry's note and tracked in the enforce-or-remove worklist (#2998 Track B / ADR-0049). 2026-07-30 (#3896 close-out sweep): the dead authoring keys were REMOVED — tombstoned at the schema with prescriptions (retiredKey) and stripped by the protocol-17 close-out conversions; entries deleted per the #3715 precedent. widget.performance (no ledger file of its own) was verified dead the corrected way — zero readers in either repo; objectui virtual scrolling reads the LIVE top-level virtualScroll — and removed with them. 2026-08-28 (#13003): all five `path:NNN` citations in this file were re-anchored to their consuming symbols, and all five were wrong. Two pairs shared one wrong line each — `list.name`/`listViews` on a schema declaration, `form.sharing`/`formViews` on a comment about API routes — and `object` was falsified in PROSE as well as position, naming a function that lives in another package.", + "_note": "ViewSchema (object view container: list/form/listViews/formViews). Seeded from docs/audits/2026-06-viewschema-property-liveness.md (objectui consumer cross-reference) and re-verified against objectui@fb35e48 (2026-07-16) — several audit-era DEAD findings have since gone LIVE (submitBehavior, sharing.lockedBy, ViewData providers on the list path) and are classified from the current reads, not the stale audit lines. objectui paths cited as 'objectui: ' prose (not resolved against this repo). Sub-sub-key divergences (userActions.buttons, addRecord.mode/formView, tabs[].order) can't be drilled (one level only) — captured in the parent entry's note and tracked in the enforce-or-remove worklist (#2998 Track B / ADR-0049). 2026-07-30 (#3896 close-out sweep): the dead authoring keys were REMOVED — tombstoned at the schema with prescriptions (retiredKey) and stripped by the protocol-17 close-out conversions; entries deleted per the #3715 precedent. widget.performance (no ledger file of its own) was verified dead the corrected way — zero readers in either repo; objectui virtual scrolling reads the LIVE top-level virtualScroll — and removed with them. 2026-08-28 (commit 8f10a79f7): all five `path:NNN` citations in this file were re-anchored to their consuming symbols, and all five were wrong. Two pairs shared one wrong line each — `list.name`/`listViews` on a schema declaration, `form.sharing`/`formViews` on a comment about API routes — and `object` was falsified in PROSE as well as position, naming a function that lives in another package.", "props": { "name": { "status": "dead", @@ -18,7 +18,7 @@ "status": "live", "verifiedAt": "2026-08-28", "evidence": "packages/objectql/src/engine.ts#resolveMetadataItemName (`return item?.object || item?.list?.data?.object || item?.form?.data?.object` — a stack-level `views:` container has no top-level name, so this key IS its registry key and therefore the object every expanded ViewItem is stamped with); packages/metadata/src/metadata-manager.ts#getViewsByObject (`v.object === object` — the index `GET /meta/view?object=` answers from)", - "note": "How a stack-level `views: [...]` entry says which object its views belong to — the container is 'view definitions for a specific object' (this file's own note on ObjectListViewSchema), and the object index is what reads the binding. Declared in #4001 batch 6e: it was undeclared and therefore stripped, so a container's object binding was dropped on every parse. Found by the CLI's migrate e2e, whose fixture carries it. 2026-08-28: RE-ANCHORED (#13003) and REPOINTED, position AND prose — `engine.ts:1653` had rotted onto a hook `excludeObjects` guard ~361 lines below the resolver, and the parenthetical credited `getViewsByObject()` to THAT file, where it does not exist: it lives in `packages/metadata/src/metadata-manager.ts`. Both halves of a citation can be wrong at once, and the prose half is the one a reader trusts when the line still looks plausible. Re-closed by hand against 8cb96ec41." + "note": "How a stack-level `views: [...]` entry says which object its views belong to — the container is 'view definitions for a specific object' (this file's own note on ObjectListViewSchema), and the object index is what reads the binding. Declared in #4001 batch 6e: it was undeclared and therefore stripped, so a container's object binding was dropped on every parse. Found by the CLI's migrate e2e, whose fixture carries it. 2026-08-28: RE-ANCHORED (commit 8f10a79f7) and REPOINTED, position AND prose — `engine.ts:1653` had rotted onto a hook `excludeObjects` guard ~361 lines below the resolver, and the parenthetical credited `getViewsByObject()` to THAT file, where it does not exist: it lives in `packages/metadata/src/metadata-manager.ts`. Both halves of a citation can be wrong at once, and the prose half is the one a reader trusts when the line still looks plausible. Re-closed by hand against 8cb96ec41." }, "list": { "children": { @@ -26,7 +26,7 @@ "status": "live", "verifiedAt": "2026-08-28", "evidence": "packages/spec/src/ui/view.zod.ts#expandViewContainerWithDiagnostics (`const key = typeof defaultList.name === 'string' && defaultList.name ? defaultList.name : 'default'` — the default list view's own name becomes its `.` identity, and a collision with a `listViews` key is renamed and diagnosed)", - "note": "view identity — expandViewContainer key; objectui ListView/ViewTabBar. 2026-08-28: RE-ANCHORED (#13003) and REPOINTED — `:1432` had rotted onto `}, {`, a shape-boundary line of the view-config schema ~2,974 lines above the expander. It was a DECLARATION site rather than a consumer even when it was right; the key's liveness rests on the expander reading it, which is what the anchor names. Re-closed by hand against 8cb96ec41." + "note": "view identity — expandViewContainer key; objectui ListView/ViewTabBar. 2026-08-28: RE-ANCHORED (commit 8f10a79f7) and REPOINTED — `:1432` had rotted onto `}, {`, a shape-boundary line of the view-config schema ~2,974 lines above the expander. It was a DECLARATION site rather than a consumer even when it was right; the key's liveness rests on the expander reading it, which is what the anchor names. Re-closed by hand against 8cb96ec41." }, "label": { "status": "live", @@ -344,7 +344,7 @@ "status": "live", "verifiedAt": "2026-08-28", "evidence": "packages/rest/src/rest-server.ts#findPublicFormView (`slugMatchesPublicLink(sharing.publicLink, slug)` — scanned across `form` and every `formViews` entry); packages/rest/src/rest-server.ts#resolveFormBySlug (grants `publicFormGrant` for the matched form's object)", - "note": "Framework-side consumer: public (anonymous) form endpoints opt in via FormView.sharing — /forms/:slug resolves sharing.publicLink across form + formViews (rest-server.ts:1716, :4366-4405) and grants publicFormGrant. Renderer-side the config is not read (audit L20) — the public form is served, not re-parsed client-side. 2026-08-28: RE-ANCHORED (#13003) and REPOINTED — `:4384` had rotted onto a comment about `api`-only route enumeration, ~4,020 lines above the form endpoints; the note's own inline pointers (`:1716`, `:4366-4405`) had gone with it and are superseded by the anchors. Re-closed by hand against 8cb96ec41." + "note": "Framework-side consumer: public (anonymous) form endpoints opt in via FormView.sharing — /forms/:slug resolves sharing.publicLink across form + formViews (rest-server.ts:1716, :4366-4405) and grants publicFormGrant. Renderer-side the config is not read (audit L20) — the public form is served, not re-parsed client-side. 2026-08-28: RE-ANCHORED (commit 8f10a79f7) and REPOINTED — `:4384` had rotted onto a comment about `api`-only route enumeration, ~4,020 lines above the form endpoints; the note's own inline pointers (`:1716`, `:4366-4405`) had gone with it and are superseded by the anchors. Re-closed by hand against 8cb96ec41." }, "submitBehavior": { "status": "live", @@ -374,13 +374,13 @@ "status": "live", "verifiedAt": "2026-08-28", "evidence": "packages/spec/src/ui/view.zod.ts#expandViewContainerWithDiagnostics (`container.listViews` — each entry becomes an independent ViewItem named `.`, with collisions renamed and reported)", - "note": "Named list views. Framework: expandViewContainer flattens container views into per-object view items (collision diagnostics via expandViewContainerWithDiagnostics). objectui: MetadataProvider.tsx:118-146 merges view metadata into objectDef.listViews — the saved-view switcher (ViewTabBar) reads only listViews (ADR-0047 'views' mode). Same inner shape as `list`; per-key classification lives under list.children. 2026-08-28: RE-ANCHORED (#13003) and REPOINTED — `:1432` had rotted onto the same schema-declaration line its sibling `list.name` carried; two keys shared one wrong pointer. Re-closed by hand against 8cb96ec41." + "note": "Named list views. Framework: expandViewContainer flattens container views into per-object view items (collision diagnostics via expandViewContainerWithDiagnostics). objectui: MetadataProvider.tsx:118-146 merges view metadata into objectDef.listViews — the saved-view switcher (ViewTabBar) reads only listViews (ADR-0047 'views' mode). Same inner shape as `list`; per-key classification lives under list.children. 2026-08-28: RE-ANCHORED (commit 8f10a79f7) and REPOINTED — `:1432` had rotted onto the same schema-declaration line its sibling `list.name` carried; two keys shared one wrong pointer. Re-closed by hand against 8cb96ec41." }, "formViews": { "status": "live", "verifiedAt": "2026-08-28", "evidence": "packages/rest/src/rest-server.ts#findPublicFormView (`const formViews = view.formViews` — every named form view is a public-link candidate); packages/spec/src/ui/view.zod.ts#expandViewContainerWithDiagnostics (flattens them into independent ViewItems)", - "note": "Named form views. Framework: public-form slug resolution scans form + every formViews entry (rest-server.ts:4384-4405); expandViewContainer flattens them. objectui: MetadataProvider routes viewKind:'form' items into objectDef.formViews (never into the list switcher). Same inner shape as `form`; per-key classification lives under form.children. 2026-08-28: RE-ANCHORED (#13003) and REPOINTED — `:4384` had rotted onto the same `api`-only comment its sibling `form.sharing` cited; the note's `rest-server.ts:4384-4405` range went with it. Re-closed by hand against 8cb96ec41." + "note": "Named form views. Framework: public-form slug resolution scans form + every formViews entry (rest-server.ts:4384-4405); expandViewContainer flattens them. objectui: MetadataProvider routes viewKind:'form' items into objectDef.formViews (never into the list switcher). Same inner shape as `form`; per-key classification lives under form.children. 2026-08-28: RE-ANCHORED (commit 8f10a79f7) and REPOINTED — `:4384` had rotted onto the same `api`-only comment its sibling `form.sharing` cited; the note's `rest-server.ts:4384-4405` range went with it. Re-closed by hand against 8cb96ec41." } } }