diff --git a/.changeset/twelve-hidden-migrate-sentences.md b/.changeset/twelve-hidden-migrate-sentences.md new file mode 100644 index 0000000000..54f401a6f8 --- /dev/null +++ b/.changeset/twelve-hidden-migrate-sentences.md @@ -0,0 +1,5 @@ +--- +"@objectstack/spec": patch +--- + +12 more protocol-17 `retiredKey()` prescriptions now close with the house sentence ``Run `os migrate meta --from 16` to rewrite existing sources automatically.`` (#7062, the literal-level remainder of #6914/#6856 route D). These sites were invisible to the file-level census because their files already carried the sentence elsewhere: `agent.knowledge`, `action.shortcut`/`bulkEnabled`, the seven `app.*` tombstones (`version`/`objects`/`apis`/`sharing`/`embed`/`mobileNavigation`/`aria`) and `dashboard.aria`/`performance` — each verified against its registered v17 conversion (`agent-knowledge-removed`, `action-inert-keys-removed`, `app-dead-authoring-keys-removed`, `dashboard-inert-keys-removed`). Guidance prose before the appended sentence is unchanged; tombstones without a covering conversion deliberately stay silent. diff --git a/content/docs/references/ai/agent.mdx b/content/docs/references/ai/agent.mdx index 06b62379dc..d333b78ff0 100644 --- a/content/docs/references/ai/agent.mdx +++ b/content/docs/references/ai/agent.mdx @@ -54,7 +54,7 @@ const result = AIModelConfigSchema.parse(data); | **surface** | `Enum<'ask' \| 'build'>` | ✅ | Product surface this agent binds ('ask' \| 'build') — ADR-0063 §1 | | **skills** | `string[]` | optional | Skill names to attach (Agent→Skill→Tool architecture) | | **tools** | `never` | optional | [REMOVED] `agent.tools` was removed in @objectstack/spec 17 (#3894) — use `skills`. An agent reaches exactly the tools its surface-compatible skills declare (ADR-0064), so move each reference into a skill: a platform tool by its registered name, or `action_` for one of your own AI-exposed Actions. This is NOT a rename — there is no key the value moves to: the migration DELETES the key and emits a notice naming each tool that was listed, and you re-declare each one in a skill by hand. Run `os migrate meta --from 16` to rewrite existing sources automatically. | -| **knowledge** | `never` | optional | [REMOVED] `agent.knowledge` was removed in @objectstack/spec 17.0.0 (#3896 audit close-out) — declaring knowledge sources/indexes on an agent never scoped retrieval: the `search_knowledge` tool takes `sourceIds` from the LLM's tool-call arguments, not from the agent record. Delete the block. Restrict retrieval at the knowledge-service / source level (per-source permissions), and describe intended grounding in `instructions` so the model asks for the right sources. | +| **knowledge** | `never` | optional | [REMOVED] `agent.knowledge` was removed in @objectstack/spec 17.0.0 (#3896 audit close-out) — declaring knowledge sources/indexes on an agent never scoped retrieval: the `search_knowledge` tool takes `sourceIds` from the LLM's tool-call arguments, not from the agent record. Delete the block. Restrict retrieval at the knowledge-service / source level (per-source permissions), and describe intended grounding in `instructions` so the model asks for the right sources. Run `os migrate meta --from 16` to rewrite existing sources automatically. | | **active** | `boolean` | ✅ | | | **access** | `string[]` | optional | Who can chat with this agent | | **permissions** | `string[]` | optional | Required permission-set capabilities | diff --git a/content/docs/references/ui/action.mdx b/content/docs/references/ui/action.mdx index 7d953b0919..f5efe38a08 100644 --- a/content/docs/references/ui/action.mdx +++ b/content/docs/references/ui/action.mdx @@ -84,8 +84,8 @@ const result = ActionSchema.parse(data); | **requiresFeature** | `Enum<'twoFactor' \| 'passkeys' \| 'magicLink' \| 'organization' \| 'multiOrgEnabled' \| 'degradedTenancy' \| 'oidcProvider' \| 'sso' \| 'ssoEnforced' \| 'deviceAuthorization' \| … +3 more>` | optional | Public auth feature flag gating this action; lowered into `visible` at parse time. | | **disabled** | `boolean \| string \| { dialect: Enum<'cel' \| 'cron' \| 'template'>; source?: string; ast?: any; meta?: object }` | optional | Disabled predicate — `true`/`false` literal, CEL string, or `{dialect, source}` envelope. The action is shown but refused when it evaluates TRUE. Omit = never disabled. | | **requiredPermissions** | `string[]` | optional | [ADR-0066 D4] Capabilities required to invoke this action. Enforced with 403 on the platform action route (script/flow/modal + MCP) and mirrored as a UI hide; a `type: api` action pointed at a custom endpoint must re-check it there. | -| **shortcut** | `never` | optional | [REMOVED] `action.shortcut` was removed in @objectstack/spec 17.0.0 (#3896 audit close-out) — it never triggered anything: no keydown listener feeds ActionEngine.getShortcuts(), and objectui's keyboard stack (useKeyboardShortcuts) is hand-registered and never consults action metadata. Delete the key. For a real shortcut, register the key in the Console keyboard stack and have its handler invoke the action by name. | -| **bulkEnabled** | `never` | optional | [REMOVED] `action.bulkEnabled` was removed in @objectstack/spec 17.0.0 (#3896 audit close-out) — the multi-select toolbar is driven by the LIST VIEW's `bulkActions` / `bulkActionDefs`, never by this flag, so setting it changed nothing. Delete the key and declare the action in the view's `bulkActions` instead. | +| **shortcut** | `never` | optional | [REMOVED] `action.shortcut` was removed in @objectstack/spec 17.0.0 (#3896 audit close-out) — it never triggered anything: no keydown listener feeds ActionEngine.getShortcuts(), and objectui's keyboard stack (useKeyboardShortcuts) is hand-registered and never consults action metadata. Delete the key. For a real shortcut, register the key in the Console keyboard stack and have its handler invoke the action by name. Run `os migrate meta --from 16` to rewrite existing sources automatically. | +| **bulkEnabled** | `never` | optional | [REMOVED] `action.bulkEnabled` was removed in @objectstack/spec 17.0.0 (#3896 audit close-out) — the multi-select toolbar is driven by the LIST VIEW's `bulkActions` / `bulkActionDefs`, never by this flag, so setting it changed nothing. Delete the key and declare the action in the view's `bulkActions` instead. Run `os migrate meta --from 16` to rewrite existing sources automatically. | | **ai** | `{ exposed?: boolean; description?: string; category?: Enum<'data' \| 'action' \| 'flow' \| 'integration' \| 'vector_search' \| 'analytics' \| 'utility'>; paramHints?: Record; … }` | optional | AI exposure (opt-in). Set ai.exposed=true + ai.description to make this callable by agents. | | **recordIdParam** | `string` | optional | Body key to inject the row id into when running from a list_item context. | | **recordIdField** | `string` | optional | Row field whose value seeds recordIdParam. Defaults to "id". | diff --git a/content/docs/references/ui/app.mdx b/content/docs/references/ui/app.mdx index 254a71b012..86b7f70098 100644 --- a/content/docs/references/ui/app.mdx +++ b/content/docs/references/ui/app.mdx @@ -66,7 +66,7 @@ const result = ActionNavItemSchema.parse(data); | :--- | :--- | :--- | :--- | | **name** | `string` | ✅ | App unique machine name (lowercase snake_case) | | **label** | `string \| Record` | ✅ | App display label | -| **version** | `never` | optional | [REMOVED] `App.version` was removed in @objectstack/spec 17.0.0 (2026-06 liveness audit — no consumer in framework or objectui). An app is versioned by its owning package: use `manifest.version`. Delete the key. | +| **version** | `never` | optional | [REMOVED] `App.version` was removed in @objectstack/spec 17.0.0 (2026-06 liveness audit — no consumer in framework or objectui). An app is versioned by its owning package: use `manifest.version`. Delete the key. Run `os migrate meta --from 16` to rewrite existing sources automatically. | | **description** | `string \| Record` | optional | App description | | **icon** | `string` | optional | App icon used in the App Launcher | | **branding** | `{ primaryColor?: string; accentColor?: string; logo?: string; favicon?: string }` | optional | App-specific branding | @@ -79,13 +79,13 @@ const result = ActionNavItemSchema.parse(data); | **contextSelectors** | `{ id: string; label: string \| Record; icon?: string; optionsSource: object; … }[]` | optional | App-level scope dropdowns whose value is injected into nav items as `{}` template vars | | **homePageId** | `never` | optional | [REMOVED] `app.homePageId` was removed in @objectstack/spec 17.0.0 (#4667, #4709, ADR-0049). objectui's console did read it before v17 (`resolveLandingRoute`), so this key had a consumer — it was retired because the capability is better expressed on the navigation item itself than as an ID cross-reference that silently falls back when it dangles. An app's landing page IS its first navigation item (by `order`), and the root landing follows `isDefault` routing. Delete the key; to change where an app opens, reorder `navigation` so the intended entry is first, and set `isDefault` on the app that should own the root landing. Run `os migrate meta --from 16` to rewrite existing sources automatically. | | **requiredPermissions** | `string[]` | optional | Permissions required to access this app | -| **objects** | `never` | optional | [REMOVED] `App.objects` was removed in @objectstack/spec 17.0.0 (2026-06 liveness audit — never read; the spec itself labelled it "config file convenience"). Objects belong to the stack (`defineStack({ objects })`); an app reaches them through its navigation items. Delete the key. | -| **apis** | `never` | optional | [REMOVED] `App.apis` was removed in @objectstack/spec 17.0.0 (2026-06 liveness audit — never read). Delete the key and declare the endpoint one level up, on the STACK: `defineStack({ apis })`. That surface EXECUTES from protocol 17 (#5040). Between #4936 and the executor landing it was refused wholesale — nothing mounted a declared path, so every key including `authRequired` parsed and gated nothing — and that blanket refusal is now narrowed to five per-endpoint publish gates (namespace, supported target, mapping, policy, uniqueness): an endpoint that passes them is mounted and serves traffic as soon as the stack is published. Two things to get right when you move it: the path must sit inside your own carve-out, `/api/v1/apps//` with an explicit `manifest.namespace` (ADR-0121 D1/D2), and `authRequired` defaults to `true` — an explicit `false` is the only thing that opens anonymous access, and ADR-0121 D6 then requires an armed `rateLimit: { enabled: true, windowMs, maxRequests }`. Read the `declarative-apis-endpoints-live` entry of the protocol upgrade guide first; it is a security review, not a rename. A route that genuinely needs handler CODE still belongs in a plugin manifest `contributes.routes` entry. | -| **sharing** | `never` | optional | [REMOVED] `App.sharing` was removed in @objectstack/spec 17.0.0 (2026-06 liveness audit / ADR-0049 enforce-or-remove) — no public-app route ever read it, so it declared sharing that did not exist. Public access is granted per FORM VIEW (`FormView.sharing`, the public-data-collection surface). Delete the key. | -| **embed** | `never` | optional | [REMOVED] `App.embed` was removed in @objectstack/spec 17.0.0 (2026-06 liveness audit / ADR-0049) — no iframe route ever read it. Embedding is a per-form-view surface (`FormView.sharing`), not an app-level switch. Delete the key. | -| **mobileNavigation** | `never` | optional | [REMOVED] `App.mobileNavigation` was removed in @objectstack/spec 17.0.0 (2026-06 liveness audit — fully unimplemented; no renderer, including packages/mobile, ever read it). Delete the key; the block returns if/when a real mobile navigation ships. | +| **objects** | `never` | optional | [REMOVED] `App.objects` was removed in @objectstack/spec 17.0.0 (2026-06 liveness audit — never read; the spec itself labelled it "config file convenience"). Objects belong to the stack (`defineStack({ objects })`); an app reaches them through its navigation items. Delete the key. Run `os migrate meta --from 16` to rewrite existing sources automatically. | +| **apis** | `never` | optional | [REMOVED] `App.apis` was removed in @objectstack/spec 17.0.0 (2026-06 liveness audit — never read). Delete the key and declare the endpoint one level up, on the STACK: `defineStack({ apis })`. That surface EXECUTES from protocol 17 (#5040). Between #4936 and the executor landing it was refused wholesale — nothing mounted a declared path, so every key including `authRequired` parsed and gated nothing — and that blanket refusal is now narrowed to five per-endpoint publish gates (namespace, supported target, mapping, policy, uniqueness): an endpoint that passes them is mounted and serves traffic as soon as the stack is published. Two things to get right when you move it: the path must sit inside your own carve-out, `/api/v1/apps//` with an explicit `manifest.namespace` (ADR-0121 D1/D2), and `authRequired` defaults to `true` — an explicit `false` is the only thing that opens anonymous access, and ADR-0121 D6 then requires an armed `rateLimit: { enabled: true, windowMs, maxRequests }`. Read the `declarative-apis-endpoints-live` entry of the protocol upgrade guide first; it is a security review, not a rename. A route that genuinely needs handler CODE still belongs in a plugin manifest `contributes.routes` entry. Run `os migrate meta --from 16` to rewrite existing sources automatically. | +| **sharing** | `never` | optional | [REMOVED] `App.sharing` was removed in @objectstack/spec 17.0.0 (2026-06 liveness audit / ADR-0049 enforce-or-remove) — no public-app route ever read it, so it declared sharing that did not exist. Public access is granted per FORM VIEW (`FormView.sharing`, the public-data-collection surface). Delete the key. Run `os migrate meta --from 16` to rewrite existing sources automatically. | +| **embed** | `never` | optional | [REMOVED] `App.embed` was removed in @objectstack/spec 17.0.0 (2026-06 liveness audit / ADR-0049) — no iframe route ever read it. Embedding is a per-form-view surface (`FormView.sharing`), not an app-level switch. Delete the key. Run `os migrate meta --from 16` to rewrite existing sources automatically. | +| **mobileNavigation** | `never` | optional | [REMOVED] `App.mobileNavigation` was removed in @objectstack/spec 17.0.0 (2026-06 liveness audit — fully unimplemented; no renderer, including packages/mobile, ever read it). Delete the key; the block returns if/when a real mobile navigation ships. Run `os migrate meta --from 16` to rewrite existing sources automatically. | | **defaultAgent** | `string` | optional | Platform agent bound to this app's ambient chat ('ask' is the implicit default; 'build' for authoring surfaces) — ADR-0063 §1 | -| **aria** | `never` | optional | [REMOVED] `App.aria` was removed in @objectstack/spec 17.0.0 (2026-06 liveness audit — no renderer read app-level ARIA attributes). Declare `aria` on the page component that renders the DOM node instead (`page.components[].aria`; `page.aria` and the list view `aria` are live too). Delete the key. | +| **aria** | `never` | optional | [REMOVED] `App.aria` was removed in @objectstack/spec 17.0.0 (2026-06 liveness audit — no renderer read app-level ARIA attributes). Declare `aria` on the page component that renders the DOM node instead (`page.components[].aria`; `page.aria` and the list view `aria` are live too). Delete the key. Run `os migrate meta --from 16` to rewrite existing sources automatically. | | **protection** | `{ lock: Enum<'none' \| 'no-overlay' \| 'no-delete' \| 'full'>; reason: string; docsUrl?: string }` | optional | Package author protection block — lock policy for this app. | | **_lock** | `Enum<'none' \| 'no-overlay' \| 'no-delete' \| 'full'>` | optional | Item-level lock — controls overlay & delete (ADR-0010). | | **_lockReason** | `string` | optional | Human-readable reason shown when a write is refused by _lock. | diff --git a/content/docs/references/ui/dashboard.mdx b/content/docs/references/ui/dashboard.mdx index 34877716e4..2a89c06e4b 100644 --- a/content/docs/references/ui/dashboard.mdx +++ b/content/docs/references/ui/dashboard.mdx @@ -39,8 +39,8 @@ const result = DashboardSchema.parse(data); | **refreshInterval** | `number` | optional | Auto-refresh interval in seconds | | **dateRange** | `{ field?: string; defaultRange: Enum<'today' \| 'yesterday' \| 'this_week' \| 'last_week' \| 'this_month' \| 'last_month' \| … +8 more>; allowCustomRange: boolean }` | optional | Global dashboard date range filter configuration | | **globalFilters** | `{ name?: string; field: string; label?: string \| Record; type?: Enum<'text' \| 'select' \| 'date' \| 'number' \| 'lookup'>; … }[]` | optional | Global filters that apply to all widgets in the dashboard | -| **aria** | `never` | optional | [REMOVED] `dashboard.aria` was removed in @objectstack/spec 17.0.0 (#3896 audit close-out) — no dashboard renderer ever applied it, so declared ARIA attributes silently did not reach the DOM. Delete the key. | -| **performance** | `never` | optional | [REMOVED] `dashboard.performance` was removed in @objectstack/spec 17.0.0 (#3896 audit close-out) — no renderer or runtime read it; dashboard performance tuning was never implemented. Delete the key. | +| **aria** | `never` | optional | [REMOVED] `dashboard.aria` was removed in @objectstack/spec 17.0.0 (#3896 audit close-out) — no dashboard renderer ever applied it, so declared ARIA attributes silently did not reach the DOM. Delete the key. Run `os migrate meta --from 16` to rewrite existing sources automatically. | +| **performance** | `never` | optional | [REMOVED] `dashboard.performance` was removed in @objectstack/spec 17.0.0 (#3896 audit close-out) — no renderer or runtime read it; dashboard performance tuning was never implemented. Delete the key. Run `os migrate meta --from 16` to rewrite existing sources automatically. | | **protection** | `{ lock: Enum<'none' \| 'no-overlay' \| 'no-delete' \| 'full'>; reason: string; docsUrl?: string }` | optional | Package author protection block — lock policy for this dashboard. | | **_lock** | `Enum<'none' \| 'no-overlay' \| 'no-delete' \| 'full'>` | optional | Item-level lock — controls overlay & delete (ADR-0010). | | **_lockReason** | `string` | optional | Human-readable reason shown when a write is refused by _lock. | diff --git a/packages/spec/src/ai/agent.zod.ts b/packages/spec/src/ai/agent.zod.ts index bd598fa0f1..d36fa7d54b 100644 --- a/packages/spec/src/ai/agent.zod.ts +++ b/packages/spec/src/ai/agent.zod.ts @@ -251,7 +251,8 @@ export const AgentSchema = lazySchema(() => strictObject({ "`search_knowledge` tool takes `sourceIds` from the LLM's tool-call arguments, not from " + 'the agent record. Delete the block. Restrict retrieval at the knowledge-service / ' + 'source level (per-source permissions), and describe intended grounding in ' + - '`instructions` so the model asks for the right sources.', + '`instructions` so the model asks for the right sources. ' + + 'Run `os migrate meta --from 16` to rewrite existing sources automatically.', ), /** Interface */ diff --git a/packages/spec/src/ui/action.zod.ts b/packages/spec/src/ui/action.zod.ts index a2760d07e4..5b4091cc60 100644 --- a/packages/spec/src/ui/action.zod.ts +++ b/packages/spec/src/ui/action.zod.ts @@ -994,13 +994,15 @@ const actionObject = () => strictObject({ 'it never triggered anything: no keydown listener feeds ActionEngine.getShortcuts(), and ' + "objectui's keyboard stack (useKeyboardShortcuts) is hand-registered and never consults " + 'action metadata. Delete the key. For a real shortcut, register the key in the Console ' + - 'keyboard stack and have its handler invoke the action by name.', + 'keyboard stack and have its handler invoke the action by name. ' + + 'Run `os migrate meta --from 16` to rewrite existing sources automatically.', ), bulkEnabled: retiredKey( '`action.bulkEnabled` was removed in @objectstack/spec 17.0.0 (#3896 audit close-out) — ' + 'the multi-select toolbar is driven by the LIST VIEW\'s `bulkActions` / `bulkActionDefs`, ' + 'never by this flag, so setting it changed nothing. Delete the key and declare the action ' + - "in the view's `bulkActions` instead.", + "in the view's `bulkActions` instead. " + + 'Run `os migrate meta --from 16` to rewrite existing sources automatically.', ), /** diff --git a/packages/spec/src/ui/app.zod.ts b/packages/spec/src/ui/app.zod.ts index efcf831770..37f988d16d 100644 --- a/packages/spec/src/ui/app.zod.ts +++ b/packages/spec/src/ui/app.zod.ts @@ -1253,7 +1253,8 @@ export const AppSchema = lazySchema(() => strictObject( version: retiredKey( '`App.version` was removed in @objectstack/spec 17.0.0 (2026-06 liveness audit — ' + 'no consumer in framework or objectui). An app is versioned by its owning package: ' + - 'use `manifest.version`. Delete the key.', + 'use `manifest.version`. Delete the key. ' + + 'Run `os migrate meta --from 16` to rewrite existing sources automatically.', ), /** Description */ @@ -1394,7 +1395,8 @@ export const AppSchema = lazySchema(() => strictObject( '`App.objects` was removed in @objectstack/spec 17.0.0 (2026-06 liveness audit — ' + 'never read; the spec itself labelled it "config file convenience"). Objects belong ' + 'to the stack (`defineStack({ objects })`); an app reaches them through its ' + - 'navigation items. Delete the key.', + 'navigation items. Delete the key. ' + + 'Run `os migrate meta --from 16` to rewrite existing sources automatically.', ), apis: retiredKey( '`App.apis` was removed in @objectstack/spec 17.0.0 (2026-06 liveness audit — ' + @@ -1412,7 +1414,8 @@ export const AppSchema = lazySchema(() => strictObject( '`rateLimit: { enabled: true, windowMs, maxRequests }`. Read the ' + '`declarative-apis-endpoints-live` entry of the protocol upgrade guide first; it is a ' + 'security review, not a rename. A route that genuinely needs handler CODE still ' + - 'belongs in a plugin manifest `contributes.routes` entry.', + 'belongs in a plugin manifest `contributes.routes` entry. ' + + 'Run `os migrate meta --from 16` to rewrite existing sources automatically.', ), /** @@ -1426,12 +1429,14 @@ export const AppSchema = lazySchema(() => strictObject( '`App.sharing` was removed in @objectstack/spec 17.0.0 (2026-06 liveness audit / ' + 'ADR-0049 enforce-or-remove) — no public-app route ever read it, so it declared ' + 'sharing that did not exist. Public access is granted per FORM VIEW ' + - '(`FormView.sharing`, the public-data-collection surface). Delete the key.', + '(`FormView.sharing`, the public-data-collection surface). Delete the key. ' + + 'Run `os migrate meta --from 16` to rewrite existing sources automatically.', ), embed: retiredKey( '`App.embed` was removed in @objectstack/spec 17.0.0 (2026-06 liveness audit / ' + 'ADR-0049) — no iframe route ever read it. Embedding is a per-form-view surface ' + - '(`FormView.sharing`), not an app-level switch. Delete the key.', + '(`FormView.sharing`), not an app-level switch. Delete the key. ' + + 'Run `os migrate meta --from 16` to rewrite existing sources automatically.', ), /** @@ -1443,7 +1448,8 @@ export const AppSchema = lazySchema(() => strictObject( mobileNavigation: retiredKey( '`App.mobileNavigation` was removed in @objectstack/spec 17.0.0 (2026-06 liveness ' + 'audit — fully unimplemented; no renderer, including packages/mobile, ever read ' + - 'it). Delete the key; the block returns if/when a real mobile navigation ships.', + 'it). Delete the key; the block returns if/when a real mobile navigation ships. ' + + 'Run `os migrate meta --from 16` to rewrite existing sources automatically.', ), /** @@ -1482,7 +1488,8 @@ export const AppSchema = lazySchema(() => strictObject( '`App.aria` was removed in @objectstack/spec 17.0.0 (2026-06 liveness audit — no ' + 'renderer read app-level ARIA attributes). Declare `aria` on the page component ' + 'that renders the DOM node instead (`page.components[].aria`; `page.aria` and the ' + - 'list view `aria` are live too). Delete the key.', + 'list view `aria` are live too). Delete the key. ' + + 'Run `os migrate meta --from 16` to rewrite existing sources automatically.', ), /** diff --git a/packages/spec/src/ui/dashboard.zod.ts b/packages/spec/src/ui/dashboard.zod.ts index 0f53fc447b..bd0f929de9 100644 --- a/packages/spec/src/ui/dashboard.zod.ts +++ b/packages/spec/src/ui/dashboard.zod.ts @@ -910,12 +910,14 @@ export const DashboardSchema = lazySchema(() => strictObject({ aria: retiredKey( '`dashboard.aria` was removed in @objectstack/spec 17.0.0 (#3896 audit close-out) — no ' + 'dashboard renderer ever applied it, so declared ARIA attributes silently did not reach ' + - 'the DOM. Delete the key.', + 'the DOM. Delete the key. ' + + 'Run `os migrate meta --from 16` to rewrite existing sources automatically.', ), performance: retiredKey( '`dashboard.performance` was removed in @objectstack/spec 17.0.0 (#3896 audit ' + 'close-out) — no renderer or runtime read it; dashboard performance tuning was never ' + - 'implemented. Delete the key.', + 'implemented. Delete the key. ' + + 'Run `os migrate meta --from 16` to rewrite existing sources automatically.', ), /** * ADR-0010 §3.7 — Package-level protection envelope. Package