diff --git a/.changeset/tombstone-migrate-sentence-completion.md b/.changeset/tombstone-migrate-sentence-completion.md new file mode 100644 index 0000000000..bedb96e461 --- /dev/null +++ b/.changeset/tombstone-migrate-sentence-completion.md @@ -0,0 +1,27 @@ +--- +"@objectstack/spec": patch +--- + +docs(spec): 14 `retiredKey()` prescriptions over protocol-17 conversions now close with the house `os migrate meta` sentence (#6914) + +The tombstone guidance string IS the migration doc for whoever hits it +(`shared/retired-key.ts`), and for these 14 keys an ADR-0087 conversion has +existed all along — but the prescription never said so, telling the author +(very often an AI, ADR-0033) to hand-edit sources a tool rewrites mechanically. +Each now ends with the #6856 route-D house sentence: +`` Run `os migrate meta --from 16` to rewrite existing sources automatically. `` + +Sites: `skill.triggerPhrases`; `flow.active` / `flow.template` / +`flow.nodes[].outputSchema` / `flow.errorHandling.fallbackNodeId`; +`waitEventConfig.timeoutMs` / `.onTimeout`; `stack.api.requireAuth` (both the +stack block and the forwarded `RestApiConfigSchema` copy); +`rowLevelSecurity[].priority`; `view.list.responsive` / `view.list.performance` +/ `view.form.defaultSort` / `view.form.aria`. + +Verified per site against `spec-changes.json`'s v17 `converted` list and the +conversion's `apply()` in `conversions/registry.ts`. The remaining silent +tombstones stay silent deliberately: no conversion exists for their surfaces +(API request/response keys, engine options, transport envelopes — e.g. +`environment-artifact.zod.ts` and `HookContext.session.roles` say so in so many +words), the `data/driver.zod.ts:108` precedent. Guidance prose before the +appended sentence is byte-identical; the legal metadata set is unchanged. diff --git a/content/docs/references/ai/skill.mdx b/content/docs/references/ai/skill.mdx index 04c9fb714f..097f3b3809 100644 --- a/content/docs/references/ai/skill.mdx +++ b/content/docs/references/ai/skill.mdx @@ -38,7 +38,7 @@ const result = SkillSchema.parse(data); | **surface** | `Enum<'ask' \| 'build' \| 'both'>` | ✅ | Agent surface this skill binds to ('ask' \| 'build' \| 'both') — ADR-0063 §3; read by the cloud agent runtime only | | **instructions** | `string` | optional | LLM instructions when skill is active — also served as an MCP prompt (#3905) | | **tools** | `string[]` | ✅ | Tool names belonging to this skill (supports trailing wildcard, e.g. `action_*`) — bound by the cloud agent runtime only | -| **triggerPhrases** | `never` | optional | [REMOVED] `skill.triggerPhrases` was removed in @objectstack/spec 17.0.0 (#3896 audit close-out) — phrases were never matched against the user's message; skill activation is `triggerConditions` (AND of context field/operator/value) intersected with the agent's `skills[]`, plus explicit /skill-name pinning. Delete the key. Put routing intent in `triggerConditions`; describe intent in `description`/`instructions` for the LLM. | +| **triggerPhrases** | `never` | optional | [REMOVED] `skill.triggerPhrases` was removed in @objectstack/spec 17.0.0 (#3896 audit close-out) — phrases were never matched against the user's message; skill activation is `triggerConditions` (AND of context field/operator/value) intersected with the agent's `skills[]`, plus explicit /skill-name pinning. Delete the key. Put routing intent in `triggerConditions`; describe intent in `description`/`instructions` for the LLM. Run `os migrate meta --from 16` to rewrite existing sources automatically. | | **triggerConditions** | `{ field: string; operator: Enum<'eq' \| 'neq' \| 'in' \| 'not_in' \| 'contains'>; value: string \| string[] }[]` | optional | Programmatic activation conditions — evaluated by the cloud agent runtime only | | **active** | `boolean` | ✅ | Whether the skill is enabled | | **protection** | `{ lock: Enum<'none' \| 'no-overlay' \| 'no-delete' \| 'full'>; reason: string; docsUrl?: string }` | optional | Package author protection block — lock policy for this skill. | diff --git a/content/docs/references/api/automation-api.mdx b/content/docs/references/api/automation-api.mdx index 616b427227..c6c6bd5899 100644 --- a/content/docs/references/api/automation-api.mdx +++ b/content/docs/references/api/automation-api.mdx @@ -92,12 +92,12 @@ const result = AutomationApiErrorCode.parse(data); | **errorMessage** | `string` | optional | Toast shown when a screen flow fails (defaults to the raw error). | | **version** | `integer` | optional | Version number | | **status** | `Enum<'draft' \| 'active' \| 'obsolete' \| 'invalid'>` | optional | Deployment status | -| **template** | `never` | optional | [REMOVED] `flow.template` was removed in @objectstack/spec 17.0.0 (#3896 audit close-out) — no designer or engine path ever read it, so flagging a flow as a template/subflow did nothing. Delete the key. Shared logic is invoked via a subflow NODE referencing the flow by name. | +| **template** | `never` | optional | [REMOVED] `flow.template` was removed in @objectstack/spec 17.0.0 (#3896 audit close-out) — no designer or engine path ever read it, so flagging a flow as a template/subflow did nothing. Delete the key. Shared logic is invoked via a subflow NODE referencing the flow by name. Run `os migrate meta --from 16` to rewrite existing sources automatically. | | **type** | `Enum<'autolaunched' \| 'record_change' \| 'schedule' \| 'screen' \| 'api'>` | ✅ | Flow type | | **variables** | `{ name: string; type: string; isInput?: boolean; isOutput?: boolean; … }[]` | optional | Flow variables | | **nodes** | `{ id: string; type: string; label: string; config?: Record; … }[]` | ✅ | Flow nodes | | **edges** | `{ id: string; source: string; target: string; condition?: string \| object; … }[]` | ✅ | Flow connections | -| **active** | `never` | optional | [REMOVED] `flow.active` was removed in @objectstack/spec 17.0.0 (#3896 audit close-out) — it never had an effect: the engine arms flows from `status`, and `active: false` did NOT stop a flow (worse, the default read as disabled while the engine treated unset as enabled). Delete the key. Use `status: 'obsolete'` (or 'invalid') to unbind and disable a flow, `status: 'active'` to arm it. | +| **active** | `never` | optional | [REMOVED] `flow.active` was removed in @objectstack/spec 17.0.0 (#3896 audit close-out) — it never had an effect: the engine arms flows from `status`, and `active: false` did NOT stop a flow (worse, the default read as disabled while the engine treated unset as enabled). Delete the key. Use `status: 'obsolete'` (or 'invalid') to unbind and disable a flow, `status: 'active'` to arm it. Run `os migrate meta --from 16` to rewrite existing sources automatically. | | **runAs** | `Enum<'system' \| 'user'>` | optional | Execution identity for the run: system = elevated (bypasses RLS), user = the triggering user (RLS-respecting). A run with no trigger user has no identity to scope to, so under user its data operations are REFUSED — declare system to make the elevation explicit. This covers schedule/time-relative/api triggers AND any record-change flow fired by a write that carried no user. | | **errorHandling** | `{ strategy?: Enum<'fail' \| 'retry' \| 'continue'>; maxRetries?: integer; backoffMs?: integer; backoffMultiplier?: number; … }` | optional | Flow-level error handling configuration | | **protection** | `{ lock: Enum<'none' \| 'no-overlay' \| 'no-delete' \| 'full'>; reason: string; docsUrl?: string }` | optional | Package author protection block — lock policy for this flow. | diff --git a/content/docs/references/api/rest-server.mdx b/content/docs/references/api/rest-server.mdx index 609861bac1..ed3868dfa3 100644 --- a/content/docs/references/api/rest-server.mdx +++ b/content/docs/references/api/rest-server.mdx @@ -156,7 +156,7 @@ const result = BatchEndpointsConfigSchema.parse(data); | **enableOpenApi** | `boolean` | ✅ | Enable OpenAPI 3.1 spec & docs viewer endpoints | | **enableProjectScoping** | `boolean` | ✅ | Enable project-scoped routing for data/meta/AI APIs | | **projectResolution** | `Enum<'required' \| 'optional' \| 'auto'>` | ✅ | Project ID resolution strategy | -| **requireAuth** | `never` | optional | [REMOVED] `api.requireAuth` was removed in @objectstack/spec 17 (#3963). Anonymous access to object data is now always denied — auth is a kernel concern, not a deployment posture. Delete the key. To publish something publicly, declare it: a public form view (`sharing.allowAnonymous`), a share link, or `book.audience: 'public'` — each derives its own narrow authorization instead of opening the whole data plane. | +| **requireAuth** | `never` | optional | [REMOVED] `api.requireAuth` was removed in @objectstack/spec 17 (#3963). Anonymous access to object data is now always denied — auth is a kernel concern, not a deployment posture. Delete the key. To publish something publicly, declare it: a public form view (`sharing.allowAnonymous`), a share link, or `book.audience: 'public'` — each derives its own narrow authorization instead of opening the whole data plane. Run `os migrate meta --from 16` to rewrite existing sources automatically. | | **documentation** | `{ enabled: boolean; title: string; description?: string; version?: string; … }` | optional | OpenAPI/Swagger documentation config | | **responseFormat** | `{ envelope: boolean; includeMetadata: boolean; includePagination: boolean }` | optional | Response format options | diff --git a/content/docs/references/automation/flow.mdx b/content/docs/references/automation/flow.mdx index 5199535b2a..33bdaa091e 100644 --- a/content/docs/references/automation/flow.mdx +++ b/content/docs/references/automation/flow.mdx @@ -46,12 +46,12 @@ const result = FlowSchema.parse(data); | **errorMessage** | `string` | optional | Toast shown when a screen flow fails (defaults to the raw error). | | **version** | `integer` | optional | Version number | | **status** | `Enum<'draft' \| 'active' \| 'obsolete' \| 'invalid'>` | optional | Deployment status | -| **template** | `never` | optional | [REMOVED] `flow.template` was removed in @objectstack/spec 17.0.0 (#3896 audit close-out) — no designer or engine path ever read it, so flagging a flow as a template/subflow did nothing. Delete the key. Shared logic is invoked via a subflow NODE referencing the flow by name. | +| **template** | `never` | optional | [REMOVED] `flow.template` was removed in @objectstack/spec 17.0.0 (#3896 audit close-out) — no designer or engine path ever read it, so flagging a flow as a template/subflow did nothing. Delete the key. Shared logic is invoked via a subflow NODE referencing the flow by name. Run `os migrate meta --from 16` to rewrite existing sources automatically. | | **type** | `Enum<'autolaunched' \| 'record_change' \| 'schedule' \| 'screen' \| 'api'>` | ✅ | Flow type | | **variables** | `{ name: string; type: string; isInput?: boolean; isOutput?: boolean; … }[]` | optional | Flow variables | | **nodes** | `{ id: string; type: string; label: string; config?: Record; … }[]` | ✅ | Flow nodes | | **edges** | `{ id: string; source: string; target: string; condition?: string \| object; … }[]` | ✅ | Flow connections | -| **active** | `never` | optional | [REMOVED] `flow.active` was removed in @objectstack/spec 17.0.0 (#3896 audit close-out) — it never had an effect: the engine arms flows from `status`, and `active: false` did NOT stop a flow (worse, the default read as disabled while the engine treated unset as enabled). Delete the key. Use `status: 'obsolete'` (or 'invalid') to unbind and disable a flow, `status: 'active'` to arm it. | +| **active** | `never` | optional | [REMOVED] `flow.active` was removed in @objectstack/spec 17.0.0 (#3896 audit close-out) — it never had an effect: the engine arms flows from `status`, and `active: false` did NOT stop a flow (worse, the default read as disabled while the engine treated unset as enabled). Delete the key. Use `status: 'obsolete'` (or 'invalid') to unbind and disable a flow, `status: 'active'` to arm it. Run `os migrate meta --from 16` to rewrite existing sources automatically. | | **runAs** | `Enum<'system' \| 'user'>` | optional | Execution identity for the run: system = elevated (bypasses RLS), user = the triggering user (RLS-respecting). A run with no trigger user has no identity to scope to, so under user its data operations are REFUSED — declare system to make the elevation explicit. This covers schedule/time-relative/api triggers AND any record-change flow fired by a write that carried no user. | | **errorHandling** | `{ strategy?: Enum<'fail' \| 'retry' \| 'continue'>; maxRetries?: integer; backoffMs?: integer; backoffMultiplier?: number; … }` | optional | Flow-level error handling configuration | | **protection** | `{ lock: Enum<'none' \| 'no-overlay' \| 'no-delete' \| 'full'>; reason: string; docsUrl?: string }` | optional | Package author protection block — lock policy for this flow. | @@ -97,7 +97,7 @@ const result = FlowSchema.parse(data); | **position** | `{ x: number; y: number }` | optional | | | **timeoutMs** | `integer` | optional | Maximum execution time for this node in milliseconds | | **inputSchema** | `Record; required?: boolean; description?: string }>` | optional | Input parameter schema for this node | -| **outputSchema** | `never` | optional | [REMOVED] `flow.nodes[].outputSchema` was removed in @objectstack/spec 17.0.0 (#3896 audit close-out) — it was never validated: the engine does not check node outputs against it, so it documented a contract nothing enforced. Delete the key. Downstream nodes read prior outputs via expressions (`{{nodeId.field}}`) regardless of any declaration. | +| **outputSchema** | `never` | optional | [REMOVED] `flow.nodes[].outputSchema` was removed in @objectstack/spec 17.0.0 (#3896 audit close-out) — it was never validated: the engine does not check node outputs against it, so it documented a contract nothing enforced. Delete the key. Downstream nodes read prior outputs via expressions (`{{nodeId.field}}`) regardless of any declaration. Run `os migrate meta --from 16` to rewrite existing sources automatically. | | **waitEventConfig** | `{ eventType: Enum<'timer' \| 'signal' \| 'webhook' \| 'manual' \| 'condition'>; timerDuration?: string; signalName?: string }` | optional | Configuration for wait node event resumption | | **boundaryConfig** | `{ attachedToNodeId: string; eventType: Enum<'error' \| 'timer' \| 'signal' \| 'cancel'>; interrupting?: boolean; errorCode?: string; … }` | optional | Configuration for boundary events attached to host nodes | diff --git a/content/docs/references/security/rls.mdx b/content/docs/references/security/rls.mdx index 9f3bc0fb53..25273b4b3c 100644 --- a/content/docs/references/security/rls.mdx +++ b/content/docs/references/security/rls.mdx @@ -175,7 +175,7 @@ const result = RLSEvaluationResultSchema.parse(data); | **check** | `string` | optional | Validation condition for INSERT/UPDATE (defaults to USING clause if not specified - enforced at application level) | | **positions** | `string[]` | optional | Positions this policy applies to (omit for all) | | **enabled** | `boolean` | ✅ | Whether this policy is active | -| **priority** | `never` | optional | [REMOVED] `rowLevelSecurity[].priority` was removed in @objectstack/spec 17.0.0 (#3896 security audit). It never had an effect and could not: applicable policies OR-combine (most permissive wins), so there is no conflict to order. Delete the key — policy outcomes are unchanged. | +| **priority** | `never` | optional | [REMOVED] `rowLevelSecurity[].priority` was removed in @objectstack/spec 17.0.0 (#3896 security audit). It never had an effect and could not: applicable policies OR-combine (most permissive wins), so there is no conflict to order. Delete the key — policy outcomes are unchanged. Run `os migrate meta --from 16` to rewrite existing sources automatically. | | **tags** | `string[]` | optional | Policy categorization tags | diff --git a/content/docs/references/ui/view.mdx b/content/docs/references/ui/view.mdx index 8a6feaf536..6f7db1eabe 100644 --- a/content/docs/references/ui/view.mdx +++ b/content/docs/references/ui/view.mdx @@ -264,12 +264,12 @@ Column footer summary configuration | **sections** | `{ name?: string; label?: string \| Record; description?: string; collapsible?: boolean; … }[]` | optional | | | **groups** | `{ name?: string; label?: string \| Record; description?: string; collapsible?: boolean; … }[]` | optional | | | **subforms** | `{ childObject: string; relationshipField?: string; columns?: any[]; amountField?: string; … }[]` | optional | Inline master-detail child collections | -| **defaultSort** | `never` | optional | [REMOVED] `form.defaultSort` was removed in @objectstack/spec 17.0.0 (#3896 audit close-out) — nothing read it: a related list inside a form sorts by its own list view's `sort`. Delete the key and set the sort on the related list view instead. | +| **defaultSort** | `never` | optional | [REMOVED] `form.defaultSort` was removed in @objectstack/spec 17.0.0 (#3896 audit close-out) — nothing read it: a related list inside a form sorts by its own list view's `sort`. Delete the key and set the sort on the related list view instead. Run `os migrate meta --from 16` to rewrite existing sources automatically. | | **sharing** | `{ enabled?: boolean; publicLink?: string; password?: string; allowedDomains?: string[]; … }` | optional | Public sharing configuration for this form | | **submitBehavior** | `{ kind: 'thank-you'; title?: string; message?: string } \| { kind: 'redirect'; url: string; delayMs?: integer } \| { kind: 'continue' } \| { kind: 'next-record' }` | optional | Post-submit behavior | | **buttons** | `{ submit?: object; cancel?: object; reset?: object }` | optional | Form action-button visibility & labels; folded onto the flat renderer props by ObjectUI ObjectForm (framework#1894 / #2998). | | **defaults** | `Record` | optional | Initial field values for create-mode forms (folded into ObjectUI ObjectForm initial values; framework#1894 / #2998). | -| **aria** | `never` | optional | [REMOVED] `form.aria` was removed in @objectstack/spec 17.0.0 (#3896 audit close-out) — no form renderer ever applied it, so declared ARIA attributes silently did not reach the DOM. Delete the key. The form renderer emits its own semantic markup; report gaps as renderer issues rather than per-view attribute overrides. | +| **aria** | `never` | optional | [REMOVED] `form.aria` was removed in @objectstack/spec 17.0.0 (#3896 audit close-out) — no form renderer ever applied it, so declared ARIA attributes silently did not reach the DOM. Delete the key. The form renderer emits its own semantic markup; report gaps as renderer issues rather than per-view attribute overrides. Run `os migrate meta --from 16` to rewrite existing sources automatically. | --- @@ -493,8 +493,8 @@ List chart view configuration | **allowPrinting** | `boolean` | optional | Allow users to print the view | | **emptyState** | `{ title?: string \| Record; message?: string \| Record; icon?: string }` | optional | Empty state configuration when no records found | | **aria** | `{ ariaLabel?: string \| Record; ariaDescribedBy?: string; role?: string }` | optional | ARIA accessibility attributes for the list view | -| **responsive** | `never` | optional | [REMOVED] `view.responsive` was removed in @objectstack/spec 17.0.0 (#3896 audit close-out) — no renderer ever read it; the grid is responsive by its own layout rules. Delete the key. | -| **performance** | `never` | optional | [REMOVED] `view.performance` was removed in @objectstack/spec 17.0.0 (#3896 audit close-out) — no renderer or runtime read it; list-view performance tuning was never implemented. Delete the key. | +| **responsive** | `never` | optional | [REMOVED] `view.responsive` was removed in @objectstack/spec 17.0.0 (#3896 audit close-out) — no renderer ever read it; the grid is responsive by its own layout rules. Delete the key. Run `os migrate meta --from 16` to rewrite existing sources automatically. | +| **performance** | `never` | optional | [REMOVED] `view.performance` was removed in @objectstack/spec 17.0.0 (#3896 audit close-out) — no renderer or runtime read it; list-view performance tuning was never implemented. Delete the key. Run `os migrate meta --from 16` to rewrite existing sources automatically. | --- @@ -581,8 +581,8 @@ List chart view configuration | **allowPrinting** | `boolean` | optional | Allow users to print the view | | **emptyState** | `{ title?: string \| Record; message?: string \| Record; icon?: string }` | optional | Empty state configuration when no records found | | **aria** | `{ ariaLabel?: string \| Record; ariaDescribedBy?: string; role?: string }` | optional | ARIA accessibility attributes for the list view | -| **responsive** | `never` | optional | [REMOVED] `view.responsive` was removed in @objectstack/spec 17.0.0 (#3896 audit close-out) — no renderer ever read it; the grid is responsive by its own layout rules. Delete the key. | -| **performance** | `never` | optional | [REMOVED] `view.performance` was removed in @objectstack/spec 17.0.0 (#3896 audit close-out) — no renderer or runtime read it; list-view performance tuning was never implemented. Delete the key. | +| **responsive** | `never` | optional | [REMOVED] `view.responsive` was removed in @objectstack/spec 17.0.0 (#3896 audit close-out) — no renderer ever read it; the grid is responsive by its own layout rules. Delete the key. Run `os migrate meta --from 16` to rewrite existing sources automatically. | +| **performance** | `never` | optional | [REMOVED] `view.performance` was removed in @objectstack/spec 17.0.0 (#3896 audit close-out) — no renderer or runtime read it; list-view performance tuning was never implemented. Delete the key. Run `os migrate meta --from 16` to rewrite existing sources automatically. | | **userFilters** | `{ element?: Enum<'dropdown' \| 'toggle'>; fields?: object[] }` | optional | | diff --git a/packages/spec/src/ai/skill.zod.ts b/packages/spec/src/ai/skill.zod.ts index 92e764b445..501edb09ec 100644 --- a/packages/spec/src/ai/skill.zod.ts +++ b/packages/spec/src/ai/skill.zod.ts @@ -197,7 +197,8 @@ export const SkillSchema = lazySchema(() => strictObject({ "— phrases were never matched against the user's message; skill activation is " + "`triggerConditions` (AND of context field/operator/value) intersected with the agent's " + '`skills[]`, plus explicit /skill-name pinning. Delete the key. Put routing intent in ' + - '`triggerConditions`; describe intent in `description`/`instructions` for the LLM.', + '`triggerConditions`; describe intent in `description`/`instructions` for the LLM. ' + + 'Run `os migrate meta --from 16` to rewrite existing sources automatically.', ), /** diff --git a/packages/spec/src/api/rest-server.zod.ts b/packages/spec/src/api/rest-server.zod.ts index 60c84b2272..a99bb3f259 100644 --- a/packages/spec/src/api/rest-server.zod.ts +++ b/packages/spec/src/api/rest-server.zod.ts @@ -127,7 +127,8 @@ export const RestApiConfigSchema = lazySchema(() => z.object({ + 'is now always denied — auth is a kernel concern, not a deployment posture. Delete the key. ' + 'To publish something publicly, declare it: a public form view (`sharing.allowAnonymous`), a ' + "share link, or `book.audience: 'public'` — each derives its own narrow authorization instead of " - + 'opening the whole data plane.', + + 'opening the whole data plane. ' + + 'Run `os migrate meta --from 16` to rewrite existing sources automatically.', ), /** diff --git a/packages/spec/src/automation/flow.zod.ts b/packages/spec/src/automation/flow.zod.ts index 1692a30ec9..e71a8882b6 100644 --- a/packages/spec/src/automation/flow.zod.ts +++ b/packages/spec/src/automation/flow.zod.ts @@ -365,7 +365,8 @@ function flowNodeObject() { return strictObject( '`flow.nodes[].outputSchema` was removed in @objectstack/spec 17.0.0 (#3896 audit ' + 'close-out) — it was never validated: the engine does not check node outputs against ' + 'it, so it documented a contract nothing enforced. Delete the key. Downstream nodes ' + - "read prior outputs via expressions ({{nodeId.field}}) regardless of any declaration.", + "read prior outputs via expressions ({{nodeId.field}}) regardless of any declaration. " + + 'Run `os migrate meta --from 16` to rewrite existing sources automatically.', ), /** @@ -437,13 +438,15 @@ function flowNodeObject() { return strictObject( + '`timerDuration` — but QUOTE the number: the key is a string, and a bare numeric string is ' + "read as milliseconds, making `timeoutMs: 60000` and `timerDuration: '60000'` the same wait " + "(`timerDuration: 'PT1M'` is the ISO 8601 spelling of that same 60s). Stored flows are " - + 'converted automatically — the conversion does the quoting for you.', + + 'converted automatically — the conversion does the quoting for you. ' + + 'Run `os migrate meta --from 16` to rewrite existing sources automatically.', ), onTimeout: retiredKey( '`waitEventConfig.onTimeout` was removed in @objectstack/spec 17 (#4158). It had no readers at ' + 'all — no code path ever inspected it, so neither `fail` nor `continue` ever happened. Delete ' + 'the key. There is no replacement: `wait` has no timeout, and a wait node resumes only when ' - + 'its timer elapses or its signal arrives.', + + 'its timer elapses or its signal arrives. ' + + 'Run `os migrate meta --from 16` to rewrite existing sources automatically.', ), }).optional().describe('Configuration for wait node event resumption'), @@ -630,7 +633,8 @@ export const FlowSchema = lazySchema(() => strictObject( '`flow.template` was removed in @objectstack/spec 17.0.0 (#3896 audit close-out) — ' + 'no designer or engine path ever read it, so flagging a flow as a template/subflow did ' + 'nothing. Delete the key. Shared logic is invoked via a subflow NODE referencing the ' + - 'flow by name.', + 'flow by name. ' + + 'Run `os migrate meta --from 16` to rewrite existing sources automatically.', ), /** Trigger Type */ @@ -653,7 +657,8 @@ export const FlowSchema = lazySchema(() => strictObject( 'never had an effect: the engine arms flows from `status`, and `active: false` did NOT ' + 'stop a flow (worse, the default read as disabled while the engine treated unset as ' + "enabled). Delete the key. Use `status: 'obsolete'` (or 'invalid') to unbind and " + - "disable a flow, `status: 'active'` to arm it.", + "disable a flow, `status: 'active'` to arm it. " + + 'Run `os migrate meta --from 16` to rewrite existing sources automatically.', ), // ADR-0049 / #1888 — ENFORCED. The service-automation engine establishes the // declared identity for the run's data operations and restores the caller's @@ -787,7 +792,8 @@ export const FlowSchema = lazySchema(() => strictObject( 'audit close-out) — the engine routes unrecoverable node errors via per-node fault ' + "edges (an edge with type: 'fault'), and never read this key: a fallback " + 'configured here silently did not exist. Delete the key and draw a fault edge from ' + - 'the failing node to the handler node instead.', + 'the failing node to the handler node instead. ' + + 'Run `os migrate meta --from 16` to rewrite existing sources automatically.', ), }).superRefine((eh, ctx) => { // `strategy: 'retry'` with 0 attempts is `strategy: 'fail'` wearing a diff --git a/packages/spec/src/security/rls.zod.ts b/packages/spec/src/security/rls.zod.ts index c2062dca9e..02ae77c0aa 100644 --- a/packages/spec/src/security/rls.zod.ts +++ b/packages/spec/src/security/rls.zod.ts @@ -432,7 +432,8 @@ export const RowLevelSecurityPolicySchema = lazySchema(() => strictObject( priority: retiredKey( '`rowLevelSecurity[].priority` was removed in @objectstack/spec 17.0.0 (#3896 security audit). ' + 'It never had an effect and could not: applicable policies OR-combine (most permissive wins), ' + - 'so there is no conflict to order. Delete the key — policy outcomes are unchanged.', + 'so there is no conflict to order. Delete the key — policy outcomes are unchanged. ' + + 'Run `os migrate meta --from 16` to rewrite existing sources automatically.', ), /** diff --git a/packages/spec/src/stack.zod.ts b/packages/spec/src/stack.zod.ts index 485687e663..4ddddf56a3 100644 --- a/packages/spec/src/stack.zod.ts +++ b/packages/spec/src/stack.zod.ts @@ -350,7 +350,8 @@ export const ObjectStackDefinitionSchema = lazySchema(() => z.object({ '`api.requireAuth` was removed in @objectstack/spec 17 (#3963). Anonymous access to object data ' + 'is now always denied. Delete the key; publish public surfaces by declaration instead — a public ' + "form view, a share link, or `book.audience: 'public'`. A stack that mounts no auth at all now " - + 'fails at boot rather than silently serving object data to anonymous callers.', + + 'fails at boot rather than silently serving object data to anonymous callers. ' + + 'Run `os migrate meta --from 16` to rewrite existing sources automatically.', ), /** Enable environment-scoped routing for data/meta/AI APIs. */ enableProjectScoping: z.boolean().optional(), diff --git a/packages/spec/src/ui/view.zod.ts b/packages/spec/src/ui/view.zod.ts index 714c9fbf35..50e90e30b2 100644 --- a/packages/spec/src/ui/view.zod.ts +++ b/packages/spec/src/ui/view.zod.ts @@ -1284,12 +1284,14 @@ export const ListViewSchema = lazySchema(() => strictObject({ // objectui@fb35e48; ledger: dead). responsive: retiredKey( '`view.responsive` was removed in @objectstack/spec 17.0.0 (#3896 audit close-out) — ' + - 'no renderer ever read it; the grid is responsive by its own layout rules. Delete the key.', + 'no renderer ever read it; the grid is responsive by its own layout rules. Delete the key. ' + + 'Run `os migrate meta --from 16` to rewrite existing sources automatically.', ), performance: retiredKey( '`view.performance` was removed in @objectstack/spec 17.0.0 (#3896 audit close-out) — ' + 'no renderer or runtime read it; list-view performance tuning was never implemented. ' + - 'Delete the key.', + 'Delete the key. ' + + 'Run `os migrate meta --from 16` to rewrite existing sources automatically.', ), })); @@ -1710,7 +1712,8 @@ export const FormViewSchema = lazySchema(() => strictObject({ defaultSort: retiredKey( '`form.defaultSort` was removed in @objectstack/spec 17.0.0 (#3896 audit close-out) — ' + 'nothing read it: a related list inside a form sorts by its own list view\'s `sort`. ' + - 'Delete the key and set the sort on the related list view instead.', + 'Delete the key and set the sort on the related list view instead. ' + + 'Run `os migrate meta --from 16` to rewrite existing sources automatically.', ), /** Public form sharing configuration */ @@ -1808,7 +1811,8 @@ export const FormViewSchema = lazySchema(() => strictObject({ '`form.aria` was removed in @objectstack/spec 17.0.0 (#3896 audit close-out) — no form ' + 'renderer ever applied it, so declared ARIA attributes silently did not reach the DOM. ' + 'Delete the key. The form renderer emits its own semantic markup; report gaps as ' + - 'renderer issues rather than per-view attribute overrides.', + 'renderer issues rather than per-view attribute overrides. ' + + 'Run `os migrate meta --from 16` to rewrite existing sources automatically.', ), }).superRefine((view, ctx) => { // `section.pane` is split-only vocabulary. On any other form type it would