From d6551e479bf3cdf8a9e2bab2aed5925e9437a862 Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 27 Aug 2026 13:32:09 +0000 Subject: [PATCH 1/3] =?UTF-8?q?feat(spec):=20retire=20preview=20mode=20?= =?UTF-8?q?=E2=80=94=20RuntimeMode=20'preview'=20and=20the=20PreviewModeCo?= =?UTF-8?q?nfig=20block?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes #11846 (ADR-0049 enforce-or-remove; maintainer ruling 2026-08-27, Option A: remove). The declaration promised an auth bypass no layer implemented; zero consumers measured in objectstack, objectui and cloud. - 'preview' leaves the RuntimeMode enum; the prescription hangs on the enum's own error map (the HookBodyCapability precedent) - KernelContext.previewMode is tombstoned with retiredKey() (non-strict schema — a bare deletion would silently strip); the TenantRuntimeContext extend copy inherits it; both keys registered in RETIRED_KEYS_BY_MAJOR[18] - kernel/PreviewModeConfig leaves the emitted set whole (orphan value schema, #3950): RETIRED_DEFS_BY_MAJOR[18] + deliberate manifest deletion - no D2 conversion (host-constructed context, no stack seam — the kernel/Manifest:loading disposition); D3 semantic entry kernel-context-preview-mode-retired carries the prescription - pin tests for both rejection directions; regenerated authorable surface/defaults, api-surface, export-origins, docs, skill refs, strictness ledger; breaking changeset with the ADR-0087 marker Co-Authored-By: Claude --- .../kernel-context-preview-mode-retired.md | 67 ++++++ content/docs/references/index.mdx | 10 +- content/docs/references/kernel/context.mdx | 54 +---- ...07-unknown-key-strictness-ledger.counts.md | 2 +- packages/spec/api-surface/kernel.json | 3 - packages/spec/authorable-defaults/kernel.json | 5 - packages/spec/authorable-surface/kernel.json | 10 +- packages/spec/export-origins/kernel.json | 3 - .../spec/json-schema.manifest/kernel.json | 1 - packages/spec/src/kernel/context.test.ts | 80 +------ packages/spec/src/kernel/context.zod.ts | 150 ++++++------ .../kernel/preview-mode-retirement.test.ts | 216 ++++++++++++++++++ .../18.kernel__PreviewModeConfig.ts | 20 ++ .../18.kernel__KernelContext__previewMode.ts | 27 +++ ...rnel__TenantRuntimeContext__previewMode.ts | 10 + .../18.kernel-context-preview-mode-retired.ts | 83 +++++++ packages/spec/src/migrations/registry.ts | 130 +++++++++++ .../objectstack-platform/references/_index.md | 2 +- 18 files changed, 646 insertions(+), 227 deletions(-) create mode 100644 .changeset/kernel-context-preview-mode-retired.md create mode 100644 packages/spec/src/kernel/preview-mode-retirement.test.ts create mode 100644 packages/spec/src/migrations/entries/retired-defs/18.kernel__PreviewModeConfig.ts create mode 100644 packages/spec/src/migrations/entries/retired-keys/18.kernel__KernelContext__previewMode.ts create mode 100644 packages/spec/src/migrations/entries/retired-keys/18.kernel__TenantRuntimeContext__previewMode.ts create mode 100644 packages/spec/src/migrations/entries/semantic/18.kernel-context-preview-mode-retired.ts diff --git a/.changeset/kernel-context-preview-mode-retired.md b/.changeset/kernel-context-preview-mode-retired.md new file mode 100644 index 0000000000..2c894eaf71 --- /dev/null +++ b/.changeset/kernel-context-preview-mode-retired.md @@ -0,0 +1,67 @@ +--- +"@objectstack/spec": minor +--- + +feat(spec): retire preview mode — the `'preview'` RuntimeMode value and the whole `KernelContext.previewMode` / `PreviewModeConfig` block (#11846, ADR-0049) + + + +**BREAKING** accept-set narrowing and export removal, landing after the +v17.0.0 cut (the lockstep launch-window convention ships it as `minor`; the +prescription is registered under protocol major 18 — +`RETIRED_KEYS_BY_MAJOR[18]` for both walked-shape keys, +`RETIRED_DEFS_BY_MAJOR[18]` for the def, plus the D3 semantic entry +`kernel-context-preview-mode-retired` — where `os migrate meta` users will +look). + +The declaration was the sharpest declared-≠-enforced shape on a SECURITY +surface: the schema promised "bypass auth, simulate admin identity" and named +a production guard "the runtime must enforce", and NO code path implemented +either half. Measured zero consumers in objectstack, objectui and cloud +(cloud#1651, closed 2026-08-26 with positive controls: `RuntimeMode` has zero +hits repo-wide there, and `ArtifactKernelFactory` — where preview auto-login +would live if anywhere — has 20+ hits and never touches `previewMode`; +re-verified in objectstack at dispatch, 2026-08-27). An author — very often +an AI — could write the six-key block per the reference docs, parse cleanly, +and get no behaviour and no diagnostic. + +FROM → TO: + +- `mode: 'preview'` → *(removed value)* — `mode` defaults to `'production'`; + use `'development'` for local demo work. The rejection carries the + prescription via the enum's own error map (the `HookBodyCapability` + precedent); every other mode keeps zod's own message. +- `previewMode: { … }` on `KernelContext` / `TenantRuntimeContext` → + *(removed key)* — tombstoned with `retiredKey()` (the schemas are not + `.strict()`, so a bare deletion would be a silent strip): authoring it is + now a `tsc` error and a parse error carrying the prescription. +- `PreviewModeConfigSchema` / `PreviewModeConfig` / `PreviewModeConfigParsed` + → *(removed — no replacement)*. The def described behaviour no layer + implemented; an exported value schema with no consumer reads as a + capability (#3950). + +One-line fix: delete the key and the value — neither ever changed runtime +behaviour, so removing them changes nothing observable. Preview deployment +ROUTING is untouched: `OS_PREVIEW_MODE` / `OS_PREVIEW_BASE_DOMAINS` keep +working exactly as documented (deployment routing, never identity). If a +preview experience becomes a product capability it re-declares fresh, with +the production-posture hard-refusal as the first-landed half (#11846 ruling +record, maintainer 2026-08-27). + +The retirement kit: + +- tombstones at both declarations (`kernel/KernelContext:previewMode` and the + `.extend()` copy `kernel/TenantRuntimeContext:previewMode`, both in + `RETIRED_KEYS_BY_MAJOR[18]`); the enum value's prescription on + `RuntimeMode`'s error map (enum-VALUE retirements register nothing in + RETIRED_KEYS_BY_MAJOR and leave the surface ratchets byte-identical) +- whole-def deletion `kernel/PreviewModeConfig` in `RETIRED_DEFS_BY_MAJOR[18]` + (manifest key deliberately removed; the #4725 gate adjudicated it) +- deliberately NO D2 conversion: a kernel context is constructed by host code + at boot — not a stack collection member, never a `sys_metadata` row — so + the conversion chain has no seam that would ever see one (the + `kernel/Manifest:loading` disposition); the D3 semantic entry carries the + prescription +- pin tests (`kernel/preview-mode-retirement.test.ts`): both rejection sites + flip from silent parse to the prescription; zero holders for all 3 retired + export names on every public entry; the carrier schemas survive diff --git a/content/docs/references/index.mdx b/content/docs/references/index.mdx index e23fc15613..58ba0bb364 100644 --- a/content/docs/references/index.mdx +++ b/content/docs/references/index.mdx @@ -1,6 +1,6 @@ --- title: Protocol Reference -description: Every schema published by @objectstack/spec — 1584 schemas across 14 protocol modules +description: Every schema published by @objectstack/spec — 1583 schemas across 14 protocol modules --- {/* ⚠️ AUTO-GENERATED — DO NOT EDIT. Run build-docs.ts to regenerate. Hand-written docs live in the module folders under content/docs/. */} @@ -26,14 +26,14 @@ counts are sums of the rows they head. Regenerate with | [Data Protocol](/docs/references/data) | 29 | 166 | Objects, fields, queries, filters, datasources and drivers — the ObjectQL layer. | | [Identity Protocol](/docs/references/identity) | 5 | 27 | Users and accounts, organizations, positions, SCIM provisioning. | | [Integration Protocol](/docs/references/integration) | 1 | 27 | The single connector protocol (ADR-0097) — catalog descriptors and provider-bound instances. | -| [Kernel Protocol](/docs/references/kernel) | 31 | 171 | Plugin lifecycle and manifests, capabilities and security, metadata loading, service registry. | +| [Kernel Protocol](/docs/references/kernel) | 31 | 170 | Plugin lifecycle and manifests, capabilities and security, metadata loading, service registry. | | [QA Protocol](/docs/references/qa) | 1 | 8 | Declarative test suites — scenarios, steps, actions and assertions. | | [Security Protocol](/docs/references/security) | 5 | 27 | Permission sets, row-level security, sharing rules, tenancy posture. | | [Shared Protocol](/docs/references/shared) | 8 | 32 | Primitives used across every protocol — identifiers, HTTP, expressions, error maps, enums. | | [Studio Protocol](/docs/references/studio) | 3 | 35 | Studio designer metadata — the authoring surfaces for the protocols above. | | [System Protocol](/docs/references/system) | 36 | 288 | The runtime environment — logging, jobs, cache, metrics, notifications, i18n and compliance. | | [UI Protocol](/docs/references/ui) | 16 | 152 | Apps, pages, views, dashboards, reports, actions and themes — the ObjectUI layer. | -| **Total** | **199** | **1584** | 14 protocol modules | +| **Total** | **199** | **1583** | 14 protocol modules | --- @@ -215,7 +215,7 @@ The single connector protocol (ADR-0097) — catalog descriptors and provider-bo ## Kernel Protocol -**Source:** `packages/spec/src/kernel/` · **Import:** `@objectstack/spec/kernel` · **31 pages, 171 schemas** +**Source:** `packages/spec/src/kernel/` · **Import:** `@objectstack/spec/kernel` · **31 pages, 170 schemas** Plugin lifecycle and manifests, capabilities and security, metadata loading, service registry. @@ -223,7 +223,7 @@ Plugin lifecycle and manifests, capabilities and security, metadata loading, ser | :--- | :--- | | [`cli-extension.zod.ts`](/docs/references/kernel/cli-extension) | `OclifPluginConfig` | | [`cluster.zod.ts`](/docs/references/kernel/cluster) | `ClusterCapabilityConfig`, `ClusterDriver`, `ClusterTenantIsolation`, `EventClusterOptions`, `EventDeliverySemantics`, `EventScope`, `MetadataChangeOperation`, `ServiceClusterAnnotations`, `ServiceClusterScope`, `ServiceLeaderStrategy` | -| [`context.zod.ts`](/docs/references/kernel/context) | `KernelContext`, `PreviewModeConfig`, `RuntimeMode`, `TenantRuntimeContext` | +| [`context.zod.ts`](/docs/references/kernel/context) | `KernelContext`, `RuntimeMode`, `TenantRuntimeContext` | | [`dependency-resolution.zod.ts`](/docs/references/kernel/dependency-resolution) | `DependencyResolutionResult`, `DependencyStatusEnum`, `RequiredAction`, `ResolvedDependency` | | [`events/bus.zod.ts`](/docs/references/kernel/events-bus) | `EventBusConfig` | | [`events/core.zod.ts`](/docs/references/kernel/events-core) | `Event`, `EventMetadata`, `EventPriority`, `EventTypeDefinition` | diff --git a/content/docs/references/kernel/context.mdx b/content/docs/references/kernel/context.mdx index 6c5a9a1f4e..7d6ef892c0 100644 --- a/content/docs/references/kernel/context.mdx +++ b/content/docs/references/kernel/context.mdx @@ -5,9 +5,6 @@ description: Context protocol schemas {/* ⚠️ AUTO-GENERATED — DO NOT EDIT. Run build-docs.ts to regenerate. Hand-written docs live in the module folders under content/docs/. */} -Runtime Mode Enum -Defines the operating mode of the kernel - **Source:** `packages/spec/src/kernel/context.zod.ts` @@ -15,8 +12,8 @@ Defines the operating mode of the kernel ## TypeScript Usage ```typescript -import { KernelContextSchema, PreviewModeConfigSchema, RuntimeMode, TenantRuntimeContextSchema } from '@objectstack/spec/kernel'; -import type { KernelContext, PreviewModeConfig, RuntimeMode, TenantRuntimeContext } from '@objectstack/spec/kernel'; +import { KernelContextSchema, RuntimeMode, TenantRuntimeContextSchema } from '@objectstack/spec/kernel'; +import type { KernelContext, RuntimeMode, TenantRuntimeContext } from '@objectstack/spec/kernel'; // Validate data const result = KernelContextSchema.parse(data); @@ -31,41 +28,14 @@ const result = KernelContextSchema.parse(data); | Property | Type | Required | Description | | :--- | :--- | :--- | :--- | | **instanceId** | `string` | ✅ | Unique UUID for this running kernel process | -| **mode** | `Enum<'development' \| 'production' \| 'test' \| 'provisioning' \| 'preview'>` | optional (default: `"production"`) | Kernel operating mode | +| **mode** | `Enum<'development' \| 'production' \| 'test' \| 'provisioning'>` | optional (default: `"production"`) | Kernel operating mode | | **version** | `string` | ✅ | Kernel version | | **appName** | `string` | optional | Host application name | | **cwd** | `string` | ✅ | Current working directory | | **workspaceRoot** | `string` | optional | Workspace root if different from cwd | | **startTime** | `integer` | ✅ | Boot timestamp (ms) | | **features** | `Record` | optional (default: `{}`) | Global feature toggles | -| **previewMode** | `{ autoLogin: boolean; simulatedRole: Enum<'admin' \| 'user' \| 'viewer'>; simulatedUserName: string; readOnly: boolean; … }` | optional | Preview/demo mode configuration (used when mode is "preview") | - -### Nested Shape: `KernelContext.previewMode` - -| Property | Type | Required | Description | -| :--- | :--- | :--- | :--- | -| **autoLogin** | `boolean` | optional (default: `true`) | Auto-login as simulated user, skipping login/registration pages | -| **simulatedRole** | `Enum<'admin' \| 'user' \| 'viewer'>` | optional (default: `"admin"`) | Permission role for the simulated preview user | -| **simulatedUserName** | `string` | optional (default: `"Preview User"`) | Display name for the simulated preview user | -| **readOnly** | `boolean` | optional (default: `false`) | Restrict the preview session to read-only operations | -| **expiresInSeconds** | `integer` | optional (default: `0`) | Preview session duration in seconds (0 = no expiration) | -| **bannerMessage** | `string` | optional | Banner message displayed in the UI during preview mode | - - ---- - -## PreviewModeConfig - -### Properties - -| Property | Type | Required | Description | -| :--- | :--- | :--- | :--- | -| **autoLogin** | `boolean` | optional (default: `true`) | Auto-login as simulated user, skipping login/registration pages | -| **simulatedRole** | `Enum<'admin' \| 'user' \| 'viewer'>` | optional (default: `"admin"`) | Permission role for the simulated preview user | -| **simulatedUserName** | `string` | optional (default: `"Preview User"`) | Display name for the simulated preview user | -| **readOnly** | `boolean` | optional (default: `false`) | Restrict the preview session to read-only operations | -| **expiresInSeconds** | `integer` | optional (default: `0`) | Preview session duration in seconds (0 = no expiration) | -| **bannerMessage** | `string` | optional | Banner message displayed in the UI during preview mode | +| **previewMode** | `never` | optional | [REMOVED] `context.previewMode` was removed in @objectstack/spec 17 (#11846, ADR-0049 enforce-or-remove) — nothing ever read the block: none of its six keys (`autoLogin`, `simulatedRole`, `simulatedUserName`, `readOnly`, `expiresInSeconds`, `bannerMessage`) had a consumer in any repo, so an authored block parsed cleanly and configured NOTHING, while its own docstring promised an auth bypass ("skips authentication screens", "simulates an admin identity") and named a production guard no runtime ever received. Delete the key. Preview/demo deployments belong to the deployment layer, which owns auth per-project (`ArtifactKernelFactory` in the cloud distribution); `OS_PREVIEW_MODE` stays there as a routing-only switch. If a preview experience becomes a product capability it re-declares fresh, with the production-posture hard-refusal as the first-landed half (#11846 ruling record). | --- @@ -80,7 +50,6 @@ Kernel operating mode * `production` * `test` * `provisioning` -* `preview` --- @@ -94,31 +63,20 @@ Tenant-aware kernel runtime context | Property | Type | Required | Description | | :--- | :--- | :--- | :--- | | **instanceId** | `string` | ✅ | Unique UUID for this running kernel process | -| **mode** | `Enum<'development' \| 'production' \| 'test' \| 'provisioning' \| 'preview'>` | optional (default: `"production"`) | Kernel operating mode | +| **mode** | `Enum<'development' \| 'production' \| 'test' \| 'provisioning'>` | optional (default: `"production"`) | Kernel operating mode | | **version** | `string` | ✅ | Kernel version | | **appName** | `string` | optional | Host application name | | **cwd** | `string` | ✅ | Current working directory | | **workspaceRoot** | `string` | optional | Workspace root if different from cwd | | **startTime** | `integer` | ✅ | Boot timestamp (ms) | | **features** | `Record` | optional (default: `{}`) | Global feature toggles | -| **previewMode** | `{ autoLogin: boolean; simulatedRole: Enum<'admin' \| 'user' \| 'viewer'>; simulatedUserName: string; readOnly: boolean; … }` | optional | Preview/demo mode configuration (used when mode is "preview") | +| **previewMode** | `never` | optional | [REMOVED] `context.previewMode` was removed in @objectstack/spec 17 (#11846, ADR-0049 enforce-or-remove) — nothing ever read the block: none of its six keys (`autoLogin`, `simulatedRole`, `simulatedUserName`, `readOnly`, `expiresInSeconds`, `bannerMessage`) had a consumer in any repo, so an authored block parsed cleanly and configured NOTHING, while its own docstring promised an auth bypass ("skips authentication screens", "simulates an admin identity") and named a production guard no runtime ever received. Delete the key. Preview/demo deployments belong to the deployment layer, which owns auth per-project (`ArtifactKernelFactory` in the cloud distribution); `OS_PREVIEW_MODE` stays there as a routing-only switch. If a preview experience becomes a product capability it re-declares fresh, with the production-posture hard-refusal as the first-landed half (#11846 ruling record). | | **tenantId** | `string` | ✅ | Resolved tenant identifier | | **tenantPlan** | `Enum<'free' \| 'pro' \| 'enterprise'>` | ✅ | Tenant subscription plan | | **tenantRegion** | `string` | optional | Tenant deployment region | | **tenantDbUrl** | `string` | ✅ | Tenant database connection URL | | **tenantQuotas** | `{ maxUsers?: integer; maxStorage?: integer; apiRateLimit?: integer; maxObjects?: integer; … }` | optional | Tenant resource quotas | -### Nested Shape: `TenantRuntimeContext.previewMode` - -| Property | Type | Required | Description | -| :--- | :--- | :--- | :--- | -| **autoLogin** | `boolean` | optional (default: `true`) | Auto-login as simulated user, skipping login/registration pages | -| **simulatedRole** | `Enum<'admin' \| 'user' \| 'viewer'>` | optional (default: `"admin"`) | Permission role for the simulated preview user | -| **simulatedUserName** | `string` | optional (default: `"Preview User"`) | Display name for the simulated preview user | -| **readOnly** | `boolean` | optional (default: `false`) | Restrict the preview session to read-only operations | -| **expiresInSeconds** | `integer` | optional (default: `0`) | Preview session duration in seconds (0 = no expiration) | -| **bannerMessage** | `string` | optional | Banner message displayed in the UI during preview mode | - ### Nested Shape: `TenantRuntimeContext.tenantQuotas` | Property | Type | Required | Description | diff --git a/docs/audits/2026-07-unknown-key-strictness-ledger.counts.md b/docs/audits/2026-07-unknown-key-strictness-ledger.counts.md index 822d858d9e..43b7b6d702 100644 --- a/docs/audits/2026-07-unknown-key-strictness-ledger.counts.md +++ b/docs/audits/2026-07-unknown-key-strictness-ledger.counts.md @@ -261,7 +261,7 @@ directory rather than per file. | `cloud/` | 83 | | `identity/` | 32 | | `integration/` | 10 | -| `kernel/` | 272 | +| `kernel/` | 271 | | `qa/` | 6 | | `shared/` | 20 | | `system/` | 361 | diff --git a/packages/spec/api-surface/kernel.json b/packages/spec/api-surface/kernel.json index 8ce5a68ead..f4c61813bb 100644 --- a/packages/spec/api-surface/kernel.json +++ b/packages/spec/api-surface/kernel.json @@ -356,9 +356,6 @@ "PluginVersionMetadata (type)", "PluginVersionMetadataParsed (type)", "PluginVersionMetadataSchema (const)", - "PreviewModeConfig (type)", - "PreviewModeConfigParsed (type)", - "PreviewModeConfigSchema (const)", "ProtocolFeature (type)", "ProtocolFeatureParsed (type)", "ProtocolFeatureSchema (const)", diff --git a/packages/spec/authorable-defaults/kernel.json b/packages/spec/authorable-defaults/kernel.json index 8328219da3..dfda8051b1 100644 --- a/packages/spec/authorable-defaults/kernel.json +++ b/packages/spec/authorable-defaults/kernel.json @@ -119,11 +119,6 @@ "kernel/PluginTrustScore:badges = []", "kernel/PluginVendor:trustLevel = \"unverified\"", "kernel/PluginVendor:verified = false", - "kernel/PreviewModeConfig:autoLogin = true", - "kernel/PreviewModeConfig:expiresInSeconds = 0", - "kernel/PreviewModeConfig:readOnly = false", - "kernel/PreviewModeConfig:simulatedRole = \"admin\"", - "kernel/PreviewModeConfig:simulatedUserName = \"Preview User\"", "kernel/ProtocolFeature:enabled = true", "kernel/RealTimeNotificationConfig:enabled = true", "kernel/RealTimeNotificationConfig:eventPattern = \"*\"", diff --git a/packages/spec/authorable-surface/kernel.json b/packages/spec/authorable-surface/kernel.json index 5bbce3b588..e565acf6c7 100644 --- a/packages/spec/authorable-surface/kernel.json +++ b/packages/spec/authorable-surface/kernel.json @@ -250,7 +250,7 @@ "kernel/KernelContext:features", "kernel/KernelContext:instanceId", "kernel/KernelContext:mode", - "kernel/KernelContext:previewMode", + "kernel/KernelContext:previewMode [RETIRED]", "kernel/KernelContext:startTime", "kernel/KernelContext:version", "kernel/KernelContext:workspaceRoot", @@ -654,12 +654,6 @@ "kernel/PluginVersionMetadata:support", "kernel/PluginVersionMetadata:version", "kernel/PluginVersionMetadata:versionString", - "kernel/PreviewModeConfig:autoLogin", - "kernel/PreviewModeConfig:bannerMessage", - "kernel/PreviewModeConfig:expiresInSeconds", - "kernel/PreviewModeConfig:readOnly", - "kernel/PreviewModeConfig:simulatedRole", - "kernel/PreviewModeConfig:simulatedUserName", "kernel/ProtocolFeature:deprecatedSince", "kernel/ProtocolFeature:description", "kernel/ProtocolFeature:enabled", @@ -801,7 +795,7 @@ "kernel/TenantRuntimeContext:features", "kernel/TenantRuntimeContext:instanceId", "kernel/TenantRuntimeContext:mode", - "kernel/TenantRuntimeContext:previewMode", + "kernel/TenantRuntimeContext:previewMode [RETIRED]", "kernel/TenantRuntimeContext:startTime", "kernel/TenantRuntimeContext:tenantDbUrl", "kernel/TenantRuntimeContext:tenantId", diff --git a/packages/spec/export-origins/kernel.json b/packages/spec/export-origins/kernel.json index 3911c719d1..6347ed682a 100644 --- a/packages/spec/export-origins/kernel.json +++ b/packages/spec/export-origins/kernel.json @@ -356,9 +356,6 @@ "PluginVersionMetadata": "src/kernel/plugin-versioning.zod.ts#PluginVersionMetadata (type)", "PluginVersionMetadataParsed": "src/kernel/plugin-versioning.zod.ts#PluginVersionMetadataParsed (type)", "PluginVersionMetadataSchema": "src/kernel/plugin-versioning.zod.ts#PluginVersionMetadataSchema (const)", - "PreviewModeConfig": "src/kernel/context.zod.ts#PreviewModeConfig (type)", - "PreviewModeConfigParsed": "src/kernel/context.zod.ts#PreviewModeConfigParsed (type)", - "PreviewModeConfigSchema": "src/kernel/context.zod.ts#PreviewModeConfigSchema (const)", "ProtocolFeature": "src/kernel/plugin-capability.zod.ts#ProtocolFeature (type)", "ProtocolFeatureParsed": "src/kernel/plugin-capability.zod.ts#ProtocolFeatureParsed (type)", "ProtocolFeatureSchema": "src/kernel/plugin-capability.zod.ts#ProtocolFeatureSchema (const)", diff --git a/packages/spec/json-schema.manifest/kernel.json b/packages/spec/json-schema.manifest/kernel.json index 7f69207949..822c964283 100644 --- a/packages/spec/json-schema.manifest/kernel.json +++ b/packages/spec/json-schema.manifest/kernel.json @@ -128,7 +128,6 @@ "kernel/PluginTrustScore", "kernel/PluginVendor", "kernel/PluginVersionMetadata", - "kernel/PreviewModeConfig", "kernel/ProtocolFeature", "kernel/ProtocolReference", "kernel/ProtocolVersion", diff --git a/packages/spec/src/kernel/context.test.ts b/packages/spec/src/kernel/context.test.ts index b7ea6ca81f..723fabe960 100644 --- a/packages/spec/src/kernel/context.test.ts +++ b/packages/spec/src/kernel/context.test.ts @@ -2,7 +2,6 @@ import { describe, it, expect } from 'vitest'; import { RuntimeMode, KernelContextSchema, - PreviewModeConfigSchema, TenantRuntimeContextSchema, type KernelContext, type TenantRuntimeContext, @@ -14,13 +13,15 @@ describe('RuntimeMode', () => { expect(() => RuntimeMode.parse('production')).not.toThrow(); expect(() => RuntimeMode.parse('test')).not.toThrow(); expect(() => RuntimeMode.parse('provisioning')).not.toThrow(); - expect(() => RuntimeMode.parse('preview')).not.toThrow(); }); it('should reject invalid runtime modes', () => { expect(() => RuntimeMode.parse('staging')).toThrow(); expect(() => RuntimeMode.parse('debug')).toThrow(); expect(() => RuntimeMode.parse('')).toThrow(); + // 'preview' was RETIRED (#11846) — the full prescription pins live in + // preview-mode-retirement.test.ts; this list only records the narrowing. + expect(() => RuntimeMode.parse('preview')).toThrow(); }); }); @@ -91,82 +92,19 @@ describe('KernelContextSchema', () => { }); it('should accept all runtime modes in context', () => { - const modes = ['development', 'production', 'test', 'provisioning', 'preview'] as const; + // 'preview' left this list in #11846 — see preview-mode-retirement.test.ts. + const modes = ['development', 'production', 'test', 'provisioning'] as const; modes.forEach(mode => { const parsed = KernelContextSchema.parse({ ...validContext, mode }); expect(parsed.mode).toBe(mode); }); }); - it('should accept preview mode with previewMode config', () => { - const parsed = KernelContextSchema.parse({ - ...validContext, - mode: 'preview', - previewMode: { - autoLogin: true, - simulatedRole: 'admin', - simulatedUserName: 'Demo Admin', - readOnly: true, - expiresInSeconds: 3600, - bannerMessage: 'You are viewing a demo of this application.', - }, - }); - expect(parsed.mode).toBe('preview'); - expect(parsed.previewMode?.autoLogin).toBe(true); - expect(parsed.previewMode?.simulatedRole).toBe('admin'); - expect(parsed.previewMode?.simulatedUserName).toBe('Demo Admin'); - expect(parsed.previewMode?.readOnly).toBe(true); - expect(parsed.previewMode?.expiresInSeconds).toBe(3600); - expect(parsed.previewMode?.bannerMessage).toContain('demo'); - }); - - it('should accept context without previewMode (optional)', () => { + it('should accept a context that does not author previewMode (retired key, absence is legal)', () => { const parsed = KernelContextSchema.parse(validContext); - expect(parsed.previewMode).toBeUndefined(); - }); -}); - -describe('PreviewModeConfigSchema', () => { - it('should apply defaults for zero-config preview', () => { - const parsed = PreviewModeConfigSchema.parse({}); - expect(parsed.autoLogin).toBe(true); - expect(parsed.simulatedRole).toBe('admin'); - expect(parsed.simulatedUserName).toBe('Preview User'); - expect(parsed.readOnly).toBe(false); - expect(parsed.expiresInSeconds).toBe(0); - expect(parsed.bannerMessage).toBeUndefined(); - }); - - it('should accept all simulated roles', () => { - const roles = ['admin', 'user', 'viewer'] as const; - roles.forEach(role => { - const parsed = PreviewModeConfigSchema.parse({ simulatedRole: role }); - expect(parsed.simulatedRole).toBe(role); - }); - }); - - it('should reject invalid simulated role', () => { - expect(() => PreviewModeConfigSchema.parse({ simulatedRole: 'superadmin' })).toThrow(); - }); - - it('should accept read-only preview for marketplace demos', () => { - const parsed = PreviewModeConfigSchema.parse({ - autoLogin: true, - simulatedRole: 'viewer', - readOnly: true, - bannerMessage: 'This is a preview. Sign up to get started!', - }); - expect(parsed.readOnly).toBe(true); - expect(parsed.simulatedRole).toBe('viewer'); - expect(parsed.bannerMessage).toContain('preview'); - }); - - it('should reject negative expiresInSeconds', () => { - expect(() => PreviewModeConfigSchema.parse({ expiresInSeconds: -1 })).toThrow(); - }); - - it('should reject non-integer expiresInSeconds', () => { - expect(() => PreviewModeConfigSchema.parse({ expiresInSeconds: 1.5 })).toThrow(); + // The non-strict strip path: absence must stay absence. The retirement + // pins for the AUTHORED case live in preview-mode-retirement.test.ts. + expect(parsed).not.toHaveProperty('previewMode'); }); }); diff --git a/packages/spec/src/kernel/context.zod.ts b/packages/spec/src/kernel/context.zod.ts index 50d630178b..6b0678a709 100644 --- a/packages/spec/src/kernel/context.zod.ts +++ b/packages/spec/src/kernel/context.zod.ts @@ -2,95 +2,80 @@ import { z } from 'zod'; import { TenantQuotaSchema } from '../system/tenant.zod.js'; +import { lazySchema } from '../shared/lazy-schema'; +import { retiredKey } from '../shared/retired-key'; + +// Retirement prescriptions (#11846, ADR-0049 enforce-or-remove; maintainer +// ruling 2026-08-27). Declared with `//` (never `/** */`) and ABOVE the enum's +// JSDoc on purpose — build-docs takes the file's FIRST JSDoc as the reference +// page's module blurb (the hook-body.zod.ts placement precedent). +// +// No `os migrate meta` sentence in either string, deliberately: there is no D2 +// conversion behind this retirement — a kernel context is constructed by HOST +// CODE at boot, never authored in a stack collection or stored as a +// `sys_metadata` row, so the conversion chain has no seam that would ever see +// one (the `kernel/Manifest:loading` precedent). The prescription reaches +// authors through these two rejection sites plus the D3 semantic entry +// `kernel-context-preview-mode-retired`. +const RUNTIME_MODE_PREVIEW_RETIRED = + "`context.mode: 'preview'` was removed from `RuntimeMode` in @objectstack/spec 17 " + + '(#11846, ADR-0049 enforce-or-remove) — no layer of the platform ever branched on it: ' + + 'the value promised "bypass auth, simulate admin identity" and no code path implemented ' + + 'either half, so a deployment declaring it ran with ordinary production behaviour under ' + + 'a misleading label. Delete the value — `mode` defaults to `production`; use ' + + '`development` for local demo work. Preview DEPLOYMENTS are the deployment layer\'s ' + + 'job (`OS_PREVIEW_MODE` is routing-only and never touched identity). If a preview ' + + 'experience becomes a product capability it re-declares fresh, with the ' + + 'production-posture hard-refusal as the first-landed half (#11846 ruling record).'; +const PREVIEW_MODE_RETIRED = + '`context.previewMode` was removed in @objectstack/spec 17 (#11846, ADR-0049 ' + + 'enforce-or-remove) — nothing ever read the block: none of its six keys (`autoLogin`, ' + + '`simulatedRole`, `simulatedUserName`, `readOnly`, `expiresInSeconds`, `bannerMessage`) ' + + 'had a consumer in any repo, so an authored block parsed cleanly and configured ' + + 'NOTHING, while its own docstring promised an auth bypass ("skips authentication ' + + 'screens", "simulates an admin identity") and named a production guard no runtime ever ' + + 'received. Delete the key. Preview/demo deployments belong to the deployment layer, ' + + 'which owns auth per-project (`ArtifactKernelFactory` in the cloud distribution); ' + + '`OS_PREVIEW_MODE` stays there as a routing-only switch. If a preview experience ' + + 'becomes a product capability it re-declares fresh, with the production-posture ' + + 'hard-refusal as the first-landed half (#11846 ruling record).'; /** * Runtime Mode Enum * Defines the operating mode of the kernel */ -import { lazySchema } from '../shared/lazy-schema'; export const RuntimeMode = z.enum([ 'development', // Hot-reload, verbose logging 'production', // Optimized, strict security 'test', // Mocked interfaces 'provisioning', // Setup/Migration mode - 'preview', // Demo/preview mode — bypass auth, simulate admin identity -]).describe('Kernel operating mode'); + // 'preview' was RETIRED in #11846 — see RUNTIME_MODE_PREVIEW_RETIRED above. +], { + // Only the value that USED to be legal gets the retirement prescription — + // telling the author of a typo that their mode "was removed" would + // misinform. Everything else keeps zod's own enum message, which already + // lists the legal values. (The `HookBodyCapability` / `managedBy: 'system'` + // precedent.) + error: (issue) => (issue.input === 'preview' ? RUNTIME_MODE_PREVIEW_RETIRED : undefined), +}).describe('Kernel operating mode'); export type RuntimeMode = z.input; -/** - * Preview Mode Configuration Schema - * - * Configures the kernel's preview/demo mode behaviour. - * When `mode` is set to `'preview'`, the platform skips authentication - * screens and optionally simulates an admin identity so that visitors - * (e.g. app-marketplace customers) can explore the system without - * registering or logging in. - * - * **Security note:** preview mode should NEVER be used in production. - * The runtime must enforce this constraint. - * - * @example - * ```ts - * const ctx = KernelContextSchema.parse({ - * instanceId: '550e8400-e29b-41d4-a716-446655440000', - * mode: 'preview', - * version: '1.0.0', - * cwd: '/app', - * startTime: Date.now(), - * previewMode: { - * autoLogin: true, - * simulatedRole: 'admin', - * }, - * }); - * ``` - */ -export const PreviewModeConfigSchema = lazySchema(() => z.object({ - /** - * Automatically log in as a simulated user on startup. - * When enabled, the frontend skips login/registration screens entirely. - */ - autoLogin: z.boolean().default(true) - .describe('Auto-login as simulated user, skipping login/registration pages'), - - /** - * Role of the simulated user. - * Determines the permission level of the auto-created preview session. - */ - simulatedRole: z.enum(['admin', 'user', 'viewer']).default('admin') - .describe('Permission role for the simulated preview user'), - - /** - * Display name for the simulated user shown in the UI. - */ - simulatedUserName: z.string().default('Preview User') - .describe('Display name for the simulated preview user'), - - /** - * Whether the preview session is read-only. - * When true, all write operations (create, update, delete) are blocked. - */ - readOnly: z.boolean().default(false) - .describe('Restrict the preview session to read-only operations'), - - /** - * Session duration in seconds. After expiry the preview session ends. - * 0 means no expiration. - */ - expiresInSeconds: z.number().int().min(0).default(0) - .describe('Preview session duration in seconds (0 = no expiration)'), - - /** - * Optional banner message shown in the UI to indicate preview mode. - * Useful for marketplace demos so visitors know they are in a sandbox. - */ - bannerMessage: z.string().optional() - .describe('Banner message displayed in the UI during preview mode'), -})); - -export type PreviewModeConfig = z.input; -/** Post-parse shape of {@link PreviewModeConfig} — defaults applied, transforms run (ADR-0122). */ -export type PreviewModeConfigParsed = z.infer; +// ── `PreviewModeConfigSchema` was RETIRED here (#11846, ADR-0049) ──────────── +// +// The whole def — six authorable keys (`autoLogin` default true, +// `simulatedRole` default 'admin', `simulatedUserName`, `readOnly`, +// `expiresInSeconds`, `bannerMessage`) — left the published set together with +// its `PreviewModeConfig` / `PreviewModeConfigParsed` types: its only carrier +// key (`KernelContext.previewMode`, tombstoned below) is retired, and an +// exported value schema with no consumer reads as a capability (#3950, the +// `PerformanceConfigSchema` rule). Registered as `kernel/PreviewModeConfig` in +// `RETIRED_DEFS_BY_MAJOR[18]`; the prescription lives on the tombstone below, +// the `RuntimeMode` error map above, and the D3 semantic entry +// `kernel-context-preview-mode-retired`. What actually produces preview +// deployments is the deployment layer — the cloud distribution owns auth +// per-project (`ArtifactKernelFactory`), and `OS_PREVIEW_MODE` there is +// routing-only. /** * Kernel Context Schema @@ -126,12 +111,15 @@ export const KernelContextSchema = lazySchema(() => z.object({ features: z.record(z.string(), z.boolean()).default({}).describe('Global feature toggles'), /** - * Preview Mode Configuration. - * Only relevant when `mode` is `'preview'`. Configures auto-login, - * simulated identity, read-only restrictions, and UI banner. + * RETIRED (#11846, ADR-0049 enforce-or-remove): the `previewMode` block — + * declared as an auth bypass, enforced by nothing — is unwritable. The + * schema is not `.strict()`, so a bare deletion would have Zod silently + * STRIP the key (#3733, ADR-0104); the tombstone keeps the removal audible + * in both channels (`tsc` types the key `never`; the parse raises the + * prescription). `TenantRuntimeContextSchema` extends this shape and + * inherits the tombstone. */ - previewMode: PreviewModeConfigSchema.optional() - .describe('Preview/demo mode configuration (used when mode is "preview")'), + previewMode: retiredKey(PREVIEW_MODE_RETIRED), })); export type KernelContext = z.input; diff --git a/packages/spec/src/kernel/preview-mode-retirement.test.ts b/packages/spec/src/kernel/preview-mode-retirement.test.ts new file mode 100644 index 0000000000..1af469a3f5 --- /dev/null +++ b/packages/spec/src/kernel/preview-mode-retirement.test.ts @@ -0,0 +1,216 @@ +// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license. + +import { describe, it, expect } from 'vitest'; + +import { + RuntimeMode, + KernelContextSchema, + TenantRuntimeContextSchema, +} from './context.zod'; +import { + EXPORT_ENTRY_POINTS, + exportNamesOf, + holdersOf, +} from '../../scripts/lib/export-origins-testkit'; + +// ─── [#11846] Preview mode is RETIRED: the `'preview'` RuntimeMode value and +// the whole `previewMode` / `PreviewModeConfig` block ──────────────────── +// +// ADR-0049 enforce-or-remove; maintainer ruling 2026-08-27 (Option A: remove). +// The declaration promised an auth bypass — "skips authentication screens", +// "simulates an admin identity", with a docstring naming a production guard +// "the runtime must enforce" — and NOTHING implemented any of it. Measured +// three-repo zero consumers (objectstack in-card + re-verified at dispatch; +// objectui in-card; cloud#1651 with positive controls on 2026-08-26): no +// runtime branches on the mode, nothing reads any of the six config keys, and +// `OS_PREVIEW_MODE` is deployment ROUTING, unrelated to identity — it stays. +// +// Two rejection sites, three bookkeeping shapes: +// +// 1. `mode: 'preview'` — enum-VALUE narrowing. Invisible to the four +// surface ratchets (no def changed), so the prescription hangs on the +// enum's own error map (the `HookBodyCapability` / `crypto.hash` +// precedent), dispatched by `issue.input`. +// 2. `previewMode:` — `retiredKey()` tombstone on the non-strict +// `KernelContextSchema` (a bare deletion would be a SILENT STRIP, +// #3733 / ADR-0104). `TenantRuntimeContextSchema` extends the shape, so +// the tombstone lands in that walked shape too; both keys are registered +// in `RETIRED_KEYS_BY_MAJOR[18]`. +// 3. `PreviewModeConfigSchema` + its 2 types — orphan value schema, def +// removed whole (`kernel/PreviewModeConfig` in `RETIRED_DEFS_BY_MAJOR[18]`; +// an exported value schema with no consumer reads as a capability, #3950). +// +// No D2 conversion, deliberately: a kernel context is constructed by HOST CODE +// at boot — it is not a stack collection member and nothing stores one as a +// `sys_metadata` row, so the conversion chain has no seam that would ever see +// it (the `kernel/Manifest:loading` precedent). The D3 semantic entry +// `kernel-context-preview-mode-retired` carries the prescription outward. +// +// On the assertion set (the #8586 precedent, same reasoning): a schema refusal +// raises a `ZodError` whose issues carry `code` and `path` but no ADR-0112 +// `status` — that envelope belongs to the API error surface. So these pins +// assert the strongest set this surface really has: refusal, the issue `code`, +// the `path` naming WHICH site refused, and the prescription text (#5240: +// where the wording is the contract, pin the wording). +describe("[#11846] RuntimeMode 'preview' retirement", () => { + it("no longer offers 'preview' as a mode", () => { + expect(RuntimeMode.options).toEqual([ + 'development', + 'production', + 'test', + 'provisioning', + ]); + expect(RuntimeMode.options).not.toContain('preview'); + }); + + it("REJECTS mode: 'preview', carrying the retirement prescription", () => { + const result = RuntimeMode.safeParse('preview'); + expect(result.success).toBe(false); + if (result.success) return; // narrowing; the assertion above already failed + + const message = JSON.stringify(result.error.issues); + // The prescription itself, not a bare "invalid enum value": it must name + // the value, say it was removed, and tell the author what to do instead. + expect(message).toMatch(/`context\.mode: 'preview'`.*was removed.*17.*#11846/s); + expect(message).toMatch(/no layer of the platform ever branched on it/s); + expect(message).toMatch(/Delete the value/s); + // The live mechanism must be named: preview DEPLOYMENTS are the + // deployment layer's job, and the env var that stays is routing-only. + expect(message).toMatch(/OS_PREVIEW_MODE.*routing-only/s); + // The recorded fallback: re-declaring is fresh, production refusal first. + expect(message).toMatch(/production-posture hard-refusal.*first-landed half/s); + }); + + it('REJECTS it through the context embed too, at path `mode`', () => { + const result = KernelContextSchema.safeParse({ + instanceId: '550e8400-e29b-41d4-a716-446655440000', + mode: 'preview', + version: '1.0.0', + cwd: '/app', + startTime: Date.now(), + }); + expect(result.success).toBe(false); + if (result.success) return; + + const issue = result.error.issues.find((i) => i.path[0] === 'mode'); + expect(issue, 'the refusal must land at `mode`').toBeDefined(); + expect(issue!.message).toMatch(/`context\.mode: 'preview'`.*was removed.*#11846/s); + }); + + it("gives an UNKNOWN mode zod's own message, not the retirement one", () => { + // Only the value that used to be legal gets "was removed" — telling the + // author of a typo that their mode was retired would misinform. + const result = RuntimeMode.safeParse('previeww'); + expect(result.success).toBe(false); + if (result.success) return; + expect(JSON.stringify(result.error.issues)).not.toMatch(/was removed/); + }); +}); + +describe('[#11846] KernelContext.previewMode retirement', () => { + const baseContext = { + instanceId: '550e8400-e29b-41d4-a716-446655440000', + mode: 'production', + version: '1.0.0', + cwd: '/app', + startTime: Date.now(), + } as const; + + /** The block exactly as the retired docs taught authors to write it. */ + const authoredBlock = { autoLogin: true, simulatedRole: 'admin' } as const; + + it('REJECTS an authored `previewMode` block, naming the key and carrying the fix', () => { + const result = KernelContextSchema.safeParse({ + ...baseContext, + previewMode: authoredBlock, + }); + expect(result.success).toBe(false); + if (result.success) return; + + const issue = result.error.issues.find((i) => i.path[0] === 'previewMode'); + expect(issue, 'the refusal must name `previewMode`').toBeDefined(); + // The machine-readable half of the envelope this surface actually has: + // a `retiredKey()` tombstone raises `invalid_type` from its `z.never()`. + expect(issue!.code).toBe('invalid_type'); + expect(issue!.path).toEqual(['previewMode']); + // The prescription IS the migration doc for whoever hits it — contract, + // not commentary. + expect(issue!.message).toMatch(/`context\.previewMode`.*was removed.*17.*#11846/s); + expect(issue!.message).toMatch(/nothing ever read the block/s); + expect(issue!.message).toMatch(/Delete the key/s); + // The live mechanism: the deployment layer owns preview deployments. + expect(issue!.message).toMatch(/deployment layer/s); + expect(issue!.message).toMatch(/OS_PREVIEW_MODE.*routing-only/s); + }); + + it('REJECTS it through TenantRuntimeContextSchema too (the `.extend()` copy)', () => { + const result = TenantRuntimeContextSchema.safeParse({ + ...baseContext, + tenantId: 'tenant_abc', + tenantPlan: 'pro', + tenantDbUrl: 'libsql://tenant-abc-myorg.turso.io', + previewMode: authoredBlock, + }); + expect(result.success).toBe(false); + if (result.success) return; + const issue = result.error.issues.find((i) => i.path[0] === 'previewMode'); + expect(issue, 'the refusal must surface on the tenant context too').toBeDefined(); + expect(issue!.code).toBe('invalid_type'); + expect(issue!.message).toMatch(/`context\.previewMode`.*was removed/s); + }); + + it('parses cleanly once the key is deleted, and grows no `previewMode` property', () => { + const parsed = KernelContextSchema.parse({ ...baseContext }); + expect(parsed.mode).toBe('production'); // control: the live keys still work + // The non-strict strip path: absence must stay absence. If the tombstone + // were ever replaced by a plain deletion, an authored `previewMode` would + // be stripped here in silence — this pin plus the rejections above are + // what make that regression loud. + expect(parsed).not.toHaveProperty('previewMode'); + }); +}); + +describe('[#11846] kernel/PreviewModeConfig def retirement', () => { + /** The 3 names the retired def exported (1 schema const + 2 types). */ + const RETIRED_NAMES = [ + 'PreviewModeConfigSchema', + 'PreviewModeConfig', + 'PreviewModeConfigParsed', + ] as const; + + it('every retired name has ZERO holders on any public entry; the carrier survives', () => { + // Anti-vacuity: the baseline must cover the real surface. + for (const needed of ['.', './kernel']) { + expect(EXPORT_ENTRY_POINTS, `exports map must include ${needed}`).toContain(needed); + } + expect( + exportNamesOf('./kernel').length, + './kernel must export a non-trivial surface', + ).toBeGreaterThan(50); + + // ── ABSENCE (every entry, not just ./kernel) ────────────────────────── + for (const name of RETIRED_NAMES) { + expect(holdersOf(name), `${name} must have zero holders after #11846`).toEqual([]); + } + + // ── SURVIVAL ────────────────────────────────────────────────────────── + // The context module itself stays: the carrier def and its neighbours are + // untouched — this retirement is a narrowing, not a module sweep. + const kernelNames = exportNamesOf('./kernel'); + for (const name of [ + 'RuntimeMode', + 'KernelContextSchema', + 'TenantRuntimeContextSchema', + ]) { + expect(kernelNames, `${name} must SURVIVE this retirement`).toContain(name); + } + }); + + it('the kernel barrel resolves without the retired schema and keeps the survivors', async () => { + const kernel = await import('./index'); + expect(kernel).not.toHaveProperty('PreviewModeConfigSchema'); + // Anti-vacuity: the barrel really resolved and still exports the carrier. + expect(kernel).toHaveProperty('KernelContextSchema'); + expect(kernel).toHaveProperty('RuntimeMode'); + }); +}); diff --git a/packages/spec/src/migrations/entries/retired-defs/18.kernel__PreviewModeConfig.ts b/packages/spec/src/migrations/entries/retired-defs/18.kernel__PreviewModeConfig.ts new file mode 100644 index 0000000000..0fcebc95d9 --- /dev/null +++ b/packages/spec/src/migrations/entries/retired-defs/18.kernel__PreviewModeConfig.ts @@ -0,0 +1,20 @@ +// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license. + +// #11846 — `kernel/PreviewModeConfig` (the six-key preview/demo config block: +// `autoLogin` default true, `simulatedRole` default 'admin', +// `simulatedUserName`, `readOnly`, `expiresInSeconds`, `bannerMessage`). Its +// only carrier key, `KernelContext.previewMode`, is tombstoned in this same +// major (both walked-shape copies — see the two `…:previewMode` entries in +// RETIRED_KEYS_BY_MAJOR[18]), and an exported value schema with no consumer +// reads as a capability (#3950, the `PerformanceConfigSchema` rule) — so the +// def leaves the emitted set whole, with its `PreviewModeConfig` / +// `PreviewModeConfigParsed` types. Measured before removal: zero consumers of +// the schema or any of its six keys in objectstack, objectui or cloud +// (cloud#1651, 2026-08-26, positive controls on record). The declared +// behaviour (auto-login as a simulated admin, a read-only demo session) was +// never implemented by any layer; preview DEPLOYMENTS belong to the +// deployment layer, whose `OS_PREVIEW_MODE` is routing-only and stays. If a +// preview experience becomes a product capability it re-declares fresh, with +// the production-posture hard-refusal as the first-landed half (#11846 ruling +// record). +export const entry = 'kernel/PreviewModeConfig'; diff --git a/packages/spec/src/migrations/entries/retired-keys/18.kernel__KernelContext__previewMode.ts b/packages/spec/src/migrations/entries/retired-keys/18.kernel__KernelContext__previewMode.ts new file mode 100644 index 0000000000..95421b82cc --- /dev/null +++ b/packages/spec/src/migrations/entries/retired-keys/18.kernel__KernelContext__previewMode.ts @@ -0,0 +1,27 @@ +// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license. + +// #11846 — ADR-0049 enforce-or-remove on the preview-mode block (maintainer +// ruling 2026-08-27, Option A: remove). The key was declared as an auth bypass +// — its docstring promised auto-login as a simulated admin and named a +// production guard "the runtime must enforce" — and NOTHING implemented any of +// it: zero consumers measured in objectstack, objectui and cloud (cloud#1651, +// 2026-08-26, with positive controls; `ArtifactKernelFactory` — where serve.ts +// predicted preview auto-login would live if anywhere — never touches it). An +// author could write the six-key block today, parse cleanly, and get no +// behaviour and no diagnostic, while the reference docs said the capability +// existed. Tombstoned with `retiredKey()` — `KernelContextSchema` is not +// `.strict()`, so a bare deletion would be a silent strip (#3733, ADR-0104). +// +// Registered here but NOT in `src/conversions/registry.ts`, the +// `kernel/Manifest:loading` reasoning: a kernel context is constructed by HOST +// CODE at boot — it is not a stack collection member (`PLURAL_TO_SINGULAR` has +// no entry for it) and nothing stores one as a `sys_metadata` row, so a +// MetadataConversion would be a transform with no seam that ever runs. The +// prescription reaches authors through the tombstone plus the D3 semantic +// entry `kernel-context-preview-mode-retired`. +// +// Registered under 18, not 17: v17.0.0 was cut before this landed, so the +// removal ships on the 17.x line (launch-window convention: accept-set +// narrowings ride minor releases) and the prescription lives at the major +// boundary where `migrate meta` users look (the #8495 / PR #8666 precedent). +export const entry = 'kernel/KernelContext:previewMode'; diff --git a/packages/spec/src/migrations/entries/retired-keys/18.kernel__TenantRuntimeContext__previewMode.ts b/packages/spec/src/migrations/entries/retired-keys/18.kernel__TenantRuntimeContext__previewMode.ts new file mode 100644 index 0000000000..2ac1b87a48 --- /dev/null +++ b/packages/spec/src/migrations/entries/retired-keys/18.kernel__TenantRuntimeContext__previewMode.ts @@ -0,0 +1,10 @@ +// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license. + +// #11846 — the `TenantRuntimeContextSchema` copy of +// `kernel/KernelContext:previewMode`: the def is `KernelContextSchema.extend(…)`, +// so the tombstone lands in this walked shape too and `authorable-surface/` +// marks it `[RETIRED]` separately. Registered per key, as gate (b) reads them — +// nothing radiates from the base (the `shared/FieldMapping:transform` +// precedent). See the base entry for the full record and the +// no-D2-conversion reasoning. +export const entry = 'kernel/TenantRuntimeContext:previewMode'; diff --git a/packages/spec/src/migrations/entries/semantic/18.kernel-context-preview-mode-retired.ts b/packages/spec/src/migrations/entries/semantic/18.kernel-context-preview-mode-retired.ts new file mode 100644 index 0000000000..6c206bcfe0 --- /dev/null +++ b/packages/spec/src/migrations/entries/semantic/18.kernel-context-preview-mode-retired.ts @@ -0,0 +1,83 @@ +// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license. + +import type { SemanticMigration } from '../../types.js'; + +export const entry: SemanticMigration = { + id: 'kernel-context-preview-mode-retired', + // No backticks in `surface` — build-upgrade-guide.ts renders it inside a + // code span AND a table cell. + surface: + "context.mode — the value 'preview' left the RuntimeMode enum — and " + + 'context.previewMode, the whole PreviewModeConfig block it keyed ' + + '(autoLogin / simulatedRole / simulatedUserName / readOnly / ' + + 'expiresInSeconds / bannerMessage, declared on KernelContext and on the ' + + 'TenantRuntimeContext extension). The exported ' + + 'PreviewModeConfigSchema / PreviewModeConfig / PreviewModeConfigParsed ' + + 'names left with the def', + replacement: + 'nothing declarative — the capability the block described was never ' + + 'implemented by any layer, so there is no working configuration to ' + + 'migrate to. Preview/demo DEPLOYMENTS belong to the deployment layer, ' + + 'which owns auth per-project (ArtifactKernelFactory in the cloud ' + + 'distribution); the OS_PREVIEW_MODE environment variable stays exactly ' + + 'as it is — deployment ROUTING (widening the trusted-origin list for ' + + 'preview subdomains), unrelated to identity. If a preview experience ' + + 'becomes a product capability it re-declares fresh, with the ' + + 'production-posture hard-refusal as the first-landed half (#11846 ' + + 'ruling record)', + reason: + 'ADR-0049 enforce-or-remove; maintainer ruling 2026-08-27 on #11846 ' + + '(decision-inbox batch 2, Option A: remove — all four decision facets ' + + 'pointed the same way). The declaration was the sharpest ' + + 'declared-≠-enforced shape on a SECURITY surface: the schema promised ' + + '"bypass auth, simulate admin identity" and named a production guard ' + + '"the runtime must enforce", and NO code path implemented either half. ' + + 'Measured zero consumers in all three repos, each leg with positive ' + + 'controls: objectstack — no runtime branches on the mode; the only ' + + "non-declaration hits for RuntimeMode or mode === 'preview' are the " + + 'schema unit test, a type-alias pin and a measurement-test comment ' + + '(re-verified at dispatch, 2026-08-27, origin/main 15bf9e8). objectui — ' + + 'the #11846 card records the measurement. cloud — cloud#1651 (closed ' + + '2026-08-26): previewMode appears only as a local variable for ' + + 'OS_PREVIEW_MODE whose effect is adding preview-domain wildcards to ' + + "better-auth's CSRF trusted origins; RuntimeMode has zero hits " + + 'repo-wide; the positive control ArtifactKernelFactory (where serve.ts ' + + 'predicted preview auto-login would live if it existed) has 20+ hits ' + + 'and never touches previewMode. An author — very often an AI (ADR-0033) ' + + '— could write the six-key block per the reference docs, parse cleanly, ' + + 'and get no behaviour and no diagnostic, while a reader of the docs had ' + + 'no way to tell the block from the keys that work. Bookkeeping: the ' + + "enum-VALUE half ('preview') puts nothing in RETIRED_KEYS_BY_MAJOR and " + + 'leaves the four surface ratchets untouched by itself — its ' + + "prescription hangs on the enum's own error map (the HookBodyCapability " + + 'precedent); the KEY half is tombstoned with retiredKey() on the ' + + 'non-strict KernelContextSchema (both walked-shape copies registered in ' + + 'RETIRED_KEYS_BY_MAJOR[18]); the DEF half (kernel/PreviewModeConfig, ' + + 'with no carrier left) is registered in RETIRED_DEFS_BY_MAJOR[18]. It ' + + 'is a SEMANTIC entry rather than a D2 conversion because there is no ' + + 'source to rewrite: a kernel context is constructed by host code at ' + + 'boot — not a stack collection member, never stored as a sys_metadata ' + + 'row — so the conversion chain has no seam that would ever see one ' + + '(the kernel/Manifest:loading disposition). ADR-0049 / ADR-0087, ' + + '#11846.', + acceptanceCriteria: + "No host constructs a kernel context with mode: 'preview' or a " + + 'previewMode block: both now fail tsc at the authoring site and fail ' + + 'the parse with the prescription (pinned in ' + + 'kernel/preview-mode-retirement.test.ts). Concretely, check three ' + + "places. (1) Host boot code composing a KernelContext: delete `mode: " + + "'preview'` (mode defaults to production; use development for local " + + 'demo work) and delete any previewMode block — neither ever changed ' + + 'runtime behaviour, so removing them changes nothing observable. ' + + '(2) Code importing PreviewModeConfigSchema, PreviewModeConfig or ' + + 'PreviewModeConfigParsed from @objectstack/spec or @objectstack/spec/' + + 'kernel: every one is TS2305 after upgrade; no working replacement ' + + 'exists to point at, because the vocabulary described nothing real. ' + + "(3) TypeScript branching on the RuntimeMode type (a mode === " + + "'preview' arm, a switch over modes): the arm is now unreachable and " + + 'an exhaustiveness check will fail to compile if it stays — that ' + + 'compile error is the enforced channel for TypeScript consumers. ' + + 'Preview deployment ROUTING is untouched: OS_PREVIEW_MODE and ' + + 'OS_PREVIEW_BASE_DOMAINS keep working exactly as documented ' + + '(deployment routing, never identity).', +}; diff --git a/packages/spec/src/migrations/registry.ts b/packages/spec/src/migrations/registry.ts index 2c2d5b775c..7096377060 100644 --- a/packages/spec/src/migrations/registry.ts +++ b/packages/spec/src/migrations/registry.ts @@ -6377,6 +6377,85 @@ const step18: MigrationStep = { + 'read the schema, so removing it removes no behaviour — mint and verify ' + 'work byte-identically before and after.', }, + { + id: 'kernel-context-preview-mode-retired', + // No backticks in `surface` — build-upgrade-guide.ts renders it inside a + // code span AND a table cell. + surface: + "context.mode — the value 'preview' left the RuntimeMode enum — and " + + 'context.previewMode, the whole PreviewModeConfig block it keyed ' + + '(autoLogin / simulatedRole / simulatedUserName / readOnly / ' + + 'expiresInSeconds / bannerMessage, declared on KernelContext and on the ' + + 'TenantRuntimeContext extension). The exported ' + + 'PreviewModeConfigSchema / PreviewModeConfig / PreviewModeConfigParsed ' + + 'names left with the def', + replacement: + 'nothing declarative — the capability the block described was never ' + + 'implemented by any layer, so there is no working configuration to ' + + 'migrate to. Preview/demo DEPLOYMENTS belong to the deployment layer, ' + + 'which owns auth per-project (ArtifactKernelFactory in the cloud ' + + 'distribution); the OS_PREVIEW_MODE environment variable stays exactly ' + + 'as it is — deployment ROUTING (widening the trusted-origin list for ' + + 'preview subdomains), unrelated to identity. If a preview experience ' + + 'becomes a product capability it re-declares fresh, with the ' + + 'production-posture hard-refusal as the first-landed half (#11846 ' + + 'ruling record)', + reason: + 'ADR-0049 enforce-or-remove; maintainer ruling 2026-08-27 on #11846 ' + + '(decision-inbox batch 2, Option A: remove — all four decision facets ' + + 'pointed the same way). The declaration was the sharpest ' + + 'declared-≠-enforced shape on a SECURITY surface: the schema promised ' + + '"bypass auth, simulate admin identity" and named a production guard ' + + '"the runtime must enforce", and NO code path implemented either half. ' + + 'Measured zero consumers in all three repos, each leg with positive ' + + 'controls: objectstack — no runtime branches on the mode; the only ' + + "non-declaration hits for RuntimeMode or mode === 'preview' are the " + + 'schema unit test, a type-alias pin and a measurement-test comment ' + + '(re-verified at dispatch, 2026-08-27, origin/main 15bf9e8). objectui — ' + + 'the #11846 card records the measurement. cloud — cloud#1651 (closed ' + + '2026-08-26): previewMode appears only as a local variable for ' + + 'OS_PREVIEW_MODE whose effect is adding preview-domain wildcards to ' + + "better-auth's CSRF trusted origins; RuntimeMode has zero hits " + + 'repo-wide; the positive control ArtifactKernelFactory (where serve.ts ' + + 'predicted preview auto-login would live if it existed) has 20+ hits ' + + 'and never touches previewMode. An author — very often an AI (ADR-0033) ' + + '— could write the six-key block per the reference docs, parse cleanly, ' + + 'and get no behaviour and no diagnostic, while a reader of the docs had ' + + 'no way to tell the block from the keys that work. Bookkeeping: the ' + + "enum-VALUE half ('preview') puts nothing in RETIRED_KEYS_BY_MAJOR and " + + 'leaves the four surface ratchets untouched by itself — its ' + + "prescription hangs on the enum's own error map (the HookBodyCapability " + + 'precedent); the KEY half is tombstoned with retiredKey() on the ' + + 'non-strict KernelContextSchema (both walked-shape copies registered in ' + + 'RETIRED_KEYS_BY_MAJOR[18]); the DEF half (kernel/PreviewModeConfig, ' + + 'with no carrier left) is registered in RETIRED_DEFS_BY_MAJOR[18]. It ' + + 'is a SEMANTIC entry rather than a D2 conversion because there is no ' + + 'source to rewrite: a kernel context is constructed by host code at ' + + 'boot — not a stack collection member, never stored as a sys_metadata ' + + 'row — so the conversion chain has no seam that would ever see one ' + + '(the kernel/Manifest:loading disposition). ADR-0049 / ADR-0087, ' + + '#11846.', + acceptanceCriteria: + "No host constructs a kernel context with mode: 'preview' or a " + + 'previewMode block: both now fail tsc at the authoring site and fail ' + + 'the parse with the prescription (pinned in ' + + 'kernel/preview-mode-retirement.test.ts). Concretely, check three ' + + "places. (1) Host boot code composing a KernelContext: delete `mode: " + + "'preview'` (mode defaults to production; use development for local " + + 'demo work) and delete any previewMode block — neither ever changed ' + + 'runtime behaviour, so removing them changes nothing observable. ' + + '(2) Code importing PreviewModeConfigSchema, PreviewModeConfig or ' + + 'PreviewModeConfigParsed from @objectstack/spec or @objectstack/spec/' + + 'kernel: every one is TS2305 after upgrade; no working replacement ' + + 'exists to point at, because the vocabulary described nothing real. ' + + "(3) TypeScript branching on the RuntimeMode type (a mode === " + + "'preview' arm, a switch over modes): the arm is now unreachable and " + + 'an exhaustiveness check will fail to compile if it stays — that ' + + 'compile error is the enforced channel for TypeScript consumers. ' + + 'Preview deployment ROUTING is untouched: OS_PREVIEW_MODE and ' + + 'OS_PREVIEW_BASE_DOMAINS keep working exactly as documented ' + + '(deployment routing, never identity).', + }, { id: 'memory-persistence-placeholder-refused', surface: 'memory driver config `persistence.path` (file persistence and the `auto` ' + @@ -7584,6 +7663,31 @@ export const RETIRED_KEYS_BY_MAJOR: Readonly> // declaration, and the registration-time refusal in // `HotReloadManager.registerPlugin` is the door for the audience that exists. 'kernel/HotReloadConfig:watchPatterns', + // #11846 — ADR-0049 enforce-or-remove on the preview-mode block (maintainer + // ruling 2026-08-27, Option A: remove). The key was declared as an auth bypass + // — its docstring promised auto-login as a simulated admin and named a + // production guard "the runtime must enforce" — and NOTHING implemented any of + // it: zero consumers measured in objectstack, objectui and cloud (cloud#1651, + // 2026-08-26, with positive controls; `ArtifactKernelFactory` — where serve.ts + // predicted preview auto-login would live if anywhere — never touches it). An + // author could write the six-key block today, parse cleanly, and get no + // behaviour and no diagnostic, while the reference docs said the capability + // existed. Tombstoned with `retiredKey()` — `KernelContextSchema` is not + // `.strict()`, so a bare deletion would be a silent strip (#3733, ADR-0104). + // + // Registered here but NOT in `src/conversions/registry.ts`, the + // `kernel/Manifest:loading` reasoning: a kernel context is constructed by HOST + // CODE at boot — it is not a stack collection member (`PLURAL_TO_SINGULAR` has + // no entry for it) and nothing stores one as a `sys_metadata` row, so a + // MetadataConversion would be a transform with no seam that ever runs. The + // prescription reaches authors through the tombstone plus the D3 semantic + // entry `kernel-context-preview-mode-retired`. + // + // Registered under 18, not 17: v17.0.0 was cut before this landed, so the + // removal ships on the 17.x line (launch-window convention: accept-set + // narrowings ride minor releases) and the prescription lives at the major + // boundary where `migrate meta` users look (the #8495 / PR #8666 precedent). + 'kernel/KernelContext:previewMode', // #10724 — ADR-0049 enforce-or-remove on the plugin manifest's `contributes` // block; one of NINE members tombstoned together. Census, registration major, // and the why-no-D2-conversion reasoning are recorded once in the sibling @@ -7935,6 +8039,14 @@ export const RETIRED_KEYS_BY_MAJOR: Readonly> // registration-time refusal in `PluginHealthMonitor.registerPlugin` is the door // for the audience that exists. 'kernel/PluginHealthCheck:restartBackoff', + // #11846 — the `TenantRuntimeContextSchema` copy of + // `kernel/KernelContext:previewMode`: the def is `KernelContextSchema.extend(…)`, + // so the tombstone lands in this walked shape too and `authorable-surface/` + // marks it `[RETIRED]` separately. Registered per key, as gate (b) reads them — + // nothing radiates from the base (the `shared/FieldMapping:transform` + // precedent). See the base entry for the full record and the + // no-D2-conversion reasoning. + 'kernel/TenantRuntimeContext:previewMode', // #12497 — the RESPONSE-side face of `security/ObjectPermission:allowPurge` // (see that entry for the full rationale: ADR-0049 enforce-or-remove, // maintainer ruling 2026-08-26 accepting #1883's recommendation B; the key @@ -8793,6 +8905,24 @@ export const RETIRED_DEFS_BY_MAJOR: Readonly> // implementation first. See `18.kernel__AdvancedPluginLifecycleConfig.ts` // for the family record. 'kernel/PluginUpdateStrategy', + // #11846 — `kernel/PreviewModeConfig` (the six-key preview/demo config block: + // `autoLogin` default true, `simulatedRole` default 'admin', + // `simulatedUserName`, `readOnly`, `expiresInSeconds`, `bannerMessage`). Its + // only carrier key, `KernelContext.previewMode`, is tombstoned in this same + // major (both walked-shape copies — see the two `…:previewMode` entries in + // RETIRED_KEYS_BY_MAJOR[18]), and an exported value schema with no consumer + // reads as a capability (#3950, the `PerformanceConfigSchema` rule) — so the + // def leaves the emitted set whole, with its `PreviewModeConfig` / + // `PreviewModeConfigParsed` types. Measured before removal: zero consumers of + // the schema or any of its six keys in objectstack, objectui or cloud + // (cloud#1651, 2026-08-26, positive controls on record). The declared + // behaviour (auto-login as a simulated admin, a read-only demo session) was + // never implemented by any layer; preview DEPLOYMENTS belong to the + // deployment layer, whose `OS_PREVIEW_MODE` is routing-only and stays. If a + // preview experience becomes a product capability it re-declares fresh, with + // the production-posture hard-refusal as the first-landed half (#11846 ruling + // record). + 'kernel/PreviewModeConfig', // #10485 — `ui/BorderRadius` (the border-radius scale sub-block) left with `ui/Theme`: // its ONLY consumer was the retired `ThemeSchema` (the #3950 rule — an // exported value schema with no consumer reads as a capability). See diff --git a/skills/objectstack-platform/references/_index.md b/skills/objectstack-platform/references/_index.md index b0e81065fe..55dd5f05e6 100644 --- a/skills/objectstack-platform/references/_index.md +++ b/skills/objectstack-platform/references/_index.md @@ -11,7 +11,7 @@ from `node_modules` — there is no local copy in the skill bundle. - `node_modules/@objectstack/spec/src/data/datasource.zod.ts` — Driver Identifier - `node_modules/@objectstack/spec/src/data/seed.zod.ts` — Seed Import Strategy -- `node_modules/@objectstack/spec/src/kernel/context.zod.ts` — Runtime Mode Enum +- `node_modules/@objectstack/spec/src/kernel/context.zod.ts` — Exports: RuntimeMode, KernelContextSchema, TenantRuntimeContextSchema - `node_modules/@objectstack/spec/src/kernel/manifest.zod.ts` — Exports: PluginPermissionsSchema, ManifestPermissionsSchema, PluginEnginesSchema, PluginRuntimeSchema, PluginPackagingSchema - `node_modules/@objectstack/spec/src/kernel/metadata-plugin.zod.ts` — Metadata Plugin Protocol - `node_modules/@objectstack/spec/src/kernel/plugin-capability.zod.ts` — Plugin Capability Protocol From 5eb237fd75179e3ae840f31b26ab51b31c9a81d1 Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 27 Aug 2026 14:53:23 +0000 Subject: [PATCH 2/3] chore(spec): regenerate artifacts on the merged tree (#11846 x #12704) os-regen-merge four-step: merge commit first (deferral recorded), then the deliberate manifest + surface-baseline deletions re-applied on the merged tree and the whole chain regenerated with repo tooling. Both sides' sources verified present (retirement tombstone + registry entries; #12704 OrgScopingEntitlement tenancy-posture + capabilities). Co-Authored-By: Claude --- content/docs/references/index.mdx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/content/docs/references/index.mdx b/content/docs/references/index.mdx index 58ba0bb364..d1cc1d8dcf 100644 --- a/content/docs/references/index.mdx +++ b/content/docs/references/index.mdx @@ -1,6 +1,6 @@ --- title: Protocol Reference -description: Every schema published by @objectstack/spec — 1583 schemas across 14 protocol modules +description: Every schema published by @objectstack/spec — 1585 schemas across 14 protocol modules --- {/* ⚠️ AUTO-GENERATED — DO NOT EDIT. Run build-docs.ts to regenerate. Hand-written docs live in the module folders under content/docs/. */} @@ -28,12 +28,12 @@ counts are sums of the rows they head. Regenerate with | [Integration Protocol](/docs/references/integration) | 1 | 27 | The single connector protocol (ADR-0097) — catalog descriptors and provider-bound instances. | | [Kernel Protocol](/docs/references/kernel) | 31 | 170 | Plugin lifecycle and manifests, capabilities and security, metadata loading, service registry. | | [QA Protocol](/docs/references/qa) | 1 | 8 | Declarative test suites — scenarios, steps, actions and assertions. | -| [Security Protocol](/docs/references/security) | 5 | 27 | Permission sets, row-level security, sharing rules, tenancy posture. | +| [Security Protocol](/docs/references/security) | 5 | 29 | Permission sets, row-level security, sharing rules, tenancy posture. | | [Shared Protocol](/docs/references/shared) | 8 | 32 | Primitives used across every protocol — identifiers, HTTP, expressions, error maps, enums. | | [Studio Protocol](/docs/references/studio) | 3 | 35 | Studio designer metadata — the authoring surfaces for the protocols above. | | [System Protocol](/docs/references/system) | 36 | 288 | The runtime environment — logging, jobs, cache, metrics, notifications, i18n and compliance. | | [UI Protocol](/docs/references/ui) | 16 | 152 | Apps, pages, views, dashboards, reports, actions and themes — the ObjectUI layer. | -| **Total** | **199** | **1583** | 14 protocol modules | +| **Total** | **199** | **1585** | 14 protocol modules | --- @@ -269,14 +269,14 @@ Declarative test suites — scenarios, steps, actions and assertions. ## Security Protocol -**Source:** `packages/spec/src/security/` · **Import:** `@objectstack/spec/security` · **5 pages, 27 schemas** +**Source:** `packages/spec/src/security/` · **Import:** `@objectstack/spec/security` · **5 pages, 29 schemas** Permission sets, row-level security, sharing rules, tenancy posture. | File | Schemas | | :--- | :--- | | [`explain.zod.ts`](/docs/references/security/explain) | `AccessMatrix`, `AccessMatrixEntry`, `AuthzPosture`, `ExplainDecision`, `ExplainLayer`, `ExplainMatchedRule`, `ExplainOperation`, `ExplainRecordAttribution`, `ExplainRequest` | -| [`misc`](/docs/references/security/misc) *(no single source file)* | `CapabilityDeclaration`, `TenancyPosture` | +| [`misc`](/docs/references/security/misc) *(no single source file)* | `CapabilityDeclaration`, `OrgScopingEntitlement`, `PlatformGlobalObjects`, `TenancyPosture` | | [`permission.zod.ts`](/docs/references/security/permission) | `AdminScope`, `EffectiveObjectPermission`, `FieldPermission`, `ObjectAccessScope`, `ObjectPermission`, `PermissionSet` | | [`rls.zod.ts`](/docs/references/security/rls) | `RLSEvaluationResult`, `RLSOperation`, `RLSUserContext`, `RowLevelSecurityPolicy` | | [`sharing.zod.ts`](/docs/references/security/sharing) | `CriteriaSharingRule`, `OWDModel`, `ShareRecipientType`, `SharingLevel`, `SharingRule`, `SharingRuleType` | From dbbb7810cd468dc9b3edd60ec5401f53f2e28ce8 Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 28 Aug 2026 06:10:35 +0000 Subject: [PATCH 3/3] chore(spec): regenerate artifacts on the merged tree (#11846 x #12848) --- content/docs/references/index.mdx | 20 ++++++++++--------- ...07-unknown-key-strictness-ledger.counts.md | 4 ++-- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/content/docs/references/index.mdx b/content/docs/references/index.mdx index d1cc1d8dcf..1fa890ef0a 100644 --- a/content/docs/references/index.mdx +++ b/content/docs/references/index.mdx @@ -1,6 +1,6 @@ --- title: Protocol Reference -description: Every schema published by @objectstack/spec — 1585 schemas across 14 protocol modules +description: Every schema published by @objectstack/spec — 1604 schemas across 14 protocol modules --- {/* ⚠️ AUTO-GENERATED — DO NOT EDIT. Run build-docs.ts to regenerate. Hand-written docs live in the module folders under content/docs/. */} @@ -20,7 +20,7 @@ counts are sums of the rows they head. Regenerate with | Module | Pages | Schemas | Description | | :--- | ---: | ---: | :--- | | [AI Protocol](/docs/references/ai) | 11 | 66 | Agents, tools, skills, RAG and knowledge sources, model registry, conversations. | -| [API Protocol](/docs/references/api) | 29 | 423 | REST contracts, endpoints, routing, realtime, batch, discovery. | +| [API Protocol](/docs/references/api) | 31 | 439 | REST contracts, endpoints, routing, realtime, batch, discovery. | | [Automation Protocol](/docs/references/automation) | 13 | 68 | Flows and their nodes, approvals, ETL pipelines, webhooks, state machines, execution records. | | [Cloud Protocol](/docs/references/cloud) | 11 | 94 | Environments, packages and versions, marketplace, developer portal, tenancy. | | [Data Protocol](/docs/references/data) | 29 | 166 | Objects, fields, queries, filters, datasources and drivers — the ObjectQL layer. | @@ -31,9 +31,9 @@ counts are sums of the rows they head. Regenerate with | [Security Protocol](/docs/references/security) | 5 | 29 | Permission sets, row-level security, sharing rules, tenancy posture. | | [Shared Protocol](/docs/references/shared) | 8 | 32 | Primitives used across every protocol — identifiers, HTTP, expressions, error maps, enums. | | [Studio Protocol](/docs/references/studio) | 3 | 35 | Studio designer metadata — the authoring surfaces for the protocols above. | -| [System Protocol](/docs/references/system) | 36 | 288 | The runtime environment — logging, jobs, cache, metrics, notifications, i18n and compliance. | +| [System Protocol](/docs/references/system) | 36 | 291 | The runtime environment — logging, jobs, cache, metrics, notifications, i18n and compliance. | | [UI Protocol](/docs/references/ui) | 16 | 152 | Apps, pages, views, dashboards, reports, actions and themes — the ObjectUI layer. | -| **Total** | **199** | **1585** | 14 protocol modules | +| **Total** | **201** | **1604** | 14 protocol modules | --- @@ -61,7 +61,7 @@ Agents, tools, skills, RAG and knowledge sources, model registry, conversations. ## API Protocol -**Source:** `packages/spec/src/api/` · **Import:** `@objectstack/spec/api` · **29 pages, 423 schemas** +**Source:** `packages/spec/src/api/` · **Import:** `@objectstack/spec/api` · **31 pages, 439 schemas** REST contracts, endpoints, routing, realtime, batch, discovery. @@ -83,10 +83,12 @@ REST contracts, endpoints, routing, realtime, batch, discovery. | [`export.zod.ts`](/docs/references/api/export) | `CreateExportJobRequest`, `CreateExportJobResponse`, `CreateImportJobRequest`, `CreateImportJobResponse`, `DeduplicationStrategy`, `ExportFormat`, `ExportImportTemplate`, `ExportJobProgress`, `ExportJobStatus`, `ExportJobSummary`, `FieldMappingEntry`, `GetExportJobDownloadRequest`, `GetExportJobDownloadResponse`, `ImportJobProgress`, `ImportJobResults`, `ImportJobStatus`, `ImportJobSummary`, `ImportMapping`, `ImportRequest`, `ImportResponse`, `ImportRowResult`, `ImportValidationConfig`, `ImportValidationMode`, `ImportValidationResult`, `ImportWriteMode`, `ListExportJobsRequest`, `ListExportJobsResponse`, `ListImportJobsRequest`, `ListImportJobsResponse`, `ScheduleExportRequest`, `ScheduleExportResponse`, `ScheduledExport`, `UndoImportJobResponse` | | [`http-cache.zod.ts`](/docs/references/api/http-cache) | `CacheControl`, `CacheDirective`, `CacheInvalidationRequest`, `CacheInvalidationResponse`, `CacheInvalidationTarget`, `ETag`, `MetadataCacheRequest`, `MetadataCacheResponse` | | [`metadata.zod.ts`](/docs/references/api/metadata) | `AppDefinitionResponse`, `ConceptListResponse`, `MetadataBulkRegisterRequest`, `MetadataBulkResponse`, `MetadataBulkUnregisterRequest`, `MetadataDeleteResponse`, `MetadataDependenciesResponse`, `MetadataDependentsResponse`, `MetadataEffectiveResponse`, `MetadataExistsResponse`, `MetadataExportRequest`, `MetadataExportResponse`, `MetadataImportRequest`, `MetadataImportResponse`, `MetadataItemResponse`, `MetadataListResponse`, `MetadataNamesResponse`, `MetadataOverlayResponse`, `MetadataOverlaySaveRequest`, `MetadataQueryRequest`, `MetadataQueryResponse`, `MetadataRegisterRequest`, `MetadataTypeInfoResponse`, `MetadataTypesResponse`, `MetadataValidateRequest`, `MetadataValidateResponse`, `ObjectDefinitionResponse` | +| [`misc`](/docs/references/api/misc) *(no single source file)* | `ResolvedBook`, `ResolvedEntry`, `ResolvedGroup` | | [`odata.zod.ts`](/docs/references/api/odata) | `ODataConfig`, `ODataError`, `ODataFilterFunction`, `ODataMetadata`, `ODataQuery`, `ODataResponse` | -| [`package-api.zod.ts`](/docs/references/api/package-api) | `GetInstalledPackageRequest`, `GetInstalledPackageResponse`, `ListInstalledPackagesRequest`, `ListInstalledPackagesResponse`, `PackageApiErrorCode`, `PackageInstallRequest`, `PackageInstallResponse`, `PackagePathParams`, `PackageRollbackRequest`, `PackageRollbackResponse`, `PackageUpgradeRequest`, `PackageUpgradeResponse`, `ResolveDependenciesRequest`, `ResolveDependenciesResponse`, `UninstallPackageApiRequest`, `UninstallPackageApiResponse`, `UploadArtifactRequest`, `UploadArtifactResponse` | +| [`package-api.zod.ts`](/docs/references/api/package-api) | `GetInstalledPackageRequest`, `GetInstalledPackageResponse`, `ListInstalledPackagesRequest`, `ListInstalledPackagesResponse`, `PackageApiErrorCode`, `PackageInstallRequest`, `PackageInstallResponse`, `PackagePathParams`, `PackageRollbackRequest`, `PackageUpgradeRequest`, `PackageUpgradeResponse`, `ResolveDependenciesRequest`, `ResolveDependenciesResponse`, `UninstallPackageApiRequest`, `UninstallPackageApiResponse`, `UploadArtifactRequest`, `UploadArtifactResponse` | +| [`package-lifecycle.zod.ts`](/docs/references/api/package-lifecycle) | `DiscardPackageDraftsResponse`, `DuplicatePackageResponse`, `ListPackageCommitsResponse`, `PackageExportManifest`, `PackagePublishResult`, `ReassignOrphanedMetadataResponse`, `RevertPackageCommitResponse`, `RollbackToPackageCommitResponse` | | [`plugin-rest-api.zod.ts`](/docs/references/api/plugin-rest-api) | `ErrorHandlingConfig`, `HandlerStatus`, `OpenApiGenerationConfig`, `RequestValidationConfig`, `ResponseEnvelopeConfig`, `RestApiEndpoint`, `RestApiPluginConfig`, `RestApiRouteCategory`, `RestApiRouteRegistration`, `RouteCoverageEntry`, `RouteCoverageReport`, `ValidationMode` | -| [`protocol.zod.ts`](/docs/references/api/protocol) | `AiAgentCapabilities`, `AiAgentChatRequest`, `AiAgentSummary`, `AiAgentsResponse`, `AiChatRequest`, `AiChatResponse`, `AiCompleteRequest`, `AiConversation`, `AiMessage`, `AiModelsResponse`, `AiPendingAction`, `AiPendingActionStatus`, `AiStreamChunk`, `ApproveAiPendingActionResponse`, `AuditMetaItemRequest`, `AuditMetaItemResponse`, `AutomationActionsResponse`, `AutomationTriggerRequest`, `AutomationTriggerResponse`, `BatchDataRequest`, `BatchDataResponse`, `CheckPermissionRequest`, `CheckPermissionResponse`, `CloneDataResponse`, `CreateAiConversationRequest`, `CreateDataRequest`, `CreateDataResponse`, `CreateManyDataRequest`, `CreateManyDataResponse`, `DeleteDataRequest`, `DeleteDataResponse`, `DeleteManyDataRequest`, `DeleteManyDataResponse`, `DeleteMetaItemRequest`, `DeleteMetaItemResponse`, `DisablePackageRequest`, `DisablePackageResponse`, `EnablePackageRequest`, `EnablePackageResponse`, `FindDataRequest`, `FindDataResponse`, `GetDataRequest`, `GetDataResponse`, `GetDiscoveryRequest`, `GetDiscoveryResponse`, `GetEffectivePermissionsRequest`, `GetEffectivePermissionsResponse`, `GetFieldLabelsRequest`, `GetFieldLabelsResponse`, `GetLocalesRequest`, `GetLocalesResponse`, `GetMetaItemCachedRequest`, `GetMetaItemCachedResponse`, `GetMetaItemLayeredRequest`, `GetMetaItemLayeredResponse`, `GetMetaItemRequest`, `GetMetaItemResponse`, `GetMetaItemsRequest`, `GetMetaItemsResponse`, `GetMetaTypesRequest`, `GetMetaTypesResponse`, `GetNotificationPreferencesRequest`, `GetNotificationPreferencesResponse`, `GetObjectPermissionsRequest`, `GetObjectPermissionsResponse`, `GetPackageRequest`, `GetPackageResponse`, `GetPresenceRequest`, `GetPresenceResponse`, `GetTranslationsRequest`, `GetTranslationsResponse`, `GetUiViewRequest`, `GetUiViewResponse`, `HttpFindQueryParams`, `InstallPackageRequest`, `InstallPackageResponse`, `ListAiConversationsRequest`, `ListAiConversationsResponse`, `ListAiPendingActionsRequest`, `ListAiPendingActionsResponse`, `ListNotificationsRequest`, `ListNotificationsResponse`, `ListPackagesRequest`, `ListPackagesResponse`, `MarkAllNotificationsReadRequest`, `MarkAllNotificationsReadResponse`, `MarkNotificationsReadRequest`, `MarkNotificationsReadResponse`, `Notification`, `NotificationPreferences`, `PublishMetaItemRequest`, `PublishMetaItemResponse`, `PublishPackageDraftsResponse`, `RealtimeConnectRequest`, `RealtimeConnectResponse`, `RealtimeDisconnectRequest`, `RealtimeDisconnectResponse`, `RealtimeSubscribeRequest`, `RealtimeSubscribeResponse`, `RealtimeUnsubscribeRequest`, `RealtimeUnsubscribeResponse`, `RegisterDeviceRequest`, `RegisterDeviceResponse`, `RejectAiPendingActionResponse`, `RuntimeAuthoringIssue`, `SaveMetaItemRequest`, `SaveMetaItemResponse`, `SearchAllHit`, `SearchAllResponse`, `SetPresenceRequest`, `SetPresenceResponse`, `UninstallPackageRequest`, `UninstallPackageResponse`, `UnregisterDeviceRequest`, `UnregisterDeviceResponse`, `UpdateAiConversationRequest`, `UpdateDataRequest`, `UpdateDataResponse`, `UpdateManyDataRequest`, `UpdateManyDataResponse`, `UpdateNotificationPreferencesRequest`, `UpdateNotificationPreferencesResponse`, `ValidateDataIssue`, `ValidateDataRequest`, `ValidateDataResponse` | +| [`protocol.zod.ts`](/docs/references/api/protocol) | `AiAgentCapabilities`, `AiAgentChatRequest`, `AiAgentSummary`, `AiAgentsResponse`, `AiChatRequest`, `AiChatResponse`, `AiCompleteRequest`, `AiConversation`, `AiMessage`, `AiModelsResponse`, `AiPendingAction`, `AiPendingActionStatus`, `AiStreamChunk`, `ApproveAiPendingActionResponse`, `AuditMetaItemRequest`, `AuditMetaItemResponse`, `AutomationActionsResponse`, `AutomationTriggerRequest`, `AutomationTriggerResponse`, `BatchDataRequest`, `BatchDataResponse`, `CheckPermissionRequest`, `CheckPermissionResponse`, `CloneDataResponse`, `CreateAiConversationRequest`, `CreateDataRequest`, `CreateDataResponse`, `CreateManyDataRequest`, `CreateManyDataResponse`, `DeleteDataRequest`, `DeleteDataResponse`, `DeleteManyDataRequest`, `DeleteManyDataResponse`, `DeleteMetaItemRequest`, `DeleteMetaItemResponse`, `DiffMetaItemResponse`, `DisablePackageRequest`, `DisablePackageResponse`, `EnablePackageRequest`, `EnablePackageResponse`, `FindDataRequest`, `FindDataResponse`, `FindReferencesToMetaResponse`, `GetDataRequest`, `GetDataResponse`, `GetDiscoveryRequest`, `GetDiscoveryResponse`, `GetEffectivePermissionsRequest`, `GetEffectivePermissionsResponse`, `GetFieldLabelsRequest`, `GetFieldLabelsResponse`, `GetLocalesRequest`, `GetLocalesResponse`, `GetMetaDiagnosticsResponse`, `GetMetaItemCachedRequest`, `GetMetaItemCachedResponse`, `GetMetaItemLayeredRequest`, `GetMetaItemLayeredResponse`, `GetMetaItemRequest`, `GetMetaItemResponse`, `GetMetaItemsRequest`, `GetMetaItemsResponse`, `GetMetaTypesRequest`, `GetMetaTypesResponse`, `GetNotificationPreferencesRequest`, `GetNotificationPreferencesResponse`, `GetObjectPermissionsRequest`, `GetObjectPermissionsResponse`, `GetPackageRequest`, `GetPackageResponse`, `GetPresenceRequest`, `GetPresenceResponse`, `GetPublishedMetaItemResponse`, `GetTranslationsRequest`, `GetTranslationsResponse`, `GetUiViewRequest`, `GetUiViewResponse`, `HttpFindQueryParams`, `InstallPackageRequest`, `InstallPackageResponse`, `ListAiConversationsRequest`, `ListAiConversationsResponse`, `ListAiPendingActionsRequest`, `ListAiPendingActionsResponse`, `ListDraftsResponse`, `ListNotificationsRequest`, `ListNotificationsResponse`, `ListPackagesRequest`, `ListPackagesResponse`, `MarkAllNotificationsReadRequest`, `MarkAllNotificationsReadResponse`, `MarkNotificationsReadRequest`, `MarkNotificationsReadResponse`, `Notification`, `NotificationPreferences`, `PublishMetaItemRequest`, `PublishMetaItemResponse`, `PublishPackageDraftsResponse`, `RealtimeConnectRequest`, `RealtimeConnectResponse`, `RealtimeDisconnectRequest`, `RealtimeDisconnectResponse`, `RealtimeSubscribeRequest`, `RealtimeSubscribeResponse`, `RealtimeUnsubscribeRequest`, `RealtimeUnsubscribeResponse`, `RegisterDeviceRequest`, `RegisterDeviceResponse`, `RejectAiPendingActionResponse`, `RollbackMetaItemResponse`, `RuntimeAuthoringIssue`, `SaveMetaItemRequest`, `SaveMetaItemResponse`, `SearchAllHit`, `SearchAllResponse`, `SetPresenceRequest`, `SetPresenceResponse`, `UninstallPackageRequest`, `UninstallPackageResponse`, `UnregisterDeviceRequest`, `UnregisterDeviceResponse`, `UpdateAiConversationRequest`, `UpdateDataRequest`, `UpdateDataResponse`, `UpdateManyDataRequest`, `UpdateManyDataResponse`, `UpdateNotificationPreferencesRequest`, `UpdateNotificationPreferencesResponse`, `ValidateDataIssue`, `ValidateDataRequest`, `ValidateDataResponse` | | [`query-adapter.zod.ts`](/docs/references/api/query-adapter) | `ODataQueryAdapter`, `OperatorMapping`, `QueryAdapterConfig`, `QueryAdapterTarget`, `RestQueryAdapter` | | [`realtime.zod.ts`](/docs/references/api/realtime) | `RealtimeConfig`, `RealtimeEvent`, `RealtimeEventType`, `RealtimePresence`, `Subscription`, `SubscriptionEvent`, `TransportProtocol` | | [`realtime-shared.zod.ts`](/docs/references/api/realtime-shared) | `BasePresence`, `PresenceStatus`, `RealtimeRecordAction` | @@ -318,7 +320,7 @@ Studio designer metadata — the authoring surfaces for the protocols above. ## System Protocol -**Source:** `packages/spec/src/system/` · **Import:** `@objectstack/spec/system` · **36 pages, 288 schemas** +**Source:** `packages/spec/src/system/` · **Import:** `@objectstack/spec/system` · **36 pages, 291 schemas** The runtime environment — logging, jobs, cache, metrics, notifications, i18n and compliance. @@ -326,7 +328,7 @@ The runtime environment — logging, jobs, cache, metrics, notifications, i18n a | :--- | :--- | | [`app-install.zod.ts`](/docs/references/system/app-install) | `AppCompatibilityCheck`, `AppInstallRequest`, `AppInstallResult`, `AppManifest` | | [`auth-config.zod.ts`](/docs/references/system/auth-config) | `AdvancedAuthConfig`, `AudienceConfig`, `AuthConfig`, `AuthPluginConfig`, `AuthProviderConfig`, `EmailAndPasswordConfig`, `EmailVerificationConfig`, `MutualTLSConfig`, `OidcProviderConfig`, `OidcProvidersConfig`, `SocialProviderConfig` | -| [`book.zod.ts`](/docs/references/system/book) | `Book`, `BookAudience`, `BookGroup`, `BookInclude`, `BookNode` | +| [`book.zod.ts`](/docs/references/system/book) | `Book`, `BookAudience`, `BookGroup`, `BookInclude`, `BookNode`, `ResolvedBook`, `ResolvedEntry`, `ResolvedGroup` | | [`cache.zod.ts`](/docs/references/system/cache) | `CacheAvalanchePrevention`, `CacheConfig`, `CacheConsistency`, `CacheInvalidation`, `CacheStrategy`, `CacheTier`, `CacheWarmup`, `DistributedCacheConfig` | | [`change-management.zod.ts`](/docs/references/system/change-management) | `ChangeImpact`, `ChangePriority`, `ChangeRequest`, `ChangeStatus`, `ChangeType`, `RollbackPlan` | | [`collaboration.zod.ts`](/docs/references/system/collaboration) | `AwarenessEvent`, `AwarenessSession`, `AwarenessUpdate`, `AwarenessUserState`, `CRDTMergeResult`, `CRDTState`, `CRDTType`, `CollaborationMode`, `CollaborationSession`, `CollaborationSessionConfig`, `CollaborativeCursor`, `CounterOperation`, `CursorColorPreset`, `CursorSelection`, `CursorStyle`, `CursorUpdate`, `GCounter`, `LWWRegister`, `ORSet`, `ORSetElement`, `OTComponent`, `OTOperation`, `OTOperationType`, `OTTransformResult`, `PNCounter`, `TextCRDTOperation`, `TextCRDTState`, `UserActivityStatus`, `VectorClock` | diff --git a/docs/audits/2026-07-unknown-key-strictness-ledger.counts.md b/docs/audits/2026-07-unknown-key-strictness-ledger.counts.md index 43b7b6d702..9cd7a480d2 100644 --- a/docs/audits/2026-07-unknown-key-strictness-ledger.counts.md +++ b/docs/audits/2026-07-unknown-key-strictness-ledger.counts.md @@ -257,11 +257,11 @@ directory rather than per file. | Dir | Sites | |---|---| | `ai/` | 77 | -| `api/` | 416 | +| `api/` | 444 | | `cloud/` | 83 | | `identity/` | 32 | | `integration/` | 10 | | `kernel/` | 271 | | `qa/` | 6 | | `shared/` | 20 | -| `system/` | 361 | +| `system/` | 364 |