diff --git a/.changeset/dev-plugin-protocol-family-removed.md b/.changeset/dev-plugin-protocol-family-removed.md
new file mode 100644
index 0000000000..46a431ec27
--- /dev/null
+++ b/.changeset/dev-plugin-protocol-family-removed.md
@@ -0,0 +1,42 @@
+---
+"@objectstack/spec": major
+---
+
+refactor(spec)!: remove the Dev Mode Plugin Protocol family — a declared dev protocol nothing implemented, whose stub vocabulary described the design ADR-0115 retired (#4149)
+
+`DevPluginConfigSchema`, `DevServiceOverrideSchema`, `DevFixtureConfigSchema`,
+`DevToolsConfigSchema` and `DevPluginPreset` (`@objectstack/spec/kernel`,
+dev-plugin.zod) are removed outright. The family declared a full dev-mode
+configuration protocol — presets (minimal/standard/full), fixture loading, a
+dev-tools dashboard on port 4400, per-service `mock`/`memory`/`stub`/
+`passthrough` strategies, simulated latency — and none of it ever existed:
+
+- **Zero consumers.** `@objectstack/plugin-dev` reads its own
+ `DevPluginOptions` interface and never imported these schemas; no other
+ package did either. The only references were the generated artifacts and the
+ family's own shape test.
+- **No load path parsed it.** `stack.devPlugins` takes
+ `ManifestSchema | string` (plugin manifests/names), not this config — so no
+ authored source can carry these keys, which is why there is deliberately NO
+ `retiredKey()` tombstone and NO ADR-0087 conversion: a prescription nobody
+ can receive is noise, and there is no source for `os migrate meta` to
+ rewrite (the `plugin-runtime.zod.ts` DynamicLoadingConfig precedent, #3950).
+- **Its vocabulary contradicted the platform.** `strategy: 'stub'` taught the
+ fill-the-slot-with-a-fake design that ADR-0115 retired; keeping the schema
+ meant the spec recommending what the runtime forbids.
+
+FROM → TO: if you imported any of the five types from
+`@objectstack/spec/kernel`, delete the import — there is nothing to migrate to,
+because nothing ever consumed the values. To configure local development, use
+`DevPluginOptions` from `@objectstack/plugin-dev` (port, seedAdminUser,
+authSecret, per-part `services` toggles, extraPlugins, stack).
+
+The retirement kit: baselines dropped deliberately (`json-schema.manifest.json`
+minus the five `kernel/Dev*` entries; `authorable-surface.json` minus the 22
+`kernel/Dev*` lines — nothing can author them, so no `[RETIRED]` markers);
+`api-surface.json` regenerated (the five exports leave the public surface);
+generated reference doc removed by `gen:docs`; v17 release notes' dead-clusters
+table extended. No liveness-ledger entries existed (the ledger tracks metadata
+types; this was never one).
+
+No runtime behaviour changes — that impossibility is the reason for the removal.
diff --git a/content/docs/references/kernel/dev-plugin.mdx b/content/docs/references/kernel/dev-plugin.mdx
deleted file mode 100644
index f523f7056f..0000000000
--- a/content/docs/references/kernel/dev-plugin.mdx
+++ /dev/null
@@ -1,130 +0,0 @@
----
-title: Dev Plugin
-description: Dev Plugin protocol schemas
----
-
-{/* ⚠️ AUTO-GENERATED — DO NOT EDIT. Run build-docs.ts to regenerate. Hand-written docs live in the module folders under content/docs/. */}
-
-# Dev Mode Plugin Protocol
-
-Declared configuration vocabulary for a development-mode plugin: per-service
-
-dev strategies, fixture loading, developer tooling, presets.
-
-⚠️ **Declared, not implemented — pending enforce-or-remove (#4149).**
-
-The shipped `@objectstack/plugin-dev` consumes its own `DevPluginOptions`
-
-interface, NOT this schema, and none of the surfaces below (presets,
-
-fixtures, dev-tools dashboard, per-service strategies, simulated latency)
-
-exist in it. Since ADR-0115 it is an **assembly** plugin: it wires the real
-
-platform plugins for local development and registers no stub or simulated
-
-services — an unfilled slot answers exactly as it does in production. The
-
-`strategy: 'stub'` value in particular describes a behaviour the platform
-
-has retired. Do not build against this file until #4149 resolves it.
-
-Original design goals, kept for the #4149 evaluation:
-
-- Zero-config by default: `devPlugins: ['@objectstack/plugin-dev']`
-
-- Every service can be overridden or disabled individually
-
-- Preset profiles (minimal / standard / full) for common scenarios
-
-
-**Source:** `packages/spec/src/kernel/dev-plugin.zod.ts`
-
-
-## TypeScript Usage
-
-```typescript
-import { DevFixtureConfig, DevPluginConfig, DevPluginPreset, DevServiceOverride, DevToolsConfig } from '@objectstack/spec/kernel';
-import type { DevFixtureConfig, DevPluginConfig, DevPluginPreset, DevServiceOverride, DevToolsConfig } from '@objectstack/spec/kernel';
-
-// Validate data
-const result = DevFixtureConfig.parse(data);
-```
-
----
-
-## DevFixtureConfig
-
-### Properties
-
-| Property | Type | Required | Description |
-| :--- | :--- | :--- | :--- |
-| **enabled** | `boolean` | ✅ | Load fixture data on startup |
-| **paths** | `string[]` | optional | Glob patterns for fixture files |
-| **resetBeforeLoad** | `boolean` | ✅ | Clear existing data before loading fixtures |
-| **envFilter** | `string[]` | optional | Only load fixtures matching these environment tags |
-
-
----
-
-## DevPluginConfig
-
-### Properties
-
-| Property | Type | Required | Description |
-| :--- | :--- | :--- | :--- |
-| **preset** | `Enum<'minimal' \| 'standard' \| 'full'>` | ✅ | Base configuration preset |
-| **services** | `Record; config?: Record }>` | optional | Per-service dev overrides keyed by service name |
-| **fixtures** | `{ enabled: boolean; paths?: string[]; resetBeforeLoad: boolean; envFilter?: string[] }` | optional | Fixture data loading configuration |
-| **tools** | `{ hotReload: boolean; requestInspector: boolean; dbExplorer: boolean; verboseLogging: boolean; … }` | optional | Developer tooling settings |
-| **port** | `integer` | ✅ | Port for the dev-tools dashboard |
-| **open** | `boolean` | ✅ | Auto-open dev dashboard in browser |
-| **seedAdminUser** | `boolean` | ✅ | Create a default admin user for development |
-| **simulatedLatency** | `integer` | ✅ | Artificial latency (ms) added to service calls |
-
-
----
-
-## DevPluginPreset
-
-Predefined dev configuration profile
-
-### Allowed Values
-
-* `minimal`
-* `standard`
-* `full`
-
-
----
-
-## DevServiceOverride
-
-### Properties
-
-| Property | Type | Required | Description |
-| :--- | :--- | :--- | :--- |
-| **service** | `string` | ✅ | Target service identifier |
-| **enabled** | `boolean` | ✅ | Enable or disable this service |
-| **strategy** | `Enum<'mock' \| 'memory' \| 'stub' \| 'passthrough'>` | ✅ | Implementation strategy for development |
-| **config** | `Record` | optional | Strategy-specific configuration for this service override |
-
-
----
-
-## DevToolsConfig
-
-### Properties
-
-| Property | Type | Required | Description |
-| :--- | :--- | :--- | :--- |
-| **hotReload** | `boolean` | ✅ | Enable HMR / live-reload |
-| **requestInspector** | `boolean` | ✅ | Enable request inspector |
-| **dbExplorer** | `boolean` | ✅ | Enable database explorer UI |
-| **verboseLogging** | `boolean` | ✅ | Enable verbose logging |
-| **apiDocs** | `boolean` | ✅ | Serve OpenAPI docs at /_dev/docs |
-| **mailCatcher** | `boolean` | ✅ | Capture outbound emails in dev |
-
-
----
-
diff --git a/content/docs/references/kernel/index.mdx b/content/docs/references/kernel/index.mdx
index d0576bd6d2..a969832035 100644
--- a/content/docs/references/kernel/index.mdx
+++ b/content/docs/references/kernel/index.mdx
@@ -10,7 +10,6 @@ This section contains all protocol schemas for the kernel layer of ObjectStack.
-
diff --git a/content/docs/references/kernel/meta.json b/content/docs/references/kernel/meta.json
index 89f77f1f99..0fd274d631 100644
--- a/content/docs/references/kernel/meta.json
+++ b/content/docs/references/kernel/meta.json
@@ -25,7 +25,6 @@
"cli-extension",
"cluster",
"context",
- "dev-plugin",
"execution-context",
"metadata-customization",
"metadata-loader",
diff --git a/content/docs/releases/v17.mdx b/content/docs/releases/v17.mdx
index e3abaca579..00023347fd 100644
--- a/content/docs/releases/v17.mdx
+++ b/content/docs/releases/v17.mdx
@@ -806,6 +806,7 @@ import or the authored key.
| `AuditConfig` cluster (`@objectstack/spec/system`) | dead since #1878 |
| Capabilities-descriptor cluster (`ObjectQL`/`ObjectUI`/`Kernel`/`ObjectStack`/`ObjectOS CapabilitiesSchema`) | static snapshots superseded by runtime discovery |
| `FeatureFlagSchema` (`kernel` feature.zod) | orphaned module |
+| `DevPluginConfigSchema` cluster (`kernel` dev-plugin.zod — `DevServiceOverride` / `DevFixtureConfig` / `DevToolsConfig` / `DevPluginPreset`) | a declared dev-mode protocol (presets, fixtures, dev-tools dashboard, per-service mock/stub strategies, simulated latency) nothing implemented and no load path parsed — `@objectstack/plugin-dev` reads its own `DevPluginOptions`, and the `strategy: 'stub'` vocabulary described the dev-stub design ADR-0115 retired (#4149) |
| `SkillSchema.permissions` | never gated anything (#3686) |
| `tool.requiresConfirmation` | a safety flag nothing enforced (#3715) |
| `object.enable.trash` / `enable.mru` | ADR-0049 enforce-or-remove close-out (#2377) |
diff --git a/packages/spec/api-surface.json b/packages/spec/api-surface.json
index 06a14958a8..f97400ee67 100644
--- a/packages/spec/api-surface.json
+++ b/packages/spec/api-surface.json
@@ -1405,16 +1405,6 @@
"DependencyStatusEnum (const)",
"DeprecationNotice (type)",
"DeprecationNoticeSchema (const)",
- "DevFixtureConfig (type)",
- "DevFixtureConfigSchema (const)",
- "DevPluginConfig (type)",
- "DevPluginConfigInput (type)",
- "DevPluginConfigSchema (const)",
- "DevPluginPreset (type)",
- "DevServiceOverride (type)",
- "DevServiceOverrideSchema (const)",
- "DevToolsConfig (type)",
- "DevToolsConfigSchema (const)",
"DisablePackageRequest (type)",
"DisablePackageRequestSchema (const)",
"DisablePackageResponse (type)",
diff --git a/packages/spec/authorable-surface.json b/packages/spec/authorable-surface.json
index 0477710954..12dd1b800b 100644
--- a/packages/spec/authorable-surface.json
+++ b/packages/spec/authorable-surface.json
@@ -1,5 +1,5 @@
{
- "description": "Ratchet of every AUTHORABLE key in the spec — what a metadata author may write, which for this platform IS the third-party API. Auto-updated on additions (commit the change). A key that disappears without a tombstone fails gen:schema, because these schemas are not .strict() and Zod would silently strip it. \"[RETIRED]\" marks a tombstoned key that still rejects with an upgrade prescription. See #3855, ADR-0059 §5.",
+ "description": "Ratchet of every AUTHORABLE key in the spec \u2014 what a metadata author may write, which for this platform IS the third-party API. Auto-updated on additions (commit the change). A key that disappears without a tombstone fails gen:schema, because these schemas are not .strict() and Zod would silently strip it. \"[RETIRED]\" marks a tombstoned key that still rejects with an upgrade prescription. See #3855, ADR-0059 \u00a75.",
"keys": [
"ai/AIModelConfig:maxTokens",
"ai/AIModelConfig:model",
@@ -4598,28 +4598,6 @@
"kernel/DeprecationNotice:migrationPath",
"kernel/DeprecationNotice:reason",
"kernel/DeprecationNotice:removeIn",
- "kernel/DevFixtureConfig:enabled",
- "kernel/DevFixtureConfig:envFilter",
- "kernel/DevFixtureConfig:paths",
- "kernel/DevFixtureConfig:resetBeforeLoad",
- "kernel/DevPluginConfig:fixtures",
- "kernel/DevPluginConfig:open",
- "kernel/DevPluginConfig:port",
- "kernel/DevPluginConfig:preset",
- "kernel/DevPluginConfig:seedAdminUser",
- "kernel/DevPluginConfig:services",
- "kernel/DevPluginConfig:simulatedLatency",
- "kernel/DevPluginConfig:tools",
- "kernel/DevServiceOverride:config",
- "kernel/DevServiceOverride:enabled",
- "kernel/DevServiceOverride:service",
- "kernel/DevServiceOverride:strategy",
- "kernel/DevToolsConfig:apiDocs",
- "kernel/DevToolsConfig:dbExplorer",
- "kernel/DevToolsConfig:hotReload",
- "kernel/DevToolsConfig:mailCatcher",
- "kernel/DevToolsConfig:requestInspector",
- "kernel/DevToolsConfig:verboseLogging",
"kernel/DisablePackageRequest:id",
"kernel/DisablePackageResponse:message",
"kernel/DisablePackageResponse:package",
diff --git a/packages/spec/json-schema.manifest.json b/packages/spec/json-schema.manifest.json
index 5893376d74..ede9396721 100644
--- a/packages/spec/json-schema.manifest.json
+++ b/packages/spec/json-schema.manifest.json
@@ -1,5 +1,5 @@
{
- "description": "Ratchet manifest of every JSON Schema emitted by scripts/build-schemas.ts. Auto-appended when new schemas are added (commit the change). A listed schema that a build no longer emits fails gen:schema — remove a key ONLY for a deliberate retirement. See #2978.",
+ "description": "Ratchet manifest of every JSON Schema emitted by scripts/build-schemas.ts. Auto-appended when new schemas are added (commit the change). A listed schema that a build no longer emits fails gen:schema \u2014 remove a key ONLY for a deliberate retirement. See #2978.",
"schemas": [
"ai/AIModelConfig",
"ai/AIUsageRecord",
@@ -957,11 +957,6 @@
"kernel/DependencyResolutionResult",
"kernel/DependencyStatusEnum",
"kernel/DeprecationNotice",
- "kernel/DevFixtureConfig",
- "kernel/DevPluginConfig",
- "kernel/DevPluginPreset",
- "kernel/DevServiceOverride",
- "kernel/DevToolsConfig",
"kernel/DisablePackageRequest",
"kernel/DisablePackageResponse",
"kernel/DistributedStateConfig",
diff --git a/packages/spec/src/kernel/dev-plugin.test.ts b/packages/spec/src/kernel/dev-plugin.test.ts
deleted file mode 100644
index eb861cf4f7..0000000000
--- a/packages/spec/src/kernel/dev-plugin.test.ts
+++ /dev/null
@@ -1,234 +0,0 @@
-import { describe, it, expect } from 'vitest';
-import {
- DevServiceOverrideSchema,
- DevFixtureConfigSchema,
- DevToolsConfigSchema,
- DevPluginPreset,
- DevPluginConfigSchema,
-} from './dev-plugin.zod';
-
-describe('Dev Mode Plugin Protocol', () => {
- // ==========================================================================
- // DevServiceOverrideSchema
- // ==========================================================================
- describe('DevServiceOverrideSchema', () => {
- it('should validate minimal service override', () => {
- const result = DevServiceOverrideSchema.safeParse({ service: 'auth' });
- expect(result.success).toBe(true);
- if (result.success) {
- expect(result.data.enabled).toBe(true);
- expect(result.data.strategy).toBe('memory');
- }
- });
-
- it('should validate full service override', () => {
- const override = {
- service: 'eventBus',
- enabled: true,
- strategy: 'mock' as const,
- config: { recordCalls: true },
- };
-
- const result = DevServiceOverrideSchema.safeParse(override);
- expect(result.success).toBe(true);
- if (result.success) {
- expect(result.data.strategy).toBe('mock');
- expect(result.data.config?.recordCalls).toBe(true);
- }
- });
-
- it('should accept all strategy values', () => {
- const strategies = ['mock', 'memory', 'stub', 'passthrough'] as const;
- for (const strategy of strategies) {
- const result = DevServiceOverrideSchema.safeParse({ service: 'svc', strategy });
- expect(result.success).toBe(true);
- }
- });
-
- it('should reject empty service name', () => {
- const result = DevServiceOverrideSchema.safeParse({ service: '' });
- expect(result.success).toBe(false);
- });
-
- it('should reject invalid strategy', () => {
- const result = DevServiceOverrideSchema.safeParse({
- service: 'auth',
- strategy: 'invalid',
- });
- expect(result.success).toBe(false);
- });
- });
-
- // ==========================================================================
- // DevFixtureConfigSchema
- // ==========================================================================
- describe('DevFixtureConfigSchema', () => {
- it('should apply default values', () => {
- const result = DevFixtureConfigSchema.parse({});
- expect(result.enabled).toBe(true);
- expect(result.resetBeforeLoad).toBe(true);
- });
-
- it('should validate full fixture config', () => {
- const config = {
- enabled: true,
- paths: ['./fixtures/*.json', './test/data/*.yml'],
- resetBeforeLoad: false,
- envFilter: ['dev', 'demo'],
- };
-
- const result = DevFixtureConfigSchema.safeParse(config);
- expect(result.success).toBe(true);
- if (result.success) {
- expect(result.data.paths).toHaveLength(2);
- expect(result.data.envFilter).toEqual(['dev', 'demo']);
- }
- });
-
- it('should allow disabled fixtures', () => {
- const result = DevFixtureConfigSchema.parse({ enabled: false });
- expect(result.enabled).toBe(false);
- });
- });
-
- // ==========================================================================
- // DevToolsConfigSchema
- // ==========================================================================
- describe('DevToolsConfigSchema', () => {
- it('should apply default values', () => {
- const result = DevToolsConfigSchema.parse({});
- expect(result.hotReload).toBe(true);
- expect(result.requestInspector).toBe(false);
- expect(result.dbExplorer).toBe(false);
- expect(result.verboseLogging).toBe(true);
- expect(result.apiDocs).toBe(true);
- expect(result.mailCatcher).toBe(false);
- });
-
- it('should accept all tools enabled', () => {
- const config = {
- hotReload: true,
- requestInspector: true,
- dbExplorer: true,
- verboseLogging: true,
- apiDocs: true,
- mailCatcher: true,
- };
-
- const result = DevToolsConfigSchema.safeParse(config);
- expect(result.success).toBe(true);
- if (result.success) {
- expect(result.data.mailCatcher).toBe(true);
- expect(result.data.dbExplorer).toBe(true);
- }
- });
- });
-
- // ==========================================================================
- // DevPluginPreset
- // ==========================================================================
- describe('DevPluginPreset', () => {
- it('should validate preset values', () => {
- expect(DevPluginPreset.safeParse('minimal').success).toBe(true);
- expect(DevPluginPreset.safeParse('standard').success).toBe(true);
- expect(DevPluginPreset.safeParse('full').success).toBe(true);
- });
-
- it('should reject invalid preset', () => {
- expect(DevPluginPreset.safeParse('custom').success).toBe(false);
- });
- });
-
- // ==========================================================================
- // DevPluginConfigSchema
- // ==========================================================================
- describe('DevPluginConfigSchema', () => {
- it('should accept zero-config (empty object)', () => {
- const result = DevPluginConfigSchema.parse({});
- expect(result.preset).toBe('standard');
- expect(result.port).toBe(4400);
- expect(result.open).toBe(false);
- expect(result.seedAdminUser).toBe(true);
- expect(result.simulatedLatency).toBe(0);
- });
-
- it('should accept preset-only config', () => {
- const result = DevPluginConfigSchema.parse({ preset: 'full' });
- expect(result.preset).toBe('full');
- });
-
- it('should accept config with per-service overrides', () => {
- const config = {
- preset: 'standard' as const,
- services: {
- auth: { enabled: true, strategy: 'mock' as const },
- fileStorage: { enabled: false },
- },
- };
-
- const result = DevPluginConfigSchema.safeParse(config);
- expect(result.success).toBe(true);
- if (result.success) {
- expect(result.data.services?.auth.enabled).toBe(true);
- expect(result.data.services?.auth.strategy).toBe('mock');
- expect(result.data.services?.fileStorage.enabled).toBe(false);
- }
- });
-
- it('should accept full configuration', () => {
- const config = {
- preset: 'full' as const,
- services: {
- auth: { enabled: true, strategy: 'mock' as const },
- eventBus: { enabled: true, strategy: 'memory' as const },
- fileStorage: { enabled: false },
- },
- fixtures: {
- enabled: true,
- paths: ['./fixtures/*.json'],
- resetBeforeLoad: true,
- },
- tools: {
- hotReload: true,
- dbExplorer: true,
- apiDocs: true,
- },
- port: 5500,
- open: true,
- seedAdminUser: true,
- simulatedLatency: 200,
- };
-
- const result = DevPluginConfigSchema.safeParse(config);
- expect(result.success).toBe(true);
- if (result.success) {
- expect(result.data.port).toBe(5500);
- expect(result.data.open).toBe(true);
- expect(result.data.simulatedLatency).toBe(200);
- expect(result.data.fixtures?.paths).toEqual(['./fixtures/*.json']);
- }
- });
-
- it('should reject invalid port', () => {
- expect(
- DevPluginConfigSchema.safeParse({ port: 0 }).success,
- ).toBe(false);
- expect(
- DevPluginConfigSchema.safeParse({ port: 99999 }).success,
- ).toBe(false);
- });
-
- it('should reject negative simulated latency', () => {
- expect(
- DevPluginConfigSchema.safeParse({ simulatedLatency: -10 }).success,
- ).toBe(false);
- });
-
- it('should reject empty string as service key', () => {
- const result = DevPluginConfigSchema.safeParse({
- services: { '': { enabled: true } },
- });
- expect(result.success).toBe(false);
- });
- });
-});
diff --git a/packages/spec/src/kernel/dev-plugin.zod.ts b/packages/spec/src/kernel/dev-plugin.zod.ts
deleted file mode 100644
index 196f99c499..0000000000
--- a/packages/spec/src/kernel/dev-plugin.zod.ts
+++ /dev/null
@@ -1,250 +0,0 @@
-// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.
-
-import { z } from 'zod';
-
-/**
- * # Dev Mode Plugin Protocol
- *
- * Declared configuration vocabulary for a development-mode plugin: per-service
- * dev strategies, fixture loading, developer tooling, presets.
- *
- * ⚠️ **Declared, not implemented — pending enforce-or-remove (#4149).**
- * The shipped `@objectstack/plugin-dev` consumes its own `DevPluginOptions`
- * interface, NOT this schema, and none of the surfaces below (presets,
- * fixtures, dev-tools dashboard, per-service strategies, simulated latency)
- * exist in it. Since ADR-0115 it is an **assembly** plugin: it wires the real
- * platform plugins for local development and registers no stub or simulated
- * services — an unfilled slot answers exactly as it does in production. The
- * `strategy: 'stub'` value in particular describes a behaviour the platform
- * has retired. Do not build against this file until #4149 resolves it.
- *
- * Original design goals, kept for the #4149 evaluation:
- * - Zero-config by default: `devPlugins: ['@objectstack/plugin-dev']`
- * - Every service can be overridden or disabled individually
- * - Preset profiles (minimal / standard / full) for common scenarios
- */
-
-// ============================================================================
-// Dev Service Override
-// ============================================================================
-
-/**
- * Dev Service Override Schema
- *
- * Allows fine-grained control over a single service in development mode.
- * Each override targets a service by name and specifies whether it should
- * be enabled, which implementation strategy to use, and optional config.
- */
-import { lazySchema } from '../shared/lazy-schema';
-export const DevServiceOverrideSchema = lazySchema(() => z.object({
- /** Service identifier (e.g. 'auth', 'eventBus', 'fileStorage') */
- service: z.string().min(1).describe('Target service identifier'),
-
- /** Whether this service is enabled in dev mode */
- enabled: z.boolean().default(true).describe('Enable or disable this service'),
-
- /**
- * Implementation strategy for the service in dev mode.
- * - mock: Use a mock/stub that records calls (for assertions)
- * - memory: Use a real but in-memory implementation (e.g. SQLite, Map)
- * - stub: Use a static/no-op implementation
- * - passthrough: Use the real production implementation (for integration testing)
- */
- strategy: z.enum(['mock', 'memory', 'stub', 'passthrough']).default('memory')
- .describe('Implementation strategy for development'),
-
- /** Optional per-service configuration (strategy-specific) */
- config: z.record(z.string(), z.unknown()).optional()
- .describe('Strategy-specific configuration for this service override'),
-}));
-
-export type DevServiceOverride = z.infer;
-
-// ============================================================================
-// Dev Fixture Configuration
-// ============================================================================
-
-/**
- * Dev Fixture Config Schema
- *
- * Configures automatic seed/fixture data loading in development mode.
- * Fixtures provide a reproducible dataset for local development and demos.
- */
-export const DevFixtureConfigSchema = lazySchema(() => z.object({
- /** Whether to load fixtures on startup */
- enabled: z.boolean().default(true).describe('Load fixture data on startup'),
-
- /**
- * Glob patterns pointing to fixture files
- * (e.g. `["./fixtures/*.json", "./test/data/*.yml"]`)
- */
- paths: z.array(z.string()).optional()
- .describe('Glob patterns for fixture files'),
-
- /** Whether to reset data before loading fixtures */
- resetBeforeLoad: z.boolean().default(true)
- .describe('Clear existing data before loading fixtures'),
-
- /**
- * Environment tag filter – only load fixtures tagged for these environments.
- * When omitted, all fixtures are loaded.
- */
- envFilter: z.array(z.string()).optional()
- .describe('Only load fixtures matching these environment tags'),
-}));
-
-export type DevFixtureConfig = z.infer;
-
-// ============================================================================
-// Dev Tools Configuration
-// ============================================================================
-
-/**
- * Dev Tools Config Schema
- *
- * Optional developer tooling that can be enabled alongside the dev plugin.
- */
-export const DevToolsConfigSchema = lazySchema(() => z.object({
- /** Enable hot-module replacement / live reload */
- hotReload: z.boolean().default(true).describe('Enable HMR / live-reload'),
-
- /** Enable request inspector UI for debugging HTTP traffic */
- requestInspector: z.boolean().default(false).describe('Enable request inspector'),
-
- /** Enable an in-browser database explorer */
- dbExplorer: z.boolean().default(false).describe('Enable database explorer UI'),
-
- /** Enable verbose logging across all services */
- verboseLogging: z.boolean().default(true).describe('Enable verbose logging'),
-
- /** Enable OpenAPI / Swagger documentation endpoint */
- apiDocs: z.boolean().default(true).describe('Serve OpenAPI docs at /_dev/docs'),
-
- /** Enable a mail catcher for outbound email (like MailHog) */
- mailCatcher: z.boolean().default(false).describe('Capture outbound emails in dev'),
-}));
-
-export type DevToolsConfig = z.infer;
-
-// ============================================================================
-// Dev Plugin Preset
-// ============================================================================
-
-/**
- * Dev Plugin Preset
- *
- * Predefined configuration profiles for common development scenarios.
- * - minimal: Only core data services (fast startup, low memory)
- * - standard: Core + API + auth + events (typical full-stack dev)
- * - full: Every service enabled, including background jobs and AI agents
- */
-export const DevPluginPreset = z.enum([
- 'minimal',
- 'standard',
- 'full',
-]).describe('Predefined dev configuration profile');
-
-export type DevPluginPreset = z.infer;
-
-// ============================================================================
-// Dev Plugin Configuration
-// ============================================================================
-
-/**
- * Dev Plugin Config Schema
- *
- * Top-level configuration for the development-mode plugin.
- * This is the shape of the configuration payload that
- * `@objectstack/plugin-dev` (or equivalent) understands.
- *
- * The outer wiring (e.g. how a stack declares `devPlugins`) is defined
- * by the stack/manifest schemas; this type only describes the plugin's
- * own config object.
- *
- * @example Minimal usage (zero-config)
- * ```ts
- * const devConfig: DevPluginConfig = {};
- * ```
- *
- * @example With preset
- * ```ts
- * const devConfig: DevPluginConfig = {
- * preset: 'full',
- * };
- * ```
- *
- * @example Fine-grained overrides
- * ```ts
- * const devConfig: DevPluginConfig = {
- * preset: 'standard',
- * services: {
- * auth: { enabled: true, strategy: 'mock' },
- * fileStorage: { enabled: false },
- * },
- * fixtures: { paths: ['./fixtures/*.json'] },
- * tools: { dbExplorer: true },
- * };
- * ```
- */
-export const DevPluginConfigSchema = lazySchema(() => z.object({
- /**
- * Configuration preset.
- * When provided, services and tools are pre-configured for the selected
- * profile. Individual `services` and `tools` settings override the preset.
- * @default 'standard'
- */
- preset: DevPluginPreset.default('standard')
- .describe('Base configuration preset'),
-
- /**
- * Per-service overrides.
- * Keys are service names; values configure the dev strategy.
- * Only services explicitly listed here override the preset defaults.
- */
- services: z.record(
- z.string().min(1),
- DevServiceOverrideSchema.omit({ service: true }),
- ).optional().describe('Per-service dev overrides keyed by service name'),
-
- /** Fixture / seed data configuration */
- fixtures: DevFixtureConfigSchema.optional()
- .describe('Fixture data loading configuration'),
-
- /** Developer tooling configuration */
- tools: DevToolsConfigSchema.optional()
- .describe('Developer tooling settings'),
-
- /**
- * Port for the dev-tools UI dashboard.
- * Serves a lightweight web dashboard for inspecting services, events,
- * and request logs during development.
- * @default 4400
- */
- port: z.number().int().min(1).max(65535).default(4400)
- .describe('Port for the dev-tools dashboard'),
-
- /**
- * Auto-open the dev-tools dashboard in the default browser on startup.
- */
- open: z.boolean().default(false)
- .describe('Auto-open dev dashboard in browser'),
-
- /**
- * Seed a default admin user for development.
- * When enabled, the dev plugin creates a pre-authenticated admin user
- * so that developers can bypass login flows.
- */
- seedAdminUser: z.boolean().default(true)
- .describe('Create a default admin user for development'),
-
- /**
- * Simulated latency (ms) to add to service calls.
- * Helps developers build UIs that handle loading states correctly.
- * Set to 0 to disable.
- */
- simulatedLatency: z.number().int().min(0).default(0)
- .describe('Artificial latency (ms) added to service calls'),
-}));
-
-export type DevPluginConfig = z.infer;
-export type DevPluginConfigInput = z.input;
diff --git a/packages/spec/src/kernel/index.ts b/packages/spec/src/kernel/index.ts
index 9eb70a630b..b5bc8eb401 100644
--- a/packages/spec/src/kernel/index.ts
+++ b/packages/spec/src/kernel/index.ts
@@ -4,7 +4,15 @@ export * from './cli-extension.zod';
export * from './cluster.zod';
export * from './context.zod';
export * from './dependency-resolution.zod';
-export * from './dev-plugin.zod';
+// dev-plugin.zod (DevPluginConfigSchema / DevServiceOverrideSchema /
+// DevFixtureConfigSchema / DevToolsConfigSchema / DevPluginPreset) was REMOVED
+// per ADR-0049 enforce-or-remove (#4149): the whole family had zero consumers —
+// @objectstack/plugin-dev reads its own DevPluginOptions and never imported it,
+// no load path parsed it (`stack.devPlugins` takes ManifestSchema | string, not
+// this config), and none of the declared surfaces (presets, fixtures, dev-tools
+// dashboard, per-service strategies, simulated latency) were ever implemented.
+// Its `strategy: 'stub'` vocabulary described the dev-stub design ADR-0115
+// retired. The real dev assembly contract is plugin-dev's DevPluginOptions.
export * from './events.zod';
// feature.zod (FeatureFlagSchema / FeatureStrategy / FeatureFlag factory) was
// REMOVED per ADR-0056 D8: zero runtime consumers, and its only protocol home —