You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@maka.apache.org by ku...@apache.org on 2026/09/01 03:02:29 UTC

(maka) branch main updated: feat(runtime): add Plugin Platform foundation (#3729)

This is an automated email from the ASF dual-hosted git repository.

likun666661 pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/maka.git


The following commit(s) were added to refs/heads/main by this push:
     new 8fa1e8947d feat(runtime): add Plugin Platform foundation (#3729)
8fa1e8947d is described below

commit 8fa1e8947de3b92e89053594f8e91f643f84b596
Author: Xinhao Xu <84...@users.noreply.github.com>
AuthorDate: Tue Sep 1 11:02:24 2026 +0800

    feat(runtime): add Plugin Platform foundation (#3729)
    
    * feat(runtime): add plugin platform foundation
    
    * fix(runtime-host): recover package install boundaries
    
    * fix(plugin): preserve foundation consistency
    
    * fix(plugin): harden prototype and query boundaries
    
    * fix(plugin): make platform state and convergence explicit
    
    * fix(plugin): harden recovery and reconciliation
---
 package-lock.json                                  |    1 +
 .../runtime-host-operator-command.test.ts          |   93 ++
 packages/cli/src/cli-core.ts                       |   17 +
 packages/cli/src/runtime-host-cli.ts               |  105 +-
 packages/cli/src/runtime-host-plugin-command.ts    |  141 ++
 packages/runtime-host/package.json                 |    1 +
 .../src/__tests__/plugin-platform.test.ts          | 1651 ++++++++++++++++++++
 packages/runtime-host/src/protocol/index.ts        |    4 +-
 .../runtime-host/src/protocol/operation-spec.ts    |    1 +
 packages/runtime-host/src/protocol/operations.ts   |    3 +
 .../runtime-host/src/protocol/plugin-platform.ts   |  744 +++++++++
 .../src/server/execution-composition.ts            |   19 +
 .../runtime-host/src/server/extension-bundle.ts    |  279 ++++
 .../src/server/extension-package-manifest.ts       |  338 ++++
 packages/runtime-host/src/server/index.ts          |   29 +
 .../src/server/operation-dispatcher.ts             |    5 +
 .../src/server/plugin-composition-patch.ts         |   63 +
 .../src/server/plugin-composition-store.ts         |  171 ++
 .../src/server/plugin-package-loader.ts            |  157 ++
 .../src/server/plugin-package-store.ts             |  604 +++++++
 .../src/server/plugin-platform-coordinator.ts      |  329 ++++
 .../runtime-host/src/server/plugin-platform.ts     | 1507 ++++++++++++++++++
 .../__tests__/plugin-composition-loader.test.ts    |  280 +++-
 packages/runtime/src/plugin-composition-loader.ts  |  263 +++-
 packages/runtime/src/plugin-runtime.ts             |  304 +++-
 25 files changed, 7031 insertions(+), 78 deletions(-)

diff --git a/package-lock.json b/package-lock.json
index bb1e604af8..15ccc3ad4e 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -14357,6 +14357,7 @@
         "@maka/runtime": "0.1.0",
         "@maka/storage": "0.1.0",
         "ws": "^8.21.3",
+        "yaml": "^2.9.0",
         "zod": "^4.4.3"
       },
       "devDependencies": {
diff --git a/packages/cli/src/__tests__/runtime-host-operator-command.test.ts b/packages/cli/src/__tests__/runtime-host-operator-command.test.ts
index 0486e79a63..04b5991f16 100644
--- a/packages/cli/src/__tests__/runtime-host-operator-command.test.ts
+++ b/packages/cli/src/__tests__/runtime-host-operator-command.test.ts
@@ -34,6 +34,7 @@ import {
   type RuntimeHostAccessIssueOptions,
 } from '../runtime-host-access-command.js';
 import { parseRuntimeHostCommand } from '../runtime-host-cli.js';
+import { runRuntimeHostPluginCli } from '../runtime-host-plugin-command.js';
 import { runRuntimeHostProjectCli } from '../runtime-host-project-command.js';
 import { createRuntimeHostServiceReadyEvent } from '../runtime-host-service-command.js';
 
@@ -157,6 +158,34 @@ describe('Runtime Host operator commands', () => {
         prefer: false,
       },
     );
+    assert.deepEqual(
+      parseRuntimeHostCommand([
+        'plugin',
+        'inspect',
+        '--scope',
+        'profile',
+        '--cursor',
+        'opaque-cursor',
+        '--limit',
+        '16',
+      ]),
+      {
+        kind: 'runtime-host-plugin',
+        action: 'inspect',
+        rootId: 'profile',
+        cursor: 'opaque-cursor',
+        limit: 16,
+      },
+    );
+    assert.deepEqual(
+      parseRuntimeHostCommand(['plugin', 'export', 'fixture-plugin', './fixture.maka-extension']),
+      {
+        kind: 'runtime-host-plugin',
+        action: 'export',
+        subject: 'fixture-plugin',
+        targetPath: './fixture.maka-extension',
+      },
+    );
     assert.deepEqual(
       parseRuntimeHostCommand([
         'project',
@@ -301,6 +330,8 @@ describe('Runtime Host operator commands', () => {
       assert.equal(resolved.operationGrants.includes('access.credential.rotation.prepare'), false);
       assert.equal(resolved.operationGrants.includes('access.credential.rotation.revoke'), false);
       assert.equal(resolved.operationGrants.includes('host.upgrade.prepare'), false);
+      assert.equal(resolved.operationGrants.includes('plugin.platform.query'), false);
+      assert.equal(resolved.operationGrants.includes('plugin.package.install'), false);
       assert.equal(resolved.operationGrants.includes('turn.start'), true);
       assert.equal(resolved.operationGrants.includes('project.catalog.query'), true);
     }
@@ -432,6 +463,13 @@ describe('Runtime Host operator commands', () => {
         'peer.mesh.remove',
         'peer.mesh.rename',
         'peer.mesh.transit.set',
+        'plugin.composition.apply',
+        'plugin.package.export',
+        'plugin.package.install',
+        'plugin.package.reload',
+        'plugin.package.uninstall',
+        'plugin.platform.query',
+        'plugin.platform.reconcile',
       ],
     );
   });
@@ -533,6 +571,61 @@ describe('Runtime Host operator commands', () => {
       ['project-1', 'project-1'],
     );
   });
+
+  test('uses every Plugin Platform surface through the Runtime Host', async () => {
+    const requests: unknown[] = [];
+    let closeCount = 0;
+    const connection = {
+      request: async (operation: string, input: unknown) => {
+        requests.push({ operation, input });
+        return {};
+      },
+      close: async () => {
+        closeCount += 1;
+      },
+    } as unknown as RuntimeHostConnection;
+    const overrides = {
+      connect: async () => connection,
+      readText: async () => '{"operations":[{"type":"remove","entryId":"entry-one"}]}',
+      write: () => undefined,
+    };
+    const commands = [
+      { rootPath: '/srv/maka', action: 'status' as const },
+      { rootPath: '/srv/maka', action: 'list' as const },
+      { rootPath: '/srv/maka', action: 'inspect' as const, rootId: 'profile' },
+      { rootPath: '/srv/maka', action: 'failures' as const },
+      { rootPath: '/srv/maka', action: 'install' as const, subject: './plugin' },
+      { rootPath: '/srv/maka', action: 'uninstall' as const, subject: 'plugin' },
+      { rootPath: '/srv/maka', action: 'reload' as const, subject: 'plugin' },
+      {
+        rootPath: '/srv/maka',
+        action: 'export' as const,
+        subject: 'plugin',
+        targetPath: './plugin.maka-extension',
+      },
+      { rootPath: '/srv/maka', action: 'apply' as const, subject: './operations.json' },
+      { rootPath: '/srv/maka', action: 'reconcile' as const },
+    ];
+    for (const command of commands) {
+      assert.equal(await runRuntimeHostPluginCli(command, overrides), 0);
+    }
+    assert.deepEqual(
+      requests.map((request) => (request as { operation: string }).operation),
+      [
+        'plugin.platform.query',
+        'plugin.platform.query',
+        'plugin.platform.query',
+        'plugin.platform.query',
+        'plugin.package.install',
+        'plugin.package.uninstall',
+        'plugin.package.reload',
+        'plugin.package.export',
+        'plugin.composition.apply',
+        'plugin.platform.reconcile',
+      ],
+    );
+    assert.equal(closeCount, commands.length);
+  });
 });
 
 function presetOptions(
diff --git a/packages/cli/src/cli-core.ts b/packages/cli/src/cli-core.ts
index b1b068fb54..e99c46dbea 100644
--- a/packages/cli/src/cli-core.ts
+++ b/packages/cli/src/cli-core.ts
@@ -160,6 +160,11 @@ function helpText(cliCommand: string): string {
     `  ${cliCommand} runtime-host access revoke --credential <id>`,
     `  ${cliCommand} runtime-host project list [--root <path>]`,
     `  ${cliCommand} runtime-host project add <path> [--prefer] [--root <path>]`,
+    `  ${cliCommand} runtime-host plugin status|list|inspect|failures [--root <path>]`,
+    `  ${cliCommand} runtime-host plugin install|uninstall|reload <target> [--root <path>]`,
+    `  ${cliCommand} runtime-host plugin export <extension-id> <bundle-path> [--root <path>]`,
+    `  ${cliCommand} runtime-host plugin apply <operations.json> [--root <path>]`,
+    `  ${cliCommand} runtime-host plugin reconcile [--root <path>]`,
     `  ${cliCommand} runtime-host profile list`,
     `  ${cliCommand} runtime-host profile set --id <id> --name <name> --tls-url <wss-url> --expected-root <root-id> [--credential-env <name>]`,
     `  ${cliCommand} runtime-host profile set --id <id> --name <name> --ssh-destination <us...@host> --ssh-remote-port <port> --expected-root <root-id> [--ssh-port <port>] [--credential-env <name>]`,
@@ -708,6 +713,18 @@ export async function runMakaCli(
             prefer: command.prefer,
           });
     }
+    case 'runtime-host-plugin': {
+      const { runRuntimeHostPluginCli } = await import('./runtime-host-plugin-command.js');
+      return runRuntimeHostPluginCli({
+        rootPath: command.rootPath ?? dataRoots.workspaceRoot,
+        action: command.action,
+        ...(command.subject ? { subject: command.subject } : {}),
+        ...(command.targetPath ? { targetPath: command.targetPath } : {}),
+        ...(command.rootId ? { rootId: command.rootId } : {}),
+        ...(command.cursor === undefined ? {} : { cursor: command.cursor }),
+        ...(command.limit === undefined ? {} : { limit: command.limit }),
+      });
+    }
     case 'runtime-host-capability-provider-serve': {
       const { runRuntimeHostCapabilityProviderCli } = await import(
         './runtime-host-capability-provider-command.js'
diff --git a/packages/cli/src/runtime-host-cli.ts b/packages/cli/src/runtime-host-cli.ts
index c52df12063..5f7c52f7ac 100644
--- a/packages/cli/src/runtime-host-cli.ts
+++ b/packages/cli/src/runtime-host-cli.ts
@@ -301,6 +301,26 @@ export type RuntimeHostCliCommand =
       path: string;
       prefer: boolean;
     }
+  | {
+      kind: 'runtime-host-plugin';
+      rootPath?: string;
+      action:
+        | 'status'
+        | 'list'
+        | 'inspect'
+        | 'failures'
+        | 'install'
+        | 'uninstall'
+        | 'reload'
+        | 'export'
+        | 'apply'
+        | 'reconcile';
+      subject?: string;
+      targetPath?: string;
+      rootId?: string;
+      cursor?: string;
+      limit?: number;
+    }
   | {
       kind: 'runtime-host-capability-provider-serve';
       url: string;
@@ -360,6 +380,7 @@ export function parseRuntimeHostCommand(argv: string[]): RuntimeHostCliCommand {
   if (argv[0] === 'service') return parseServiceManagementCommand(argv.slice(1));
   if (argv[0] === 'access') return parseAccessCommand(argv.slice(1));
   if (argv[0] === 'project') return parseProjectCommand(argv.slice(1));
+  if (argv[0] === 'plugin') return parsePluginCommand(argv.slice(1));
   if (argv[0] === 'capability-provider') {
     return parseCapabilityProviderCommand(argv.slice(1));
   }
@@ -367,7 +388,7 @@ export function parseRuntimeHostCommand(argv: string[]): RuntimeHostCliCommand {
   return error(
     argv[0]
       ? `Unexpected runtime-host command: ${argv[0]}`
-      : 'runtime-host requires the activate, connect, serve, setup, service, access, project, profile, or capability-provider command',
+      : 'runtime-host requires the activate, connect, serve, setup, service, access, project, plugin, profile, or capability-provider command',
   );
 }
 
@@ -1545,6 +1566,88 @@ function parseProjectCommand(argv: string[]): RuntimeHostCliCommand {
   };
 }
 
+function parsePluginCommand(argv: string[]): RuntimeHostCliCommand {
+  const action = argv[0];
+  const actions = [
+    'status',
+    'list',
+    'inspect',
+    'failures',
+    'install',
+    'uninstall',
+    'reload',
+    'export',
+    'apply',
+    'reconcile',
+  ] as const;
+  if (!actions.includes(action as (typeof actions)[number])) {
+    return error(
+      action
+        ? `Unexpected runtime-host plugin command: ${action}`
+        : 'runtime-host plugin requires an action',
+    );
+  }
+  let rootPath: string | undefined;
+  let rootId: string | undefined;
+  let cursor: string | undefined;
+  let limit: number | undefined;
+  const positional: string[] = [];
+  for (let index = 1; index < argv.length; index += 1) {
+    const argument = argv[index];
+    if (
+      argument === '--root' ||
+      argument === '--scope' ||
+      argument === '--cursor' ||
+      argument === '--limit'
+    ) {
+      const parsed = optionValue(argv, index, argument);
+      if (typeof parsed !== 'string') return parsed;
+      if (argument === '--root') rootPath = parsed;
+      else if (argument === '--scope') rootId = parsed;
+      else if (argument === '--cursor') cursor = parsed;
+      else {
+        const numeric = Number(parsed);
+        if (!Number.isSafeInteger(numeric) || numeric < 0 || numeric < 1 || numeric > 64) {
+          return error('--limit requires an integer between 1 and 64');
+        }
+        limit = numeric;
+      }
+      index += 1;
+      continue;
+    }
+    positional.push(argument ?? '');
+  }
+  const selected = action as (typeof actions)[number];
+  const expected =
+    selected === 'export'
+      ? 2
+      : ['install', 'uninstall', 'reload', 'apply'].includes(selected)
+        ? 1
+        : 0;
+  if (positional.length !== expected) {
+    return error(
+      `runtime-host plugin ${selected} requires ${expected} target${expected === 1 ? '' : 's'}`,
+    );
+  }
+  if (rootId && selected !== 'inspect') return error('--scope is only valid for plugin inspect');
+  if (
+    (cursor !== undefined || limit !== undefined) &&
+    !['list', 'inspect', 'failures'].includes(selected)
+  ) {
+    return error('--cursor and --limit require a paged Plugin query');
+  }
+  return {
+    kind: 'runtime-host-plugin',
+    action: selected,
+    ...(rootPath ? { rootPath } : {}),
+    ...(positional[0] ? { subject: positional[0] } : {}),
+    ...(positional[1] ? { targetPath: positional[1] } : {}),
+    ...(rootId ? { rootId } : {}),
+    ...(cursor ? { cursor } : {}),
+    ...(limit === undefined ? {} : { limit }),
+  };
+}
+
 function parseProfileCommand(argv: string[]): RuntimeHostCliCommand {
   const action = argv[0];
   if (action === 'list') {
diff --git a/packages/cli/src/runtime-host-plugin-command.ts b/packages/cli/src/runtime-host-plugin-command.ts
new file mode 100644
index 0000000000..ca87bd1c10
--- /dev/null
+++ b/packages/cli/src/runtime-host-plugin-command.ts
@@ -0,0 +1,141 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import { connectExistingRuntimeHost, type RuntimeHostConnection } from '@maka/runtime-host/client';
+import { RUNTIME_HOST_PROTOCOL_VERSION } from '@maka/runtime-host/protocol';
+import { readFile } from 'node:fs/promises';
+import { resolve } from 'node:path';
+
+const PROTOCOL = {
+  min: RUNTIME_HOST_PROTOCOL_VERSION,
+  max: RUNTIME_HOST_PROTOCOL_VERSION,
+} as const;
+
+export interface RuntimeHostPluginCommand {
+  readonly rootPath: string;
+  readonly action:
+    | 'status'
+    | 'list'
+    | 'inspect'
+    | 'failures'
+    | 'install'
+    | 'uninstall'
+    | 'reload'
+    | 'export'
+    | 'apply'
+    | 'reconcile';
+  readonly subject?: string;
+  readonly targetPath?: string;
+  readonly rootId?: string;
+  readonly cursor?: string;
+  readonly limit?: number;
+}
+
+interface RuntimeHostPluginCommandDeps {
+  readonly connect: (rootPath: string) => Promise<RuntimeHostConnection>;
+  readonly readText: (path: string) => Promise<string>;
+  readonly write: (value: string) => void;
+}
+
+export async function runRuntimeHostPluginCli(
+  command: RuntimeHostPluginCommand,
+  overrides: Partial<RuntimeHostPluginCommandDeps> = {},
+): Promise<number> {
+  const deps = { ...defaultDeps(), ...overrides };
+  const connection = await deps.connect(command.rootPath);
+  try {
+    const result = await execute(connection, command, deps.readText);
+    deps.write(`${JSON.stringify(result, null, 2)}\n`);
+    return 0;
+  } finally {
+    await connection.close();
+  }
+}
+
+async function execute(
+  connection: RuntimeHostConnection,
+  command: RuntimeHostPluginCommand,
+  readText: (path: string) => Promise<string>,
+): Promise<unknown> {
+  const paging = {
+    ...(command.cursor === undefined ? {} : { cursor: command.cursor }),
+    ...(command.limit === undefined ? {} : { limit: command.limit }),
+  };
+  switch (command.action) {
+    case 'status':
+      return await connection.request('plugin.platform.query', { view: 'status' });
+    case 'list':
+      return await connection.request('plugin.platform.query', { view: 'packages', ...paging });
+    case 'inspect':
+      return await connection.request('plugin.platform.query', {
+        view: 'entries',
+        ...paging,
+        ...(command.rootId ? { rootId: command.rootId } : {}),
+      } as never);
+    case 'failures':
+      return await connection.request('plugin.platform.query', { view: 'failures', ...paging });
+    case 'install':
+      return await connection.request('plugin.package.install', {
+        sourcePath: resolve(requireSubject(command)),
+      });
+    case 'uninstall':
+      return await connection.request('plugin.package.uninstall', {
+        extensionId: requireSubject(command),
+      });
+    case 'reload':
+      return await connection.request('plugin.package.reload', {
+        extensionId: requireSubject(command),
+      });
+    case 'export':
+      return await connection.request('plugin.package.export', {
+        extensionId: requireSubject(command),
+        targetPath: resolve(command.targetPath ?? missing('Plugin export target path')),
+      });
+    case 'apply': {
+      const decoded = JSON.parse(await readText(resolve(requireSubject(command)))) as unknown;
+      return await connection.request('plugin.composition.apply', decoded as never);
+    }
+    case 'reconcile':
+      return await connection.request('plugin.platform.reconcile', {});
+  }
+}
+
+function requireSubject(command: RuntimeHostPluginCommand): string {
+  return command.subject ?? missing(`Plugin ${command.action} target`);
+}
+
+function missing(label: string): never {
+  throw new Error(`${label} is missing`);
+}
+
+function defaultDeps(): RuntimeHostPluginCommandDeps {
+  return {
+    connect: connectLocalOwner,
+    readText: (path) => readFile(path, 'utf8'),
+    write: (value) => process.stdout.write(value),
+  };
+}
+
+async function connectLocalOwner(rootPath: string): Promise<RuntimeHostConnection> {
+  const result = await connectExistingRuntimeHost({ rootPath, protocol: PROTOCOL });
+  if (result.kind !== 'connected') {
+    throw new Error(`Runtime Host service is not available (${result.kind})`);
+  }
+  return result.connection;
+}
diff --git a/packages/runtime-host/package.json b/packages/runtime-host/package.json
index e6c8afb72a..58aa06632c 100644
--- a/packages/runtime-host/package.json
+++ b/packages/runtime-host/package.json
@@ -31,6 +31,7 @@
     "@maka/runtime": "0.1.0",
     "@maka/storage": "0.1.0",
     "ws": "^8.21.3",
+    "yaml": "^2.9.0",
     "zod": "^4.4.3"
   },
   "devDependencies": {
diff --git a/packages/runtime-host/src/__tests__/plugin-platform.test.ts b/packages/runtime-host/src/__tests__/plugin-platform.test.ts
new file mode 100644
index 0000000000..99e4646f7b
--- /dev/null
+++ b/packages/runtime-host/src/__tests__/plugin-platform.test.ts
@@ -0,0 +1,1651 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import assert from 'node:assert/strict';
+import { mkdir, mkdtemp, readFile, readdir, rm, writeFile } from 'node:fs/promises';
+import { tmpdir } from 'node:os';
+import { join } from 'node:path';
+import { test } from 'node:test';
+import { waitFor } from '@maka/core/test-only/async-primitives';
+import { MakaCompositionLoader } from '@maka/runtime/plugin-composition-loader';
+import {
+  decodePluginCompositionApplyInput,
+  decodeRequestFrame,
+  decodeResponseFrame,
+  operationAllowsRemoteOwner,
+} from '../protocol/index.js';
+import { PLUGIN_PLATFORM_QUERY_RESULT_MAX_BYTES } from '../protocol/plugin-platform.js';
+import {
+  HostPluginCompositionStore,
+  HostPluginCompositionStoreError,
+  type PersistedPluginComposition,
+} from '../server/plugin-composition-store.js';
+import { HostPluginPlatformCoordinator } from '../server/plugin-platform-coordinator.js';
+import { TrustedPluginPackageLoader } from '../server/plugin-package-loader.js';
+import { PluginPackageStore } from '../server/plugin-package-store.js';
+import { HostPluginPlatform, type HostPluginPlatformOptions } from '../server/plugin-platform.js';
+
+interface TestPlatformInternals {
+  readonly composition: MakaCompositionLoader;
+  readonly packages: PluginPackageStore;
+  readonly store: HostPluginCompositionStore;
+}
+
+const testPlatformInternals = new WeakMap<HostPluginPlatform, TestPlatformInternals>();
+
+function createPlatform(
+  controlDirectory: string,
+  options: HostPluginPlatformOptions = {},
+): HostPluginPlatform {
+  const composition = options.composition ?? new MakaCompositionLoader();
+  const packages = options.packages ?? new PluginPackageStore(controlDirectory);
+  const packageLoader =
+    options.packageLoader ?? new TrustedPluginPackageLoader(controlDirectory, packages);
+  const store = options.store ?? new HostPluginCompositionStore(controlDirectory);
+  const platform = new HostPluginPlatform(controlDirectory, {
+    composition,
+    packages,
+    packageLoader,
+    store,
+  });
+  testPlatformInternals.set(platform, { composition, packages, store });
+  return platform;
+}
+
+function internals(platform: HostPluginPlatform): TestPlatformInternals {
+  return testPlatformInternals.get(platform)!;
+}
+
+test('Plugin Platform installs, activates, persists, and recovers a generic package', async () => {
+  const root = await mkdtemp(join(tmpdir(), 'maka-plugin-platform-'));
+  try {
+    const source = await writeFixturePackage(root, 'fixture-package', 'first', {
+      composition: [
+        {
+          type: 'insert',
+          rootId: 'profile',
+          entry: { id: 'fixture-entry', packageId: 'fixture-package' },
+        },
+      ],
+    });
+    const platform = createPlatform(join(root, 'control'));
+    await platform.recover();
+
+    assert.deepEqual(await platform.installPackage(source), {
+      extensionId: 'fixture-package',
+      authorityEpoch: 1,
+      durability: 'committed',
+      convergence: 'converged',
+      cleanup: 'complete',
+      failures: [],
+    });
+    const published = internals(platform).composition.package('fixture-package');
+    assert.deepEqual(published.contributions, [{ id: 'first', kind: 'foundation-test' }]);
+    const bundle = join(root, 'fixture-package.maka-extension');
+    await platform.exportPackage('fixture-package', bundle);
+    const imported = createPlatform(join(root, 'import-control'));
+    await imported.recover();
+    assert.equal((await imported.installPackage(bundle)).convergence, 'converged');
+    assert.equal(imported.inspect('profile')[0]?.id, 'fixture-entry');
+    await imported.close();
+    await platform.close();
+
+    const recovered = createPlatform(join(root, 'control'));
+    await recovered.recover();
+    assert.equal(recovered.inspect('profile')[0]?.status, 'active');
+    assert.equal(recovered.desiredComposition().generation, 1);
+    assert.deepEqual(internals(recovered).composition.package('fixture-package').contributions, [
+      { id: 'first', kind: 'foundation-test' },
+    ]);
+    assert.deepEqual(Object.keys((await internals(recovered).store.read()) ?? {}).sort(), [
+      'generation',
+      'overlays',
+      'packageLayers',
+      'schemaVersion',
+    ]);
+    await recovered.close();
+
+    const generationRoot = join(root, 'control', 'plugin-generations-v1');
+    assert.deepEqual(await readdir(generationRoot).catch(() => []), []);
+  } finally {
+    await rm(root, { recursive: true, force: true });
+  }
+});
+
+test('Plugin Platform coordinator keeps package and composition operations generic', async () => {
+  const root = await mkdtemp(join(tmpdir(), 'maka-plugin-protocol-'));
+  try {
+    const source = await writeFixturePackage(root, 'protocol-package', 'generic', {
+      composition: [
+        {
+          type: 'insert',
+          entry: { id: 'protocol-entry', packageId: 'protocol-package' },
+        },
+      ],
+    });
+    const platform = createPlatform(join(root, 'control'));
+    const coordinator = new HostPluginPlatformCoordinator(platform);
+    await platform.recover();
+
+    const installed = await coordinator.handlers['plugin.package.install'](
+      { sourcePath: source },
+      null as never,
+    );
+    assert.deepEqual(installed, {
+      ok: true,
+      result: {
+        extensionId: 'protocol-package',
+        authorityEpoch: 1,
+        durability: 'committed',
+        convergence: 'converged',
+        cleanup: 'complete',
+        failures: [],
+      },
+    });
+    const queried = await coordinator.handlers['plugin.platform.query'](
+      { view: 'packages' },
+      null as never,
+    );
+    assert.equal(queried.ok, true);
+    if (queried.ok && queried.result.view === 'packages') {
+      assert.deepEqual(
+        queried.result.items.map(({ extensionId }) => extensionId),
+        ['protocol-package'],
+      );
+    }
+    const entries = await coordinator.handlers['plugin.platform.query'](
+      { view: 'entries', rootId: 'profile' },
+      null as never,
+    );
+    assert.equal(entries.ok && entries.result.view === 'entries', true);
+    if (entries.ok && entries.result.view === 'entries') {
+      assert.equal(entries.result.items[0]?.id, 'protocol-entry');
+    }
+    const reloaded = await coordinator.handlers['plugin.package.reload'](
+      { extensionId: 'protocol-package' },
+      null as never,
+    );
+    assert.equal(reloaded.ok && reloaded.result.convergence, 'converged');
+    await platform.close();
+  } finally {
+    await rm(root, { recursive: true, force: true });
+  }
+});
+
+test('Plugin Platform query pages share the protocol byte budget across multiple items', async () => {
+  const root = await mkdtemp(join(tmpdir(), 'maka-plugin-query-budget-'));
+  try {
+    const platform = createPlatform(join(root, 'control'));
+    const coordinator = new HostPluginPlatformCoordinator(platform);
+    await platform.recover();
+    for (let index = 0; index < 12; index += 1) {
+      await platform.apply({
+        operations: [
+          {
+            type: 'insert',
+            entry: {
+              id: `large-query-entry-${index}`,
+              config: { payload: `${index}:${'x'.repeat(60 * 1024)}` },
+            },
+          },
+        ],
+      });
+    }
+
+    const queried = await coordinator.handlers['plugin.platform.query'](
+      { view: 'entries', limit: 64 },
+      null as never,
+    );
+    assert.equal(queried.ok, true);
+    if (!queried.ok || queried.result.view !== 'entries') throw new Error('Expected Entry page');
+    assert.ok(queried.result.items.length > 1);
+    assert.ok(queried.result.items.length < 12);
+    assert.notEqual(queried.result.nextCursor, null);
+    assert.ok(
+      Buffer.byteLength(JSON.stringify(queried.result), 'utf8') <=
+        PLUGIN_PLATFORM_QUERY_RESULT_MAX_BYTES,
+    );
+    assert.doesNotThrow(() =>
+      decodeResponseFrame({
+        requestId: 'bounded-query',
+        operation: 'plugin.platform.query',
+        ok: true,
+        result: queried.result,
+      }),
+    );
+    await platform.close();
+  } finally {
+    await rm(root, { recursive: true, force: true });
+  }
+});
+
+test('Plugin Platform lifecycle gates operations and recovery runs exactly once', async () => {
+  const root = await mkdtemp(join(tmpdir(), 'maka-plugin-lifecycle-'));
+  try {
+    const platform = createPlatform(join(root, 'control'));
+    const coordinator = new HostPluginPlatformCoordinator(platform);
+    const before = await coordinator.handlers['plugin.platform.query'](
+      { view: 'status' },
+      null as never,
+    );
+    assert.equal(before.ok, false);
+    if (!before.ok) assert.equal(before.error.code, 'host_not_ready');
+    await platform.recover();
+    await assert.rejects(() => platform.recover(), /cannot recover from phase ready/u);
+    assert.equal((await platform.status()).phase, 'ready');
+    platform.beginDrain();
+    await assert.rejects(() => platform.apply({ operations: [] }), /draining/u);
+    await platform.close();
+  } finally {
+    await rm(root, { recursive: true, force: true });
+  }
+});
+
+test('Plugin Platform cursors reject a changed query snapshot', async () => {
+  const root = await mkdtemp(join(tmpdir(), 'maka-plugin-stale-cursor-'));
+  try {
+    const platform = createPlatform(join(root, 'control'));
+    const coordinator = new HostPluginPlatformCoordinator(platform);
+    await platform.recover();
+    await platform.apply({
+      operations: [
+        { type: 'insert', entry: { id: 'cursor-one' } },
+        { type: 'insert', entry: { id: 'cursor-two' } },
+      ],
+    });
+    const first = await coordinator.handlers['plugin.platform.query'](
+      { view: 'entries', limit: 1 },
+      null as never,
+    );
+    if (!first.ok || first.result.view !== 'entries' || !first.result.nextCursor) {
+      throw new Error('Expected a paged Entry snapshot');
+    }
+    await platform.apply({ operations: [{ type: 'insert', entry: { id: 'cursor-three' } }] });
+    const stale = await coordinator.handlers['plugin.platform.query'](
+      { view: 'entries', limit: 1, cursor: first.result.nextCursor },
+      null as never,
+    );
+    assert.equal(stale.ok, false);
+    if (!stale.ok) assert.equal(stale.error.code, 'stale_cursor');
+    await platform.close();
+  } finally {
+    await rm(root, { recursive: true, force: true });
+  }
+});
+
+test('Package composition declares and exposes structural dependencies', async () => {
+  const root = await mkdtemp(join(tmpdir(), 'maka-plugin-structural-dependencies-'));
+  try {
+    const platform = createPlatform(join(root, 'control'));
+    const coordinator = new HostPluginPlatformCoordinator(platform);
+    await platform.recover();
+    await platform.installPackage(
+      await writeFixturePackage(root, 'structural-base', 'base', {
+        composition: [{ type: 'insert', entry: { id: 'structural-parent' } }],
+      }),
+    );
+    const undeclared = await writeFixturePackage(root, 'undeclared-child', 'undeclared', {
+      composition: [
+        {
+          type: 'insert',
+          parentId: 'structural-parent',
+          entry: { id: 'undeclared-entry' },
+        },
+      ],
+    });
+    await assert.rejects(
+      () => platform.installPackage(undeclared),
+      /structural dependencies do not match/u,
+    );
+    const childSource = await writeFixturePackage(root, 'structural-child', 'child', {
+      structuralDependencies: ['structural-base'],
+      composition: [
+        {
+          type: 'insert',
+          parentId: 'structural-parent',
+          entry: { id: 'structural-child-entry' },
+        },
+      ],
+    });
+    await platform.installPackage(childSource);
+    const packages = await coordinator.handlers['plugin.platform.query'](
+      { view: 'packages' },
+      null as never,
+    );
+    if (!packages.ok || packages.result.view !== 'packages') throw new Error('Expected packages');
+    assert.match(
+      packages.result.items.find(({ extensionId }) => extensionId === 'structural-child')
+        ?.contentDigest ?? '',
+      /^sha256-[a-f0-9]{64}$/u,
+    );
+    assert.deepEqual(
+      packages.result.items.find(({ extensionId }) => extensionId === 'structural-child')
+        ?.structuralDependencies,
+      ['structural-base'],
+    );
+    assert.deepEqual(
+      packages.result.items.find(({ extensionId }) => extensionId === 'structural-base')
+        ?.requiredBy,
+      ['structural-child'],
+    );
+    await assert.rejects(
+      () => platform.uninstallPackage('structural-base'),
+      /structurally required/u,
+    );
+    await platform.close();
+  } finally {
+    await rm(root, { recursive: true, force: true });
+  }
+});
+
+test('Package replacement releases a single-provider Service before activating its successor', async () => {
+  const root = await mkdtemp(join(tmpdir(), 'maka-plugin-service-reload-'));
+  try {
+    const platform = createPlatform(join(root, 'control'));
+    await platform.recover();
+    await platform.installPackage(
+      await writeFixturePackage(root, 'service-package', 'first', {
+        provideService: 'replacementService',
+        composition: [
+          { type: 'insert', entry: { id: 'service-entry', packageId: 'service-package' } },
+        ],
+      }),
+    );
+    const replacement = await writeFixturePackage(root, 'service-package', 'second', {
+      directorySuffix: 'replacement',
+      provideService: 'replacementService',
+      composition: [
+        { type: 'insert', entry: { id: 'service-entry', packageId: 'service-package' } },
+      ],
+    });
+    const receipt = await platform.installPackage(replacement);
+    assert.equal(receipt.convergence, 'converged');
+    assert.equal(platform.inspect('profile')[0]?.status, 'active');
+    assert.deepEqual(internals(platform).composition.root.get('replacementService'), {
+      source: 'second',
+    });
+    await platform.close();
+  } finally {
+    await rm(root, { recursive: true, force: true });
+  }
+});
+
+test('package Composition layers override in install order and unwind on uninstall', async () => {
+  const root = await mkdtemp(join(tmpdir(), 'maka-plugin-layers-'));
+  try {
+    const platform = createPlatform(join(root, 'control'));
+    await platform.recover();
+    await platform.installPackage(
+      await writeFixturePackage(root, 'layer-base', 'base', {
+        manifest: {
+          configuration: {
+            properties: { theme: { type: 'string', default: 'base' } },
+          },
+        },
+        composition: [
+          {
+            type: 'insert',
+            entry: {
+              id: 'layer-entry',
+              packageId: 'layer-base',
+              config: { theme: 'base' },
+            },
+          },
+        ],
+      }),
+    );
+    const overrideSource = await writeFixturePackage(root, 'layer-override', 'override', {
+      structuralDependencies: ['layer-base'],
+      composition: [
+        { type: 'update', entryId: 'layer-entry', patch: { config: { theme: 'override' } } },
+      ],
+    });
+    await platform.installPackage(overrideSource);
+    const tailSource = await writeFixturePackage(root, 'layer-tail', 'tail', {
+      structuralDependencies: ['layer-base'],
+      composition: [
+        { type: 'update', entryId: 'layer-entry', patch: { config: { theme: 'tail' } } },
+      ],
+    });
+    await platform.installPackage(tailSource);
+
+    assert.deepEqual(platform.desiredComposition().roots.profile[0]?.config, {
+      theme: 'tail',
+    });
+    await platform.installPackage(overrideSource);
+    assert.deepEqual(platform.desiredComposition().roots.profile[0]?.config, { theme: 'tail' });
+    await platform.uninstallPackage('layer-tail');
+    await platform.uninstallPackage('layer-override');
+    assert.deepEqual(platform.desiredComposition().roots.profile[0]?.config, { theme: 'base' });
+    await platform.installPackage(overrideSource);
+    await platform.apply({
+      operations: [
+        { type: 'update', entryId: 'layer-entry', patch: { config: { theme: 'user' } } },
+      ],
+    });
+    assert.deepEqual(platform.desiredComposition().roots.profile[0]?.config, { theme: 'user' });
+    await platform.uninstallPackage('layer-override');
+    assert.deepEqual(platform.desiredComposition().roots.profile[0]?.config, { theme: 'user' });
+    assert.deepEqual((await internals(platform).store.read())?.packageLayers, ['layer-base']);
+    await platform.close();
+  } finally {
+    await rm(root, { recursive: true, force: true });
+  }
+});
+
+test('invalid package Composition patch is rejected before package publication', async () => {
+  const root = await mkdtemp(join(tmpdir(), 'maka-plugin-invalid-patch-'));
+  try {
+    const platform = createPlatform(join(root, 'control'));
+    await platform.recover();
+    const source = await writeFixturePackage(root, 'invalid-patch', 'invalid', {
+      composition: [{}],
+    });
+    await assert.rejects(() => platform.installPackage(source), /Composition patch is invalid/u);
+    assert.deepEqual(await internals(platform).packages.identities(), []);
+    assert.deepEqual(platform.desiredComposition().roots.profile, []);
+
+    const semanticSource = await writeFixturePackage(root, 'invalid-layer', 'invalid', {
+      composition: [
+        {
+          type: 'insert',
+          entry: { id: 'missing-package-entry', packageId: 'missing-package' },
+        },
+      ],
+    });
+    await assert.rejects(() => platform.installPackage(semanticSource), /missing-package/u);
+    assert.deepEqual(await internals(platform).packages.identities(), []);
+    assert.deepEqual(platform.desiredComposition().roots.profile, []);
+    await platform.close();
+  } finally {
+    await rm(root, { recursive: true, force: true });
+  }
+});
+
+test('failed package replacement restores both stored bytes and live Runtime package', async () => {
+  const root = await mkdtemp(join(tmpdir(), 'maka-plugin-rollback-'));
+  try {
+    const source = await writeFixturePackage(root, 'rollback-package', 'stable');
+    const platform = createPlatform(join(root, 'control'));
+    await platform.recover();
+    await platform.installPackage(source);
+    await platform.apply({
+      operations: [
+        {
+          type: 'insert',
+          entry: { id: 'rollback-entry', packageId: 'rollback-package' },
+        },
+      ],
+    });
+    const before = internals(platform).composition.package('rollback-package').contributions;
+    const invalid = await writeFixturePackage(root, 'rollback-package', 'replacement', {
+      runtimePackageId: 'wrong-package',
+      directorySuffix: 'invalid',
+    });
+
+    await assert.rejects(() => platform.installPackage(invalid), /does not match manifest/u);
+    assert.deepEqual(
+      internals(platform).composition.package('rollback-package').contributions,
+      before,
+    );
+    assert.equal(
+      (await internals(platform).packages.load('rollback-package')).manifest.id,
+      'rollback-package',
+    );
+    await platform.close();
+
+    const recovered = createPlatform(join(root, 'control'));
+    await recovered.recover();
+    assert.deepEqual(
+      internals(recovered).composition.package('rollback-package').contributions,
+      before,
+    );
+    await recovered.close();
+  } finally {
+    await rm(root, { recursive: true, force: true });
+  }
+});
+
+test('package replacement recovery follows the durable Composition generation', async () => {
+  const root = await mkdtemp(join(tmpdir(), 'maka-plugin-package-generation-'));
+  try {
+    for (const mode of ['before', 'after'] as const) {
+      const control = join(root, mode);
+      const store = new AmbiguousCompositionStore(control);
+      const initial = createPlatform(control, { store });
+      await initial.recover();
+      await initial.installPackage(
+        await writeFixturePackage(root, `generation-${mode}`, 'stable', {
+          composition: [
+            {
+              type: 'insert',
+              entry: { id: `entry-${mode}`, packageId: `generation-${mode}` },
+            },
+          ],
+        }),
+      );
+      store.mode = mode;
+      const replacement = await writeFixturePackage(root, `generation-${mode}`, 'replacement', {
+        directorySuffix: mode,
+        composition: [
+          {
+            type: 'insert',
+            entry: { id: `entry-${mode}`, packageId: `generation-${mode}` },
+          },
+        ],
+      });
+      await assert.rejects(() => initial.installPackage(replacement), /commit outcome is unknown/u);
+      assert.equal(
+        internals(initial).composition.package(`generation-${mode}`).contributions?.[0]?.id,
+        'stable',
+        'Runtime convergence waits until the authority outcome is known',
+      );
+      await initial.close();
+
+      const recovered = createPlatform(control);
+      await recovered.recover();
+      assert.equal(
+        internals(recovered).composition.package(`generation-${mode}`).contributions?.[0]?.id,
+        mode === 'after' ? 'replacement' : 'stable',
+      );
+      await recovered.close();
+    }
+  } finally {
+    await rm(root, { recursive: true, force: true });
+  }
+});
+
+test('package replacement fences and preserves recovery evidence when candidate publication fails', async () => {
+  const root = await mkdtemp(join(tmpdir(), 'maka-plugin-package-publication-'));
+  try {
+    const control = join(root, 'control');
+    const packages = new FailingCandidatePublishPackageStore(control);
+    const platform = createPlatform(control, { packages });
+    await platform.recover();
+    await platform.installPackage(await writeFixturePackage(root, 'publication-package', 'stable'));
+    packages.failNextCandidatePublication = true;
+
+    await assert.rejects(
+      async () =>
+        platform.installPackage(
+          await writeFixturePackage(root, 'publication-package', 'replacement', {
+            directorySuffix: 'replacement',
+          }),
+        ),
+      /publication outcome is unknown/u,
+    );
+    assert.equal((await platform.status()).phase, 'fenced');
+    assert.equal(
+      (await readdir(packages.root)).some((entry) => entry.startsWith('.install-')),
+      true,
+      'the install journal must survive for generation-based recovery',
+    );
+    await platform.close();
+
+    const recovered = createPlatform(control);
+    await recovered.recover();
+    assert.equal((await recovered.status()).phase, 'ready');
+    assert.equal(
+      internals(recovered).composition.package('publication-package').contributions?.[0]?.id,
+      'stable',
+    );
+    assert.equal(
+      (await readdir(internals(recovered).packages.root)).some((entry) =>
+        entry.startsWith('.install-'),
+      ),
+      false,
+    );
+    await recovered.close();
+  } finally {
+    await rm(root, { recursive: true, force: true });
+  }
+});
+
+test('automatic reconciliation retries after a transient exceptional failure', async () => {
+  const root = await mkdtemp(join(tmpdir(), 'maka-plugin-reconcile-retry-'));
+  try {
+    const control = join(root, 'control');
+    const packages = new TransientRecoveryPackageStore(control);
+    const source = await writeFixturePackage(root, 'reconcile-package', 'loaded');
+    const prepared = await packages.prepareInstall(source);
+    await prepared.publish(0, 1);
+    await prepared.commit();
+    const packageLoader = new FailOncePackageLoader(control, packages);
+    const platform = createPlatform(control, { packages, packageLoader });
+
+    await platform.recover();
+    assert.equal((await platform.status()).phase, 'degraded');
+    await waitFor(async () => (await platform.status()).phase === 'ready', {
+      timeoutMs: 3_000,
+      pollMs: 20,
+      message: 'automatic Plugin reconciliation did not retry after an exception',
+    });
+    assert.equal(packages.recoverCalls >= 3, true);
+    assert.equal(packageLoader.loadCalls >= 2, true);
+    await platform.close();
+  } finally {
+    await rm(root, { recursive: true, force: true });
+  }
+});
+
+test('Plugin Platform recovery removes orphaned bundle import roots', async () => {
+  const root = await mkdtemp(join(tmpdir(), 'maka-plugin-bundle-import-recovery-'));
+  try {
+    const control = join(root, 'control');
+    const imports = join(control, 'bundle-imports-v1');
+    const orphan = join(imports, 'owner-died');
+    await mkdir(orphan, { recursive: true });
+    await writeFile(join(orphan, 'partial-package'), 'orphan');
+
+    const platform = createPlatform(control);
+    await platform.recover();
+    await assert.rejects(() => readdir(imports), isEnoent);
+    await platform.close();
+  } finally {
+    await rm(root, { recursive: true, force: true });
+  }
+});
+
+test('Plugin Platform protocol rejects open and malformed generic composition shapes', () => {
+  for (const operation of [
+    'plugin.platform.query',
+    'plugin.platform.reconcile',
+    'plugin.package.install',
+    'plugin.package.uninstall',
+    'plugin.package.reload',
+    'plugin.package.export',
+    'plugin.composition.apply',
+  ] as const) {
+    assert.equal(operationAllowsRemoteOwner(operation), false);
+  }
+  assert.equal(
+    decodeRequestFrame({
+      requestId: 'plugin-reload',
+      operation: 'plugin.package.reload',
+      input: { extensionId: 'fixture-package' },
+    }).operation,
+    'plugin.package.reload',
+  );
+  assert.deepEqual(
+    decodeRequestFrame({
+      requestId: 'plugin-request',
+      operation: 'plugin.composition.apply',
+      input: {
+        baseGeneration: 4,
+        operations: [
+          {
+            type: 'insert',
+            rootId: 'session:one',
+            entry: {
+              id: 'fixture-entry',
+              packageId: 'fixture-package',
+              config: { enabled: true },
+              intercept: { policy: { nested: true } },
+            },
+          },
+        ],
+      },
+    }).operation,
+    'plugin.composition.apply',
+  );
+  assert.throws(() =>
+    decodeRequestFrame({
+      requestId: 'plugin-request',
+      operation: 'plugin.package.install',
+      input: { sourcePath: '/tmp/package', unexpected: true },
+    }),
+  );
+  assert.throws(() =>
+    decodeResponseFrame({
+      requestId: 'plugin-request',
+      operation: 'plugin.platform.query',
+      ok: true,
+      result: {
+        view: 'entries',
+        items: [],
+        nextCursor: 1,
+      },
+    }),
+  );
+
+  const prototypeKeys = decodePluginCompositionApplyInput(
+    JSON.parse(
+      '{"operations":[{"type":"insert","entry":{"id":"prototype-fields","config":{"__proto__":"configured","constructor":"constructor-value"},"isolate":{"constructor":"mapped"}}}]}',
+    ),
+  );
+  const operation = prototypeKeys.operations[0];
+  assert.equal(operation?.type, 'insert');
+  if (operation?.type !== 'insert') throw new Error('Expected insert operation');
+  const config = operation.entry.config as Readonly<Record<string, unknown>>;
+  const isolate = operation.entry.isolate as Readonly<Record<string, unknown>>;
+  assert.equal(Object.hasOwn(config, '__proto__'), true);
+  assert.equal(config['__proto__'], 'configured');
+  assert.equal(Object.hasOwn(isolate, 'constructor'), true);
+  assert.equal(isolate['constructor'], 'mapped');
+  assert.throws(() =>
+    decodePluginCompositionApplyInput(
+      JSON.parse(
+        '{"operations":[{"type":"insert","entry":{"id":"invalid-isolate","isolate":{"__proto__":true}}}]}',
+      ),
+    ),
+  );
+});
+
+test('durable overlays may accumulate beyond one command frame without oversized responses', () => {
+  const input = {
+    operations: Array.from({ length: 700 }, (_, index) => ({
+      type: 'insert' as const,
+      entry: { id: `large-entry-${index}`, config: { value: 'x'.repeat(900) } },
+    })),
+  };
+  assert.throws(() => decodePluginCompositionApplyInput(input), /byte limit/u);
+  assert.equal(decodePluginCompositionApplyInput(input, 2 * 1024 * 1024).operations.length, 700);
+  assert.doesNotThrow(() =>
+    decodeResponseFrame({
+      requestId: 'large-apply',
+      operation: 'plugin.composition.apply',
+      ok: true,
+      result: {
+        authorityEpoch: 700,
+        durability: 'committed',
+        convergence: 'converged',
+        cleanup: 'complete',
+        failures: [],
+      },
+    }),
+  );
+});
+
+test('failed desired-state persistence leaves Runtime composition unchanged', async () => {
+  const root = await mkdtemp(join(tmpdir(), 'maka-plugin-persistence-'));
+  try {
+    const control = join(root, 'control');
+    const store = new FailingCompositionStore(control);
+    const source = await writeFixturePackage(root, 'persistent-package', 'stable');
+    const platform = createPlatform(control, { store });
+    await platform.recover();
+    await platform.installPackage(source);
+    await platform.apply({
+      operations: [
+        {
+          type: 'insert',
+          entry: { id: 'persistent-entry', packageId: 'persistent-package' },
+        },
+      ],
+    });
+    const before = internals(platform).composition.compositionState();
+    store.fail = true;
+
+    await assert.rejects(
+      () =>
+        platform.apply({
+          baseGeneration: before.generation,
+          operations: [{ type: 'update', entryId: 'persistent-entry', patch: { disabled: true } }],
+        }),
+      /Runtime state was not changed/u,
+    );
+    assert.deepEqual(internals(platform).composition.compositionState(), before);
+    assert.equal(platform.inspect('profile')[0]?.status, 'active');
+    await platform.close();
+  } finally {
+    await rm(root, { recursive: true, force: true });
+  }
+});
+
+test('recovery loads installed packages that do not yet have an Entry', async () => {
+  const root = await mkdtemp(join(tmpdir(), 'maka-plugin-unused-package-'));
+  try {
+    const control = join(root, 'control');
+    const source = await writeFixturePackage(root, 'unused-package', 'available');
+    const initial = createPlatform(control);
+    await initial.recover();
+    await initial.installPackage(source);
+    await initial.close();
+
+    const recovered = createPlatform(control);
+    await recovered.recover();
+    await recovered.apply({
+      operations: [{ type: 'insert', entry: { id: 'later-entry', packageId: 'unused-package' } }],
+    });
+    assert.equal(recovered.inspect('profile')[0]?.status, 'active');
+    await recovered.close();
+  } finally {
+    await rm(root, { recursive: true, force: true });
+  }
+});
+
+test('immutable package generation is owned by package lifetime across repeated Entries', async () => {
+  const root = await mkdtemp(join(tmpdir(), 'maka-plugin-generation-owner-'));
+  try {
+    const control = join(root, 'control');
+    const platform = createPlatform(control);
+    await platform.recover();
+    await platform.installPackage(await writeFixturePackage(root, 'shared-package', 'shared'));
+    await platform.apply({
+      operations: [
+        { type: 'insert', entry: { id: 'shared-one', packageId: 'shared-package' } },
+        { type: 'insert', entry: { id: 'shared-two', packageId: 'shared-package' } },
+      ],
+    });
+    const generations = join(control, 'plugin-generations-v1');
+    assert.equal((await readdir(generations)).length, 1);
+
+    await platform.apply({ operations: [{ type: 'remove', entryId: 'shared-one' }] });
+    assert.equal((await readdir(generations)).length, 1);
+    assert.equal(internals(platform).composition.inspect('shared-two').status, 'active');
+
+    await platform.apply({ operations: [{ type: 'remove', entryId: 'shared-two' }] });
+    await platform.uninstallPackage('shared-package');
+    assert.deepEqual(await readdir(generations).catch(() => []), []);
+    await platform.close();
+  } finally {
+    await rm(root, { recursive: true, force: true });
+  }
+});
+
+test('unknown desired-state commit outcome fences mutation without inventing a rollback', async () => {
+  const root = await mkdtemp(join(tmpdir(), 'maka-plugin-unknown-commit-'));
+  try {
+    const control = join(root, 'control');
+    const store = new UnknownCommitCompositionStore(control);
+    const platform = createPlatform(control, { store });
+    await platform.recover();
+    store.fail = true;
+
+    await assert.rejects(
+      () => platform.apply({ operations: [{ type: 'insert', entry: { id: 'uncertain-entry' } }] }),
+      /commit outcome is unknown/u,
+    );
+    assert.deepEqual(internals(platform).composition.compositionState().roots.profile, []);
+    await assert.rejects(
+      () => platform.apply({ operations: [{ type: 'remove', entryId: 'uncertain-entry' }] }),
+      /fenced/u,
+    );
+    await platform.close();
+  } finally {
+    await rm(root, { recursive: true, force: true });
+  }
+});
+
+test('a queued mutation rechecks the fence after an unknown commit outcome', async () => {
+  const root = await mkdtemp(join(tmpdir(), 'maka-plugin-queued-fence-'));
+  try {
+    const control = join(root, 'control');
+    const store = new DeferredUnknownCompositionStore(control);
+    const platform = createPlatform(control, { store });
+    await platform.recover();
+    store.fail = true;
+
+    const first = platform.apply({
+      operations: [{ type: 'insert', entry: { id: 'first-uncertain' } }],
+    });
+    await store.entered;
+    const second = platform.apply({
+      operations: [{ type: 'insert', entry: { id: 'second-must-not-run' } }],
+    });
+    store.release();
+
+    await assert.rejects(() => first, /commit outcome is unknown/u);
+    await assert.rejects(() => second, /fenced/u);
+    assert.deepEqual(platform.desiredComposition().roots.profile, []);
+    await platform.close();
+  } finally {
+    await rm(root, { recursive: true, force: true });
+  }
+});
+
+test('failed uninstall keeps Package layers and desired state unchanged', async () => {
+  const root = await mkdtemp(join(tmpdir(), 'maka-plugin-uninstall-plan-'));
+  try {
+    const control = join(root, 'control');
+    const platform = createPlatform(control);
+    await platform.recover();
+    await platform.installPackage(
+      await writeFixturePackage(root, 'uninstall-plan', 'installed', {
+        composition: [
+          {
+            type: 'insert',
+            entry: { id: 'package-default', packageId: 'uninstall-plan' },
+          },
+        ],
+      }),
+    );
+    await platform.apply({
+      operations: [{ type: 'insert', entry: { id: 'user-entry', packageId: 'uninstall-plan' } }],
+    });
+    const authority = await internals(platform).store.read();
+    const desired = platform.desiredComposition();
+
+    await assert.rejects(() => platform.uninstallPackage('uninstall-plan'), /used by desired/u);
+    assert.deepEqual(await internals(platform).store.read(), authority);
+    assert.deepEqual(platform.desiredComposition(), desired);
+    assert.equal(platform.inspect('profile').length, 2);
+    await platform.close();
+  } finally {
+    await rm(root, { recursive: true, force: true });
+  }
+});
+
+test('package storage uninstall failure reports committed authority with pending cleanup', async () => {
+  const root = await mkdtemp(join(tmpdir(), 'maka-plugin-uninstall-rollback-'));
+  try {
+    const control = join(root, 'control');
+    const packages = new FailingUninstallPackageStore(control);
+    const platform = createPlatform(control, { packages });
+    await platform.recover();
+    await platform.installPackage(
+      await writeFixturePackage(root, 'uninstall-rollback', 'installed', {
+        composition: [
+          {
+            type: 'insert',
+            entry: { id: 'package-default', packageId: 'uninstall-rollback' },
+          },
+        ],
+      }),
+    );
+    packages.failUninstall = true;
+
+    const receipt = await platform.uninstallPackage('uninstall-rollback');
+    assert.equal(receipt.convergence, 'diverged');
+    assert.equal(receipt.cleanup, 'pending');
+    assert.match(receipt.failures[0]?.diagnostic ?? '', /injected package uninstall failure/u);
+
+    const authority = await internals(platform).store.read();
+    assert.deepEqual(authority?.packageLayers, []);
+    assert.deepEqual(platform.desiredComposition().roots.profile, []);
+    assert.deepEqual(internals(platform).composition.compositionState().roots.profile, []);
+    assert.deepEqual(await internals(platform).packages.identities(), ['uninstall-rollback']);
+    await platform.close();
+  } finally {
+    await rm(root, { recursive: true, force: true });
+  }
+});
+
+test('composition authority commits before Runtime convergence and exposes divergence', async () => {
+  const root = await mkdtemp(join(tmpdir(), 'maka-plugin-divergence-'));
+  try {
+    const platform = createPlatform(join(root, 'control'));
+    const coordinator = new HostPluginPlatformCoordinator(platform);
+    await platform.recover();
+    await platform.installPackage(
+      await writeFixturePackage(root, 'failing-package', 'failing', { throwOnApply: true }),
+    );
+
+    const receipt = await platform.apply({
+      operations: [
+        { type: 'insert', entry: { id: 'desired-failure', packageId: 'failing-package' } },
+      ],
+    });
+    assert.equal(receipt.durability, 'committed');
+    assert.equal(receipt.convergence, 'diverged');
+    assert.equal(platform.desiredComposition().roots.profile[0]?.id, 'desired-failure');
+    assert.deepEqual(internals(platform).composition.compositionState().roots.profile, []);
+    const queried = await coordinator.handlers['plugin.platform.query'](
+      { view: 'failures' },
+      null as never,
+    );
+    assert.equal(queried.ok, true);
+    if (queried.ok && queried.result.view === 'failures') {
+      assert.equal(queried.result.items[0]?.entryId, 'desired-failure');
+    }
+    await platform.close();
+  } finally {
+    await rm(root, { recursive: true, force: true });
+  }
+});
+
+test('recovery is fail-open for Host and isolates a broken desired Entry', async () => {
+  const root = await mkdtemp(join(tmpdir(), 'maka-plugin-partial-recovery-'));
+  try {
+    const control = join(root, 'control');
+    const initial = createPlatform(control);
+    await initial.recover();
+    await initial.installPackage(await writeFixturePackage(root, 'healthy-package', 'healthy'));
+    await initial.close();
+    await new HostPluginCompositionStore(control).replace({
+      schemaVersion: 1,
+      generation: 5,
+      packageLayers: [],
+      overlays: [
+        {
+          type: 'insert',
+          entry: { id: 'healthy-entry', packageId: 'healthy-package', config: {} },
+        },
+        {
+          type: 'insert',
+          entry: { id: 'broken-entry', packageId: 'missing-package', config: {} },
+        },
+      ],
+    });
+
+    const recovered = createPlatform(control);
+    await recovered.recover();
+    assert.equal(recovered.inspect('profile')[0]?.id, 'healthy-entry');
+    assert.equal(recovered.desiredComposition().generation, 5);
+    assert.deepEqual(
+      recovered.desiredComposition().roots.profile.map(({ id }) => id),
+      ['healthy-entry', 'broken-entry'],
+    );
+    assert.equal(
+      recovered.failures().some(({ entryId }) => entryId === 'broken-entry'),
+      true,
+    );
+    await recovered.close();
+  } finally {
+    await rm(root, { recursive: true, force: true });
+  }
+});
+
+test('corrupt Plugin authority fails closed locally without failing Host recovery', async () => {
+  const root = await mkdtemp(join(tmpdir(), 'maka-plugin-corrupt-authority-'));
+  try {
+    const control = join(root, 'control');
+    await mkdir(control, { recursive: true });
+    await writeFile(join(control, 'plugin-composition-v2.json'), '{not-json');
+    const platform = createPlatform(control);
+    const coordinator = new HostPluginPlatformCoordinator(platform);
+
+    await platform.recover();
+    const queried = await coordinator.handlers['plugin.platform.query'](
+      { view: 'status' },
+      null as never,
+    );
+    assert.equal(queried.ok, true);
+    if (queried.ok && queried.result.view === 'status') {
+      assert.equal(queried.result.phase, 'fenced');
+      assert.equal(queried.result.convergence, 'unknown');
+    }
+    await platform.close();
+  } finally {
+    await rm(root, { recursive: true, force: true });
+  }
+});
+
+test('a package that fails Runtime loading can still be uninstalled for repair', async () => {
+  const root = await mkdtemp(join(tmpdir(), 'maka-plugin-corrupt-package-removal-'));
+  try {
+    const control = join(root, 'control');
+    const source = await writeFixturePackage(root, 'broken-package', 'broken', {
+      runtimePackageId: 'wrong-package',
+    });
+    const prepared = await new PluginPackageStore(control).prepareInstall(source);
+    await prepared.publish(0, 1);
+    await prepared.commit();
+    const platform = createPlatform(control);
+    await platform.recover();
+    assert.equal(
+      platform.failures().some(({ extensionId }) => extensionId === 'broken-package'),
+      true,
+    );
+
+    await platform.uninstallPackage('broken-package');
+    assert.deepEqual(await internals(platform).packages.identities(), []);
+    assert.equal(
+      platform.failures().some(({ extensionId }) => extensionId === 'broken-package'),
+      false,
+    );
+    await platform.close();
+  } finally {
+    await rm(root, { recursive: true, force: true });
+  }
+});
+
+test('Manifest configuration is enforced before desired state is committed', async () => {
+  const root = await mkdtemp(join(tmpdir(), 'maka-plugin-config-contract-'));
+  try {
+    const platform = createPlatform(join(root, 'control'));
+    await platform.recover();
+    await platform.installPackage(
+      await writeFixturePackage(root, 'configured-package', 'configured', {
+        manifest: {
+          configuration: {
+            properties: { enabled: { type: 'boolean' } },
+            required: ['enabled'],
+          },
+        },
+      }),
+    );
+
+    await assert.rejects(
+      () =>
+        platform.apply({
+          operations: [
+            { type: 'insert', entry: { id: 'configured-entry', packageId: 'configured-package' } },
+          ],
+        }),
+      (error: unknown) =>
+        error instanceof Error &&
+        error.cause instanceof Error &&
+        /missing required key/u.test(error.cause.message),
+    );
+    assert.deepEqual(platform.desiredComposition().roots.profile, []);
+    assert.deepEqual(internals(platform).composition.compositionState().roots.profile, []);
+    await platform.close();
+  } finally {
+    await rm(root, { recursive: true, force: true });
+  }
+});
+
+test('Manifest configuration defaults are committed to desired and live Entries', async () => {
+  const root = await mkdtemp(join(tmpdir(), 'maka-plugin-config-defaults-'));
+  try {
+    const platform = createPlatform(join(root, 'control'));
+    await platform.recover();
+    await platform.installPackage(
+      await writeFixturePackage(root, 'defaulted-package', 'defaulted', {
+        manifest: {
+          configuration: {
+            properties: { enabled: { type: 'boolean', default: true } },
+          },
+        },
+      }),
+    );
+
+    await platform.apply({
+      operations: [
+        { type: 'insert', entry: { id: 'defaulted-entry', packageId: 'defaulted-package' } },
+      ],
+    });
+    assert.deepEqual(platform.desiredComposition().roots.profile[0]?.config, { enabled: true });
+    assert.deepEqual(internals(platform).composition.compositionState().roots.profile[0]?.config, {
+      enabled: true,
+    });
+    await platform.close();
+  } finally {
+    await rm(root, { recursive: true, force: true });
+  }
+});
+
+test('Manifest v1 rejects unsupported secret configuration metadata', async () => {
+  const root = await mkdtemp(join(tmpdir(), 'maka-plugin-config-secret-'));
+  try {
+    const platform = createPlatform(join(root, 'control'));
+    await platform.recover();
+    const source = await writeFixturePackage(root, 'secret-package', 'secret', {
+      manifest: {
+        configuration: {
+          properties: { token: { type: 'string', secret: true } },
+        },
+      },
+    });
+
+    await assert.rejects(() => platform.installPackage(source), /manifest fields are invalid/u);
+    assert.deepEqual(await internals(platform).packages.identities(), []);
+    await platform.close();
+  } finally {
+    await rm(root, { recursive: true, force: true });
+  }
+});
+
+test('Manifest configuration reads declared prototype-named keys as own values', async () => {
+  const root = await mkdtemp(join(tmpdir(), 'maka-plugin-config-prototype-'));
+  try {
+    const platform = createPlatform(join(root, 'control'));
+    await platform.recover();
+    await platform.installPackage(
+      await writeFixturePackage(root, 'prototype-config-package', 'prototype-config', {
+        manifest: {
+          configuration: {
+            properties: { constructor: { type: 'string' } },
+            required: ['constructor'],
+          },
+        },
+      }),
+    );
+
+    await platform.apply({
+      operations: [
+        {
+          type: 'insert',
+          entry: {
+            id: 'prototype-config-entry',
+            packageId: 'prototype-config-package',
+            config: { constructor: 'configured' },
+          },
+        },
+      ],
+    });
+    const config = platform.desiredComposition().roots.profile[0]?.config;
+    assert.equal(Object.hasOwn(config ?? {}, 'constructor'), true);
+    assert.equal(config?.constructor, 'configured');
+    await platform.close();
+  } finally {
+    await rm(root, { recursive: true, force: true });
+  }
+});
+
+test('Manifest dependencies gate activation and protect required packages', async () => {
+  const root = await mkdtemp(join(tmpdir(), 'maka-plugin-package-dependencies-'));
+  try {
+    const platform = createPlatform(join(root, 'control'));
+    await platform.recover();
+    await platform.installPackage(
+      await writeFixturePackage(root, 'dependent-package', 'dependent', {
+        manifest: { dependencies: [{ id: 'required-package' }] },
+      }),
+    );
+    await assert.rejects(
+      () =>
+        platform.apply({
+          operations: [
+            { type: 'insert', entry: { id: 'dependent-entry', packageId: 'dependent-package' } },
+          ],
+        }),
+      /Plugin composition mutation failed/u,
+    );
+    assert.deepEqual(platform.desiredComposition().roots.profile, []);
+
+    await platform.installPackage(await writeFixturePackage(root, 'required-package', 'required'));
+    await platform.apply({
+      operations: [
+        { type: 'insert', entry: { id: 'required-entry', packageId: 'required-package' } },
+        { type: 'insert', entry: { id: 'dependent-entry', packageId: 'dependent-package' } },
+      ],
+    });
+    await assert.rejects(
+      () =>
+        platform.apply({
+          operations: [{ type: 'remove', entryId: 'required-entry' }],
+        }),
+      /Plugin composition mutation failed/u,
+    );
+    await platform.close();
+  } finally {
+    await rm(root, { recursive: true, force: true });
+  }
+});
+
+test('package storage recovers every base-generation install and rollback boundary', async () => {
+  const cases = [
+    {
+      name: 'journal synced before publication',
+      target: 'old',
+      candidate: 'new',
+    },
+    {
+      name: 'previous moved out of target',
+      previous: 'old',
+      candidate: 'new',
+    },
+    {
+      name: 'candidate published before authority commit',
+      target: 'new',
+      previous: 'old',
+    },
+    {
+      name: 'rollback rejected the candidate',
+      previous: 'old',
+      rejected: 'new',
+    },
+    {
+      name: 'rollback restored the previous Package',
+      target: 'old',
+      rejected: 'new',
+    },
+    {
+      name: 'rollback returned the candidate to staging',
+      target: 'old',
+      candidate: 'new',
+    },
+  ] as const;
+  for (const state of cases) {
+    const root = await mkdtemp(join(tmpdir(), 'maka-plugin-package-recovery-'));
+    try {
+      const { store, transaction, target } = await writeInstallRecoveryState(root, state);
+      await store.recover(7);
+      assert.equal(await readPackageMarker(target), 'old', state.name);
+      await assert.rejects(() => readdir(transaction), isEnoent, state.name);
+    } finally {
+      await rm(root, { recursive: true, force: true });
+    }
+  }
+});
+
+test('package storage removes a fresh install at every base-generation boundary', async () => {
+  const cases = [
+    { name: 'prepared', candidate: 'new' },
+    { name: 'published', target: 'new' },
+    { name: 'rollback started', rejected: 'new' },
+    { name: 'rollback completed', candidate: 'new' },
+  ] as const;
+  for (const state of cases) {
+    const root = await mkdtemp(join(tmpdir(), 'maka-plugin-package-fresh-recovery-'));
+    try {
+      const { store, transaction, target } = await writeInstallRecoveryState(root, state);
+      await store.recover(7);
+      await assert.rejects(() => readdir(target), isEnoent, state.name);
+      await assert.rejects(() => readdir(transaction), isEnoent, state.name);
+    } finally {
+      await rm(root, { recursive: true, force: true });
+    }
+  }
+});
+
+test('package storage retains a Package committed by the authority generation', async () => {
+  const root = await mkdtemp(join(tmpdir(), 'maka-plugin-package-committed-recovery-'));
+  try {
+    const { store, transaction, target } = await writeInstallRecoveryState(root, {
+      target: 'new',
+      previous: 'old',
+    });
+    await store.recover(8);
+    assert.equal(await readPackageMarker(target), 'new');
+    await assert.rejects(() => readdir(transaction), isEnoent);
+  } finally {
+    await rm(root, { recursive: true, force: true });
+  }
+});
+
+test('package storage discards journal-less transaction remnants', async () => {
+  const cases = [
+    { name: 'abandoned preparation', target: 'old', candidate: 'new' },
+    { name: 'partially removed committed transaction', target: 'new', previous: 'old' },
+  ] as const;
+  for (const state of cases) {
+    const root = await mkdtemp(join(tmpdir(), 'maka-plugin-package-journal-less-'));
+    try {
+      const { store, transaction, target } = await writeInstallRecoveryState(root, state, false);
+      await store.recover(state.target === 'new' ? 8 : 7);
+      assert.equal(await readPackageMarker(target), state.target, state.name);
+      await assert.rejects(() => readdir(transaction), isEnoent, state.name);
+    } finally {
+      await rm(root, { recursive: true, force: true });
+    }
+  }
+});
+
+test('package storage still fences a corrupt install journal', async () => {
+  const root = await mkdtemp(join(tmpdir(), 'maka-plugin-package-corrupt-journal-'));
+  try {
+    const { store, transaction } = await writeInstallRecoveryState(root, {
+      target: 'old',
+      candidate: 'new',
+    });
+    await writeFile(join(transaction, 'transaction.json'), '{invalid');
+    await assert.rejects(
+      () => store.recover(7),
+      /Unable to read Plugin package install transaction/u,
+    );
+  } finally {
+    await rm(root, { recursive: true, force: true });
+  }
+});
+
+test('Plugin Platform close aggregates every resource failure', async () => {
+  const root = await mkdtemp(join(tmpdir(), 'maka-plugin-close-'));
+  try {
+    const control = join(root, 'control');
+    const packages = new PluginPackageStore(control);
+    const composition = new FailingCloseCompositionLoader();
+    const packageLoader = new FailingClosePackageLoader(control, packages);
+    const platform = createPlatform(control, { composition, packages, packageLoader });
+    await platform.recover();
+    await assert.rejects(
+      () => platform.close(),
+      (error: unknown) => error instanceof AggregateError && error.errors.length === 2,
+    );
+    assert.equal(composition.closeAttempted, true);
+    assert.equal(packageLoader.closeAttempted, true);
+  } finally {
+    await rm(root, { recursive: true, force: true });
+  }
+});
+
+interface InstallRecoveryState {
+  readonly target?: string;
+  readonly candidate?: string;
+  readonly previous?: string;
+  readonly rejected?: string;
+}
+
+async function writeInstallRecoveryState(
+  root: string,
+  state: InstallRecoveryState,
+  journal = true,
+): Promise<{
+  readonly store: PluginPackageStore;
+  readonly transaction: string;
+  readonly target: string;
+}> {
+  const store = new PluginPackageStore(join(root, 'control'));
+  const transaction = join(store.root, '.install-owner-death');
+  const target = join(store.root, 'recover-package');
+  await mkdir(transaction, { recursive: true });
+  if (journal) {
+    await writeFile(
+      join(transaction, 'transaction.json'),
+      `${JSON.stringify({
+        schemaVersion: 1,
+        extensionId: 'recover-package',
+        baseGeneration: 7,
+        nextGeneration: 8,
+      })}\n`,
+    );
+  }
+  for (const name of ['target', 'candidate', 'previous', 'rejected'] as const) {
+    const marker = state[name];
+    if (marker === undefined) continue;
+    const directory = name === 'target' ? target : join(transaction, name);
+    await mkdir(directory, { recursive: true });
+    await writeFile(join(directory, 'marker'), marker);
+  }
+  return { store, transaction, target };
+}
+
+async function readPackageMarker(root: string): Promise<string> {
+  return await readFile(join(root, 'marker'), 'utf8');
+}
+
+function isEnoent(error: unknown): boolean {
+  return (error as NodeJS.ErrnoException).code === 'ENOENT';
+}
+
+async function writeFixturePackage(
+  root: string,
+  packageId: string,
+  contributionId: string,
+  options: {
+    readonly runtimePackageId?: string;
+    readonly directorySuffix?: string;
+    readonly throwOnApply?: boolean;
+    readonly provideService?: string;
+    readonly structuralDependencies?: readonly string[];
+    readonly manifest?: Readonly<Record<string, unknown>>;
+    readonly composition?: readonly unknown[];
+  } = {},
+): Promise<string> {
+  const source = join(
+    root,
+    `source-${packageId}${options.directorySuffix ? `-${options.directorySuffix}` : ''}`,
+  );
+  await mkdir(source, { recursive: true });
+  await writeFile(
+    join(source, 'maka.extension.json'),
+    JSON.stringify({
+      schemaVersion: 1,
+      id: packageId,
+      runtime: { entry: 'index.mjs' },
+      ...(options.composition
+        ? {
+            composition: {
+              patch: 'maka.composition.yml',
+              structuralDependencies: options.structuralDependencies ?? [],
+            },
+          }
+        : {}),
+      ...(options.manifest ?? {}),
+    }),
+  );
+  if (options.composition) {
+    await writeFile(join(source, 'maka.composition.yml'), JSON.stringify(options.composition));
+  }
+  await writeFile(
+    join(source, 'index.mjs'),
+    `export default Object.freeze({
+      packageId: ${JSON.stringify(options.runtimePackageId ?? packageId)},
+      contributions: Object.freeze([{ id: ${JSON.stringify(contributionId)}, kind: 'foundation-test' }]),
+      host: Object.freeze({ apply(ctx) {
+        ${options.throwOnApply ? "throw new Error('fixture activation failed');" : ''}
+        ${options.provideService ? `ctx.provide(${JSON.stringify(options.provideService)}, { source: ${JSON.stringify(contributionId)} });` : ''}
+        ctx.effect(() => () => undefined, 'fixture');
+      } }),
+    });\n`,
+  );
+  return source;
+}
+
+class FailingCompositionStore extends HostPluginCompositionStore {
+  fail = false;
+
+  override async replace(state: PersistedPluginComposition): Promise<void> {
+    if (this.fail) throw new Error('injected persistence failure');
+    await super.replace(state);
+  }
+}
+
+class FailingUninstallPackageStore extends PluginPackageStore {
+  failUninstall = false;
+
+  override async uninstall(extensionId: string): Promise<void> {
+    if (this.failUninstall) throw new Error('injected package uninstall failure');
+    await super.uninstall(extensionId);
+  }
+}
+
+class FailingCandidatePublishPackageStore extends PluginPackageStore {
+  failNextCandidatePublication = false;
+
+  protected override async publishCandidate(staging: string, target: string): Promise<void> {
+    if (this.failNextCandidatePublication) {
+      this.failNextCandidatePublication = false;
+      throw new Error('injected candidate publication failure');
+    }
+    await super.publishCandidate(staging, target);
+  }
+}
+
+class TransientRecoveryPackageStore extends PluginPackageStore {
+  recoverCalls = 0;
+
+  override async recover(authorityGeneration = 0): Promise<void> {
+    this.recoverCalls += 1;
+    if (this.recoverCalls === 2) throw new Error('injected transient recovery failure');
+    await super.recover(authorityGeneration);
+  }
+}
+
+class FailOncePackageLoader extends TrustedPluginPackageLoader {
+  loadCalls = 0;
+
+  override async load(extensionId: string) {
+    this.loadCalls += 1;
+    if (this.loadCalls === 1) throw new Error('injected initial package load failure');
+    return await super.load(extensionId);
+  }
+}
+
+class UnknownCommitCompositionStore extends HostPluginCompositionStore {
+  fail = false;
+
+  override async replace(state: PersistedPluginComposition): Promise<void> {
+    if (this.fail) {
+      throw new HostPluginCompositionStoreError(
+        'commit_outcome_unknown',
+        'injected unknown commit outcome',
+      );
+    }
+    await super.replace(state);
+  }
+}
+
+class AmbiguousCompositionStore extends HostPluginCompositionStore {
+  mode: 'before' | 'after' | undefined;
+
+  override async replace(state: PersistedPluginComposition): Promise<void> {
+    const mode = this.mode;
+    this.mode = undefined;
+    if (mode === 'before') {
+      throw new HostPluginCompositionStoreError(
+        'commit_outcome_unknown',
+        'injected unknown commit before authority publication',
+      );
+    }
+    await super.replace(state);
+    if (mode === 'after') {
+      throw new HostPluginCompositionStoreError(
+        'commit_outcome_unknown',
+        'injected unknown commit after authority publication',
+      );
+    }
+  }
+}
+
+class DeferredUnknownCompositionStore extends HostPluginCompositionStore {
+  fail = false;
+  readonly entered: Promise<void>;
+  readonly #signalEntered: () => void;
+  readonly #gate: Promise<void>;
+  readonly #release: () => void;
+
+  constructor(controlDirectory: string) {
+    super(controlDirectory);
+    let signalEntered!: () => void;
+    let release!: () => void;
+    this.entered = new Promise<void>((resolve) => {
+      signalEntered = resolve;
+    });
+    this.#gate = new Promise<void>((resolve) => {
+      release = resolve;
+    });
+    this.#signalEntered = signalEntered;
+    this.#release = release;
+  }
+
+  release(): void {
+    this.#release();
+  }
+
+  override async replace(state: PersistedPluginComposition): Promise<void> {
+    if (!this.fail) return await super.replace(state);
+    this.#signalEntered();
+    await this.#gate;
+    throw new HostPluginCompositionStoreError(
+      'commit_outcome_unknown',
+      'injected deferred unknown commit outcome',
+    );
+  }
+}
+
+class FailingCloseCompositionLoader extends MakaCompositionLoader {
+  closeAttempted = false;
+
+  override async close(): Promise<void> {
+    this.closeAttempted = true;
+    throw new Error('injected composition close failure');
+  }
+}
+
+class FailingClosePackageLoader extends TrustedPluginPackageLoader {
+  closeAttempted = false;
+
+  override async close(): Promise<void> {
+    this.closeAttempted = true;
+    throw new Error('injected package loader close failure');
+  }
+}
diff --git a/packages/runtime-host/src/protocol/index.ts b/packages/runtime-host/src/protocol/index.ts
index 34e8139bb0..2d3d3237b5 100644
--- a/packages/runtime-host/src/protocol/index.ts
+++ b/packages/runtime-host/src/protocol/index.ts
@@ -95,7 +95,9 @@ export const RUNTIME_HOST_REGISTRATION_SCHEMA_VERSION = 1 as const;
 export const RUNTIME_HOST_PROTOCOL_VERSION = 0 as const;
 // Increment when the same protocol version no longer guarantees safe Client-Host
 // interoperability. Mismatches are rejected before domain commands are admitted.
-export const RUNTIME_HOST_COMPATIBILITY_EPOCH = 84 as const;
+export const RUNTIME_HOST_COMPATIBILITY_EPOCH = 85 as const;
+// 85: Plugin package and Entry composition operations become Host-owned protocol
+// surfaces. Older peers cannot safely exchange these strict operation shapes.
 // 84: Message content carries Host-bound directory references. Older peers
 // reject this field and cannot preserve its identity through admission/replay.
 // 83: WorkHub Coordination actions add linked replacement proposals,
diff --git a/packages/runtime-host/src/protocol/operation-spec.ts b/packages/runtime-host/src/protocol/operation-spec.ts
index 6371f1dfa8..7b85f061a4 100644
--- a/packages/runtime-host/src/protocol/operation-spec.ts
+++ b/packages/runtime-host/src/protocol/operation-spec.ts
@@ -32,6 +32,7 @@ export type HostOperationErrorCode =
   | 'capability_unavailable'
   | 'invalid_request'
   | 'projection_incomplete'
+  | 'stale_cursor'
   | 'persistence_failed'
   | 'commit_outcome_unknown'
   | 'already_resolved'
diff --git a/packages/runtime-host/src/protocol/operations.ts b/packages/runtime-host/src/protocol/operations.ts
index fb497a1cd3..1f6f900805 100644
--- a/packages/runtime-host/src/protocol/operations.ts
+++ b/packages/runtime-host/src/protocol/operations.ts
@@ -40,6 +40,7 @@ import { NETWORK_PROXY_OPERATION_SPECS } from './network-proxy.js';
 import { OAUTH_OPERATION_SPECS } from './oauth.js';
 import { PLAN_OPERATION_SPECS } from './plan.js';
 import { PEER_MESH_OPERATION_SPECS } from './peer-mesh.js';
+import { PLUGIN_PLATFORM_OPERATION_SPECS } from './plugin-platform.js';
 import { PROJECT_CATALOG_OPERATION_SPECS } from './project-catalog.js';
 import {
   composeOperationSpecMaps,
@@ -162,6 +163,7 @@ export * from './memory.js';
 export * from './network-proxy.js';
 export * from './oauth.js';
 export * from './plan.js';
+export * from './plugin-platform.js';
 export * from './project-catalog.js';
 export * from './runtime-policy.js';
 export * from './runtime-resource.js';
@@ -219,6 +221,7 @@ export const HOST_OPERATION_SPECS = composeOperationSpecMaps(
   NETWORK_PROXY_OPERATION_SPECS,
   CONFIGURATION_OPERATION_SPECS,
   WORKHUB_COORDINATION_OPERATION_SPECS,
+  PLUGIN_PLATFORM_OPERATION_SPECS,
 );
 
 export type OperationSpecMap = typeof HOST_OPERATION_SPECS;
diff --git a/packages/runtime-host/src/protocol/plugin-platform.ts b/packages/runtime-host/src/protocol/plugin-platform.ts
new file mode 100644
index 0000000000..2a0620e1e7
--- /dev/null
+++ b/packages/runtime-host/src/protocol/plugin-platform.ts
@@ -0,0 +1,744 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import {
+  validateCompositionEntry,
+  validatePluginRootId,
+  type MakaCompositionApplyInput,
+  type MakaCompositionEntry,
+  type MakaCompositionEntryInspection,
+  type MakaCompositionOperation,
+  type MakaPluginRootId,
+} from '@maka/runtime/plugin-runtime';
+import {
+  requireCount,
+  requireEncodedByteLimit,
+  requireExactRecord,
+  requireId,
+  requireRecord,
+  requireShapedRecord,
+  requireString,
+} from './codec.js';
+import { invalidProtocolFrame } from './errors.js';
+import { defineHostPathOperation, defineOperation } from './operation-spec.js';
+
+const QUERY_ERRORS = [
+  'host_not_ready',
+  'host_draining',
+  'operation_unavailable',
+  'invalid_request',
+  'persistence_failed',
+  'internal_failure',
+  'stale_cursor',
+] as const;
+const MUTATE_ERRORS = [
+  ...QUERY_ERRORS,
+  'not_found',
+  'operation_conflict',
+  'commit_outcome_unknown',
+] as const;
+const MAX_FRAME_BYTES = 512 * 1024;
+export const PLUGIN_PLATFORM_QUERY_RESULT_MAX_BYTES = 480 * 1024;
+
+export type PluginPlatformPhase =
+  | 'new'
+  | 'recovering'
+  | 'ready'
+  | 'degraded'
+  | 'fenced'
+  | 'draining'
+  | 'closed';
+
+export type PluginPlatformConvergence = 'unknown' | 'converged' | 'diverged';
+
+export interface PluginMutationReceipt {
+  readonly authorityEpoch: number;
+  readonly durability: 'committed';
+  readonly convergence: Exclude<PluginPlatformConvergence, 'unknown'>;
+  readonly cleanup: 'complete' | 'pending';
+  readonly failures: readonly PluginPlatformFailureProjection[];
+}
+
+export interface PluginPackageProjection {
+  readonly extensionId: string;
+  readonly contentDigest: string;
+  readonly displayName: string;
+  readonly description?: string;
+  readonly dependencies: readonly string[];
+  readonly structuralDependencies: readonly string[];
+  readonly requiredBy: readonly string[];
+}
+
+export interface PluginPlatformQueryInput {
+  readonly view: 'status' | 'packages' | 'entries' | 'failures';
+  readonly rootId?: MakaPluginRootId;
+  readonly cursor?: string;
+  readonly limit?: number;
+}
+
+export type PluginPlatformQueryResult =
+  | {
+      readonly view: 'status';
+      readonly phase: PluginPlatformPhase;
+      readonly authorityEpoch: number;
+      readonly convergence: PluginPlatformConvergence;
+      readonly installedPackageCount: number;
+      readonly layeredPackageCount: number;
+      readonly desiredEntryCount: number;
+      readonly liveEntryCount: number;
+      readonly failureCount: number;
+      readonly fenceDiagnostic: string | null;
+    }
+  | {
+      readonly view: 'packages';
+      readonly items: readonly PluginPackageProjection[];
+      readonly nextCursor: string | null;
+    }
+  | {
+      readonly view: 'entries';
+      readonly items: readonly MakaCompositionEntryInspection[];
+      readonly nextCursor: string | null;
+    }
+  | {
+      readonly view: 'failures';
+      readonly items: readonly PluginPlatformFailureProjection[];
+      readonly nextCursor: string | null;
+    };
+
+export interface PluginPlatformFailureProjection {
+  readonly entryId?: string;
+  readonly extensionId?: string;
+  readonly diagnostic: string;
+}
+
+export interface PluginPackageInstallInput {
+  readonly sourcePath: string;
+}
+
+export interface PluginPackageInstallResult extends PluginMutationReceipt {
+  readonly extensionId: string;
+}
+
+export interface PluginPackageUninstallInput {
+  readonly extensionId: string;
+}
+
+export interface PluginPackageExportInput extends PluginPackageUninstallInput {
+  readonly targetPath: string;
+}
+
+export interface PluginPackageExportResult {
+  readonly targetPath: string;
+}
+
+export type PluginPackageMutationResult = PluginMutationReceipt;
+export type PluginCompositionApplyResult = PluginMutationReceipt;
+
+export const PLUGIN_PLATFORM_OPERATION_SPECS = {
+  'plugin.platform.query': defineOperation<
+    PluginPlatformQueryInput,
+    PluginPlatformQueryResult,
+    (typeof QUERY_ERRORS)[number]
+  >({
+    mode: 'query',
+    availability: 'ready',
+    errors: QUERY_ERRORS,
+    decodeInput: decodePluginPlatformQueryInput,
+    decodeOutput: decodePluginPlatformQueryResult,
+  }),
+  'plugin.package.install': defineHostPathOperation<
+    PluginPackageInstallInput,
+    PluginPackageInstallResult,
+    (typeof MUTATE_ERRORS)[number]
+  >({
+    mode: 'command',
+    availability: 'ready',
+    errors: MUTATE_ERRORS,
+    decodeInput: (value) => {
+      const input = requireExactRecord(value, 'Plugin package install input', ['sourcePath']);
+      return { sourcePath: requireString(input.sourcePath, 'Plugin package source path', 4096) };
+    },
+    decodeOutput: decodePluginPackageInstallResult,
+  }),
+  'plugin.package.uninstall': defineOperation<
+    PluginPackageUninstallInput,
+    PluginPackageMutationResult,
+    (typeof MUTATE_ERRORS)[number]
+  >({
+    mode: 'command',
+    availability: 'ready',
+    errors: MUTATE_ERRORS,
+    decodeInput: decodePluginPackageUninstallInput,
+    decodeOutput: decodePluginMutationReceipt,
+  }),
+  'plugin.package.reload': defineOperation<
+    PluginPackageUninstallInput,
+    PluginPackageMutationResult,
+    (typeof MUTATE_ERRORS)[number]
+  >({
+    mode: 'command',
+    availability: 'ready',
+    errors: MUTATE_ERRORS,
+    decodeInput: decodePluginPackageUninstallInput,
+    decodeOutput: decodePluginMutationReceipt,
+  }),
+  'plugin.package.export': defineHostPathOperation<
+    PluginPackageExportInput,
+    PluginPackageExportResult,
+    (typeof MUTATE_ERRORS)[number]
+  >({
+    mode: 'command',
+    availability: 'ready',
+    errors: MUTATE_ERRORS,
+    decodeInput: (value) => {
+      const input = requireExactRecord(value, 'Plugin package export input', [
+        'extensionId',
+        'targetPath',
+      ]);
+      return {
+        extensionId: requireId(input.extensionId, 'Plugin package identity'),
+        targetPath: requireString(input.targetPath, 'Plugin package export path', 4096),
+      };
+    },
+    decodeOutput: (value) => {
+      const output = requireExactRecord(value, 'Plugin package export result', ['targetPath']);
+      return { targetPath: requireString(output.targetPath, 'Plugin package export path', 4096) };
+    },
+  }),
+  'plugin.composition.apply': defineOperation<
+    MakaCompositionApplyInput,
+    PluginCompositionApplyResult,
+    (typeof MUTATE_ERRORS)[number]
+  >({
+    mode: 'command',
+    availability: 'ready',
+    errors: MUTATE_ERRORS,
+    decodeInput: decodePluginCompositionApplyInput,
+    decodeOutput: decodePluginMutationReceipt,
+  }),
+  'plugin.platform.reconcile': defineOperation<
+    Record<string, never>,
+    PluginMutationReceipt,
+    (typeof MUTATE_ERRORS)[number]
+  >({
+    mode: 'command',
+    availability: 'ready',
+    errors: MUTATE_ERRORS,
+    decodeInput: (value) => {
+      requireExactRecord(value, 'Plugin Platform reconcile input', []);
+      return {};
+    },
+    decodeOutput: decodePluginMutationReceipt,
+  }),
+} as const;
+
+function decodePluginPlatformQueryInput(value: unknown): PluginPlatformQueryInput {
+  const input = requireShapedRecord(
+    value,
+    'Plugin Platform query input',
+    ['view'],
+    ['rootId', 'cursor', 'limit'],
+  );
+  if (!['status', 'packages', 'entries', 'failures'].includes(input.view as string)) {
+    throw invalidProtocolFrame('Invalid Plugin Platform query view');
+  }
+  const view = input.view as PluginPlatformQueryInput['view'];
+  const cursor =
+    input.cursor === undefined
+      ? undefined
+      : requireString(input.cursor, 'Plugin Platform query cursor', 4096);
+  const limit =
+    input.limit === undefined
+      ? undefined
+      : requireCount(input.limit, 'Plugin Platform query limit');
+  if (limit !== undefined && (limit < 1 || limit > 64)) {
+    throw invalidProtocolFrame('Invalid Plugin Platform query limit');
+  }
+  if (
+    view === 'status' &&
+    (input.rootId !== undefined || cursor !== undefined || limit !== undefined)
+  ) {
+    throw invalidProtocolFrame('Plugin Platform status query does not accept paging');
+  }
+  if (input.rootId !== undefined && view !== 'entries') {
+    throw invalidProtocolFrame('Plugin root identity is only valid for Entry queries');
+  }
+  let rootId: MakaPluginRootId | undefined;
+  if (input.rootId !== undefined) {
+    const decoded = requireString(input.rootId, 'Plugin root identity', 256);
+    try {
+      validatePluginRootId(decoded);
+      rootId = decoded;
+    } catch {
+      throw invalidProtocolFrame('Invalid Plugin root identity');
+    }
+  }
+  return {
+    view,
+    ...(rootId ? { rootId } : {}),
+    ...(cursor === undefined ? {} : { cursor }),
+    ...(limit === undefined ? {} : { limit }),
+  };
+}
+
+function decodePluginPlatformQueryResult(value: unknown): PluginPlatformQueryResult {
+  const record = requireRecord(value, 'Plugin Platform query result');
+  const view = record.view;
+  let decoded: PluginPlatformQueryResult;
+  if (view === 'status') {
+    const output = requireExactRecord(record, 'Plugin Platform status result', [
+      'view',
+      'phase',
+      'authorityEpoch',
+      'convergence',
+      'installedPackageCount',
+      'layeredPackageCount',
+      'desiredEntryCount',
+      'liveEntryCount',
+      'failureCount',
+      'fenceDiagnostic',
+    ]);
+    if (
+      !['new', 'recovering', 'ready', 'degraded', 'fenced', 'draining', 'closed'].includes(
+        output.phase as string,
+      ) ||
+      !['unknown', 'converged', 'diverged'].includes(output.convergence as string)
+    ) {
+      throw invalidProtocolFrame('Invalid Plugin Platform status');
+    }
+    decoded = {
+      view,
+      phase: output.phase as PluginPlatformPhase,
+      authorityEpoch: requireCount(output.authorityEpoch, 'Plugin authority epoch'),
+      convergence: output.convergence as PluginPlatformConvergence,
+      installedPackageCount: requireCount(
+        output.installedPackageCount,
+        'Installed Plugin package count',
+      ),
+      layeredPackageCount: requireCount(output.layeredPackageCount, 'Layered Plugin package count'),
+      desiredEntryCount: requireCount(output.desiredEntryCount, 'Desired Plugin Entry count'),
+      liveEntryCount: requireCount(output.liveEntryCount, 'Live Plugin Entry count'),
+      failureCount: requireCount(output.failureCount, 'Plugin failure count'),
+      fenceDiagnostic:
+        output.fenceDiagnostic === null
+          ? null
+          : requireString(output.fenceDiagnostic, 'Plugin fence diagnostic', 4096),
+    };
+  } else {
+    const output = requireExactRecord(record, 'Plugin Platform page result', [
+      'view',
+      'items',
+      'nextCursor',
+    ]);
+    if (
+      !Array.isArray(output.items) ||
+      output.items.length > 64 ||
+      !['packages', 'entries', 'failures'].includes(view as string)
+    ) {
+      throw invalidProtocolFrame('Invalid Plugin Platform page');
+    }
+    const nextCursor =
+      output.nextCursor === null
+        ? null
+        : requireString(output.nextCursor, 'Plugin Platform next cursor', 4096);
+    decoded =
+      view === 'packages'
+        ? { view, items: output.items.map(decodePackageProjection), nextCursor }
+        : view === 'entries'
+          ? { view, items: decodeInspections(output.items), nextCursor }
+          : { view: 'failures', items: output.items.map(decodePlatformFailure), nextCursor };
+  }
+  requireEncodedByteLimit(
+    decoded,
+    'Plugin Platform query result',
+    PLUGIN_PLATFORM_QUERY_RESULT_MAX_BYTES,
+  );
+  return decoded;
+}
+
+function decodePlatformFailure(value: unknown): PluginPlatformFailureProjection {
+  const failure = requireShapedRecord(
+    value,
+    'Plugin Platform failure',
+    ['diagnostic'],
+    ['entryId', 'extensionId'],
+  );
+  if (failure.entryId === undefined && failure.extensionId === undefined) {
+    throw invalidProtocolFrame('Plugin Platform failure has no identity');
+  }
+  return {
+    ...(failure.entryId === undefined
+      ? {}
+      : { entryId: requireId(failure.entryId, 'Plugin Entry identity') }),
+    ...(failure.extensionId === undefined
+      ? {}
+      : { extensionId: requireId(failure.extensionId, 'Plugin package identity') }),
+    diagnostic: requireString(failure.diagnostic, 'Plugin Platform diagnostic', 4096),
+  };
+}
+
+function decodePackageProjection(value: unknown): PluginPackageProjection {
+  const item = requireShapedRecord(
+    value,
+    'Plugin package projection',
+    [
+      'extensionId',
+      'contentDigest',
+      'displayName',
+      'dependencies',
+      'structuralDependencies',
+      'requiredBy',
+    ],
+    ['description'],
+  );
+  if (
+    !Array.isArray(item.dependencies) ||
+    !Array.isArray(item.structuralDependencies) ||
+    !Array.isArray(item.requiredBy)
+  ) {
+    throw invalidProtocolFrame('Invalid Plugin dependencies');
+  }
+  return {
+    extensionId: requireId(item.extensionId, 'Plugin package identity'),
+    contentDigest: requireDigest(item.contentDigest, 'Plugin package content digest'),
+    displayName: requireString(item.displayName, 'Plugin display name', 512),
+    ...(item.description === undefined
+      ? {}
+      : { description: requireString(item.description, 'Plugin description', 4096) }),
+    dependencies: item.dependencies.map((dependency) =>
+      requireId(dependency, 'Plugin dependency identity'),
+    ),
+    structuralDependencies: item.structuralDependencies.map((dependency) =>
+      requireId(dependency, 'Plugin structural dependency identity'),
+    ),
+    requiredBy: item.requiredBy.map((dependency) =>
+      requireId(dependency, 'Plugin dependent identity'),
+    ),
+  };
+}
+
+function decodePluginPackageInstallResult(value: unknown): PluginPackageInstallResult {
+  const output = requireExactRecord(value, 'Plugin package install result', [
+    'extensionId',
+    'authorityEpoch',
+    'durability',
+    'convergence',
+    'cleanup',
+    'failures',
+  ]);
+  const receipt = decodePluginMutationReceipt({
+    authorityEpoch: output.authorityEpoch,
+    durability: output.durability,
+    convergence: output.convergence,
+    cleanup: output.cleanup,
+    failures: output.failures,
+  });
+  return {
+    extensionId: requireId(output.extensionId, 'Plugin package identity'),
+    ...receipt,
+  };
+}
+
+function decodePluginMutationReceipt(value: unknown): PluginMutationReceipt {
+  const output = requireExactRecord(value, 'Plugin mutation receipt', [
+    'authorityEpoch',
+    'durability',
+    'convergence',
+    'cleanup',
+    'failures',
+  ]);
+  if (
+    output.durability !== 'committed' ||
+    !['converged', 'diverged'].includes(output.convergence as string) ||
+    !['complete', 'pending'].includes(output.cleanup as string) ||
+    !Array.isArray(output.failures)
+  ) {
+    throw invalidProtocolFrame('Invalid Plugin mutation receipt');
+  }
+  return {
+    authorityEpoch: requireCount(output.authorityEpoch, 'Plugin authority epoch'),
+    durability: 'committed',
+    convergence: output.convergence as PluginMutationReceipt['convergence'],
+    cleanup: output.cleanup as PluginMutationReceipt['cleanup'],
+    failures: output.failures.map(decodePlatformFailure),
+  };
+}
+
+function decodePluginPackageUninstallInput(value: unknown): PluginPackageUninstallInput {
+  const input = requireExactRecord(value, 'Plugin package uninstall input', ['extensionId']);
+  return { extensionId: requireId(input.extensionId, 'Plugin package identity') };
+}
+
+export function decodePluginCompositionApplyInput(
+  value: unknown,
+  maxBytes = MAX_FRAME_BYTES,
+): MakaCompositionApplyInput {
+  const input = requireShapedRecord(
+    value,
+    'Plugin composition apply input',
+    ['operations'],
+    ['baseGeneration'],
+  );
+  if (!Array.isArray(input.operations) || input.operations.length === 0) {
+    throw invalidProtocolFrame('Invalid Plugin composition operations');
+  }
+  const decoded = {
+    ...(input.baseGeneration === undefined
+      ? {}
+      : { baseGeneration: requireCount(input.baseGeneration, 'Plugin composition generation') }),
+    operations: input.operations.map(decodeCompositionOperation),
+  };
+  requireEncodedByteLimit(decoded, 'Plugin composition apply input', maxBytes);
+  return decoded;
+}
+
+function decodeCompositionOperation(value: unknown): MakaCompositionOperation {
+  const operation = requireRecord(value, 'Plugin composition operation');
+  switch (operation.type) {
+    case 'insert': {
+      const input = requireShapedRecord(
+        operation,
+        'Plugin insert operation',
+        ['type', 'entry'],
+        ['rootId', 'parentId', 'position'],
+      );
+      return {
+        type: 'insert',
+        ...(input.rootId === undefined ? {} : { rootId: decodeRootId(input.rootId) }),
+        ...(input.parentId === undefined
+          ? {}
+          : { parentId: requireId(input.parentId, 'Plugin parent Entry identity') }),
+        entry: decodeCompositionEntry(input.entry),
+        ...(input.position === undefined
+          ? {}
+          : { position: requireCount(input.position, 'Plugin Entry position') }),
+      };
+    }
+    case 'update': {
+      const input = requireExactRecord(operation, 'Plugin update operation', [
+        'type',
+        'entryId',
+        'patch',
+      ]);
+      return {
+        type: 'update',
+        entryId: requireId(input.entryId, 'Plugin Entry identity'),
+        patch: decodeEntryPatch(input.patch),
+      };
+    }
+    case 'move': {
+      const input = requireShapedRecord(
+        operation,
+        'Plugin move operation',
+        ['type', 'entryId'],
+        ['parentId', 'position'],
+      );
+      return {
+        type: 'move',
+        entryId: requireId(input.entryId, 'Plugin Entry identity'),
+        ...(input.parentId === undefined
+          ? {}
+          : { parentId: requireId(input.parentId, 'Plugin parent Entry identity') }),
+        ...(input.position === undefined
+          ? {}
+          : { position: requireCount(input.position, 'Plugin Entry position') }),
+      };
+    }
+    case 'remove': {
+      const input = requireExactRecord(operation, 'Plugin remove operation', ['type', 'entryId']);
+      return { type: 'remove', entryId: requireId(input.entryId, 'Plugin Entry identity') };
+    }
+    default:
+      throw invalidProtocolFrame('Invalid Plugin composition operation type');
+  }
+}
+
+function decodeCompositionEntry(value: unknown): MakaCompositionEntry {
+  const entry = requireShapedRecord(
+    value,
+    'Plugin composition Entry',
+    ['id'],
+    ['packageId', 'config', 'disabled', 'inject', 'isolate', 'intercept', 'children'],
+  );
+  const decoded: MakaCompositionEntry = {
+    id: requireId(entry.id, 'Plugin Entry identity'),
+    ...(entry.packageId === undefined
+      ? {}
+      : { packageId: requireId(entry.packageId, 'Plugin package identity') }),
+    ...(entry.config === undefined ? {} : { config: decodeScalarRecord(entry.config, 'config') }),
+    ...(entry.disabled === undefined ? {} : { disabled: requireBoolean(entry.disabled) }),
+    ...(entry.inject === undefined ? {} : { inject: decodeInject(entry.inject) }),
+    ...(entry.isolate === undefined ? {} : { isolate: decodeIsolate(entry.isolate) }),
+    ...(entry.intercept === undefined
+      ? {}
+      : { intercept: decodeJsonRecord(entry.intercept, 'intercept') }),
+    ...(entry.children === undefined ? {} : { children: decodeEntries(entry.children) }),
+  };
+  try {
+    validateCompositionEntry(decoded);
+  } catch {
+    throw invalidProtocolFrame('Invalid Plugin composition Entry');
+  }
+  return decoded;
+}
+
+function decodeEntryPatch(value: unknown): Partial<Omit<MakaCompositionEntry, 'id' | 'children'>> {
+  const patch = requireShapedRecord(
+    value,
+    'Plugin Entry patch',
+    [],
+    ['packageId', 'config', 'disabled', 'inject', 'isolate', 'intercept'],
+  );
+  return {
+    ...(patch.packageId === undefined
+      ? {}
+      : { packageId: requireId(patch.packageId, 'Plugin package identity') }),
+    ...(patch.config === undefined ? {} : { config: decodeScalarRecord(patch.config, 'config') }),
+    ...(patch.disabled === undefined ? {} : { disabled: requireBoolean(patch.disabled) }),
+    ...(patch.inject === undefined ? {} : { inject: decodeInject(patch.inject) }),
+    ...(patch.isolate === undefined ? {} : { isolate: decodeIsolate(patch.isolate) }),
+    ...(patch.intercept === undefined
+      ? {}
+      : { intercept: decodeJsonRecord(patch.intercept, 'intercept') }),
+  };
+}
+
+function decodeInspections(value: unknown): readonly MakaCompositionEntryInspection[] {
+  if (!Array.isArray(value)) throw invalidProtocolFrame('Invalid Plugin Entry inspections');
+  return value.map((item) => {
+    const inspection = requireShapedRecord(
+      item,
+      'Plugin Entry inspection',
+      ['id', 'rootId', 'disabled', 'status', 'waitingFor', 'effects', 'children'],
+      ['parentId', 'packageId', 'config', 'generation', 'diagnostic'],
+    );
+    const statuses = [
+      'disabled',
+      'pending',
+      'loading',
+      'active',
+      'failed',
+      'unloading',
+      'disposed',
+    ];
+    if (!statuses.includes(inspection.status as string)) {
+      throw invalidProtocolFrame('Invalid Plugin Entry status');
+    }
+    if (!Array.isArray(inspection.waitingFor) || !Array.isArray(inspection.effects)) {
+      throw invalidProtocolFrame('Invalid Plugin Entry inspection details');
+    }
+    return {
+      id: requireId(inspection.id, 'Plugin Entry identity'),
+      rootId: decodeRootId(inspection.rootId),
+      ...(inspection.parentId === undefined
+        ? {}
+        : { parentId: requireId(inspection.parentId, 'Plugin parent Entry identity') }),
+      ...(inspection.packageId === undefined
+        ? {}
+        : { packageId: requireId(inspection.packageId, 'Plugin package identity') }),
+      ...(inspection.config === undefined
+        ? {}
+        : { config: decodeScalarRecord(inspection.config, 'config') }),
+      disabled: requireBoolean(inspection.disabled),
+      status: inspection.status as MakaCompositionEntryInspection['status'],
+      ...(inspection.generation === undefined
+        ? {}
+        : { generation: requireCount(inspection.generation, 'Plugin Fiber generation') }),
+      waitingFor: inspection.waitingFor.map((item) => requireId(item, 'Plugin dependency')),
+      effects: inspection.effects.map((item) => requireString(item, 'Plugin Effect label', 512)),
+      children: decodeInspections(inspection.children),
+      ...(inspection.diagnostic === undefined
+        ? {}
+        : { diagnostic: requireString(inspection.diagnostic, 'Plugin diagnostic', 4096) }),
+    };
+  });
+}
+
+function decodeEntries(value: unknown): readonly MakaCompositionEntry[] {
+  if (!Array.isArray(value)) throw invalidProtocolFrame('Invalid Plugin Entry list');
+  return value.map(decodeCompositionEntry);
+}
+
+function decodeRootId(value: unknown): MakaPluginRootId {
+  const rootId = requireString(value, 'Plugin root identity', 256);
+  try {
+    validatePluginRootId(rootId);
+    return rootId;
+  } catch {
+    throw invalidProtocolFrame('Invalid Plugin root identity');
+  }
+}
+
+function decodeInject(value: unknown): readonly string[] | Readonly<Record<string, unknown>> {
+  if (Array.isArray(value)) return value.map((item) => requireId(item, 'Plugin injection'));
+  return decodeJsonRecord(value, 'inject');
+}
+
+function decodeIsolate(value: unknown): Readonly<Record<string, true | string>> {
+  const record = requireRecord(value, 'Plugin Entry isolate');
+  const output: Array<readonly [string, true | string]> = [];
+  for (const [key, item] of Object.entries(record)) {
+    requireId(key, 'Plugin Entry isolate key');
+    if (item !== true && (typeof item !== 'string' || !item)) {
+      throw invalidProtocolFrame('Invalid Plugin Entry isolate value');
+    }
+    output.push([key, item]);
+  }
+  return Object.fromEntries(output);
+}
+
+function decodeJsonRecord(value: unknown, label: string): Readonly<Record<string, unknown>> {
+  const record = requireRecord(value, `Plugin Entry ${label}`);
+  requireEncodedByteLimit(record, `Plugin Entry ${label}`, 64 * 1024);
+  try {
+    return structuredClone(record);
+  } catch {
+    throw invalidProtocolFrame(`Invalid Plugin Entry ${label}`);
+  }
+}
+
+function decodeScalarRecord(
+  value: unknown,
+  label: string,
+): Readonly<Record<string, string | number | boolean>> {
+  const record = requireRecord(value, `Plugin Entry ${label}`);
+  const output: Array<readonly [string, string | number | boolean]> = [];
+  for (const [key, item] of Object.entries(record)) {
+    requireId(key, `Plugin Entry ${label} key`);
+    if (
+      typeof item === 'string' ||
+      typeof item === 'boolean' ||
+      (typeof item === 'number' && Number.isFinite(item))
+    )
+      output.push([key, item]);
+    else throw invalidProtocolFrame(`Invalid Plugin Entry ${label} value`);
+  }
+  return Object.fromEntries(output);
+}
+
+function requireBoolean(value: unknown): boolean {
+  if (typeof value !== 'boolean') throw invalidProtocolFrame('Invalid Plugin Entry disabled flag');
+  return value;
+}
+
+function requireDigest(value: unknown, label: string): string {
+  const digest = requireString(value, label, 80);
+  if (!/^sha256-[a-f0-9]{64}$/u.test(digest)) throw invalidProtocolFrame(`Invalid ${label}`);
+  return digest;
+}
diff --git a/packages/runtime-host/src/server/execution-composition.ts b/packages/runtime-host/src/server/execution-composition.ts
index 59f967ad17..4407a1b9a3 100644
--- a/packages/runtime-host/src/server/execution-composition.ts
+++ b/packages/runtime-host/src/server/execution-composition.ts
@@ -158,6 +158,8 @@ import {
 } from './project-directory-authority.js';
 import { HostProjectCatalogCoordinator } from './project-catalog-coordinator.js';
 import { HostProjectMembershipGate } from './project-membership-gate.js';
+import { HostPluginPlatformCoordinator } from './plugin-platform-coordinator.js';
+import { HostPluginPlatform } from './plugin-platform.js';
 import { RootAdmissionOwner } from './root-admission-owner.js';
 import { RootTurnCoordinator } from './root-turn-coordinator.js';
 import { RuntimePolicyActivationGate } from './runtime-policy-activation-gate.js';
@@ -201,6 +203,7 @@ import {
 
 export interface ExecutionRuntimeHostComposition extends RuntimeHostComposition {
   readonly workspaceExecution: RuntimeHostWorkspaceExecutionComposition;
+  readonly plugins: HostPluginPlatform;
 }
 
 const CONTEXT_OFFLOAD_READER_LIMITS: ContextOffloadLimits = Object.freeze({
@@ -268,7 +271,10 @@ export async function createExecutionRuntimeHostComposition(
   let unsubscribeUsageChanges: (() => void) | undefined;
   let workspaceExecution: RuntimeHostWorkspaceExecutionComposition | undefined;
   let goalExecutions: HostGoalExecutionCoordinator | undefined;
+  let pluginPlatform: HostPluginPlatform | undefined;
   try {
+    pluginPlatform = new HostPluginPlatform(context.owner.controlDirectory);
+    const pluginPlatformCoordinator = new HostPluginPlatformCoordinator(pluginPlatform);
     const openedProjectCatalog = storage.projectCatalog;
     const runtimePolicyStores = storage.runtimePolicy;
     const oauthCredentials = new HostOAuthExecutionAuthority(runtimePolicyStores);
@@ -1609,6 +1615,13 @@ export async function createExecutionRuntimeHostComposition(
     );
     let recoverySessions: Awaited<ReturnType<typeof stores.sessionStore.listForRecovery>> = [];
     domainModules = [
+      createRuntimeHostDomainModule({
+        id: 'plugin-platform',
+        handlers: [pluginPlatformCoordinator.handlers],
+        recovery: { state: () => pluginPlatform!.recover() },
+        drain: [() => pluginPlatform!.beginDrain()],
+        close: [() => pluginPlatform!.close()],
+      }),
       createRuntimeHostDomainModule({
         id: 'memory',
         handlers: [requireMemory(memory).handlers],
@@ -1866,6 +1879,7 @@ export async function createExecutionRuntimeHostComposition(
       handlers,
       moduleIds: Object.freeze(domainModules.map(({ id }) => id)),
       workspaceExecution: requireWorkspaceExecution(workspaceExecution),
+      plugins: pluginPlatform,
       continuity: continuityCoordinator,
       clientCapabilities,
       hostChanges,
@@ -1878,6 +1892,11 @@ export async function createExecutionRuntimeHostComposition(
     };
   } catch (error) {
     const errors: unknown[] = [error];
+    try {
+      await pluginPlatform?.close();
+    } catch (closeError) {
+      errors.push(closeError);
+    }
     goalExecutions?.beginDrain();
     try {
       await workspaceExecution?.close();
diff --git a/packages/runtime-host/src/server/extension-bundle.ts b/packages/runtime-host/src/server/extension-bundle.ts
new file mode 100644
index 0000000000..6fe513e9fe
--- /dev/null
+++ b/packages/runtime-host/src/server/extension-bundle.ts
@@ -0,0 +1,279 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import { createHash, randomUUID } from 'node:crypto';
+import { constants } from 'node:fs';
+import { copyFile, mkdir, open, readdir, realpath, rm, stat } from 'node:fs/promises';
+import { dirname, isAbsolute, join, posix, resolve } from 'node:path';
+
+const MAX_FILES = 256;
+const MAX_FILE_BYTES = 8 * 1024 * 1024;
+const MAX_BUNDLE_BYTES = 16 * 1024 * 1024;
+const BUNDLE_IMPORTS_DIRECTORY = 'bundle-imports-v1';
+
+interface BundleFile {
+  readonly path: string;
+  readonly sha256: string;
+  readonly content: string;
+}
+
+interface ExtensionBundleDocument {
+  readonly schemaVersion: 1;
+  readonly digest: string;
+  readonly files: readonly BundleFile[];
+}
+
+export class ExtensionBundleError extends Error {
+  readonly name = 'ExtensionBundleError';
+  constructor(message: string, options?: ErrorOptions) {
+    super(message, options);
+  }
+}
+
+export async function exportExtensionBundle(sourceRoot: string, targetPath: string): Promise<void> {
+  if (!isAbsolute(targetPath)) throw invalid('Extension bundle targetPath must be absolute');
+  const files = await readDirectory(sourceRoot);
+  const document: ExtensionBundleDocument = Object.freeze({
+    schemaVersion: 1,
+    digest: extensionPackageContentDigest(files),
+    files: Object.freeze(
+      files.map((file) =>
+        Object.freeze({
+          path: file.path,
+          sha256: createHash('sha256').update(file.content).digest('hex'),
+          content: file.content.toString('base64'),
+        }),
+      ),
+    ),
+  });
+  const encoded = Buffer.from(`${JSON.stringify(document)}\n`, 'utf8');
+  if (encoded.byteLength > MAX_BUNDLE_BYTES * 2)
+    throw invalid('Encoded Extension bundle is too large');
+  await mkdir(dirname(targetPath), { recursive: true, mode: 0o700 });
+  const temporary = `${targetPath}.${randomUUID()}.tmp`;
+  let handle: Awaited<ReturnType<typeof open>> | undefined;
+  try {
+    handle = await open(temporary, 'wx', 0o600);
+    await handle.writeFile(encoded);
+    await handle.sync();
+    await handle.close();
+    handle = undefined;
+    await copyFile(temporary, targetPath, constants.COPYFILE_EXCL);
+  } catch (error) {
+    throw invalid('Unable to export Extension bundle', error);
+  } finally {
+    await handle?.close().catch(() => undefined);
+    await rm(temporary, { force: true }).catch(() => undefined);
+  }
+}
+
+export async function materializeExtensionPackage(
+  sourcePath: string,
+  controlDirectory: string,
+): Promise<{ readonly root: string; readonly dispose: () => Promise<void> }> {
+  if (!isAbsolute(sourcePath)) throw invalid('Extension package sourcePath must be absolute');
+  const canonical = await realpath(resolve(sourcePath)).catch((error) => {
+    throw invalid('Extension package source is unavailable', error);
+  });
+  const metadata = await stat(canonical);
+  if (metadata.isDirectory()) return { root: canonical, dispose: async () => undefined };
+  if (!metadata.isFile())
+    throw invalid('Extension package source must be a directory or bundle file');
+  if (metadata.size > MAX_BUNDLE_BYTES * 2)
+    throw invalid('Extension bundle exceeds its size limit');
+  const handle = await open(canonical, constants.O_RDONLY | constants.O_NOFOLLOW);
+  let document: ExtensionBundleDocument;
+  try {
+    document = decodeBundle(JSON.parse((await handle.readFile()).toString('utf8')));
+  } catch (error) {
+    if (error instanceof ExtensionBundleError) throw error;
+    throw invalid('Extension bundle is invalid', error);
+  } finally {
+    await handle.close();
+  }
+  const imports = join(controlDirectory, BUNDLE_IMPORTS_DIRECTORY);
+  const root = join(imports, randomUUID());
+  await mkdir(root, { recursive: true, mode: 0o700 });
+  try {
+    for (const file of document.files) {
+      const target = join(root, ...file.path.split('/'));
+      await mkdir(dirname(target), { recursive: true, mode: 0o700 });
+      const output = await open(target, 'wx', 0o600);
+      try {
+        await output.writeFile(Buffer.from(file.content, 'base64'));
+      } finally {
+        await output.close();
+      }
+    }
+    return { root, dispose: () => rm(root, { recursive: true, force: true }) };
+  } catch (error) {
+    await rm(root, { recursive: true, force: true }).catch(() => undefined);
+    throw invalid('Unable to materialize Extension bundle', error);
+  }
+}
+
+/** Removes bundle materializations left behind when the previous owner died. */
+export async function recoverExtensionBundleImports(controlDirectory: string): Promise<void> {
+  try {
+    await rm(join(controlDirectory, BUNDLE_IMPORTS_DIRECTORY), {
+      recursive: true,
+      force: true,
+    });
+  } catch (error) {
+    throw invalid('Unable to recover Extension bundle imports', error);
+  }
+}
+
+async function readDirectory(
+  rootValue: string,
+): Promise<readonly { path: string; content: Buffer }[]> {
+  const root = await realpath(rootValue);
+  if (!(await stat(root)).isDirectory())
+    throw invalid('Extension bundle source is not a directory');
+  const paths: string[] = [];
+  await collect(root, '', paths);
+  if (paths.length === 0 || paths.length > MAX_FILES)
+    throw invalid('Extension bundle file count is invalid');
+  let total = 0;
+  const files: { path: string; content: Buffer }[] = [];
+  for (const path of paths.sort()) {
+    const handle = await open(
+      join(root, ...path.split('/')),
+      constants.O_RDONLY | constants.O_NOFOLLOW,
+    );
+    try {
+      const metadata = await handle.stat();
+      if (!metadata.isFile() || metadata.size > MAX_FILE_BYTES)
+        throw invalid(`Extension bundle file is invalid: ${path}`);
+      const content = await handle.readFile();
+      total += content.byteLength;
+      if (total > MAX_BUNDLE_BYTES) throw invalid('Extension bundle payload is too large');
+      files.push({ path, content });
+    } finally {
+      await handle.close();
+    }
+  }
+  return files;
+}
+
+async function collect(root: string, directory: string, paths: string[]): Promise<void> {
+  const entries = await readdir(directory ? join(root, ...directory.split('/')) : root, {
+    withFileTypes: true,
+  });
+  for (const entry of entries.sort((left, right) => left.name.localeCompare(right.name))) {
+    if (entry.name === '.git') continue;
+    const path = directory ? `${directory}/${entry.name}` : entry.name;
+    safePath(path);
+    if (entry.isSymbolicLink()) throw invalid(`Extension bundle may not contain symlinks: ${path}`);
+    if (entry.isDirectory()) await collect(root, path, paths);
+    else if (entry.isFile()) paths.push(path);
+    else throw invalid(`Extension bundle contains an unsupported entry: ${path}`);
+    if (paths.length > MAX_FILES) throw invalid('Extension bundle contains too many files');
+  }
+}
+
+function decodeBundle(value: unknown): ExtensionBundleDocument {
+  if (!value || typeof value !== 'object' || Array.isArray(value))
+    throw invalid('Extension bundle must be an object');
+  const record = value as Record<string, unknown>;
+  if (
+    Object.keys(record).sort().join() !== 'digest,files,schemaVersion' ||
+    record.schemaVersion !== 1 ||
+    !Array.isArray(record.files) ||
+    record.files.length === 0 ||
+    record.files.length > MAX_FILES
+  ) {
+    throw invalid('Extension bundle fields are invalid');
+  }
+  let total = 0;
+  const paths = new Set<string>();
+  const files = record.files.map((value) => {
+    if (!value || typeof value !== 'object' || Array.isArray(value))
+      throw invalid('Extension bundle file is invalid');
+    const file = value as Record<string, unknown>;
+    if (
+      Object.keys(file).sort().join() !== 'content,path,sha256' ||
+      typeof file.path !== 'string' ||
+      typeof file.content !== 'string' ||
+      typeof file.sha256 !== 'string'
+    )
+      throw invalid('Extension bundle file fields are invalid');
+    const path = safePath(file.path);
+    if (paths.has(path)) throw invalid(`Extension bundle repeats file: ${path}`);
+    paths.add(path);
+    const content = Buffer.from(file.content, 'base64');
+    total += content.byteLength;
+    if (
+      content.byteLength > MAX_FILE_BYTES ||
+      total > MAX_BUNDLE_BYTES ||
+      createHash('sha256').update(content).digest('hex') !== file.sha256
+    ) {
+      throw invalid(`Extension bundle file integrity failed: ${path}`);
+    }
+    return { path, content };
+  });
+  if (typeof record.digest !== 'string' || extensionPackageContentDigest(files) !== record.digest)
+    throw invalid('Extension bundle digest is invalid');
+  return Object.freeze({
+    schemaVersion: 1,
+    digest: record.digest,
+    files: Object.freeze(
+      files.map((file) =>
+        Object.freeze({
+          path: file.path,
+          sha256: createHash('sha256').update(file.content).digest('hex'),
+          content: file.content.toString('base64'),
+        }),
+      ),
+    ),
+  });
+}
+
+export function extensionPackageContentDigest(
+  files: readonly { path: string; content: Buffer }[],
+): string {
+  const hash = createHash('sha256');
+  for (const file of files) {
+    const path = Buffer.from(file.path, 'utf8');
+    const length = Buffer.allocUnsafe(8);
+    length.writeBigUInt64BE(BigInt(path.byteLength));
+    hash.update(length).update(path);
+    length.writeBigUInt64BE(BigInt(file.content.byteLength));
+    hash.update(length).update(file.content);
+  }
+  return `sha256-${hash.digest('hex')}`;
+}
+
+function safePath(value: string): string {
+  if (
+    !value ||
+    value.length > 512 ||
+    value.includes('\\') ||
+    value.startsWith('/') ||
+    posix.normalize(value) !== value ||
+    value.split('/').some((part) => !part || part === '.' || part === '..')
+  ) {
+    throw invalid('Extension bundle path is invalid');
+  }
+  return value;
+}
+
+function invalid(message: string, cause?: unknown): ExtensionBundleError {
+  return new ExtensionBundleError(message, { cause });
+}
diff --git a/packages/runtime-host/src/server/extension-package-manifest.ts b/packages/runtime-host/src/server/extension-package-manifest.ts
new file mode 100644
index 0000000000..e4898c50c3
--- /dev/null
+++ b/packages/runtime-host/src/server/extension-package-manifest.ts
@@ -0,0 +1,338 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import { readFile } from 'node:fs/promises';
+import { join } from 'node:path';
+import { isCanonicalExtensionId } from '@maka/runtime/plugin-runtime';
+
+export const EXTENSION_PACKAGE_MANIFEST_FILE = 'maka.extension.json';
+const MAX_MANIFEST_BYTES = 256 * 1024;
+const KEY_PATTERN = /^[A-Za-z][A-Za-z0-9._-]{0,127}$/u;
+
+export type ExtensionConfigurationScalar = string | number | boolean;
+
+export interface ExtensionPackageDependency {
+  readonly id: string;
+}
+
+export interface ExtensionConfigurationProperty {
+  readonly type: 'string' | 'number' | 'boolean';
+  readonly title?: string;
+  readonly description?: string;
+  readonly default?: ExtensionConfigurationScalar;
+  readonly enum?: readonly ExtensionConfigurationScalar[];
+}
+
+export interface ExtensionConfigurationSchema {
+  readonly properties: Readonly<Record<string, ExtensionConfigurationProperty>>;
+  readonly required: readonly string[];
+}
+
+export interface ExtensionPackageManifest {
+  readonly schemaVersion: 1;
+  readonly id: string;
+  readonly displayName: string;
+  readonly description: string;
+  readonly dependencies: readonly ExtensionPackageDependency[];
+  readonly configuration: ExtensionConfigurationSchema;
+  readonly runtime?: ExtensionPackageRuntime;
+  readonly composition?: ExtensionPackageComposition;
+}
+
+export interface ExtensionPackageRuntime {
+  readonly entry: string;
+}
+
+export interface ExtensionPackageComposition {
+  readonly patch: string;
+  readonly structuralDependencies: readonly string[];
+}
+
+export class ExtensionPackageManifestError extends Error {
+  readonly name = 'ExtensionPackageManifestError';
+  constructor(message: string, options?: ErrorOptions) {
+    super(message, options);
+  }
+}
+
+export async function loadExtensionPackageManifest(
+  root: string,
+): Promise<ExtensionPackageManifest | undefined> {
+  let encoded: Buffer;
+  try {
+    encoded = await readFile(join(root, EXTENSION_PACKAGE_MANIFEST_FILE));
+  } catch (error) {
+    if ((error as NodeJS.ErrnoException).code === 'ENOENT') return undefined;
+    throw invalid('Unable to read unified Extension manifest', error);
+  }
+  if (encoded.byteLength > MAX_MANIFEST_BYTES) {
+    throw invalid('Unified Extension manifest exceeds its size limit');
+  }
+  try {
+    return decodeExtensionPackageManifest(JSON.parse(encoded.toString('utf8')));
+  } catch (error) {
+    if (error instanceof ExtensionPackageManifestError) throw error;
+    throw invalid('Unified Extension manifest is invalid JSON', error);
+  }
+}
+
+export function decodeExtensionPackageManifest(value: unknown): ExtensionPackageManifest {
+  const source = record(value, 'Extension manifest');
+  exactOptional(
+    source,
+    ['schemaVersion', 'id'],
+    ['displayName', 'description', 'dependencies', 'configuration', 'runtime', 'composition'],
+  );
+  if (source.schemaVersion !== 1) throw invalid('Extension manifest schemaVersion must be 1');
+  const id = extensionId(source.id);
+  const displayName =
+    source.displayName === undefined ? id : text(source.displayName, 'displayName', 128);
+  const description =
+    source.description === undefined ? '' : boundedDescription(source.description);
+  const dependencies = decodeDependencies(source.dependencies);
+  const configuration = decodeConfigurationSchema(source.configuration);
+  const runtime = decodeRuntime(source.runtime);
+  const composition = decodeComposition(source.composition);
+  return Object.freeze({
+    schemaVersion: 1,
+    id,
+    displayName,
+    description,
+    dependencies,
+    configuration,
+    ...(runtime === undefined ? {} : { runtime }),
+    ...(composition === undefined ? {} : { composition }),
+  });
+}
+
+function decodeComposition(value: unknown): ExtensionPackageComposition | undefined {
+  if (value === undefined) return undefined;
+  const composition = record(value, 'composition');
+  exactOptional(composition, ['patch'], ['structuralDependencies']);
+  const structuralDependencies = decodeExtensionIds(
+    composition.structuralDependencies,
+    'composition.structuralDependencies',
+  );
+  return Object.freeze({
+    patch: packagePath(composition.patch, 'composition.patch'),
+    structuralDependencies,
+  });
+}
+
+function decodeRuntime(value: unknown): ExtensionPackageRuntime | undefined {
+  if (value === undefined) return undefined;
+  const runtime = record(value, 'runtime');
+  if (runtime.entry === undefined) return undefined;
+  return Object.freeze({ entry: packagePath(runtime.entry, 'runtime.entry') });
+}
+
+function packagePath(value: unknown, label: string): string {
+  if (
+    typeof value !== 'string' ||
+    value.length === 0 ||
+    value.length > 512 ||
+    value.includes('\\') ||
+    value.startsWith('/') ||
+    value.split('/').some((part) => !part || part === '.' || part === '..')
+  ) {
+    throw invalid(`Extension manifest ${label} is invalid`);
+  }
+  return value;
+}
+
+export function validateExtensionConfiguration(
+  schema: ExtensionConfigurationSchema,
+  value: unknown,
+): Readonly<Record<string, ExtensionConfigurationScalar>> {
+  const input = value === undefined ? {} : record(value, 'Extension configuration');
+  const unknown = Object.keys(input).find((key) => !Object.hasOwn(schema.properties, key));
+  if (unknown) throw invalid(`Extension configuration key is not declared: ${unknown}`);
+  const result: Record<string, ExtensionConfigurationScalar> = {};
+  for (const [key, property] of Object.entries(schema.properties)) {
+    const configured = Object.hasOwn(input, key) ? input[key] : property.default;
+    if (configured === undefined) {
+      if (schema.required.includes(key)) {
+        throw invalid(`Extension configuration is missing required key: ${key}`);
+      }
+      continue;
+    }
+    if (typeof configured !== property.type || !isScalar(configured)) {
+      throw invalid(`Extension configuration type is invalid for key: ${key}`);
+    }
+    if (property.enum && !property.enum.some((candidate) => candidate === configured)) {
+      throw invalid(`Extension configuration value is not allowed for key: ${key}`);
+    }
+    result[key] = configured;
+  }
+  const encoded = JSON.stringify(result);
+  if (Buffer.byteLength(encoded, 'utf8') > 64 * 1024) {
+    throw invalid('Extension configuration exceeds its size limit');
+  }
+  return Object.freeze(result);
+}
+
+function decodeDependencies(value: unknown): readonly ExtensionPackageDependency[] {
+  if (value === undefined) return Object.freeze([]);
+  if (!Array.isArray(value) || value.length > 64)
+    throw invalid('Extension dependencies are invalid');
+  const ids = new Set<string>();
+  const dependencies = value.map((item, index) => {
+    const dependency = record(item, `dependencies[${index}]`);
+    exactOptional(dependency, ['id'], []);
+    const id = extensionId(dependency.id);
+    if (ids.has(id)) throw invalid(`Extension dependency repeats: ${id}`);
+    ids.add(id);
+    return Object.freeze({ id });
+  });
+  return Object.freeze(dependencies.sort((left, right) => left.id.localeCompare(right.id)));
+}
+
+function decodeExtensionIds(value: unknown, label: string): readonly string[] {
+  if (value === undefined) return Object.freeze([]);
+  if (!Array.isArray(value) || value.length > 64) throw invalid(`${label} is invalid`);
+  const ids = value.map((item) => extensionId(item));
+  if (new Set(ids).size !== ids.length) throw invalid(`${label} repeats an identity`);
+  return Object.freeze(ids.sort((left, right) => left.localeCompare(right)));
+}
+
+function decodeConfigurationSchema(value: unknown): ExtensionConfigurationSchema {
+  if (value === undefined)
+    return Object.freeze({ properties: Object.freeze({}), required: Object.freeze([]) });
+  const schema = record(value, 'configuration');
+  exactOptional(schema, ['properties'], ['required']);
+  const propertiesSource = record(schema.properties, 'configuration properties');
+  if (Object.keys(propertiesSource).length > 128)
+    throw invalid('Too many Extension configuration properties');
+  const properties: Record<string, ExtensionConfigurationProperty> = {};
+  for (const [key, value] of Object.entries(propertiesSource)) {
+    if (!KEY_PATTERN.test(key)) throw invalid(`Extension configuration key is invalid: ${key}`);
+    const property = record(value, `configuration.properties.${key}`);
+    exactOptional(property, ['type'], ['title', 'description', 'default', 'enum']);
+    if (property.type !== 'string' && property.type !== 'number' && property.type !== 'boolean') {
+      throw invalid(`Extension configuration property type is invalid: ${key}`);
+    }
+    const type = property.type;
+    const defaultValue = property.default;
+    if (defaultValue !== undefined && (typeof defaultValue !== type || !isScalar(defaultValue))) {
+      throw invalid(`Extension configuration default is invalid: ${key}`);
+    }
+    let values: readonly ExtensionConfigurationScalar[] | undefined;
+    if (property.enum !== undefined) {
+      if (
+        !Array.isArray(property.enum) ||
+        property.enum.length === 0 ||
+        property.enum.length > 64 ||
+        property.enum.some((item) => typeof item !== type || !isScalar(item))
+      )
+        throw invalid(`Extension configuration enum is invalid: ${key}`);
+      values = Object.freeze([...new Set(property.enum as ExtensionConfigurationScalar[])]);
+      if (
+        defaultValue !== undefined &&
+        !values.includes(defaultValue as ExtensionConfigurationScalar)
+      ) {
+        throw invalid(`Extension configuration default is outside enum: ${key}`);
+      }
+    }
+    properties[key] = Object.freeze({
+      type,
+      ...(property.title === undefined
+        ? {}
+        : { title: text(property.title, 'configuration title', 128) }),
+      ...(property.description === undefined
+        ? {}
+        : { description: text(property.description, 'configuration description', 1024) }),
+      ...(defaultValue === undefined
+        ? {}
+        : { default: defaultValue as ExtensionConfigurationScalar }),
+      ...(values ? { enum: values } : {}),
+    });
+  }
+  const required = schema.required === undefined ? [] : schema.required;
+  if (
+    !Array.isArray(required) ||
+    required.length > Object.keys(properties).length ||
+    required.some((key) => typeof key !== 'string' || !Object.hasOwn(properties, key)) ||
+    new Set(required).size !== required.length
+  )
+    throw invalid('Extension configuration required keys are invalid');
+  return Object.freeze({
+    properties: Object.freeze(properties),
+    required: Object.freeze(required as string[]),
+  });
+}
+
+function exactOptional(
+  value: Record<string, unknown>,
+  required: readonly string[],
+  optional: readonly string[],
+): void {
+  const allowed = new Set([...required, ...optional]);
+  if (
+    required.some((key) => !Object.hasOwn(value, key)) ||
+    Object.keys(value).some((key) => !allowed.has(key))
+  ) {
+    throw invalid('Extension manifest fields are invalid');
+  }
+}
+
+function record(value: unknown, label: string): Record<string, unknown> {
+  if (!value || typeof value !== 'object' || Array.isArray(value))
+    throw invalid(`${label} must be an object`);
+  return value as Record<string, unknown>;
+}
+
+function extensionId(value: unknown): string {
+  if (!isCanonicalExtensionId(value)) throw invalid('Extension manifest id is invalid');
+  return value;
+}
+
+function text(value: unknown, label: string, maxBytes: number): string {
+  if (
+    typeof value !== 'string' ||
+    value.length === 0 ||
+    Buffer.byteLength(value, 'utf8') > maxBytes ||
+    /[\0\r\n]/u.test(value)
+  ) {
+    throw invalid(`Extension manifest ${label} is invalid`);
+  }
+  return value;
+}
+
+function boundedDescription(value: unknown): string {
+  if (
+    typeof value !== 'string' ||
+    Buffer.byteLength(value, 'utf8') > 4096 ||
+    value.includes('\0')
+  ) {
+    throw invalid('Extension manifest description is invalid');
+  }
+  return value;
+}
+
+function isScalar(value: unknown): value is ExtensionConfigurationScalar {
+  return (
+    typeof value === 'string' ||
+    typeof value === 'boolean' ||
+    (typeof value === 'number' && Number.isFinite(value))
+  );
+}
+
+function invalid(message: string, cause?: unknown): ExtensionPackageManifestError {
+  return new ExtensionPackageManifestError(message, { cause });
+}
diff --git a/packages/runtime-host/src/server/index.ts b/packages/runtime-host/src/server/index.ts
index a1ed9f5283..cd0bc031ef 100644
--- a/packages/runtime-host/src/server/index.ts
+++ b/packages/runtime-host/src/server/index.ts
@@ -35,3 +35,32 @@ export {
   readRuntimeHostAccessCredentialMetadata,
   type RuntimeHostAccessCredentialMetadata,
 } from './access-credential-metadata.js';
+export {
+  ExtensionBundleError,
+  exportExtensionBundle,
+  materializeExtensionPackage,
+} from './extension-bundle.js';
+export {
+  EXTENSION_PACKAGE_MANIFEST_FILE,
+  ExtensionPackageManifestError,
+  decodeExtensionPackageManifest,
+  loadExtensionPackageManifest,
+  validateExtensionConfiguration,
+  type ExtensionConfigurationProperty,
+  type ExtensionConfigurationScalar,
+  type ExtensionConfigurationSchema,
+  type ExtensionPackageDependency,
+  type ExtensionPackageComposition,
+  type ExtensionPackageManifest,
+  type ExtensionPackageRuntime,
+} from './extension-package-manifest.js';
+export {
+  PluginCompositionPatchError,
+  loadPluginCompositionPatch,
+} from './plugin-composition-patch.js';
+export {
+  HostPluginPlatform,
+  HostPluginPlatformError,
+  type HostPluginPlatformFailure,
+} from './plugin-platform.js';
+export { HostPluginPlatformCoordinator } from './plugin-platform-coordinator.js';
diff --git a/packages/runtime-host/src/server/operation-dispatcher.ts b/packages/runtime-host/src/server/operation-dispatcher.ts
index d16495822c..c3d464e9b1 100644
--- a/packages/runtime-host/src/server/operation-dispatcher.ts
+++ b/packages/runtime-host/src/server/operation-dispatcher.ts
@@ -153,6 +153,7 @@ export type WebSearchOperationKey = Extract<OperationKey, `web-search.${string}`
 export type NetworkProxyOperationKey = Extract<OperationKey, `network-proxy.${string}`>;
 export type ConfigurationOperationKey = Extract<OperationKey, `configuration.${string}`>;
 export type WorkHubCoordinationOperationKey = Extract<OperationKey, `workhub.${string}`>;
+export type PluginPlatformOperationKey = Extract<OperationKey, `plugin.${string}`>;
 export type DomainOperationHandlerMap = Pick<OperationHandlerMap, DomainOperationKey>;
 export type TurnOperationHandlerMap = Pick<OperationHandlerMap, TurnOperationKey>;
 export type ContextOperationHandlerMap = Pick<OperationHandlerMap, ContextOperationKey>;
@@ -223,6 +224,10 @@ export type WorkHubCoordinationOperationHandlerMap = Pick<
   OperationHandlerMap,
   WorkHubCoordinationOperationKey
 >;
+export type PluginPlatformOperationHandlerMap = Pick<
+  OperationHandlerMap,
+  PluginPlatformOperationKey
+>;
 export type AccessAuthorityOperationHandlerMap = Pick<
   OperationHandlerMap,
   keyof typeof ACCESS_AUTHORITY_OPERATION_SPECS | keyof typeof SESSION_COLLABORATION_OPERATION_SPECS
diff --git a/packages/runtime-host/src/server/plugin-composition-patch.ts b/packages/runtime-host/src/server/plugin-composition-patch.ts
new file mode 100644
index 0000000000..5e5db76602
--- /dev/null
+++ b/packages/runtime-host/src/server/plugin-composition-patch.ts
@@ -0,0 +1,63 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import { readFile } from 'node:fs/promises';
+import { join } from 'node:path';
+import type { MakaCompositionApplyInput } from '@maka/runtime/plugin-runtime';
+import { parse } from 'yaml';
+import { decodePluginCompositionApplyInput } from '../protocol/plugin-platform.js';
+import type { InstalledPluginPackage } from './plugin-package-store.js';
+
+const MAX_PATCH_BYTES = 512 * 1024;
+
+export class PluginCompositionPatchError extends Error {
+  readonly name = 'PluginCompositionPatchError';
+}
+
+/** Reads the declarative Composition layer shipped by one installed package. */
+export async function loadPluginCompositionPatch(
+  installed: InstalledPluginPackage,
+): Promise<MakaCompositionApplyInput | undefined> {
+  const relativePath = installed.manifest.composition?.patch;
+  if (!relativePath) return undefined;
+  let encoded: Buffer;
+  try {
+    encoded = await readFile(join(installed.root, ...relativePath.split('/')));
+  } catch (error) {
+    throw invalid(`Unable to read Plugin Composition patch: ${relativePath}`, error);
+  }
+  if (encoded.byteLength > MAX_PATCH_BYTES) {
+    throw invalid(`Plugin Composition patch exceeds its size limit: ${relativePath}`);
+  }
+  let value: unknown;
+  try {
+    value = parse(encoded.toString('utf8'));
+  } catch (error) {
+    throw invalid(`Plugin Composition patch is invalid YAML: ${relativePath}`, error);
+  }
+  try {
+    return decodePluginCompositionApplyInput({ operations: value });
+  } catch (error) {
+    throw invalid(`Plugin Composition patch is invalid: ${relativePath}`, error);
+  }
+}
+
+function invalid(message: string, cause?: unknown): PluginCompositionPatchError {
+  return new PluginCompositionPatchError(message, { cause });
+}
diff --git a/packages/runtime-host/src/server/plugin-composition-store.ts b/packages/runtime-host/src/server/plugin-composition-store.ts
new file mode 100644
index 0000000000..d19b91e99a
--- /dev/null
+++ b/packages/runtime-host/src/server/plugin-composition-store.ts
@@ -0,0 +1,171 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import { randomUUID } from 'node:crypto';
+import { mkdir, open, readFile, rename, rm } from 'node:fs/promises';
+import { dirname, join } from 'node:path';
+import {
+  isCanonicalExtensionId,
+  type MakaCompositionOperation,
+} from '@maka/runtime/plugin-runtime';
+import { decodePluginCompositionApplyInput } from '../protocol/plugin-platform.js';
+
+const FILE_NAME = 'plugin-composition-v2.json';
+const MAX_BYTES = 2 * 1024 * 1024;
+
+/** Durable inputs from which the desired Entry Tree is rebuilt. */
+export interface PersistedPluginComposition {
+  readonly schemaVersion: 1;
+  readonly generation: number;
+  readonly packageLayers: readonly string[];
+  readonly overlays: readonly MakaCompositionOperation[];
+}
+
+export class HostPluginCompositionStoreError extends Error {
+  readonly name = 'HostPluginCompositionStoreError';
+
+  constructor(
+    readonly code: 'persistence_failed' | 'invalid_state' | 'commit_outcome_unknown',
+    message: string,
+    options?: ErrorOptions,
+  ) {
+    super(message, options);
+  }
+}
+
+export class HostPluginCompositionStore {
+  readonly path: string;
+
+  constructor(controlDirectory: string) {
+    this.path = join(controlDirectory, FILE_NAME);
+  }
+
+  async read(): Promise<PersistedPluginComposition | undefined> {
+    let encoded: Buffer;
+    try {
+      encoded = await readFile(this.path);
+    } catch (error) {
+      if ((error as NodeJS.ErrnoException).code === 'ENOENT') return undefined;
+      throw persistence('Unable to read Plugin Composition', error);
+    }
+    if (encoded.byteLength > MAX_BYTES) throw invalid('Plugin Composition exceeds its size limit');
+    try {
+      return decode(JSON.parse(encoded.toString('utf8')));
+    } catch (error) {
+      if (error instanceof HostPluginCompositionStoreError) throw error;
+      throw invalid('Plugin Composition is invalid JSON', error);
+    }
+  }
+
+  async replace(composition: PersistedPluginComposition): Promise<void> {
+    const normalized = decode(composition);
+    const encoded = Buffer.from(`${JSON.stringify(normalized)}\n`, 'utf8');
+    if (encoded.byteLength > MAX_BYTES) throw invalid('Plugin Composition exceeds its size limit');
+    const directory = dirname(this.path);
+    const temporary = join(directory, `.${FILE_NAME}.${randomUUID()}.tmp`);
+    let handle: Awaited<ReturnType<typeof open>> | undefined;
+    let published = false;
+    try {
+      await mkdir(directory, { recursive: true, mode: 0o700 });
+      handle = await open(temporary, 'wx', 0o600);
+      await handle.writeFile(encoded);
+      await handle.sync();
+      await handle.close();
+      handle = undefined;
+      await rename(temporary, this.path);
+      published = true;
+      const directoryHandle = await open(directory, 'r');
+      try {
+        await directoryHandle.sync();
+      } finally {
+        await directoryHandle.close();
+      }
+    } catch (error) {
+      if (published) {
+        throw new HostPluginCompositionStoreError(
+          'commit_outcome_unknown',
+          'Plugin Composition was renamed but its directory sync was not confirmed',
+          { cause: error },
+        );
+      }
+      throw persistence('Unable to persist Plugin Composition', error);
+    } finally {
+      await handle?.close().catch(() => undefined);
+      await rm(temporary, { force: true }).catch(() => undefined);
+    }
+  }
+}
+
+function decode(value: unknown): PersistedPluginComposition {
+  const root = record(value, 'Plugin Composition');
+  exact(root, ['schemaVersion', 'generation', 'packageLayers', 'overlays']);
+  if (
+    root.schemaVersion !== 1 ||
+    !Number.isSafeInteger(root.generation) ||
+    (root.generation as number) < 0
+  ) {
+    throw invalid('Plugin Composition header is invalid');
+  }
+  if (
+    !Array.isArray(root.packageLayers) ||
+    root.packageLayers.length > 256 ||
+    root.packageLayers.some((item) => !isCanonicalExtensionId(item)) ||
+    new Set(root.packageLayers).size !== root.packageLayers.length
+  ) {
+    throw invalid('Plugin Composition package layers are invalid');
+  }
+  if (!Array.isArray(root.overlays) || root.overlays.length > 4096) {
+    throw invalid('Plugin Composition overlays are invalid');
+  }
+  const overlays =
+    root.overlays.length === 0
+      ? Object.freeze([])
+      : Object.freeze(
+          decodePluginCompositionApplyInput({ operations: root.overlays }, MAX_BYTES).operations,
+        );
+  return Object.freeze({
+    schemaVersion: 1,
+    generation: root.generation as number,
+    packageLayers: Object.freeze([...(root.packageLayers as string[])]),
+    overlays,
+  });
+}
+
+function record(value: unknown, label: string): Record<string, unknown> {
+  if (!value || typeof value !== 'object' || Array.isArray(value))
+    throw invalid(`${label} must be an object`);
+  return value as Record<string, unknown>;
+}
+
+function exact(value: Record<string, unknown>, keys: readonly string[]): void {
+  if (
+    keys.some((key) => !Object.hasOwn(value, key)) ||
+    Object.keys(value).some((key) => !keys.includes(key))
+  ) {
+    throw invalid('Plugin Composition fields are invalid');
+  }
+}
+
+function invalid(message: string, cause?: unknown): HostPluginCompositionStoreError {
+  return new HostPluginCompositionStoreError('invalid_state', message, { cause });
+}
+
+function persistence(message: string, cause?: unknown): HostPluginCompositionStoreError {
+  return new HostPluginCompositionStoreError('persistence_failed', message, { cause });
+}
diff --git a/packages/runtime-host/src/server/plugin-package-loader.ts b/packages/runtime-host/src/server/plugin-package-loader.ts
new file mode 100644
index 0000000000..db26f55d1e
--- /dev/null
+++ b/packages/runtime-host/src/server/plugin-package-loader.ts
@@ -0,0 +1,157 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import { randomUUID } from 'node:crypto';
+import { cp, mkdir, rm } from 'node:fs/promises';
+import { join, relative } from 'node:path';
+import { pathToFileURL } from 'node:url';
+import {
+  type MakaPluginPackage,
+  MakaPluginRuntimeError,
+  validatePluginPackage,
+} from '@maka/runtime/plugin-runtime';
+import {
+  type InstalledPluginPackage,
+  PluginPackageStore,
+  PluginPackageStoreError,
+} from './plugin-package-store.js';
+
+const GENERATION_DIRECTORY = 'plugin-generations-v1';
+const GENERATION_PATH = Symbol('maka.pluginGenerationPath');
+
+export class PluginPackageLoaderError extends Error {
+  readonly name = 'PluginPackageLoaderError';
+
+  constructor(
+    readonly code: 'not_found' | 'invalid_package' | 'load_failed',
+    message: string,
+    options?: ErrorOptions,
+  ) {
+    super(message, options);
+  }
+}
+
+/** Loads trusted packages from immutable generation directories. */
+export class TrustedPluginPackageLoader {
+  readonly #generations: string;
+  readonly #owned = new Set<string>();
+
+  constructor(
+    controlDirectory: string,
+    readonly store: PluginPackageStore,
+  ) {
+    this.#generations = join(controlDirectory, GENERATION_DIRECTORY);
+  }
+
+  async load(extensionId: string): Promise<MakaPluginPackage> {
+    let installed;
+    try {
+      installed = await this.store.load(extensionId);
+    } catch (error) {
+      throw translate(error);
+    }
+    return await this.loadInstalled(installed);
+  }
+
+  async loadInstalled(installed: InstalledPluginPackage): Promise<MakaPluginPackage> {
+    const generation = join(this.#generations, `${installed.extensionId}-${randomUUID()}`);
+    try {
+      await mkdir(this.#generations, { recursive: true, mode: 0o700 });
+      await cp(installed.root, generation, {
+        recursive: true,
+        force: false,
+        errorOnExist: true,
+        preserveTimestamps: false,
+      });
+      const entry = join(generation, relative(installed.root, installed.entry));
+      const imported = (await import(pathToFileURL(entry).href)) as Record<string, unknown>;
+      const candidate = imported.default ?? imported.plugin;
+      if (!candidate || typeof candidate !== 'object') {
+        throw invalid('Plugin Runtime entry must export a MakaPluginPackage as default');
+      }
+      const pkg = candidate as MakaPluginPackage;
+      validatePluginPackage(pkg);
+      if (pkg.packageId !== installed.extensionId) {
+        throw invalid(
+          `Plugin Runtime packageId ${pkg.packageId} does not match manifest ${installed.extensionId}`,
+        );
+      }
+      if (!pkg.host) throw invalid('Trusted Host package must export a host Plugin');
+      const owned = freezeGeneration(pkg, generation);
+      this.#owned.add(generation);
+      return owned;
+    } catch (error) {
+      await rm(generation, { recursive: true, force: true }).catch(() => undefined);
+      throw translate(error);
+    }
+  }
+
+  async collectGarbage(): Promise<void> {
+    this.#owned.clear();
+    await rm(this.#generations, { recursive: true, force: true });
+  }
+
+  async release(pkg: MakaPluginPackage): Promise<void> {
+    const generation = (pkg as MakaPluginPackage & { readonly [GENERATION_PATH]?: string })[
+      GENERATION_PATH
+    ];
+    if (!generation || !this.#owned.delete(generation)) return;
+    await rm(generation, { recursive: true, force: true });
+  }
+
+  async close(): Promise<void> {
+    this.#owned.clear();
+    await rm(this.#generations, { recursive: true, force: true });
+  }
+}
+
+function freezeGeneration(pkg: MakaPluginPackage, generation: string): MakaPluginPackage {
+  return Object.freeze({
+    ...pkg,
+    [GENERATION_PATH]: generation,
+    ...(pkg.contributions
+      ? {
+          contributions: Object.freeze(pkg.contributions.map((item) => Object.freeze({ ...item }))),
+        }
+      : {}),
+  });
+}
+
+function invalid(message: string, cause?: unknown): PluginPackageLoaderError {
+  return new PluginPackageLoaderError('invalid_package', message, { cause });
+}
+
+function translate(error: unknown): PluginPackageLoaderError {
+  if (error instanceof PluginPackageLoaderError) return error;
+  if (error instanceof PluginPackageStoreError) {
+    return new PluginPackageLoaderError(
+      error.code === 'not_found'
+        ? 'not_found'
+        : error.code === 'invalid_package'
+          ? 'invalid_package'
+          : 'load_failed',
+      error.message,
+      { cause: error },
+    );
+  }
+  if (error instanceof MakaPluginRuntimeError) return invalid(error.message, error);
+  return new PluginPackageLoaderError('load_failed', 'Unable to load Plugin package', {
+    cause: error,
+  });
+}
diff --git a/packages/runtime-host/src/server/plugin-package-store.ts b/packages/runtime-host/src/server/plugin-package-store.ts
new file mode 100644
index 0000000000..65e5b9af4f
--- /dev/null
+++ b/packages/runtime-host/src/server/plugin-package-store.ts
@@ -0,0 +1,604 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import { randomUUID } from 'node:crypto';
+import type { Dirent } from 'node:fs';
+import { mkdir, open, readFile, readdir, realpath, rename, rm, stat } from 'node:fs/promises';
+import { dirname, join, posix } from 'node:path';
+import { isCanonicalExtensionId } from '@maka/runtime/plugin-runtime';
+import {
+  exportExtensionBundle,
+  extensionPackageContentDigest,
+  materializeExtensionPackage,
+} from './extension-bundle.js';
+import {
+  EXTENSION_PACKAGE_MANIFEST_FILE,
+  type ExtensionPackageManifest,
+  loadExtensionPackageManifest,
+} from './extension-package-manifest.js';
+
+const STORE_DIRECTORY = 'plugin-packages-v2';
+const MAX_FILES = 256;
+const MAX_FILE_BYTES = 8 * 1024 * 1024;
+const MAX_PACKAGE_BYTES = 16 * 1024 * 1024;
+
+interface PackageFile {
+  readonly path: string;
+  readonly content: Buffer;
+}
+
+export interface InstalledPluginPackage {
+  readonly extensionId: string;
+  readonly contentDigest: string;
+  readonly root: string;
+  readonly entry: string;
+  readonly manifest: ExtensionPackageManifest;
+}
+
+export interface PreparedPluginPackageInstall {
+  readonly installed: InstalledPluginPackage;
+  publish(baseGeneration: number, nextGeneration: number): Promise<void>;
+  commit(): Promise<void>;
+  rollback(): Promise<void>;
+}
+
+interface PackageInstallTransaction {
+  readonly schemaVersion: 1;
+  readonly extensionId: string;
+  readonly baseGeneration: number;
+  readonly nextGeneration: number;
+}
+
+export class PluginPackageStoreError extends Error {
+  readonly name = 'PluginPackageStoreError';
+
+  constructor(
+    readonly code:
+      | 'not_found'
+      | 'invalid_package'
+      | 'persistence_failed'
+      | 'commit_outcome_unknown',
+    message: string,
+    options?: ErrorOptions,
+  ) {
+    super(message, options);
+  }
+}
+
+/** Atomic, root-private storage for trusted in-process Plugin packages. */
+export class PluginPackageStore {
+  readonly root: string;
+  readonly #controlDirectory: string;
+
+  constructor(controlDirectory: string) {
+    this.#controlDirectory = controlDirectory;
+    this.root = join(controlDirectory, STORE_DIRECTORY);
+  }
+
+  protected async publishCandidate(staging: string, target: string): Promise<void> {
+    await rename(staging, target);
+  }
+
+  /** Repairs or removes package-store transaction remnants after owner death. */
+  async recover(authorityGeneration = 0): Promise<void> {
+    let entries: Dirent[];
+    try {
+      entries = await readdir(this.root, { withFileTypes: true });
+    } catch (error) {
+      if ((error as NodeJS.ErrnoException).code === 'ENOENT') return;
+      throw persistence('Unable to recover Plugin package storage', error);
+    }
+    let changed = false;
+    for (const entry of entries.sort((left, right) => left.name.localeCompare(right.name))) {
+      if (!entry.isDirectory() || !entry.name.startsWith('.')) continue;
+      const path = join(this.root, entry.name);
+      if (entry.name.startsWith('.install-')) {
+        await this.#recoverInstall(path, authorityGeneration);
+        changed = true;
+        continue;
+      }
+      if (entry.name.startsWith('.previous-')) {
+        try {
+          const files = await readPackage(path);
+          const decoded = await decodePackage(path, files);
+          const target = join(this.root, decoded.manifest.id);
+          try {
+            await stat(target);
+            await rm(path, { recursive: true, force: true });
+          } catch (error) {
+            if ((error as NodeJS.ErrnoException).code !== 'ENOENT') throw error;
+            await rename(path, target);
+          }
+          changed = true;
+          continue;
+        } catch (error) {
+          throw persistence(`Unable to recover Plugin package transaction ${entry.name}`, error);
+        }
+      }
+      if (
+        entry.name.startsWith('.staging-') ||
+        entry.name.startsWith('.rejected-') ||
+        entry.name.startsWith('.removed-')
+      ) {
+        await rm(path, { recursive: true, force: true });
+        changed = true;
+      }
+    }
+    if (changed) await syncDirectory(this.root);
+  }
+
+  async identities(): Promise<readonly string[]> {
+    let entries: Dirent[];
+    try {
+      entries = await readdir(this.root, { withFileTypes: true });
+    } catch (error) {
+      if ((error as NodeJS.ErrnoException).code === 'ENOENT') return Object.freeze([]);
+      throw persistence('Unable to list Plugin package identities', error);
+    }
+    return Object.freeze(
+      entries
+        .filter((entry) => entry.isDirectory() && isCanonicalExtensionId(entry.name))
+        .map((entry) => entry.name)
+        .sort((left, right) => left.localeCompare(right)),
+    );
+  }
+
+  async prepareInstall(sourcePath: string): Promise<PreparedPluginPackageInstall> {
+    const source = await materializeExtensionPackage(sourcePath, this.#controlDirectory);
+    try {
+      const files = await readPackage(source.root);
+      const decoded = await decodePackage(source.root, files);
+      const target = join(this.root, decoded.manifest.id);
+      const transaction = join(this.root, `.install-${randomUUID()}`);
+      const staging = join(transaction, 'candidate');
+      const previous = join(transaction, 'previous');
+      let movedPrevious = false;
+      let published = false;
+      let settled = false;
+      try {
+        await mkdir(this.root, { recursive: true, mode: 0o700 });
+        await mkdir(transaction, { mode: 0o700 });
+        await mkdir(staging, { mode: 0o700 });
+        for (const file of files) await writeFile(staging, file);
+        await syncTree(staging, files);
+        await syncDirectory(transaction);
+        await syncDirectory(this.root);
+        const installed = freezeInstalled(staging, decoded);
+        return Object.freeze({
+          installed,
+          publish: async (baseGeneration: number, nextGeneration: number) => {
+            if (settled || published)
+              throw persistence('Plugin package install is already settled');
+            if (
+              !Number.isSafeInteger(baseGeneration) ||
+              !Number.isSafeInteger(nextGeneration) ||
+              baseGeneration < 0 ||
+              nextGeneration !== baseGeneration + 1
+            ) {
+              throw invalid('Plugin package install generations are invalid');
+            }
+            await writeTransaction(transaction, {
+              schemaVersion: 1,
+              extensionId: decoded.manifest.id,
+              baseGeneration,
+              nextGeneration,
+            });
+            try {
+              await rename(target, previous)
+                .then(() => {
+                  movedPrevious = true;
+                })
+                .catch((error: NodeJS.ErrnoException) => {
+                  if (error.code !== 'ENOENT') throw error;
+                });
+              await this.publishCandidate(staging, target);
+              published = true;
+              await syncDirectory(this.root);
+            } catch (error) {
+              throw new PluginPackageStoreError(
+                'commit_outcome_unknown',
+                `Plugin package publication outcome is unknown: ${decoded.manifest.id}`,
+                { cause: error },
+              );
+            }
+          },
+          commit: async () => {
+            if (settled) return;
+            if (!published) throw persistence('Plugin package install was not published');
+            settled = true;
+            await rm(transaction, { recursive: true, force: true }).catch(() => undefined);
+          },
+          rollback: async () => {
+            if (settled) return;
+            settled = true;
+            if (!published) {
+              await rm(transaction, { recursive: true, force: true });
+              return;
+            }
+            await rollbackPublishedInstall(this.root, target, transaction, movedPrevious);
+          },
+        });
+      } catch (error) {
+        if (published) {
+          try {
+            await rollbackPublishedInstall(this.root, target, transaction, movedPrevious);
+          } catch (rollbackError) {
+            if (rollbackError instanceof PluginPackageStoreError) throw rollbackError;
+            throw new PluginPackageStoreError(
+              'commit_outcome_unknown',
+              `Plugin package installation outcome is unknown: ${decoded.manifest.id}`,
+              { cause: new AggregateError([error, rollbackError]) },
+            );
+          }
+        } else {
+          await rm(transaction, { recursive: true, force: true }).catch(() => undefined);
+        }
+        if (error instanceof PluginPackageStoreError) throw error;
+        throw persistence(`Unable to install Plugin package ${decoded.manifest.id}`, error);
+      }
+    } finally {
+      await source.dispose();
+    }
+  }
+
+  async #recoverInstall(transactionRoot: string, authorityGeneration: number): Promise<void> {
+    const transaction = await readTransaction(transactionRoot);
+    if (!transaction) {
+      // The journal is synced before the first canonical Package rename. A
+      // journal-less directory is therefore either an abandoned preparation
+      // or a partially removed, already-committed transaction. In both cases
+      // the transaction directory is only a remnant and is safe to discard.
+      await rm(transactionRoot, { recursive: true, force: true });
+      return;
+    }
+    const target = join(this.root, transaction.extensionId);
+    const candidate = join(transactionRoot, 'candidate');
+    const previous = join(transactionRoot, 'previous');
+    const rejected = join(transactionRoot, 'rejected');
+    const candidateExists = await exists(candidate);
+    const targetExists = await exists(target);
+    const previousExists = await exists(previous);
+    const rejectedExists = await exists(rejected);
+    if (authorityGeneration === transaction.baseGeneration) {
+      if (rejectedExists) {
+        // Rollback has already moved the candidate away from the canonical
+        // target. If target exists it is the restored previous Package; if it
+        // does not, finish restoring previous before dropping the rejected
+        // candidate with the transaction directory.
+        if (!targetExists && previousExists) await rename(previous, target);
+      } else {
+        if (!candidateExists && targetExists) {
+          await rm(target, { recursive: true, force: true });
+        }
+        if (previousExists) await rename(previous, target);
+      }
+      await syncDirectory(this.root);
+      await rm(transactionRoot, { recursive: true, force: true });
+      return;
+    }
+    if (authorityGeneration >= transaction.nextGeneration) {
+      if (candidateExists || !targetExists) {
+        throw persistence(
+          `Plugin package transaction does not match committed authority: ${transaction.extensionId}`,
+        );
+      }
+      await rm(transactionRoot, { recursive: true, force: true });
+      return;
+    }
+    throw persistence(
+      `Plugin package transaction generation is ambiguous: ${transaction.extensionId}`,
+    );
+  }
+
+  async list(): Promise<readonly InstalledPluginPackage[]> {
+    const installed: InstalledPluginPackage[] = [];
+    for (const extensionId of await this.identities()) installed.push(await this.load(extensionId));
+    return Object.freeze(installed);
+  }
+
+  async load(extensionId: string): Promise<InstalledPluginPackage> {
+    requireIdentity(extensionId);
+    const root = join(this.root, extensionId);
+    try {
+      if (!(await stat(root)).isDirectory()) throw invalid('Installed package is not a directory');
+    } catch (error) {
+      if ((error as NodeJS.ErrnoException).code === 'ENOENT') {
+        throw new PluginPackageStoreError(
+          'not_found',
+          `Plugin package is not installed: ${extensionId}`,
+        );
+      }
+      if (error instanceof PluginPackageStoreError) throw error;
+      throw persistence(`Unable to read Plugin package ${extensionId}`, error);
+    }
+    const files = await readPackage(root);
+    const decoded = await decodePackage(root, files);
+    if (decoded.manifest.id !== extensionId) {
+      throw invalid(`Installed Plugin identity does not match its directory: ${extensionId}`);
+    }
+    return freezeInstalled(root, decoded);
+  }
+
+  async export(extensionId: string, targetPath: string): Promise<void> {
+    const installed = await this.load(extensionId);
+    await exportExtensionBundle(installed.root, targetPath);
+  }
+
+  async uninstall(extensionId: string): Promise<void> {
+    await this.load(extensionId);
+    const target = join(this.root, extensionId);
+    const removed = join(this.root, `.removed-${extensionId}-${randomUUID()}`);
+    let published = false;
+    try {
+      await rename(target, removed);
+      published = true;
+      await syncDirectory(this.root);
+      await rm(removed, { recursive: true, force: true }).catch(() => undefined);
+    } catch (error) {
+      if (published) {
+        throw new PluginPackageStoreError(
+          'commit_outcome_unknown',
+          `Plugin package uninstall outcome is unknown: ${extensionId}`,
+          { cause: error },
+        );
+      }
+      if ((error as NodeJS.ErrnoException).code !== 'ENOENT') {
+        throw persistence(`Unable to uninstall Plugin package ${extensionId}`, error);
+      }
+    }
+  }
+}
+
+async function writeTransaction(
+  root: string,
+  transaction: PackageInstallTransaction,
+): Promise<void> {
+  const handle = await open(join(root, 'transaction.json'), 'wx', 0o600);
+  try {
+    await handle.writeFile(`${JSON.stringify(transaction)}\n`, 'utf8');
+    await handle.sync();
+  } finally {
+    await handle.close();
+  }
+  await syncDirectory(root);
+  await syncDirectory(dirname(root));
+}
+
+async function readTransaction(root: string): Promise<PackageInstallTransaction | undefined> {
+  let value: unknown;
+  try {
+    value = JSON.parse(await readFile(join(root, 'transaction.json'), 'utf8'));
+  } catch (error) {
+    if ((error as NodeJS.ErrnoException).code === 'ENOENT') return undefined;
+    throw persistence('Unable to read Plugin package install transaction', error);
+  }
+  if (!value || typeof value !== 'object' || Array.isArray(value)) {
+    throw persistence('Plugin package install transaction is invalid');
+  }
+  const record = value as Record<string, unknown>;
+  if (
+    Object.keys(record).length !== 4 ||
+    record.schemaVersion !== 1 ||
+    !isCanonicalExtensionId(record.extensionId) ||
+    !Number.isSafeInteger(record.baseGeneration) ||
+    !Number.isSafeInteger(record.nextGeneration) ||
+    (record.baseGeneration as number) < 0 ||
+    record.nextGeneration !== (record.baseGeneration as number) + 1
+  ) {
+    throw persistence('Plugin package install transaction is invalid');
+  }
+  return Object.freeze({
+    schemaVersion: 1,
+    extensionId: record.extensionId as string,
+    baseGeneration: record.baseGeneration as number,
+    nextGeneration: record.nextGeneration as number,
+  });
+}
+
+async function rollbackPublishedInstall(
+  storeRoot: string,
+  target: string,
+  transactionRoot: string,
+  movedPrevious: boolean,
+): Promise<void> {
+  const rejected = join(transactionRoot, 'rejected');
+  try {
+    await rename(target, rejected).catch((error: NodeJS.ErrnoException) => {
+      if (error.code !== 'ENOENT') throw error;
+    });
+    if (movedPrevious) await rename(join(transactionRoot, 'previous'), target);
+    await rename(rejected, join(transactionRoot, 'candidate')).catch(
+      (error: NodeJS.ErrnoException) => {
+        if (error.code !== 'ENOENT') throw error;
+      },
+    );
+    await syncDirectory(storeRoot);
+    await rm(transactionRoot, { recursive: true, force: true });
+    await syncDirectory(storeRoot);
+  } catch (error) {
+    throw new PluginPackageStoreError(
+      'commit_outcome_unknown',
+      'Plugin package rollback outcome is unknown',
+      { cause: error },
+    );
+  }
+}
+
+async function exists(path: string): Promise<boolean> {
+  try {
+    await stat(path);
+    return true;
+  } catch (error) {
+    if ((error as NodeJS.ErrnoException).code === 'ENOENT') return false;
+    throw error;
+  }
+}
+
+async function decodePackage(
+  root: string,
+  files: readonly PackageFile[],
+): Promise<{
+  readonly manifest: ExtensionPackageManifest;
+  readonly entry: string;
+  readonly contentDigest: string;
+}> {
+  if (!files.some((file) => file.path === EXTENSION_PACKAGE_MANIFEST_FILE)) {
+    throw invalid(`Plugin package is missing ${EXTENSION_PACKAGE_MANIFEST_FILE}`);
+  }
+  const manifest = await loadExtensionPackageManifest(root);
+  if (!manifest) throw invalid(`Plugin package is missing ${EXTENSION_PACKAGE_MANIFEST_FILE}`);
+  if (!manifest.runtime?.entry) throw invalid('Plugin package has no trusted Runtime entry');
+  if (!files.some((file) => file.path === manifest.runtime!.entry)) {
+    throw invalid(`Plugin Runtime entry does not exist: ${manifest.runtime.entry}`);
+  }
+  if (manifest.composition && !files.some((file) => file.path === manifest.composition!.patch)) {
+    throw invalid(`Plugin Composition patch does not exist: ${manifest.composition.patch}`);
+  }
+  return Object.freeze({
+    manifest,
+    entry: manifest.runtime.entry,
+    contentDigest: extensionPackageContentDigest(files),
+  });
+}
+
+async function readPackage(rootValue: string): Promise<readonly PackageFile[]> {
+  let root: string;
+  try {
+    root = await realpath(rootValue);
+  } catch (error) {
+    throw invalid('Plugin package source is unavailable', error);
+  }
+  const paths: string[] = [];
+  await collect(root, '', paths);
+  if (paths.length === 0 || paths.length > MAX_FILES) {
+    throw invalid('Plugin package file count is invalid');
+  }
+  let total = 0;
+  const files: PackageFile[] = [];
+  for (const path of paths.sort()) {
+    const handle = await open(join(root, ...path.split('/')), 'r');
+    try {
+      const metadata = await handle.stat();
+      if (!metadata.isFile() || metadata.size > MAX_FILE_BYTES) {
+        throw invalid(`Plugin package file is invalid: ${path}`);
+      }
+      const content = await handle.readFile();
+      total += content.byteLength;
+      if (total > MAX_PACKAGE_BYTES) throw invalid('Plugin package is too large');
+      files.push(Object.freeze({ path, content }));
+    } finally {
+      await handle.close();
+    }
+  }
+  return Object.freeze(files);
+}
+
+async function collect(root: string, directory: string, paths: string[]): Promise<void> {
+  const entries = await readdir(directory ? join(root, ...directory.split('/')) : root, {
+    withFileTypes: true,
+  });
+  for (const entry of entries.sort((left, right) => left.name.localeCompare(right.name))) {
+    if (entry.name === '.git') continue;
+    const path = safePath(directory ? `${directory}/${entry.name}` : entry.name);
+    if (entry.isSymbolicLink()) throw invalid(`Plugin package may not contain symlinks: ${path}`);
+    if (entry.isDirectory()) await collect(root, path, paths);
+    else if (entry.isFile()) paths.push(path);
+    else throw invalid(`Plugin package contains an unsupported entry: ${path}`);
+    if (paths.length > MAX_FILES) throw invalid('Plugin package contains too many files');
+  }
+}
+
+async function writeFile(root: string, file: PackageFile): Promise<void> {
+  const target = join(root, ...file.path.split('/'));
+  await mkdir(dirname(target), { recursive: true, mode: 0o700 });
+  const handle = await open(target, 'wx', 0o600);
+  try {
+    await handle.writeFile(file.content);
+    await handle.sync();
+  } finally {
+    await handle.close();
+  }
+}
+
+async function syncTree(root: string, files: readonly PackageFile[]): Promise<void> {
+  const directories = new Set<string>([root]);
+  for (const file of files) {
+    let current = dirname(join(root, ...file.path.split('/')));
+    while (current.startsWith(root)) {
+      directories.add(current);
+      if (current === root) break;
+      current = dirname(current);
+    }
+  }
+  for (const directory of [...directories].sort((a, b) => b.length - a.length)) {
+    await syncDirectory(directory);
+  }
+}
+
+async function syncDirectory(directory: string): Promise<void> {
+  const handle = await open(directory, 'r');
+  try {
+    await handle.sync();
+  } finally {
+    await handle.close();
+  }
+}
+
+function freezeInstalled(
+  root: string,
+  decoded: {
+    readonly manifest: ExtensionPackageManifest;
+    readonly entry: string;
+    readonly contentDigest: string;
+  },
+): InstalledPluginPackage {
+  return Object.freeze({
+    extensionId: decoded.manifest.id,
+    contentDigest: decoded.contentDigest,
+    root,
+    entry: join(root, ...decoded.entry.split('/')),
+    manifest: decoded.manifest,
+  });
+}
+
+function safePath(value: string): string {
+  if (
+    !value ||
+    value.length > 512 ||
+    value.includes('\\') ||
+    value.startsWith('/') ||
+    posix.normalize(value) !== value ||
+    value.split('/').some((part) => !part || part === '.' || part === '..')
+  ) {
+    throw invalid('Plugin package path is invalid');
+  }
+  return value;
+}
+
+function requireIdentity(extensionId: string): void {
+  if (!isCanonicalExtensionId(extensionId)) throw invalid('Plugin package identity is invalid');
+}
+
+function invalid(message: string, cause?: unknown): PluginPackageStoreError {
+  return new PluginPackageStoreError('invalid_package', message, { cause });
+}
+
+function persistence(message: string, cause?: unknown): PluginPackageStoreError {
+  return new PluginPackageStoreError('persistence_failed', message, { cause });
+}
diff --git a/packages/runtime-host/src/server/plugin-platform-coordinator.ts b/packages/runtime-host/src/server/plugin-platform-coordinator.ts
new file mode 100644
index 0000000000..ec1cc78071
--- /dev/null
+++ b/packages/runtime-host/src/server/plugin-platform-coordinator.ts
@@ -0,0 +1,329 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import { createHash } from 'node:crypto';
+import {
+  MakaPluginRuntimeError,
+  type MakaCompositionApplyInput,
+  type MakaCompositionEntryInspection,
+} from '@maka/runtime/plugin-runtime';
+import type {
+  OperationOutcome,
+  PluginPackageExportInput,
+  PluginPackageInstallInput,
+  PluginPackageProjection,
+  PluginPackageUninstallInput,
+  PluginPlatformFailureProjection,
+  PluginPlatformQueryInput,
+  PluginPlatformQueryResult,
+} from '../protocol/index.js';
+import { PLUGIN_PLATFORM_QUERY_RESULT_MAX_BYTES } from '../protocol/plugin-platform.js';
+import { ExtensionBundleError } from './extension-bundle.js';
+import { ExtensionPackageManifestError } from './extension-package-manifest.js';
+import type { PluginPlatformOperationHandlerMap } from './operation-dispatcher.js';
+import { PluginCompositionPatchError } from './plugin-composition-patch.js';
+import { PluginPackageLoaderError } from './plugin-package-loader.js';
+import { PluginPackageStoreError } from './plugin-package-store.js';
+import { HostPluginPlatform, HostPluginPlatformError } from './plugin-platform.js';
+
+export class HostPluginPlatformCoordinator {
+  readonly handlers: PluginPlatformOperationHandlerMap = {
+    'plugin.platform.query': (input) => this.#query(input),
+    'plugin.package.install': (input) => this.#install(input),
+    'plugin.package.uninstall': (input) => this.#uninstall(input),
+    'plugin.package.reload': (input) => this.#reload(input),
+    'plugin.package.export': (input) => this.#export(input),
+    'plugin.composition.apply': (input) => this.#apply(input),
+    'plugin.platform.reconcile': () => this.#reconcile(),
+  };
+
+  constructor(readonly platform: HostPluginPlatform) {}
+
+  async #query(
+    input: PluginPlatformQueryInput,
+  ): Promise<OperationOutcome<'plugin.platform.query'>> {
+    try {
+      return await this.platform.read(async () => {
+        const failures = this.platform.failures();
+        if (input.view === 'status') {
+          return {
+            ok: true,
+            result: {
+              view: 'status',
+              ...(await this.platform.status()),
+            },
+          };
+        }
+        if (input.view === 'entries') {
+          const inspections = flattenInspections(this.platform.inspect(input.rootId));
+          return { ok: true, result: boundedPage('entries', inspections, input) };
+        }
+        if (input.view === 'failures') {
+          return { ok: true, result: boundedPage('failures', failures, input) };
+        }
+        const packages = await this.platform.packageProjections();
+        return {
+          ok: true,
+          result: boundedPage('packages', packages, input),
+        };
+      });
+    } catch (error) {
+      return failure(error);
+    }
+  }
+
+  async #install(
+    input: PluginPackageInstallInput,
+  ): Promise<OperationOutcome<'plugin.package.install'>> {
+    try {
+      return { ok: true, result: await this.platform.installPackage(input.sourcePath) };
+    } catch (error) {
+      return failure(error);
+    }
+  }
+
+  async #uninstall(
+    input: PluginPackageUninstallInput,
+  ): Promise<OperationOutcome<'plugin.package.uninstall'>> {
+    try {
+      return { ok: true, result: await this.platform.uninstallPackage(input.extensionId) };
+    } catch (error) {
+      return failure(error);
+    }
+  }
+
+  async #reload(
+    input: PluginPackageUninstallInput,
+  ): Promise<OperationOutcome<'plugin.package.reload'>> {
+    try {
+      return { ok: true, result: await this.platform.reloadPackage(input.extensionId) };
+    } catch (error) {
+      return failure(error);
+    }
+  }
+
+  async #export(
+    input: PluginPackageExportInput,
+  ): Promise<OperationOutcome<'plugin.package.export'>> {
+    try {
+      await this.platform.exportPackage(input.extensionId, input.targetPath);
+      return { ok: true, result: { targetPath: input.targetPath } };
+    } catch (error) {
+      return failure(error);
+    }
+  }
+
+  async #apply(
+    input: MakaCompositionApplyInput,
+  ): Promise<OperationOutcome<'plugin.composition.apply'>> {
+    try {
+      return { ok: true, result: await this.platform.apply(input) };
+    } catch (error) {
+      return failure(error);
+    }
+  }
+
+  async #reconcile(): Promise<OperationOutcome<'plugin.platform.reconcile'>> {
+    try {
+      return { ok: true, result: await this.platform.reconcile() };
+    } catch (error) {
+      return failure(error);
+    }
+  }
+}
+
+function flattenInspections(
+  inspections: readonly MakaCompositionEntryInspection[],
+): readonly MakaCompositionEntryInspection[] {
+  const flattened: MakaCompositionEntryInspection[] = [];
+  const visit = (items: readonly MakaCompositionEntryInspection[]): void => {
+    for (const item of items) {
+      flattened.push(Object.freeze({ ...item, children: Object.freeze([]) }));
+      visit(item.children);
+    }
+  };
+  visit(inspections);
+  return Object.freeze(flattened);
+}
+
+function boundedPage(
+  view: 'packages',
+  values: readonly PluginPackageProjection[],
+  input: PluginPlatformQueryInput,
+): Extract<PluginPlatformQueryResult, { readonly view: 'packages' }>;
+function boundedPage(
+  view: 'entries',
+  values: readonly MakaCompositionEntryInspection[],
+  input: PluginPlatformQueryInput,
+): Extract<PluginPlatformQueryResult, { readonly view: 'entries' }>;
+function boundedPage(
+  view: 'failures',
+  values: readonly PluginPlatformFailureProjection[],
+  input: PluginPlatformQueryInput,
+): Extract<PluginPlatformQueryResult, { readonly view: 'failures' }>;
+function boundedPage<T>(
+  view: 'packages' | 'entries' | 'failures',
+  values: readonly T[],
+  input: PluginPlatformQueryInput,
+): PluginPlatformQueryResult {
+  const digest = pageDigest(view, input.rootId, values);
+  const cursor =
+    input.cursor === undefined ? 0 : decodeCursor(input.cursor, view, input.rootId, digest);
+  const limit = input.limit ?? 32;
+  if (cursor > values.length)
+    throw new HostPluginPlatformError('stale_cursor', 'Plugin Platform query cursor is stale');
+  const items: T[] = [];
+  for (let index = cursor; index < values.length && items.length < limit; index += 1) {
+    const candidate = [...items, values[index] as T];
+    if (
+      Buffer.byteLength(
+        JSON.stringify({
+          view,
+          items: candidate,
+          nextCursor: encodeCursor(view, input.rootId, digest, index + 1),
+        }),
+        'utf8',
+      ) > PLUGIN_PLATFORM_QUERY_RESULT_MAX_BYTES
+    ) {
+      break;
+    }
+    items.push(values[index] as T);
+  }
+  if (cursor < values.length && items.length === 0) {
+    throw new MakaPluginRuntimeError('invalid_entry', 'Plugin Platform page item is too large');
+  }
+  const next = cursor + items.length;
+  return Object.freeze({
+    view,
+    items: Object.freeze(items),
+    nextCursor: next < values.length ? encodeCursor(view, input.rootId, digest, next) : null,
+  }) as PluginPlatformQueryResult;
+}
+
+interface PageCursor {
+  readonly version: 1;
+  readonly view: 'packages' | 'entries' | 'failures';
+  readonly rootId?: string;
+  readonly digest: string;
+  readonly offset: number;
+}
+
+function pageDigest(view: string, rootId: string | undefined, values: readonly unknown[]): string {
+  return createHash('sha256')
+    .update(JSON.stringify({ view, rootId: rootId ?? null, values }))
+    .digest('base64url');
+}
+
+function encodeCursor(
+  view: PageCursor['view'],
+  rootId: string | undefined,
+  digest: string,
+  offset: number,
+): string {
+  return Buffer.from(
+    JSON.stringify({ version: 1, view, ...(rootId ? { rootId } : {}), digest, offset }),
+    'utf8',
+  ).toString('base64url');
+}
+
+function decodeCursor(
+  encoded: string,
+  view: PageCursor['view'],
+  rootId: string | undefined,
+  digest: string,
+): number {
+  try {
+    const cursor = JSON.parse(Buffer.from(encoded, 'base64url').toString('utf8')) as PageCursor;
+    if (
+      cursor.version !== 1 ||
+      cursor.view !== view ||
+      cursor.rootId !== rootId ||
+      cursor.digest !== digest ||
+      !Number.isSafeInteger(cursor.offset) ||
+      cursor.offset < 0
+    ) {
+      throw new Error('mismatch');
+    }
+    return cursor.offset;
+  } catch {
+    throw new HostPluginPlatformError('stale_cursor', 'Plugin Platform query cursor is stale');
+  }
+}
+
+function failure<K extends keyof PluginPlatformOperationHandlerMap>(
+  error: unknown,
+): OperationOutcome<K> {
+  if (error instanceof HostPluginPlatformError) {
+    if (error.code === 'not_ready') return failed('host_not_ready', error.message);
+    if (error.code === 'stale_cursor') return failed('stale_cursor', error.message);
+    if (error.code === 'closed') return failed('host_draining', error.message);
+    if (error.code === 'persistence_failed') return failed('persistence_failed', error.message);
+    if (error.code === 'recovery_failed') return failed('persistence_failed', error.message);
+    if (error.code === 'commit_outcome_unknown') {
+      return failed('commit_outcome_unknown', error.message);
+    }
+    if (error.code === 'mutation_failed' && error.cause) return failure(error.cause);
+    return failed('internal_failure', error.message);
+  }
+  if (error instanceof PluginPackageStoreError) {
+    if (error.code === 'not_found') return failed('not_found', error.message);
+    if (error.code === 'invalid_package') return failed('invalid_request', error.message);
+    if (error.code === 'commit_outcome_unknown') {
+      return failed('commit_outcome_unknown', error.message);
+    }
+    return failed('persistence_failed', error.message);
+  }
+  if (error instanceof PluginPackageLoaderError) {
+    if (error.code === 'not_found') return failed('not_found', error.message);
+    if (error.code === 'invalid_package') return failed('invalid_request', error.message);
+    return failed('persistence_failed', error.message);
+  }
+  if (
+    error instanceof ExtensionBundleError ||
+    error instanceof ExtensionPackageManifestError ||
+    error instanceof PluginCompositionPatchError
+  ) {
+    return failed('invalid_request', error.message);
+  }
+  if (error instanceof MakaPluginRuntimeError) {
+    switch (error.code) {
+      case 'package_not_found':
+      case 'entry_not_found':
+        return failed('not_found', error.message);
+      case 'package_exists':
+      case 'package_in_use':
+      case 'entry_exists':
+        return failed('operation_conflict', error.message);
+      case 'invalid_package':
+      case 'invalid_entry':
+      case 'dependency_cycle':
+        return failed('invalid_request', error.message);
+      default:
+        return failed('internal_failure', error.message);
+    }
+  }
+  return failed('internal_failure', 'Plugin Platform operation failed');
+}
+
+function failed<K extends keyof PluginPlatformOperationHandlerMap>(
+  code: string,
+  message: string,
+): OperationOutcome<K> {
+  return { ok: false, error: { code, message } } as OperationOutcome<K>;
+}
diff --git a/packages/runtime-host/src/server/plugin-platform.ts b/packages/runtime-host/src/server/plugin-platform.ts
new file mode 100644
index 0000000000..7ffec1121a
--- /dev/null
+++ b/packages/runtime-host/src/server/plugin-platform.ts
@@ -0,0 +1,1507 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import {
+  MakaCompositionLoader,
+  type MakaCompositionRecoveryFailure,
+} from '@maka/runtime/plugin-composition-loader';
+import {
+  applyCompositionState,
+  MakaPluginRuntimeError,
+  type MakaCompositionApplyInput,
+  type MakaCompositionEntry,
+  type MakaCompositionEntryInspection,
+  type MakaCompositionOperation,
+  type MakaCompositionState,
+  type MakaPluginPackage,
+  type MakaPluginRootId,
+} from '@maka/runtime/plugin-runtime';
+import type { ExtensionPackageManifest } from './extension-package-manifest.js';
+import { validateExtensionConfiguration } from './extension-package-manifest.js';
+import { recoverExtensionBundleImports } from './extension-bundle.js';
+import { loadPluginCompositionPatch } from './plugin-composition-patch.js';
+import {
+  HostPluginCompositionStore,
+  HostPluginCompositionStoreError,
+  type PersistedPluginComposition,
+} from './plugin-composition-store.js';
+import { TrustedPluginPackageLoader } from './plugin-package-loader.js';
+import { PluginPackageStore, PluginPackageStoreError } from './plugin-package-store.js';
+import type {
+  PluginMutationReceipt,
+  PluginPackageProjection,
+  PluginPlatformConvergence,
+  PluginPlatformPhase,
+} from '../protocol/plugin-platform.js';
+
+export class HostPluginPlatformError extends Error {
+  readonly name = 'HostPluginPlatformError';
+
+  constructor(
+    readonly code:
+      | 'closed'
+      | 'persistence_failed'
+      | 'commit_outcome_unknown'
+      | 'recovery_failed'
+      | 'mutation_failed'
+      | 'not_ready'
+      | 'stale_cursor',
+    message: string,
+    options?: ErrorOptions,
+  ) {
+    super(message, options);
+  }
+}
+
+export interface HostPluginPlatformOptions {
+  readonly composition?: MakaCompositionLoader;
+  readonly packages?: PluginPackageStore;
+  readonly packageLoader?: TrustedPluginPackageLoader;
+  readonly store?: HostPluginCompositionStore;
+}
+
+export interface HostPluginPlatformFailure {
+  readonly entryId?: string;
+  readonly extensionId?: string;
+  readonly diagnostic: string;
+}
+
+interface CompositionEntryRecord {
+  readonly entry: MakaCompositionEntry;
+  readonly rootId: MakaPluginRootId;
+  readonly disabled: boolean;
+}
+
+interface DesiredProjection {
+  readonly desired: MakaCompositionState;
+  readonly failures: readonly HostPluginPlatformFailure[];
+  readonly structuralDependencies: ReadonlyMap<string, ReadonlySet<string>>;
+}
+
+interface PackageOverride {
+  readonly extensionId: string;
+  readonly patch: MakaCompositionApplyInput | undefined;
+  readonly manifest: ExtensionPackageManifest;
+}
+
+/**
+ * Runtime Host's sole authority for trusted Plugin packages and Entry composition.
+ * Package layers and user overlays are durable; the desired Entry Tree is derived from them.
+ */
+export class HostPluginPlatform {
+  readonly #composition: MakaCompositionLoader;
+  readonly #packages: PluginPackageStore;
+  readonly #packageLoader: TrustedPluginPackageLoader;
+  readonly #store: HostPluginCompositionStore;
+
+  #authority: PersistedPluginComposition = emptyCompositionAuthority();
+  #desired: MakaCompositionState = emptyCompositionState();
+  #mutation: Promise<void> = Promise.resolve();
+  #phase: PluginPlatformPhase = 'new';
+  #recoveryStarted = false;
+  #recoveryComplete = false;
+  #drainRequested = false;
+  #convergence: PluginPlatformConvergence = 'unknown';
+  #fence?: Error;
+  #reconcileTimer?: ReturnType<typeof setTimeout>;
+  #reconcileDelayMs = 250;
+  #failures: readonly HostPluginPlatformFailure[] = Object.freeze([]);
+  #structuralDependencies: ReadonlyMap<string, ReadonlySet<string>> = new Map();
+
+  constructor(
+    readonly controlDirectory: string,
+    options: HostPluginPlatformOptions = {},
+  ) {
+    this.#composition = options.composition ?? new MakaCompositionLoader();
+    this.#packages = options.packages ?? new PluginPackageStore(controlDirectory);
+    this.#packageLoader =
+      options.packageLoader ?? new TrustedPluginPackageLoader(controlDirectory, this.#packages);
+    this.#store = options.store ?? new HostPluginCompositionStore(controlDirectory);
+  }
+
+  async recover(): Promise<void> {
+    if (
+      this.#recoveryStarted ||
+      (this.#phase !== 'new' && !(this.#phase === 'draining' && this.#drainRequested))
+    ) {
+      throw new HostPluginPlatformError(
+        'recovery_failed',
+        `Plugin Platform cannot recover from phase ${this.#phase}`,
+      );
+    }
+    this.#recoveryStarted = true;
+    if (!this.#drainRequested) this.#phase = 'recovering';
+    await this.#serialize(async () => {
+      try {
+        const storedAuthority = (await this.#store.read()) ?? emptyCompositionAuthority();
+        await recoverExtensionBundleImports(this.controlDirectory);
+        await this.#packages.recover(storedAuthority.generation);
+        await this.#packageLoader.collectGarbage();
+        const packageFailures: HostPluginPlatformFailure[] = [];
+        for (const extensionId of await this.#packages.identities()) {
+          let loaded: MakaPluginPackage | undefined;
+          try {
+            loaded = await this.#packageLoader.load(extensionId);
+            await this.#composition.install(loaded);
+          } catch (error) {
+            if (loaded) await this.#packageLoader.release(loaded).catch(() => undefined);
+            packageFailures.push(
+              Object.freeze({
+                extensionId,
+                diagnostic: boundedDiagnostic(error),
+              }),
+            );
+          }
+        }
+        const projection = await this.#deriveDesired(storedAuthority, 'recovery');
+        const entryFailures = await this.#recoverDesiredRuntime(projection.desired);
+        this.#failures = Object.freeze([
+          ...packageFailures,
+          ...projection.failures,
+          ...entryFailures.map((failure) =>
+            Object.freeze({ entryId: failure.entryId, diagnostic: failure.diagnostic }),
+          ),
+        ]);
+        this.#authority = storedAuthority;
+        this.#desired = projection.desired;
+        this.#structuralDependencies = projection.structuralDependencies;
+        this.#convergence = this.#failures.length > 0 ? 'diverged' : 'converged';
+        this.#recoveryComplete = true;
+        this.#phase = this.#drainRequested
+          ? 'draining'
+          : this.#failures.length > 0
+            ? 'degraded'
+            : 'ready';
+        if (this.#failures.length > 0) this.#scheduleReconcile();
+      } catch (error) {
+        this.#fence = asError(error);
+        this.#recoveryComplete = true;
+        this.#phase = 'fenced';
+        this.#convergence = 'unknown';
+      }
+    });
+  }
+
+  async installPackage(
+    sourcePath: string,
+  ): Promise<PluginMutationReceipt & { readonly extensionId: string }> {
+    this.#assertMutable();
+    return await this.#serializeMutable(async () => {
+      let prepared;
+      try {
+        prepared = await this.#packages.prepareInstall(sourcePath);
+      } catch (error) {
+        if (error instanceof PluginPackageStoreError && error.code === 'commit_outcome_unknown') {
+          throw this.#fenceUnknownPackageOutcome(error, 'preparation');
+        }
+        throw error;
+      }
+      let loaded: MakaPluginPackage | undefined;
+      let authorityCommitted = false;
+      let packageCommitted = false;
+      let runtimeAdoptionStarted = false;
+      try {
+        const compositionPatch = await loadPluginCompositionPatch(prepared.installed);
+        loaded = await this.#packageLoader.loadInstalled(prepared.installed);
+        const alreadyInstalled = this.#composition
+          .installedPackages()
+          .some(({ packageId }) => packageId === prepared.installed.extensionId);
+        const layerPlan = await this.#planPackageLayer(
+          prepared.installed.extensionId,
+          compositionPatch,
+          prepared.installed.manifest,
+        );
+        await prepared.publish(this.#authority.generation, layerPlan.planned.generation);
+        await this.#commitDesiredAuthority(
+          layerPlan.planned,
+          layerPlan.packageLayers,
+          this.#authority.overlays,
+        );
+        authorityCommitted = true;
+        this.#structuralDependencies = layerPlan.structuralDependencies;
+        await prepared.commit();
+        packageCommitted = true;
+        this.#clearPackageFailure(prepared.installed.extensionId);
+        runtimeAdoptionStarted = true;
+        const failures = await this.#adoptRuntimePackage(
+          prepared.installed.extensionId,
+          loaded,
+          layerPlan.planned,
+          alreadyInstalled,
+        );
+        await this.#publishEntryFailures(failures);
+        this.#settleConvergence(failures.length === 0);
+        return Object.freeze({
+          extensionId: prepared.installed.extensionId,
+          ...this.#receipt('complete'),
+        });
+      } catch (error) {
+        if (authorityCommitted) {
+          if (loaded && !runtimeAdoptionStarted) {
+            await this.#packageLoader.release(loaded).catch(() => undefined);
+          }
+          this.#recordPackageFailure(prepared.installed.extensionId, error);
+          this.#settleConvergence(false);
+          return Object.freeze({
+            extensionId: prepared.installed.extensionId,
+            ...this.#receipt(packageCommitted ? 'complete' : 'pending'),
+          });
+        }
+        if (error instanceof PluginPackageStoreError && error.code === 'commit_outcome_unknown') {
+          if (loaded) await this.#packageLoader.release(loaded).catch(() => undefined);
+          throw this.#fenceUnknownPackageOutcome(error, 'publication');
+        }
+        if (error instanceof HostPluginPlatformError && error.code === 'commit_outcome_unknown') {
+          if (loaded) await this.#packageLoader.release(loaded).catch(() => undefined);
+          throw error;
+        }
+        try {
+          await prepared.rollback();
+        } catch (rollbackError) {
+          if (loaded) await this.#packageLoader.release(loaded).catch(() => undefined);
+          if (
+            rollbackError instanceof PluginPackageStoreError &&
+            rollbackError.code === 'commit_outcome_unknown'
+          ) {
+            throw this.#fenceUnknownPackageOutcome(rollbackError, 'rollback');
+          }
+          this.#fence = asError(rollbackError);
+          this.#phase = 'fenced';
+          throw new HostPluginPlatformError(
+            'persistence_failed',
+            'Plugin package installation and stored-package rollback both failed',
+            { cause: new AggregateError([error, rollbackError]) },
+          );
+        }
+        if (loaded) await this.#packageLoader.release(loaded).catch(() => undefined);
+        throw error;
+      }
+    });
+  }
+
+  async reloadPackage(extensionId: string): Promise<PluginMutationReceipt> {
+    this.#assertMutable();
+    return await this.#serializeMutable(async () => {
+      const loaded = await this.#packageLoader.load(extensionId);
+      let adoptionStarted = false;
+      try {
+        await this.#validateDesired(this.desiredComposition());
+        adoptionStarted = true;
+        const failures = await this.#adoptRuntimePackage(extensionId, loaded, this.#desired, true);
+        await this.#publishEntryFailures(failures);
+        this.#clearPackageFailure(extensionId);
+        this.#settleConvergence(failures.length === 0);
+      } catch (error) {
+        if (!adoptionStarted) await this.#packageLoader.release(loaded).catch(() => undefined);
+        this.#recordPackageFailure(extensionId, error);
+        this.#settleConvergence(false);
+      }
+      return this.#receipt('complete');
+    });
+  }
+
+  async uninstallPackage(extensionId: string): Promise<PluginMutationReceipt> {
+    this.#assertMutable();
+    return await this.#serializeMutable(async () => {
+      const structuralDependent = this.#structuralDependent(extensionId);
+      if (structuralDependent) {
+        throw new MakaPluginRuntimeError(
+          'package_in_use',
+          `Plugin package is structurally required by ${structuralDependent}`,
+        );
+      }
+      const manifestDependent = await this.#manifestDependentPackage(extensionId);
+      if (manifestDependent) {
+        throw new MakaPluginRuntimeError(
+          'package_in_use',
+          `Plugin package is required by package ${manifestDependent}`,
+        );
+      }
+      const packageLayers = this.#authority.packageLayers.filter((item) => item !== extensionId);
+      const candidateAuthority = compositionAuthority(
+        this.#authority.generation +
+          (packageLayers.length === this.#authority.packageLayers.length ? 0 : 1),
+        packageLayers,
+        this.#authority.overlays,
+      );
+      const projection = await this.#deriveDesired(candidateAuthority, 'strict');
+      const desiredUser = compositionEntries(projection.desired).find(
+        (entry) => entry.packageId === extensionId,
+      );
+      if (desiredUser) {
+        throw new MakaPluginRuntimeError(
+          'package_in_use',
+          `Plugin package is used by desired entry ${desiredUser.id}`,
+        );
+      }
+      const dependent = await this.#desiredPackageDependent(extensionId, projection.desired);
+      if (dependent) {
+        throw new MakaPluginRuntimeError(
+          'package_in_use',
+          `Plugin package is required by desired entry ${dependent.id}`,
+        );
+      }
+      if (packageLayers.length !== this.#authority.packageLayers.length) {
+        await this.#commitDesiredAuthority(
+          projection.desired,
+          packageLayers,
+          this.#authority.overlays,
+        );
+        this.#structuralDependencies = projection.structuralDependencies;
+      }
+      const installedInRuntime = this.#composition
+        .installedPackages()
+        .some(({ packageId }) => packageId === extensionId);
+      const pkg = installedInRuntime ? this.#composition.package(extensionId) : undefined;
+      const postCommitErrors: unknown[] = [];
+      const failures = await this.#recoverDesiredRuntime(projection.desired).catch((error) => {
+        postCommitErrors.push(error);
+        return Object.freeze([]) as readonly MakaCompositionRecoveryFailure[];
+      });
+      await this.#publishEntryFailures(failures);
+      if (failures.length > 0) postCommitErrors.push(new Error('Runtime convergence failed'));
+      if (pkg) {
+        await this.#composition
+          .uninstall(extensionId)
+          .catch((error) => postCommitErrors.push(error));
+      }
+      await this.#packages.uninstall(extensionId).catch((error) => postCommitErrors.push(error));
+      if (pkg) await this.#releaseGeneration(pkg);
+      if (postCommitErrors.length > 0) {
+        this.#recordPackageFailure(extensionId, new AggregateError(postCommitErrors));
+        this.#settleConvergence(false);
+        return this.#receipt('pending');
+      }
+      this.#clearPackageFailure(extensionId);
+      this.#settleConvergence(true);
+      return this.#receipt('complete');
+    });
+  }
+
+  async apply(input: MakaCompositionApplyInput): Promise<PluginMutationReceipt> {
+    this.#assertMutable();
+    return await this.#serializeMutable(async () => {
+      let normalizedInput: MakaCompositionApplyInput;
+      let projection: DesiredProjection;
+      try {
+        normalizedInput = await this.#normalizeApplyInput(this.#desired, input);
+        const nextAuthority = compositionAuthority(
+          this.#authority.generation + (normalizedInput.operations.length > 0 ? 1 : 0),
+          this.#authority.packageLayers,
+          Object.freeze([...this.#authority.overlays, ...normalizedInput.operations]),
+        );
+        projection = await this.#deriveDesired(nextAuthority, 'strict');
+      } catch (error) {
+        throw new HostPluginPlatformError('mutation_failed', 'Plugin composition mutation failed', {
+          cause: error,
+        });
+      }
+      const next = compositionAuthority(
+        projection.desired.generation,
+        this.#authority.packageLayers,
+        Object.freeze([...this.#authority.overlays, ...normalizedInput.operations]),
+      );
+      try {
+        await this.#store.replace(next);
+        this.#authority = next;
+        this.#desired = projection.desired;
+        this.#structuralDependencies = projection.structuralDependencies;
+      } catch (error) {
+        if (
+          error instanceof HostPluginCompositionStoreError &&
+          error.code === 'commit_outcome_unknown'
+        ) {
+          this.#fence = error;
+          this.#phase = 'fenced';
+          throw new HostPluginPlatformError(
+            'commit_outcome_unknown',
+            'Plugin composition commit outcome is unknown; Plugin Platform was fenced',
+            { cause: error },
+          );
+        }
+        throw new HostPluginPlatformError(
+          'persistence_failed',
+          'Plugin composition persistence failed; Runtime state was not changed',
+          { cause: error },
+        );
+      }
+
+      try {
+        const failures = await this.#recoverDesiredRuntime(projection.desired);
+        await this.#publishEntryFailures(failures);
+        this.#settleConvergence(failures.length === 0);
+        return this.#receipt('complete');
+      } catch (error) {
+        await this.#publishEntryFailures(operationFailures(normalizedInput, error));
+        this.#settleConvergence(false);
+        return this.#receipt('complete');
+      }
+    });
+  }
+
+  desiredComposition(): MakaCompositionState {
+    this.#assertReadable();
+    return this.#desired;
+  }
+
+  failures(): readonly HostPluginPlatformFailure[] {
+    this.#assertReadable();
+    return this.#failures;
+  }
+
+  inspect(rootId?: MakaPluginRootId): readonly MakaCompositionEntryInspection[] {
+    this.#assertReadable();
+    return this.#composition.inspectTree(rootId);
+  }
+
+  async status(): Promise<{
+    readonly phase: PluginPlatformPhase;
+    readonly authorityEpoch: number;
+    readonly convergence: PluginPlatformConvergence;
+    readonly installedPackageCount: number;
+    readonly layeredPackageCount: number;
+    readonly desiredEntryCount: number;
+    readonly liveEntryCount: number;
+    readonly failureCount: number;
+    readonly fenceDiagnostic: string | null;
+  }> {
+    this.#assertReadable();
+    return Object.freeze({
+      phase: this.#phase,
+      authorityEpoch: this.#authority.generation,
+      convergence: this.#convergence,
+      installedPackageCount: (await this.#packages.identities()).length,
+      layeredPackageCount: this.#authority.packageLayers.length,
+      desiredEntryCount: compositionEntries(this.#desired).length,
+      liveEntryCount: countInspections(this.#composition.inspectTree()),
+      failureCount: this.#failures.length,
+      fenceDiagnostic: this.#fence ? boundedDiagnostic(this.#fence) : null,
+    });
+  }
+
+  async packageProjections(): Promise<readonly PluginPackageProjection[]> {
+    this.#assertReadable();
+    const requiredBy = new Map<string, Set<string>>();
+    for (const [actor, dependencies] of this.#structuralDependencies) {
+      if (actor.startsWith('@')) continue;
+      for (const dependency of dependencies) {
+        const users = requiredBy.get(dependency) ?? new Set<string>();
+        users.add(actor);
+        requiredBy.set(dependency, users);
+      }
+    }
+    const installedPackages = await Promise.all(
+      (await this.#packages.identities()).map((extensionId) => this.#packages.load(extensionId)),
+    );
+    for (const installed of installedPackages) {
+      for (const dependency of installed.manifest.dependencies) {
+        const users = requiredBy.get(dependency.id) ?? new Set<string>();
+        users.add(installed.extensionId);
+        requiredBy.set(dependency.id, users);
+      }
+    }
+    const projections: PluginPackageProjection[] = [];
+    for (const installed of installedPackages) {
+      const extensionId = installed.extensionId;
+      projections.push(
+        Object.freeze({
+          extensionId,
+          contentDigest: installed.contentDigest,
+          displayName: installed.manifest.displayName,
+          ...(installed.manifest.description
+            ? { description: installed.manifest.description }
+            : {}),
+          dependencies: Object.freeze(installed.manifest.dependencies.map(({ id }) => id)),
+          structuralDependencies: Object.freeze(
+            [...(this.#structuralDependencies.get(extensionId) ?? [])].sort(),
+          ),
+          requiredBy: Object.freeze([...(requiredBy.get(extensionId) ?? [])].sort()),
+        }),
+      );
+    }
+    return Object.freeze(projections);
+  }
+
+  async exportPackage(extensionId: string, targetPath: string): Promise<void> {
+    await this.read(() => this.#packages.export(extensionId, targetPath));
+  }
+
+  async reconcile(): Promise<PluginMutationReceipt> {
+    this.#assertMutable();
+    return await this.#serializeMutable(() => this.#reconcileNow());
+  }
+
+  read<T>(operation: () => T | Promise<T>): Promise<T> {
+    this.#assertReadable();
+    return this.#serialize(async () => {
+      this.#assertReadable();
+      return await operation();
+    });
+  }
+
+  beginDrain(): void {
+    if (this.#phase === 'closed') return;
+    this.#drainRequested = true;
+    this.#phase = 'draining';
+  }
+
+  async close(): Promise<void> {
+    if (this.#phase === 'closed') return;
+    this.#drainRequested = true;
+    this.#phase = 'draining';
+    if (this.#reconcileTimer) clearTimeout(this.#reconcileTimer);
+    this.#reconcileTimer = undefined;
+    const errors: unknown[] = [];
+    try {
+      await this.#mutation;
+    } catch (error) {
+      errors.push(error);
+    }
+    try {
+      await this.#composition.close();
+    } catch (error) {
+      errors.push(error);
+    }
+    try {
+      await this.#packageLoader.close();
+    } catch (error) {
+      errors.push(error);
+    }
+    this.#phase = 'closed';
+    if (errors.length > 0) {
+      throw new AggregateError(errors, 'Unable to close every Plugin Platform resource');
+    }
+  }
+
+  async #planPackageLayer(
+    extensionId: string,
+    patch: MakaCompositionApplyInput | undefined,
+    manifest: ExtensionPackageManifest,
+  ): Promise<{
+    readonly planned: MakaCompositionState;
+    readonly packageLayers: readonly string[];
+    readonly structuralDependencies: ReadonlyMap<string, ReadonlySet<string>>;
+  }> {
+    const previousIndex = this.#authority.packageLayers.indexOf(extensionId);
+    const packageLayers = this.#authority.packageLayers.filter((item) => item !== extensionId);
+    const nextIndex = previousIndex < 0 ? packageLayers.length : previousIndex;
+    packageLayers.splice(nextIndex, 0, extensionId);
+    const candidate = compositionAuthority(
+      this.#authority.generation + 1,
+      packageLayers,
+      this.#authority.overlays,
+    );
+    const projection = await this.#deriveDesired(candidate, 'strict', {
+      extensionId,
+      patch,
+      manifest,
+    });
+    return {
+      planned: projection.desired,
+      packageLayers,
+      structuralDependencies: projection.structuralDependencies,
+    };
+  }
+
+  async #deriveDesired(
+    authority: PersistedPluginComposition,
+    policy: 'strict' | 'recovery',
+    override?: PackageOverride,
+  ): Promise<DesiredProjection> {
+    let working = emptyCompositionState();
+    let owners = new Map<string, string>();
+    let dependencies = new Map<string, Set<string>>();
+    const failures: HostPluginPlatformFailure[] = [];
+
+    const applyLayer = async (
+      actor: string,
+      input: MakaCompositionApplyInput,
+      manifestOverride?: ExtensionPackageManifest,
+    ): Promise<void> => {
+      let candidate = working;
+      const candidateOwners = new Map(owners);
+      const candidateDependencies = cloneDependencyGraph(dependencies);
+      const applyOperation = async (operation: MakaCompositionOperation): Promise<void> => {
+        recordStructuralDependencies(
+          candidate,
+          candidateOwners,
+          candidateDependencies,
+          actor,
+          operation,
+        );
+        const previous = candidate;
+        candidate = applyCompositionState(candidate, { operations: [operation] });
+        updateEntryOwners(previous, candidateOwners, actor, operation);
+      };
+      if (policy === 'strict') {
+        const normalized = await this.#normalizeApplyInput(candidate, input, manifestOverride);
+        for (const operation of normalized.operations) await applyOperation(operation);
+      } else {
+        for (const operation of input.operations) {
+          try {
+            const normalized = await this.#normalizeApplyInput(
+              candidate,
+              { operations: [operation] },
+              manifestOverride,
+            );
+            await applyOperation(normalized.operations[0]!);
+          } catch (error) {
+            try {
+              await applyOperation(operation);
+            } catch {
+              // A structurally invalid operation cannot contribute to the
+              // recoverable desired tree, but its diagnostic is retained.
+            }
+            const identity = overlayFailureIdentity([operation]);
+            failures.push(
+              Object.freeze({
+                ...(actor.startsWith('@') ? { entryId: identity } : { extensionId: actor }),
+                diagnostic: boundedDiagnostic(error),
+              }),
+            );
+          }
+        }
+      }
+      if (!actor.startsWith('@') && manifestOverride) {
+        const inferred = [...(candidateDependencies.get(actor) ?? [])].sort();
+        const declared = [...(manifestOverride.composition?.structuralDependencies ?? [])].sort();
+        if (
+          inferred.length !== declared.length ||
+          inferred.some((dependency, index) => dependency !== declared[index])
+        ) {
+          throw new MakaPluginRuntimeError(
+            'invalid_package',
+            `Plugin package ${actor} structural dependencies do not match its composition patch`,
+          );
+        }
+      }
+      working = candidate;
+      owners = candidateOwners;
+      dependencies = candidateDependencies;
+    };
+
+    for (const extensionId of authority.packageLayers) {
+      try {
+        const installed =
+          override?.extensionId === extensionId
+            ? undefined
+            : await this.#packages.load(extensionId);
+        const patch =
+          override?.extensionId === extensionId
+            ? override.patch
+            : await loadPluginCompositionPatch(installed!);
+        const manifest =
+          override?.extensionId === extensionId ? override.manifest : installed!.manifest;
+        if (patch) {
+          await applyLayer(extensionId, patch, manifest);
+        }
+      } catch (error) {
+        if (policy === 'strict') throw error;
+        failures.push(Object.freeze({ extensionId, diagnostic: boundedDiagnostic(error) }));
+      }
+    }
+    if (authority.overlays.length > 0) {
+      try {
+        await applyLayer('@user-overlay', { operations: authority.overlays });
+      } catch (error) {
+        if (policy === 'strict') throw error;
+        failures.push(
+          Object.freeze({
+            entryId: overlayFailureIdentity(authority.overlays),
+            diagnostic: boundedDiagnostic(error),
+          }),
+        );
+      }
+    }
+
+    let desired = compositionWithGeneration(working, authority.generation);
+    if (policy === 'strict') await this.#validateDesired(desired, override?.manifest);
+    else desired = await this.#normalizeCompositionConfigurations(desired);
+    return Object.freeze({
+      desired,
+      failures: Object.freeze(failures),
+      structuralDependencies: freezeDependencyGraph(dependencies),
+    });
+  }
+
+  async #commitDesiredAuthority(
+    planned: MakaCompositionState,
+    packageLayers: readonly string[],
+    overlays: readonly MakaCompositionOperation[],
+  ): Promise<void> {
+    const next = compositionAuthority(planned.generation, packageLayers, overlays);
+    try {
+      await this.#store.replace(next);
+      this.#authority = next;
+      this.#desired = planned;
+    } catch (error) {
+      if (
+        error instanceof HostPluginCompositionStoreError &&
+        error.code === 'commit_outcome_unknown'
+      ) {
+        this.#fence = error;
+        this.#phase = 'fenced';
+        throw new HostPluginPlatformError(
+          'commit_outcome_unknown',
+          'Plugin composition commit outcome is unknown; Plugin Platform was fenced',
+          { cause: error },
+        );
+      }
+      throw new HostPluginPlatformError(
+        'persistence_failed',
+        'Plugin composition persistence failed; Runtime state was not changed',
+        { cause: error },
+      );
+    }
+  }
+
+  async #validateDesired(
+    state: MakaCompositionState,
+    manifestOverride?: ExtensionPackageManifest,
+  ): Promise<void> {
+    const records = compositionEntryRecords(state);
+    for (const record of records) {
+      await this.#validateEntry(record.entry, !record.disabled, manifestOverride);
+      await this.#validateActiveDependencies(record, records, manifestOverride);
+    }
+  }
+
+  async #normalizeApplyInput(
+    desired: MakaCompositionState,
+    input: MakaCompositionApplyInput,
+    manifestOverride?: ExtensionPackageManifest,
+  ): Promise<MakaCompositionApplyInput> {
+    if (input.baseGeneration !== undefined && input.baseGeneration !== desired.generation) {
+      throw new MakaPluginRuntimeError(
+        'invalid_entry',
+        `Composition generation changed from ${input.baseGeneration} to ${desired.generation}`,
+      );
+    }
+    let working = desired;
+    const operations: MakaCompositionOperation[] = [];
+    for (const operation of input.operations) {
+      let normalized: MakaCompositionOperation;
+      if (operation.type === 'insert') {
+        normalized = Object.freeze({
+          ...operation,
+          entry: await this.#normalizeEntryConfiguration(operation.entry, true, manifestOverride),
+        });
+      } else if (operation.type === 'update') {
+        const current = findCompositionEntry(working, operation.entryId);
+        if (!current) {
+          throw new MakaPluginRuntimeError(
+            'entry_not_found',
+            `Composition entry not found: ${operation.entryId}`,
+          );
+        }
+        const effective = Object.freeze({ ...current, ...operation.patch });
+        const configured = await this.#normalizeEntryConfiguration(
+          effective,
+          false,
+          manifestOverride,
+        );
+        normalized = Object.freeze({
+          ...operation,
+          patch: Object.freeze({ ...operation.patch, config: configured.config }),
+        });
+      } else {
+        normalized = operation;
+      }
+      operations.push(normalized);
+      const advanced = applyCompositionState(working, { operations: [normalized] });
+      working = compositionWithGeneration(advanced, desired.generation);
+    }
+    return Object.freeze({
+      ...(input.baseGeneration === undefined ? {} : { baseGeneration: input.baseGeneration }),
+      operations: Object.freeze(operations),
+    });
+  }
+
+  async #normalizeCompositionConfigurations(
+    state: MakaCompositionState,
+  ): Promise<MakaCompositionState> {
+    const normalize = async (entry: MakaCompositionEntry): Promise<MakaCompositionEntry> => {
+      let configured = entry;
+      try {
+        configured = await this.#normalizeEntryConfiguration(entry, false);
+      } catch {
+        // Recovery records malformed or unavailable package configuration as
+        // an Entry failure below instead of failing the Runtime Host.
+      }
+      return Object.freeze({
+        ...configured,
+        children: Object.freeze(await Promise.all((entry.children ?? []).map(normalize))),
+      });
+    };
+    const sessions = await Promise.all(
+      Object.entries(state.roots.sessions).map(
+        async ([scopeId, entries]) =>
+          [scopeId, Object.freeze(await Promise.all(entries.map(normalize)))] as const,
+      ),
+    );
+    return Object.freeze({
+      schemaVersion: 1,
+      generation: state.generation,
+      roots: Object.freeze({
+        profile: Object.freeze(await Promise.all(state.roots.profile.map(normalize))),
+        desktopUi: Object.freeze(await Promise.all(state.roots.desktopUi.map(normalize))),
+        sessions: Object.freeze(Object.fromEntries(sessions)),
+      }),
+    });
+  }
+
+  async #normalizeEntryConfiguration(
+    entry: MakaCompositionEntry,
+    recursive = true,
+    manifestOverride?: ExtensionPackageManifest,
+  ): Promise<MakaCompositionEntry> {
+    const config = entry.packageId
+      ? validateExtensionConfiguration(
+          (await this.#packageManifest(entry.packageId, manifestOverride)).configuration,
+          entry.config,
+        )
+      : scalarConfiguration(entry.config);
+    return Object.freeze({
+      ...entry,
+      config,
+      ...(recursive
+        ? {
+            children: Object.freeze(
+              await Promise.all(
+                (entry.children ?? []).map((child) =>
+                  this.#normalizeEntryConfiguration(child, true, manifestOverride),
+                ),
+              ),
+            ),
+          }
+        : {}),
+    });
+  }
+
+  async #desiredValidationFailures(
+    state: MakaCompositionState,
+  ): Promise<readonly MakaCompositionRecoveryFailure[]> {
+    const failures: MakaCompositionRecoveryFailure[] = [];
+    const records = compositionEntryRecords(state);
+    for (const record of records) {
+      try {
+        await this.#validateEntry(record.entry, !record.disabled);
+        await this.#validateActiveDependencies(record, records);
+      } catch (error) {
+        failures.push(
+          Object.freeze({ entryId: record.entry.id, diagnostic: boundedDiagnostic(error) }),
+        );
+      }
+    }
+    return Object.freeze(failures);
+  }
+
+  async #validateEntry(
+    entry: MakaCompositionEntry,
+    active = entry.disabled !== true,
+    manifestOverride?: ExtensionPackageManifest,
+  ): Promise<void> {
+    if (!entry.packageId) return;
+    const manifests = new Map<string, ExtensionPackageManifest>();
+    const visiting = new Set<string>();
+    const visited = new Set<string>();
+    const visit = async (extensionId: string): Promise<void> => {
+      if (visited.has(extensionId)) return;
+      if (visiting.has(extensionId)) {
+        throw new MakaPluginRuntimeError(
+          'dependency_cycle',
+          `Plugin package dependency cycle includes ${extensionId}`,
+        );
+      }
+      visiting.add(extensionId);
+      let manifest = manifests.get(extensionId);
+      if (!manifest) {
+        manifest = await this.#packageManifest(extensionId, manifestOverride);
+        manifests.set(extensionId, manifest);
+      }
+      for (const dependency of manifest.dependencies) await visit(dependency.id);
+      visiting.delete(extensionId);
+      visited.add(extensionId);
+    };
+    const manifest = await this.#packageManifest(entry.packageId, manifestOverride);
+    validateExtensionConfiguration(manifest.configuration, entry.config);
+    if (active) await visit(entry.packageId);
+  }
+
+  async #validateActiveDependencies(
+    record: CompositionEntryRecord,
+    records: readonly CompositionEntryRecord[],
+    manifestOverride?: ExtensionPackageManifest,
+  ): Promise<void> {
+    if (record.disabled || !record.entry.packageId) return;
+    const manifest = await this.#packageManifest(record.entry.packageId, manifestOverride);
+    for (const dependency of manifest.dependencies) {
+      if (
+        !records.some(
+          (candidate) =>
+            candidate.rootId === record.rootId &&
+            !candidate.disabled &&
+            candidate.entry.packageId === dependency.id,
+        )
+      ) {
+        throw new MakaPluginRuntimeError(
+          'package_not_found',
+          `Required dependency ${dependency.id} is not active in ${record.rootId}`,
+        );
+      }
+    }
+  }
+
+  async #packageManifest(
+    extensionId: string,
+    manifestOverride?: ExtensionPackageManifest,
+  ): Promise<ExtensionPackageManifest> {
+    return manifestOverride?.id === extensionId
+      ? manifestOverride
+      : (await this.#packages.load(extensionId)).manifest;
+  }
+
+  async #recoverDesiredRuntime(
+    desired: MakaCompositionState,
+  ): Promise<readonly MakaCompositionRecoveryFailure[]> {
+    let failures = new Map(
+      (await this.#desiredValidationFailures(desired)).map((failure) => [failure.entryId, failure]),
+    );
+    for (;;) {
+      const recovered = await this.#composition.recoverComposition(
+        withoutEntries(desired, new Set(failures.keys())),
+      );
+      for (const failure of recovered) failures.set(failure.entryId, failure);
+      const expanded = await this.#expandDependencyFailures(desired, [...failures.values()]);
+      if (expanded.length === failures.size) return Object.freeze([...failures.values()]);
+      failures = new Map(expanded.map((failure) => [failure.entryId, failure]));
+    }
+  }
+
+  async #expandDependencyFailures(
+    state: MakaCompositionState,
+    initial: readonly MakaCompositionRecoveryFailure[],
+  ): Promise<readonly MakaCompositionRecoveryFailure[]> {
+    const failures = new Map(initial.map((failure) => [failure.entryId, failure]));
+    const records = compositionEntryRecords(state);
+    let changed = true;
+    while (changed) {
+      changed = false;
+      for (const record of records) {
+        if (record.disabled || !record.entry.packageId || failures.has(record.entry.id)) continue;
+        const manifest = (await this.#packages.load(record.entry.packageId)).manifest;
+        for (const dependency of manifest.dependencies) {
+          const candidates = records.filter(
+            (candidate) =>
+              candidate.rootId === record.rootId &&
+              !candidate.disabled &&
+              candidate.entry.packageId === dependency.id,
+          );
+          if (candidates.length > 0 && candidates.every(({ entry }) => failures.has(entry.id))) {
+            failures.set(
+              record.entry.id,
+              Object.freeze({
+                entryId: record.entry.id,
+                diagnostic: `Required dependency ${dependency.id} failed in ${record.rootId}`,
+              }),
+            );
+            changed = true;
+            break;
+          }
+        }
+      }
+    }
+    return Object.freeze([...failures.values()]);
+  }
+
+  async #desiredPackageDependent(
+    extensionId: string,
+    desired: MakaCompositionState = this.desiredComposition(),
+  ): Promise<MakaCompositionEntry | undefined> {
+    const dependsOn = async (packageId: string, visited: Set<string>): Promise<boolean> => {
+      if (packageId === extensionId) return true;
+      if (visited.has(packageId)) return false;
+      visited.add(packageId);
+      const manifest = (await this.#packages.load(packageId)).manifest;
+      for (const dependency of manifest.dependencies) {
+        if (await dependsOn(dependency.id, visited)) return true;
+      }
+      return false;
+    };
+    for (const entry of compositionEntries(desired)) {
+      if (
+        entry.packageId &&
+        entry.packageId !== extensionId &&
+        entry.disabled !== true &&
+        (await dependsOn(entry.packageId, new Set()))
+      ) {
+        return entry;
+      }
+    }
+    return undefined;
+  }
+
+  async #manifestDependentPackage(extensionId: string): Promise<string | undefined> {
+    for (const candidateId of this.#authority.packageLayers) {
+      if (candidateId === extensionId) continue;
+      const manifest = (await this.#packages.load(candidateId)).manifest;
+      if (manifest.dependencies.some(({ id }) => id === extensionId)) return candidateId;
+    }
+    return undefined;
+  }
+
+  async #publishEntryFailures(failures: readonly MakaCompositionRecoveryFailure[]): Promise<void> {
+    const packageFailures = this.#failures.filter((failure) => failure.entryId === undefined);
+    this.#failures = Object.freeze([
+      ...packageFailures,
+      ...failures.map((failure) =>
+        Object.freeze({ entryId: failure.entryId, diagnostic: failure.diagnostic }),
+      ),
+    ]);
+  }
+
+  async #adoptRuntimePackage(
+    extensionId: string,
+    loaded: MakaPluginPackage,
+    desired: MakaCompositionState,
+    replacing: boolean,
+  ): Promise<readonly MakaCompositionRecoveryFailure[]> {
+    let installed = false;
+    try {
+      if (replacing) {
+        const previous = this.#composition.package(extensionId);
+        const detached = withoutPackageEntries(desired, extensionId);
+        await this.#recoverDesiredRuntime(detached);
+        await this.#composition.uninstall(extensionId);
+        await this.#releaseGeneration(previous);
+      }
+      await this.#composition.install(loaded);
+      installed = true;
+      return await this.#recoverDesiredRuntime(desired);
+    } catch (error) {
+      if (!installed) await this.#packageLoader.release(loaded).catch(() => undefined);
+      throw error;
+    }
+  }
+
+  async #releaseGeneration(pkg: MakaPluginPackage): Promise<void> {
+    try {
+      await this.#packageLoader.release(pkg);
+    } catch (error) {
+      this.#composition.root.logger.warn('Unable to remove retired Plugin generation', error);
+    }
+  }
+
+  #clearPackageFailure(extensionId: string): void {
+    this.#failures = Object.freeze(
+      this.#failures.filter((failure) => failure.extensionId !== extensionId),
+    );
+  }
+
+  #assertReadable(): void {
+    if (!this.#recoveryComplete) {
+      throw new HostPluginPlatformError('not_ready', 'Plugin Platform is not recovered');
+    }
+    if (this.#phase === 'closed') {
+      throw new HostPluginPlatformError('closed', 'Plugin Platform is closed');
+    }
+  }
+
+  #assertMutable(): void {
+    this.#assertReadable();
+    if (this.#phase === 'fenced') {
+      throw new HostPluginPlatformError('recovery_failed', 'Plugin Platform is fenced', {
+        cause: this.#fence,
+      });
+    }
+    if (this.#phase === 'draining') {
+      throw new HostPluginPlatformError('closed', 'Plugin Platform is draining');
+    }
+  }
+
+  #fenceUnknownPackageOutcome(
+    error: PluginPackageStoreError,
+    operation: string,
+  ): HostPluginPlatformError {
+    this.#fence = error;
+    this.#phase = 'fenced';
+    return new HostPluginPlatformError(
+      'commit_outcome_unknown',
+      `Plugin package ${operation} outcome is unknown; Plugin Platform was fenced`,
+      { cause: error },
+    );
+  }
+
+  #serializeMutable<T>(operation: () => Promise<T>): Promise<T> {
+    return this.#serialize(async () => {
+      this.#assertMutable();
+      return await operation();
+    });
+  }
+
+  #serialize<T>(operation: () => Promise<T>): Promise<T> {
+    const result = this.#mutation.then(operation, operation);
+    this.#mutation = result.then(
+      () => undefined,
+      () => undefined,
+    );
+    return result;
+  }
+
+  #recordPackageFailure(extensionId: string, error: unknown): void {
+    this.#clearPackageFailure(extensionId);
+    this.#failures = Object.freeze([
+      ...this.#failures,
+      Object.freeze({ extensionId, diagnostic: boundedDiagnostic(error) }),
+    ]);
+  }
+
+  #settleConvergence(converged: boolean): void {
+    this.#convergence = converged ? 'converged' : 'diverged';
+    if (!this.#drainRequested && this.#phase !== 'fenced' && this.#phase !== 'closed') {
+      this.#phase = converged ? 'ready' : 'degraded';
+    }
+    if (converged) {
+      this.#reconcileDelayMs = 250;
+      if (this.#reconcileTimer) clearTimeout(this.#reconcileTimer);
+      this.#reconcileTimer = undefined;
+    } else {
+      this.#scheduleReconcile();
+    }
+  }
+
+  async #reconcileNow(): Promise<PluginMutationReceipt> {
+    await this.#packages.recover(this.#authority.generation);
+    await this.#packageLoader.collectGarbage();
+    const projection = await this.#deriveDesired(this.#authority, 'recovery');
+    const packageFailures: HostPluginPlatformFailure[] = [];
+    const retryPackages = new Set(
+      this.#failures.flatMap(({ extensionId }) => (extensionId ? [extensionId] : [])),
+    );
+    const storedPackages = new Set(await this.#packages.identities());
+    for (const extensionId of storedPackages) {
+      const installed = this.#composition
+        .installedPackages()
+        .some(({ packageId }) => packageId === extensionId);
+      if (installed && !retryPackages.has(extensionId)) continue;
+      try {
+        const loaded = await this.#packageLoader.load(extensionId);
+        await this.#adoptRuntimePackage(extensionId, loaded, projection.desired, installed);
+      } catch (error) {
+        packageFailures.push(Object.freeze({ extensionId, diagnostic: boundedDiagnostic(error) }));
+      }
+    }
+    const runtimeFailures = await this.#recoverDesiredRuntime(projection.desired);
+    this.#desired = projection.desired;
+    this.#structuralDependencies = projection.structuralDependencies;
+    this.#failures = Object.freeze([
+      ...projection.failures,
+      ...packageFailures,
+      ...runtimeFailures.map(({ entryId, diagnostic }) => Object.freeze({ entryId, diagnostic })),
+    ]);
+    this.#settleConvergence(this.#failures.length === 0);
+    return this.#receipt('complete');
+  }
+
+  #scheduleReconcile(): void {
+    if (this.#reconcileTimer || this.#drainRequested || this.#phase !== 'degraded') return;
+    const delay = this.#reconcileDelayMs;
+    this.#reconcileDelayMs = Math.min(this.#reconcileDelayMs * 2, 30_000);
+    this.#reconcileTimer = setTimeout(() => {
+      this.#reconcileTimer = undefined;
+      void this.#serialize(async () => {
+        if (this.#phase !== 'degraded') return;
+        await this.#reconcileNow();
+      }).catch((error) => {
+        this.#composition.root.logger.warn('Unable to reconcile Plugin Platform', error);
+        this.#scheduleReconcile();
+      });
+    }, delay);
+    this.#reconcileTimer.unref?.();
+  }
+
+  #receipt(cleanup: 'complete' | 'pending'): PluginMutationReceipt {
+    return Object.freeze({
+      authorityEpoch: this.#authority.generation,
+      durability: 'committed',
+      convergence: this.#convergence === 'converged' ? 'converged' : 'diverged',
+      cleanup,
+      failures: Object.freeze(this.#failures.map((failure) => Object.freeze({ ...failure }))),
+    });
+  }
+
+  #structuralDependent(extensionId: string): string | undefined {
+    for (const [actor, dependencies] of this.#structuralDependencies) {
+      if (dependencies.has(extensionId)) return actor;
+    }
+    return undefined;
+  }
+}
+
+function emptyCompositionAuthority(): PersistedPluginComposition {
+  return Object.freeze({
+    schemaVersion: 1,
+    generation: 0,
+    packageLayers: Object.freeze([]),
+    overlays: Object.freeze([]),
+  });
+}
+
+function emptyCompositionState(): MakaCompositionState {
+  return Object.freeze({
+    schemaVersion: 1,
+    generation: 0,
+    roots: Object.freeze({
+      profile: Object.freeze([]),
+      desktopUi: Object.freeze([]),
+      sessions: Object.freeze({}),
+    }),
+  });
+}
+
+function compositionAuthority(
+  generation: number,
+  packageLayers: readonly string[],
+  overlays: readonly MakaCompositionOperation[],
+): PersistedPluginComposition {
+  return Object.freeze({
+    schemaVersion: 1,
+    generation,
+    packageLayers: Object.freeze([...packageLayers]),
+    overlays: Object.freeze(structuredClone(overlays)),
+  });
+}
+
+function compositionEntries(state: MakaCompositionState): readonly MakaCompositionEntry[] {
+  const walk = (entries: readonly MakaCompositionEntry[]): MakaCompositionEntry[] =>
+    entries.flatMap((entry) => [entry, ...walk(entry.children ?? [])]);
+  return [
+    ...walk(state.roots.profile),
+    ...walk(state.roots.desktopUi),
+    ...Object.values(state.roots.sessions).flatMap(walk),
+  ];
+}
+
+function findCompositionEntry(
+  state: MakaCompositionState,
+  entryId: string,
+): MakaCompositionEntry | undefined {
+  return compositionEntries(state).find((entry) => entry.id === entryId);
+}
+
+function compositionWithGeneration(
+  state: MakaCompositionState,
+  generation: number,
+): MakaCompositionState {
+  return Object.freeze({ ...state, generation });
+}
+
+function compositionEntryRecords(state: MakaCompositionState): readonly CompositionEntryRecord[] {
+  const records: CompositionEntryRecord[] = [];
+  const visit = (
+    entries: readonly MakaCompositionEntry[],
+    rootId: MakaPluginRootId,
+    ancestorDisabled: boolean,
+  ): void => {
+    for (const entry of entries) {
+      const disabled = ancestorDisabled || entry.disabled === true;
+      records.push(Object.freeze({ entry, rootId, disabled }));
+      visit(entry.children ?? [], rootId, disabled);
+    }
+  };
+  visit(state.roots.profile, 'profile', false);
+  visit(state.roots.desktopUi, 'desktop-ui', false);
+  for (const [scopeId, entries] of Object.entries(state.roots.sessions)) {
+    visit(entries, `session:${scopeId}`, false);
+  }
+  return Object.freeze(records);
+}
+
+function withoutEntries(
+  state: MakaCompositionState,
+  excluded: ReadonlySet<string>,
+): MakaCompositionState {
+  const filter = (entries: readonly MakaCompositionEntry[]): readonly MakaCompositionEntry[] =>
+    Object.freeze(
+      entries.flatMap((entry) =>
+        excluded.has(entry.id)
+          ? []
+          : [Object.freeze({ ...entry, children: filter(entry.children ?? []) })],
+      ),
+    );
+  return Object.freeze({
+    schemaVersion: 1,
+    generation: state.generation,
+    roots: Object.freeze({
+      profile: filter(state.roots.profile),
+      desktopUi: filter(state.roots.desktopUi),
+      sessions: Object.freeze(
+        Object.fromEntries(
+          Object.entries(state.roots.sessions).map(([scopeId, entries]) => [
+            scopeId,
+            filter(entries),
+          ]),
+        ),
+      ),
+    }),
+  });
+}
+
+function withoutPackageEntries(
+  state: MakaCompositionState,
+  extensionId: string,
+): MakaCompositionState {
+  return withoutEntries(
+    state,
+    new Set(
+      compositionEntries(state)
+        .filter(({ packageId }) => packageId === extensionId)
+        .map(({ id }) => id),
+    ),
+  );
+}
+
+function countInspections(inspections: readonly MakaCompositionEntryInspection[]): number {
+  return inspections.reduce(
+    (total, inspection) => total + 1 + countInspections(inspection.children),
+    0,
+  );
+}
+
+function cloneDependencyGraph(
+  graph: ReadonlyMap<string, ReadonlySet<string>>,
+): Map<string, Set<string>> {
+  return new Map([...graph].map(([actor, dependencies]) => [actor, new Set(dependencies)]));
+}
+
+function freezeDependencyGraph(
+  graph: ReadonlyMap<string, ReadonlySet<string>>,
+): ReadonlyMap<string, ReadonlySet<string>> {
+  return new Map(
+    [...graph].map(([actor, dependencies]) => [
+      actor,
+      Object.freeze(new Set([...dependencies].sort())) as ReadonlySet<string>,
+    ]),
+  );
+}
+
+function recordStructuralDependencies(
+  state: MakaCompositionState,
+  owners: ReadonlyMap<string, string>,
+  dependencies: Map<string, Set<string>>,
+  actor: string,
+  operation: MakaCompositionOperation,
+): void {
+  const referencedIds: string[] = [];
+  if (operation.type === 'insert') {
+    if (operation.parentId) referencedIds.push(operation.parentId);
+  } else {
+    referencedIds.push(operation.entryId);
+    if (operation.type === 'move' && operation.parentId) referencedIds.push(operation.parentId);
+  }
+  for (const entryId of referencedIds) {
+    if (!findCompositionEntry(state, entryId)) continue;
+    const owner = owners.get(entryId);
+    if (!owner || owner === actor) continue;
+    const actorDependencies = dependencies.get(actor) ?? new Set<string>();
+    actorDependencies.add(owner);
+    dependencies.set(actor, actorDependencies);
+  }
+}
+
+function updateEntryOwners(
+  previous: MakaCompositionState,
+  owners: Map<string, string>,
+  actor: string,
+  operation: MakaCompositionOperation,
+): void {
+  if (operation.type === 'insert') {
+    for (const entry of walkCompositionEntries(operation.entry)) owners.set(entry.id, actor);
+    return;
+  }
+  if (operation.type === 'remove') {
+    const removed = findCompositionEntry(previous, operation.entryId);
+    if (removed) {
+      for (const entry of walkCompositionEntries(removed)) owners.delete(entry.id);
+    }
+  }
+}
+
+function walkCompositionEntries(entry: MakaCompositionEntry): readonly MakaCompositionEntry[] {
+  return [entry, ...(entry.children ?? []).flatMap(walkCompositionEntries)];
+}
+
+function overlayFailureIdentity(operations: readonly MakaCompositionOperation[]): string {
+  const operation = operations[0];
+  if (!operation) return 'user-overlay';
+  if (operation.type === 'insert') return operation.entry.id;
+  return operation.entryId;
+}
+
+function operationFailures(
+  input: MakaCompositionApplyInput,
+  error: unknown,
+): readonly MakaCompositionRecoveryFailure[] {
+  const diagnostic = boundedDiagnostic(error);
+  const ids = new Set<string>();
+  for (const operation of input.operations) {
+    if (operation.type === 'insert') ids.add(operation.entry.id);
+    else ids.add(operation.entryId);
+  }
+  return Object.freeze([...ids].map((entryId) => Object.freeze({ entryId, diagnostic })));
+}
+
+function scalarConfiguration(value: unknown): Readonly<Record<string, string | number | boolean>> {
+  if (value === undefined) return Object.freeze({});
+  if (!value || typeof value !== 'object' || Array.isArray(value)) {
+    throw new HostPluginCompositionStoreError(
+      'invalid_state',
+      'Plugin Entry config must be a scalar record',
+    );
+  }
+  const output: Record<string, string | number | boolean> = {};
+  for (const [key, item] of Object.entries(value)) {
+    if (
+      typeof item !== 'string' &&
+      typeof item !== 'boolean' &&
+      !(typeof item === 'number' && Number.isFinite(item))
+    ) {
+      throw new HostPluginCompositionStoreError(
+        'invalid_state',
+        `Plugin Entry config value is invalid: ${key}`,
+      );
+    }
+    output[key] = item;
+  }
+  return Object.freeze(output);
+}
+
+function asError(error: unknown): Error {
+  return error instanceof Error ? error : new Error(String(error));
+}
+
+function boundedDiagnostic(error: unknown): string {
+  const message =
+    error instanceof AggregateError
+      ? error.errors.map((item) => boundedDiagnostic(item)).join('; ')
+      : error instanceof Error
+        ? error.message
+        : String(error);
+  return message.slice(0, 4096) || 'Plugin Platform operation failed';
+}
diff --git a/packages/runtime/src/__tests__/plugin-composition-loader.test.ts b/packages/runtime/src/__tests__/plugin-composition-loader.test.ts
index 53e44f61ab..3f04653180 100644
--- a/packages/runtime/src/__tests__/plugin-composition-loader.test.ts
+++ b/packages/runtime/src/__tests__/plugin-composition-loader.test.ts
@@ -19,9 +19,10 @@
 
 import assert from 'node:assert/strict';
 import { test } from 'node:test';
-import { Context, type Plugin } from '../plugin-kernel.js';
+import { Context, type Fiber, type Plugin } from '../plugin-kernel.js';
 import { MakaCompositionLoader } from '../plugin-composition-loader.js';
 import {
+  applyCompositionState,
   MakaPluginTransactionBuffer,
   type MakaCompositionEntry,
   type MakaPluginPackage,
@@ -58,6 +59,46 @@ test('composition tree supports nested groups and repeated package instances', a
   await loader.close();
 });
 
+test('package Entry descendants stay owned by the parent package Fiber', async () => {
+  const fibers = new Map<string, Fiber>();
+  const capture = (ctx: Context) => {
+    fibers.set(ctx.maka!.entryId, ctx.fiber);
+  };
+  const loader = new MakaCompositionLoader();
+  await loader.install(pkg('parent-package', capture));
+  await loader.install(pkg('child-package', capture));
+
+  await loader.create('profile', entry('parent-entry', 'parent-package'));
+  await loader.create('profile', entry('child-entry', 'child-package'), 'parent-entry');
+  assert.equal(fibers.get('child-entry')?.parent, fibers.get('parent-entry'));
+
+  await loader.create('profile', { id: 'scope-group' });
+  await loader.move('child-entry', 'scope-group');
+  assert.equal(fibers.get('child-entry')?.parent, loader.root.fiber);
+  await loader.move('child-entry', 'parent-entry');
+  assert.equal(fibers.get('child-entry')?.parent, fibers.get('parent-entry'));
+
+  await loader.recoverComposition({
+    schemaVersion: 1,
+    generation: 7,
+    roots: {
+      profile: [
+        {
+          ...entry('parent-entry', 'parent-package'),
+          children: [entry('child-entry', 'child-package')],
+        },
+      ],
+      desktopUi: [],
+      sessions: {},
+    },
+  });
+  assert.equal(fibers.get('child-entry')?.parent, fibers.get('parent-entry'));
+
+  await loader.reload(pkg('parent-package', capture));
+  assert.equal(fibers.get('child-entry')?.parent, fibers.get('parent-entry'));
+  await loader.close();
+});
+
 test('missing injected service enters pending and activates when provided', async () => {
   let started = 0;
   const plugin = Object.assign(
@@ -109,7 +150,7 @@ test('config update uses the existing Fiber and preserves entry identity', async
   const updated = await loader.update('configurable-one', { config: { value: 2 } });
   assert.equal(updated.id, initial.id);
   assert.equal(updated.generation, initial.generation);
-  assert.equal(loader.snapshot().generation, 2);
+  assert.equal(loader.compositionState().generation, 2);
   assert.deepEqual(values, [1, 2]);
   await loader.close();
 });
@@ -290,11 +331,11 @@ test('retirement cleanup failure does not roll back a published removal generati
     }),
   );
   await loader.create('profile', entry('retired-entry', 'retirement-failure'));
-  const generation = loader.snapshot().generation;
+  const generation = loader.compositionState().generation;
 
   await loader.remove('retired-entry');
 
-  assert.equal(loader.snapshot().generation, generation + 1);
+  assert.equal(loader.compositionState().generation, generation + 1);
   assert.deepEqual(loader.inspectTree('profile'), []);
   await loader.close();
 });
@@ -309,11 +350,11 @@ test('retirement cleanup failure does not roll back a published structural updat
   );
   await loader.install(pkg('replacement-package', () => undefined));
   await loader.create('profile', entry('updated-entry', 'retired-package'));
-  const generation = loader.snapshot().generation;
+  const generation = loader.compositionState().generation;
 
   await loader.update('updated-entry', { packageId: 'replacement-package' });
 
-  assert.equal(loader.snapshot().generation, generation + 1);
+  assert.equal(loader.compositionState().generation, generation + 1);
   assert.equal(loader.inspect('updated-entry').packageId, 'replacement-package');
   assert.equal(loader.inspect('updated-entry').status, 'active');
   await loader.close();
@@ -347,19 +388,19 @@ test('contribution registrations are staged and owned by the entry Fiber', async
   await loader.close();
 });
 
-test('snapshot replacement restores ordered roots and descendants', async () => {
+test('state replacement restores ordered roots and descendants', async () => {
   const loader = new MakaCompositionLoader();
-  await loader.install(pkg('snapshot', () => undefined));
-  await loader.replaceSnapshot({
+  await loader.install(pkg('state', () => undefined));
+  await loader.replaceComposition({
     schemaVersion: 1,
     generation: 41,
     roots: {
-      profile: [entry('profile-entry', 'snapshot')],
-      desktopUi: [{ id: 'ui-group', children: [entry('ui-entry', 'snapshot')] }],
-      sessions: { s1: [entry('session-entry', 'snapshot')] },
+      profile: [entry('profile-entry', 'state')],
+      desktopUi: [{ id: 'ui-group', children: [entry('ui-entry', 'state')] }],
+      sessions: { s1: [entry('session-entry', 'state')] },
     },
   });
-  assert.equal(loader.snapshot().generation, 41);
+  assert.equal(loader.compositionState().generation, 41);
   assert.deepEqual(
     loader.inspectTree().map(({ id }) => id),
     ['profile-entry', 'ui-group', 'session-entry'],
@@ -368,26 +409,26 @@ test('snapshot replacement restores ordered roots and descendants', async () =>
   await loader.close();
 });
 
-test('live snapshot and subtree replacement publish a fresh composition generation', async () => {
+test('live state and subtree replacement publish a fresh composition generation', async () => {
   const loader = new MakaCompositionLoader();
   await loader.create('profile', { id: 'before' });
-  const staleGeneration = loader.snapshot().generation;
+  const staleGeneration = loader.compositionState().generation;
 
-  await loader.replaceSnapshot({
+  await loader.replaceComposition({
     schemaVersion: 1,
     generation: staleGeneration,
     roots: { profile: [{ id: 'after' }], desktopUi: [], sessions: {} },
   });
 
-  assert.equal(loader.snapshot().generation, staleGeneration + 1);
+  assert.equal(loader.compositionState().generation, staleGeneration + 1);
   await assert.rejects(
     () => loader.apply({ baseGeneration: staleGeneration, operations: [] }),
     /Composition generation changed/u,
   );
 
-  const beforeSubtreeReplacement = loader.snapshot().generation;
+  const beforeSubtreeReplacement = loader.compositionState().generation;
   await loader.replaceSubtree('after', { id: 'after', children: [{ id: 'child' }] });
-  assert.equal(loader.snapshot().generation, beforeSubtreeReplacement + 1);
+  assert.equal(loader.compositionState().generation, beforeSubtreeReplacement + 1);
   await loader.close();
 });
 
@@ -425,18 +466,33 @@ test('replacement subtrees reject duplicate ids across different branches', asyn
   await loader.close();
 });
 
-test('snapshot preserves session ids that overlap object prototype properties', async () => {
+test('state preserves session ids that overlap object prototype properties', async () => {
   const loader = new MakaCompositionLoader();
+  const reduced = applyCompositionState(loader.compositionState(), {
+    operations: [
+      {
+        type: 'insert',
+        rootId: 'session:__proto__',
+        entry: { id: 'reduced-special-session-entry' },
+      },
+    ],
+  });
+  assert.equal(Object.hasOwn(reduced.roots.sessions, '__proto__'), true);
+  assert.deepEqual(
+    reduced.roots.sessions.__proto__?.map(({ id }) => id),
+    ['reduced-special-session-entry'],
+  );
+
   await loader.create('session:__proto__', { id: 'special-session-entry' });
 
-  const snapshot = loader.snapshot();
-  assert.equal(Object.hasOwn(snapshot.roots.sessions, '__proto__'), true);
+  const state = loader.compositionState();
+  assert.equal(Object.hasOwn(state.roots.sessions, '__proto__'), true);
   assert.deepEqual(
-    snapshot.roots.sessions.__proto__?.map(({ id }) => id),
+    state.roots.sessions.__proto__?.map(({ id }) => id),
     ['special-session-entry'],
   );
 
-  await loader.replaceSnapshot(snapshot);
+  await loader.replaceComposition(state);
   assert.deepEqual(
     loader.inspectTree('session:__proto__').map(({ id }) => id),
     ['special-session-entry'],
@@ -444,26 +500,26 @@ test('snapshot preserves session ids that overlap object prototype properties',
   await loader.close();
 });
 
-test('inspecting a missing root does not mutate the composition snapshot', async () => {
+test('inspecting a missing root does not mutate the composition state', async () => {
   const loader = new MakaCompositionLoader();
-  const before = loader.snapshot();
+  const before = loader.compositionState();
 
   assert.deepEqual(loader.inspectTree('session:missing'), []);
 
-  assert.deepEqual(loader.snapshot(), before);
+  assert.deepEqual(loader.compositionState(), before);
   await loader.close();
 });
 
 test('failed insert does not create an empty composition root', async () => {
   const loader = new MakaCompositionLoader();
-  const before = loader.snapshot();
+  const before = loader.compositionState();
 
   await assert.rejects(
     loader.create('session:ghost', { id: 'orphan' }, 'missing-parent'),
     /Composition entry not found: missing-parent/u,
   );
 
-  assert.deepEqual(loader.snapshot(), before);
+  assert.deepEqual(loader.compositionState(), before);
   await loader.close();
 });
 
@@ -477,7 +533,7 @@ test('structural updates preserve descendants added after the parent was created
   assert.equal(loader.inspect('dynamic-child').parentId, 'dynamic-group');
   assert.equal(loader.inspect('dynamic-child').disabled, true);
   assert.deepEqual(
-    loader.snapshot().roots.profile[0]?.children?.map(({ id }) => id),
+    loader.compositionState().roots.profile[0]?.children?.map(({ id }) => id),
     ['dynamic-child'],
   );
   await loader.close();
@@ -492,12 +548,12 @@ test('failed rebind leaves parent and position unchanged', async () => {
   );
   await loader.create('profile', { id: 'target-parent', intercept: { moveGuard: true } });
   await loader.create('profile', entry('movable-entry', 'move-guard'));
-  const before = loader.snapshot();
+  const before = loader.compositionState();
 
   await assert.rejects(loader.move('movable-entry', 'target-parent'), /target rejected move/u);
 
   assert.equal(loader.inspect('movable-entry').parentId, undefined);
-  assert.deepEqual(loader.snapshot(), before);
+  assert.deepEqual(loader.compositionState(), before);
   await loader.close();
 });
 
@@ -562,7 +618,7 @@ test('callable config remains inspectable after publication', async () => {
 
   assert.equal(inspection.config, config);
   assert.equal(loader.inspect('callable-config-entry').config, config);
-  assert.equal(loader.snapshot().roots.profile[0]?.config, config);
+  assert.equal(loader.compositionState().roots.profile[0]?.config, config);
   await loader.close();
 });
 
@@ -585,7 +641,7 @@ test('callable intercept changes trigger structural Context replacement', async
   await loader.update('callable-intercept-entry', { intercept: { fixture: second } });
 
   assert.deepEqual(seen, [first, second]);
-  assert.equal(loader.snapshot().roots.profile[0]?.intercept?.fixture, second);
+  assert.equal(loader.compositionState().roots.profile[0]?.intercept?.fixture, second);
   await loader.close();
 });
 
@@ -603,7 +659,7 @@ test('staging and commit failures do not retain newly created session roots', as
       });
     }),
   );
-  const before = loader.snapshot();
+  const before = loader.compositionState();
 
   await assert.rejects(
     loader.create('session:missing-package', entry('missing-package-entry', 'missing-package')),
@@ -621,14 +677,14 @@ test('staging and commit failures do not retain newly created session roots', as
     /commit failed/u,
   );
 
-  assert.deepEqual(loader.snapshot(), before);
+  assert.deepEqual(loader.compositionState(), before);
   await loader.close();
 });
 
 test('composition apply batches EntryTree operations under one generation check', async () => {
   const loader = new MakaCompositionLoader();
   await loader.install(pkg('batch', () => undefined));
-  const initial = loader.snapshot().generation;
+  const initial = loader.compositionState().generation;
   const changed = await loader.apply({
     baseGeneration: initial,
     operations: [
@@ -652,7 +708,7 @@ test('composition apply batches EntryTree operations under one generation check'
 test('failed composition batches restore the prior generation exactly', async () => {
   const loader = new MakaCompositionLoader();
   await loader.create('profile', { id: 'stable-entry' });
-  const before = loader.snapshot();
+  const before = loader.compositionState();
 
   await assert.rejects(
     () =>
@@ -666,7 +722,153 @@ test('failed composition batches restore the prior generation exactly', async ()
     /Composition entry not found: missing-entry/u,
   );
 
-  assert.deepEqual(loader.snapshot(), before);
+  assert.deepEqual(loader.compositionState(), before);
+  await loader.close();
+});
+
+test('failed composition batches preserve both the operation and rollback failures', async () => {
+  let activations = 0;
+  const loader = new MakaCompositionLoader();
+  await loader.install(
+    pkg('rollback-failure', () => {
+      activations += 1;
+      if (activations > 1) throw new Error('rollback activation failed');
+    }),
+  );
+  await loader.create('profile', entry('stable-entry', 'rollback-failure'));
+
+  await assert.rejects(
+    () =>
+      loader.apply({
+        operations: [
+          { type: 'insert', entry: { id: 'temporary-entry' } },
+          { type: 'update', entryId: 'missing-entry', patch: { disabled: true } },
+        ],
+      }),
+    (error: unknown) =>
+      error instanceof AggregateError &&
+      error.errors.length === 2 &&
+      error.errors.some((cause) => /missing-entry/u.test(String(cause))) &&
+      error.errors.some((cause) => /rollback activation failed/u.test(String(cause))),
+  );
+
+  await loader.close();
+});
+
+test('package reload replaces every matching mount without restarting unrelated Entries', async () => {
+  const events: string[] = [];
+  const host =
+    (label: string): Plugin =>
+    (ctx: Context) => {
+      events.push(`start:${label}:${ctx.maka!.entryId}`);
+      ctx.effect(() => () => events.push(`stop:${label}:${ctx.maka!.entryId}`), label);
+    };
+  const loader = new MakaCompositionLoader();
+  await loader.install(pkg('reload-target', host('old')));
+  await loader.install(pkg('reload-bystander', host('bystander')));
+  await loader.create('profile', entry('reload-one', 'reload-target'));
+  await loader.create('session:one', entry('reload-two', 'reload-target'));
+  await loader.create('profile', entry('reload-unrelated', 'reload-bystander'));
+  const unrelatedGeneration = loader.inspect('reload-unrelated').generation;
+  const desiredGeneration = loader.compositionState().generation;
+
+  await loader.reload(pkg('reload-target', host('new')));
+
+  assert.equal(loader.inspect('reload-unrelated').generation, unrelatedGeneration);
+  assert.equal(loader.compositionState().generation, desiredGeneration);
+  assert.deepEqual(
+    events.filter((event) => event.startsWith('start:new')),
+    ['start:new:reload-one', 'start:new:reload-two'],
+  );
+  assert.equal(events.includes('stop:bystander:reload-unrelated'), false);
+  await loader.close();
+});
+
+test('partial recovery preserves desired generation and isolates failed siblings', async () => {
+  const loader = new MakaCompositionLoader();
+  await loader.install(pkg('recoverable', () => undefined));
+  const failures = await loader.recoverComposition({
+    schemaVersion: 1,
+    generation: 7,
+    roots: {
+      profile: [entry('recovered-entry', 'recoverable'), entry('missing-entry', 'missing-package')],
+      desktopUi: [],
+      sessions: {},
+    },
+  });
+
+  assert.deepEqual(
+    failures.map(({ entryId }) => entryId),
+    ['missing-entry'],
+  );
+  assert.equal(loader.inspect('recovered-entry').status, 'active');
+  assert.throws(() => loader.inspect('missing-entry'), /not found/u);
+  assert.equal(loader.compositionState().generation, 7);
+  await loader.close();
+});
+
+test('desired-state reducer applies dependent operations without activating code', () => {
+  const initial = {
+    schemaVersion: 1,
+    generation: 3,
+    roots: {
+      profile: [{ id: 'parent', children: [{ id: 'child' }] }],
+      desktopUi: [],
+      sessions: {},
+    },
+  } as const;
+
+  const next = applyCompositionState(initial, {
+    baseGeneration: 3,
+    operations: [
+      { type: 'update', entryId: 'parent', patch: { disabled: true } },
+      { type: 'update', entryId: 'child', patch: { disabled: true } },
+      { type: 'move', entryId: 'child', position: 0 },
+    ],
+  });
+
+  assert.equal(next.generation, 4);
+  assert.deepEqual(next.roots.profile, [
+    { id: 'child', disabled: true, children: [] },
+    { id: 'parent', disabled: true, children: [] },
+  ]);
+});
+
+test('desired-state reducer stays equivalent to live Entry Tree batch semantics', async () => {
+  const loader = new MakaCompositionLoader();
+  await loader.replaceComposition({
+    schemaVersion: 1,
+    generation: 4,
+    roots: {
+      profile: [
+        { id: 'equivalence-a', children: [{ id: 'equivalence-a1' }, { id: 'equivalence-a2' }] },
+        { id: 'equivalence-b' },
+      ],
+      desktopUi: [],
+      sessions: {},
+    },
+  });
+  const before = loader.compositionState();
+  const input = {
+    baseGeneration: before.generation,
+    operations: [
+      { type: 'update', entryId: 'equivalence-a', patch: { disabled: true } },
+      {
+        type: 'insert',
+        parentId: 'equivalence-a',
+        position: 1,
+        entry: { id: 'equivalence-a3' },
+      },
+      { type: 'move', entryId: 'equivalence-a2', parentId: 'equivalence-b' },
+      { type: 'remove', entryId: 'equivalence-a1' },
+      { type: 'update', entryId: 'equivalence-a3', patch: { disabled: true } },
+    ],
+  } as const;
+
+  const planned = applyCompositionState(before, input);
+  await loader.apply(input);
+
+  assert.deepEqual(loader.compositionState(), planned);
   await loader.close();
 });
 
diff --git a/packages/runtime/src/plugin-composition-loader.ts b/packages/runtime/src/plugin-composition-loader.ts
index abb887437c..9ec17c2fa5 100644
--- a/packages/runtime/src/plugin-composition-loader.ts
+++ b/packages/runtime/src/plugin-composition-loader.ts
@@ -17,13 +17,13 @@
  * under the License.
  */
 
-import { Context, type Fiber, type Inject, type Plugin } from './plugin-kernel.js';
+import { Context, type Fiber, FiberState, type Inject, type Plugin } from './plugin-kernel.js';
 import {
   fiberStateName,
   type MakaCompositionEntry,
   type MakaCompositionEntryInspection,
   type MakaCompositionApplyInput,
-  type MakaCompositionSnapshot,
+  type MakaCompositionState,
   type MakaPluginMetadata,
   type MakaPluginPackage,
   type MakaPluginRootId,
@@ -60,6 +60,11 @@ export interface MakaCompositionLoaderOptions {
   readonly transaction?: (context: Context) => MakaPluginTransaction | undefined;
 }
 
+export interface MakaCompositionRecoveryFailure {
+  readonly entryId: string;
+  readonly diagnostic: string;
+}
+
 export class MakaCompositionLoader {
   readonly root: Context;
   readonly #packages = new Map<string, MakaPluginPackage>();
@@ -89,6 +94,26 @@ export class MakaCompositionLoader {
     });
   }
 
+  reload(pkg: MakaPluginPackage): Promise<void> {
+    return this.#mutate(async () => {
+      validatePluginPackage(pkg);
+      const previous = this.#packages.get(pkg.packageId);
+      if (!previous) {
+        throw new MakaPluginRuntimeError(
+          'package_not_found',
+          `Plugin package is not installed: ${pkg.packageId}`,
+        );
+      }
+      this.#packages.set(pkg.packageId, freezePackage(pkg));
+      try {
+        await this.#reloadPackage(pkg.packageId);
+      } catch (error) {
+        this.#packages.set(pkg.packageId, previous);
+        throw error;
+      }
+    });
+  }
+
   uninstall(packageId: string): Promise<void> {
     return this.#mutate(async () => {
       if (!this.#packages.has(packageId)) {
@@ -156,7 +181,7 @@ export class MakaCompositionLoader {
           'invalid_entry',
           `Composition generation changed from ${input.baseGeneration} to ${this.#compositionGeneration}`,
         );
-      const before = this.snapshot();
+      const before = this.compositionState();
       const inspections: MakaCompositionEntryInspection[] = [];
       let appliedOperations = 0;
       try {
@@ -199,7 +224,16 @@ export class MakaCompositionLoader {
         // A candidate can fail before changing the live tree. Rebuilding in
         // that case would unnecessarily dispose the current Fiber and lose
         // its registered contributions.
-        if (appliedOperations > 0) await this.#replaceSnapshot(before, 'rollback');
+        if (appliedOperations > 0) {
+          try {
+            await this.#replaceComposition(before, 'rollback');
+          } catch (rollbackError) {
+            throw new AggregateError(
+              [error, rollbackError],
+              'Plugin composition batch and rollback both failed',
+            );
+          }
+        }
         throw error;
       }
       if (input.operations.length > 0) this.#compositionGeneration += 1;
@@ -289,7 +323,7 @@ export class MakaCompositionLoader {
     }
   }
 
-  snapshot(): MakaCompositionSnapshot {
+  compositionState(): MakaCompositionState {
     const encode = (rootId: MakaPluginRootId): readonly MakaCompositionEntry[] =>
       Object.freeze((this.#roots.get(rootId)?.entries ?? []).map((entry) => serialize(entry)));
     const sessions = Object.fromEntries(
@@ -310,22 +344,137 @@ export class MakaCompositionLoader {
     });
   }
 
-  replaceSnapshot(snapshot: MakaCompositionSnapshot): Promise<void> {
-    return this.#mutate(() => this.#replaceSnapshot(snapshot, 'publish'));
+  replaceComposition(state: MakaCompositionState): Promise<void> {
+    return this.#mutate(() => this.#replaceComposition(state, 'publish'));
+  }
+
+  /** Restores an externally uncommitted mutation without advancing its generation. */
+  restoreComposition(state: MakaCompositionState): Promise<void> {
+    return this.#mutate(() => this.#replaceComposition(state, 'rollback'));
   }
 
-  async #replaceSnapshot(
-    snapshot: MakaCompositionSnapshot,
+  /**
+   * Recovers as much of a durable desired tree as possible. A failed Entry
+   * does not prevent unrelated roots or siblings from becoming active.
+   */
+  recoverComposition(
+    state: MakaCompositionState,
+  ): Promise<readonly MakaCompositionRecoveryFailure[]> {
+    return this.#mutate(async () => {
+      if (state.schemaVersion !== 1) {
+        throw new MakaPluginRuntimeError('invalid_entry', 'Unsupported composition state');
+      }
+      const failures: MakaCompositionRecoveryFailure[] = [];
+      const stagedRoots = new Map<MakaPluginRootId, LiveRoot>();
+      const stagedIds = new Set<string>();
+      const specs = new Map<MakaPluginRootId, readonly MakaCompositionEntry[]>([
+        ['profile', state.roots.profile],
+        ['desktop-ui', state.roots.desktopUi],
+        ...Object.entries(state.roots.sessions).map(
+          ([id, entries]) => [`session:${id}` as MakaPluginRootId, entries] as const,
+        ),
+      ]);
+      const recoverEntry = async (
+        spec: MakaCompositionEntry,
+        rootId: MakaPluginRootId,
+        parent: LiveEntry | undefined,
+        parentContext: Context,
+        ancestorDisabled: boolean,
+      ): Promise<LiveEntry | undefined> => {
+        for (const item of walk(spec)) {
+          if (stagedIds.has(item.id)) {
+            failures.push(
+              Object.freeze({
+                entryId: spec.id,
+                diagnostic: `Composition entry already exists: ${item.id}`,
+              }),
+            );
+            return undefined;
+          }
+        }
+        const shallow = freezeEntry({ ...spec, children: [] });
+        let live: LiveEntry | undefined;
+        try {
+          validateCompositionEntry(shallow);
+          live = await this.#stage(shallow, rootId, parent, parentContext, ancestorDisabled);
+          await this.#commitSubtree(live);
+        } catch (error) {
+          if (live) await this.#dispose(live).catch(() => undefined);
+          failures.push(
+            Object.freeze({ entryId: spec.id, diagnostic: diagnostic(error).slice(0, 4096) }),
+          );
+          return undefined;
+        }
+        stagedIds.add(spec.id);
+        const disabled = ancestorDisabled || spec.disabled === true;
+        for (const child of spec.children ?? []) {
+          const recovered = await recoverEntry(
+            child,
+            rootId,
+            live,
+            childMountContext(live),
+            disabled,
+          );
+          if (recovered) live.children.push(recovered);
+        }
+        live.spec = freezeEntry({ ...live.spec, children: live.children.map(serialize) });
+        return live;
+      };
+
+      try {
+        for (const [rootId, entries] of specs) {
+          validatePluginRootId(rootId);
+          const context = this.root.extend({ makaRootId: rootId });
+          const root: LiveRoot = { id: rootId, context, entries: [] };
+          stagedRoots.set(rootId, root);
+          for (const spec of entries) {
+            const recovered = await recoverEntry(spec, rootId, undefined, context, false);
+            if (recovered) root.entries.push(recovered);
+          }
+        }
+      } catch (error) {
+        await settleAll(
+          [...stagedRoots.values()].flatMap((root) =>
+            [...root.entries].reverse().map((entry) => this.#dispose(entry)),
+          ),
+          'Recovered composition cleanup failed',
+        );
+        throw error;
+      }
+
+      const previous = [...this.#roots.values()];
+      this.#roots.clear();
+      this.#entries.clear();
+      for (const [rootId, root] of stagedRoots) {
+        this.#roots.set(rootId, root);
+        for (const entry of root.entries) this.#index(entry);
+      }
+      this.#compositionGeneration = state.generation;
+      await this.#retire(
+        settleAll(
+          previous.flatMap((root) =>
+            [...root.entries].reverse().map((entry) => this.#dispose(entry)),
+          ),
+          'Previous composition cleanup failed',
+        ),
+        'Previous composition cleanup failed after recovering desired state',
+      );
+      return Object.freeze(failures);
+    });
+  }
+
+  async #replaceComposition(
+    state: MakaCompositionState,
     generationMode: 'publish' | 'rollback',
   ): Promise<void> {
-    if (snapshot.schemaVersion !== 1)
-      throw new MakaPluginRuntimeError('invalid_entry', 'Unsupported composition snapshot');
+    if (state.schemaVersion !== 1)
+      throw new MakaPluginRuntimeError('invalid_entry', 'Unsupported composition state');
     const previousGeneration = this.#compositionGeneration;
     const pristine = previousGeneration === 0 && this.#entries.size === 0 && this.#roots.size === 0;
     const specs = new Map<MakaPluginRootId, readonly MakaCompositionEntry[]>([
-      ['profile', snapshot.roots.profile],
-      ['desktop-ui', snapshot.roots.desktopUi],
-      ...Object.entries(snapshot.roots.sessions).map(
+      ['profile', state.roots.profile],
+      ['desktop-ui', state.roots.desktopUi],
+      ...Object.entries(state.roots.sessions).map(
         ([id, entries]) => [`session:${id}` as MakaPluginRootId, entries] as const,
       ),
     ]);
@@ -374,10 +523,10 @@ export class MakaCompositionLoader {
     }
     this.#compositionGeneration =
       generationMode === 'rollback'
-        ? snapshot.generation
+        ? state.generation
         : pristine
-          ? snapshot.generation
-          : Math.max(previousGeneration, snapshot.generation) + 1;
+          ? state.generation
+          : Math.max(previousGeneration, state.generation) + 1;
     await this.#retire(
       settleAll(
         previous.flatMap((root) =>
@@ -416,7 +565,9 @@ export class MakaCompositionLoader {
     current: LiveEntry,
     spec: MakaCompositionEntry,
   ): Promise<MakaCompositionEntryInspection> {
-    const parentContext = current.parent?.context ?? this.#root(current.rootId).context;
+    const parentContext = current.parent
+      ? childMountContext(current.parent)
+      : this.#root(current.rootId).context;
     const candidate = await this.#stage(
       spec,
       current.rootId,
@@ -446,12 +597,59 @@ export class MakaCompositionLoader {
     return this.#inspect(candidate);
   }
 
+  async #reloadPackage(packageId: string): Promise<void> {
+    const affected = [...this.#entries.values()].filter(
+      (entry) =>
+        entry.spec.packageId === packageId &&
+        ![...ancestors(entry)].some((ancestor) => ancestor.spec.packageId === packageId),
+    );
+    if (!affected.length) return;
+    const candidates: { readonly current: LiveEntry; readonly replacement: LiveEntry }[] = [];
+    try {
+      for (const current of affected) {
+        const replacement = await this.#stage(
+          serialize(current),
+          current.rootId,
+          current.parent,
+          current.parent ? childMountContext(current.parent) : this.#root(current.rootId).context,
+          current.parent ? isDisabled(current.parent) : false,
+        );
+        candidates.push({ current, replacement });
+      }
+      for (const { replacement } of candidates) await this.#commitSubtree(replacement);
+    } catch (error) {
+      return rethrowAfterCleanup(
+        error,
+        () =>
+          settleAll(
+            candidates.map(({ replacement }) => this.#dispose(replacement)),
+            `Plugin package ${packageId} candidate cleanup failed`,
+          ),
+        `Plugin package ${packageId} reload and cleanup failed`,
+      );
+    }
+    for (const { current, replacement } of candidates) {
+      const siblings = current.parent?.children ?? this.#root(current.rootId).entries;
+      const index = siblings.indexOf(current);
+      this.#unindex(current);
+      siblings[index] = replacement;
+      this.#index(replacement);
+    }
+    await this.#retire(
+      settleAll(
+        candidates.map(({ current }) => this.#dispose(current)),
+        `Plugin package ${packageId} previous generation cleanup failed`,
+      ),
+      `Plugin package ${packageId} cleanup failed after publishing its replacement`,
+    );
+  }
+
   async #rebind(entry: LiveEntry, parent: LiveEntry | undefined, position: number): Promise<void> {
     const replacement = await this.#stage(
       serialize(entry),
       entry.rootId,
       parent,
-      parent?.context ?? this.#root(entry.rootId).context,
+      parent ? childMountContext(parent) : this.#root(entry.rootId).context,
       parent ? isDisabled(parent) : false,
     );
     try {
@@ -547,8 +745,11 @@ export class MakaCompositionLoader {
       }
     }
     try {
-      for (const child of spec.children ?? [])
-        live.children.push(await this.#stage(child, rootId, live, live.context, disabled));
+      for (const child of spec.children ?? []) {
+        live.children.push(
+          await this.#stage(child, rootId, live, childMountContext(live), disabled),
+        );
+      }
     } catch (error) {
       return rethrowAfterCleanup(
         error,
@@ -632,7 +833,7 @@ export class MakaCompositionLoader {
         entry,
         rootId,
         parent,
-        parent?.context ?? root.context,
+        parent ? childMountContext(parent) : root.context,
         parent ? isDisabled(parent) : false,
       );
       try {
@@ -864,6 +1065,24 @@ function* walk(entry: MakaCompositionEntry): Generator<MakaCompositionEntry> {
   for (const child of entry.children ?? []) yield* walk(child);
 }
 
+function* walkLive(entry: LiveEntry): Generator<LiveEntry> {
+  yield entry;
+  for (const child of entry.children) yield* walkLive(child);
+}
+
+function* ancestors(entry: LiveEntry): Generator<LiveEntry> {
+  for (let current = entry.parent; current; current = current.parent) yield current;
+}
+
+/**
+ * Package Entries introduce a Fiber ownership boundary. Their descendants
+ * must mount through that Fiber's Context; scope-only Entries keep using the
+ * Context view owned by their nearest package ancestor (or the root Fiber).
+ */
+function childMountContext(entry: LiveEntry): Context {
+  return entry.fiber?.context ?? entry.context;
+}
+
 function isWithin(entry: LiveEntry, root: LiveEntry): boolean {
   for (let current: LiveEntry | undefined = entry; current; current = current.parent)
     if (current === root) return true;
diff --git a/packages/runtime/src/plugin-runtime.ts b/packages/runtime/src/plugin-runtime.ts
index 06fbfe0408..8b8e106e6c 100644
--- a/packages/runtime/src/plugin-runtime.ts
+++ b/packages/runtime/src/plugin-runtime.ts
@@ -46,7 +46,7 @@ export interface MakaCompositionEntry {
   readonly children?: readonly MakaCompositionEntry[];
 }
 
-export interface MakaCompositionSnapshot {
+export interface MakaCompositionState {
   readonly schemaVersion: 1;
   readonly generation: number;
   readonly roots: {
@@ -82,6 +82,210 @@ export interface MakaCompositionApplyInput {
   readonly operations: readonly MakaCompositionOperation[];
 }
 
+/**
+ * Applies Entry Tree operations to the desired-state value without activating
+ * Plugin code. Runtime Host uses this reducer to durably commit desired state
+ * before asking the live Composition Loader to converge.
+ */
+export function applyCompositionState(
+  state: MakaCompositionState,
+  input: MakaCompositionApplyInput,
+): MakaCompositionState {
+  if (state.schemaVersion !== 1) {
+    throw new MakaPluginRuntimeError('invalid_entry', 'Unsupported composition state');
+  }
+  if (input.baseGeneration !== undefined && input.baseGeneration !== state.generation) {
+    throw new MakaPluginRuntimeError(
+      'invalid_entry',
+      `Composition generation changed from ${input.baseGeneration} to ${state.generation}`,
+    );
+  }
+  if (input.operations.length === 0) return state;
+  if (state.generation >= Number.MAX_SAFE_INTEGER) {
+    throw new MakaPluginRuntimeError('invalid_entry', 'Composition generation is exhausted');
+  }
+
+  interface MutableLocation {
+    entry: MakaCompositionEntry;
+    parent?: MutableLocation;
+    readonly rootId: MakaPluginRootId;
+    siblings: MakaCompositionEntry[];
+  }
+
+  const profile = state.roots.profile.map(cloneCompositionEntry);
+  const desktopUi = state.roots.desktopUi.map(cloneCompositionEntry);
+  const sessions = Object.fromEntries(
+    Object.entries(state.roots.sessions).map(([scopeId, entries]) => [
+      scopeId,
+      entries.map(cloneCompositionEntry),
+    ]),
+  ) as Record<string, MakaCompositionEntry[]>;
+  const locations = new Map<string, MutableLocation>();
+
+  const index = (
+    entries: MakaCompositionEntry[],
+    rootId: MakaPluginRootId,
+    parent?: MutableLocation,
+  ): void => {
+    validatePluginRootId(rootId);
+    for (const entry of entries) {
+      validateCompositionEntry(entry);
+      if (locations.has(entry.id)) {
+        throw new MakaPluginRuntimeError(
+          'entry_exists',
+          `Composition entry already exists: ${entry.id}`,
+        );
+      }
+      const location: MutableLocation = { entry, parent, rootId, siblings: entries };
+      locations.set(entry.id, location);
+      index(entry.children as MakaCompositionEntry[], rootId, location);
+    }
+  };
+  index(profile, 'profile');
+  index(desktopUi, 'desktop-ui');
+  for (const [scopeId, entries] of Object.entries(sessions)) {
+    index(entries, `session:${scopeId}`);
+  }
+
+  const requireLocation = (entryId: string): MutableLocation => {
+    const location = locations.get(entryId);
+    if (!location) {
+      throw new MakaPluginRuntimeError(
+        'entry_not_found',
+        `Composition entry not found: ${entryId}`,
+      );
+    }
+    return location;
+  };
+  const rootEntries = (rootId: MakaPluginRootId): MakaCompositionEntry[] => {
+    validatePluginRootId(rootId);
+    if (rootId === 'profile') return profile;
+    if (rootId === 'desktop-ui') return desktopUi;
+    const scopeId = rootId.slice('session:'.length);
+    if (!Object.hasOwn(sessions, scopeId)) {
+      Object.defineProperty(sessions, scopeId, {
+        value: [],
+        writable: true,
+        enumerable: true,
+        configurable: true,
+      });
+    }
+    return sessions[scopeId]!;
+  };
+  const unindex = (entry: MakaCompositionEntry): void => {
+    locations.delete(entry.id);
+    for (const child of entry.children ?? []) unindex(child);
+  };
+  const indexInserted = (
+    entry: MakaCompositionEntry,
+    rootId: MakaPluginRootId,
+    siblings: MakaCompositionEntry[],
+    parent?: MutableLocation,
+  ): void => {
+    if (locations.has(entry.id)) {
+      throw new MakaPluginRuntimeError(
+        'entry_exists',
+        `Composition entry already exists: ${entry.id}`,
+      );
+    }
+    const location: MutableLocation = { entry, parent, rootId, siblings };
+    locations.set(entry.id, location);
+    for (const child of entry.children ?? []) {
+      indexInserted(child, rootId, entry.children as MakaCompositionEntry[], location);
+    }
+  };
+
+  for (const operation of input.operations) {
+    switch (operation.type) {
+      case 'insert': {
+        const parent = operation.parentId ? requireLocation(operation.parentId) : undefined;
+        const rootId = operation.rootId ?? parent?.rootId ?? 'profile';
+        validatePluginRootId(rootId);
+        if (parent && parent.rootId !== rootId) {
+          throw new MakaPluginRuntimeError(
+            'invalid_entry',
+            'Composition entries cannot move between roots',
+          );
+        }
+        const entry = cloneCompositionEntry(operation.entry);
+        validateCompositionEntry(entry);
+        const subtreeIds = new Set<string>();
+        for (const item of walkCompositionEntry(entry)) {
+          if (subtreeIds.has(item.id) || locations.has(item.id)) {
+            throw new MakaPluginRuntimeError(
+              'entry_exists',
+              `Composition entry already exists: ${item.id}`,
+            );
+          }
+          subtreeIds.add(item.id);
+        }
+        const siblings = parent
+          ? (parent.entry.children as MakaCompositionEntry[])
+          : rootEntries(rootId);
+        siblings.splice(Math.min(operation.position ?? Infinity, siblings.length), 0, entry);
+        indexInserted(entry, rootId, siblings, parent);
+        break;
+      }
+      case 'update': {
+        const location = requireLocation(operation.entryId);
+        const next: MakaCompositionEntry = {
+          ...location.entry,
+          ...operation.patch,
+          id: location.entry.id,
+          children: location.entry.children,
+        };
+        validateCompositionEntry(next);
+        const position = location.siblings.indexOf(location.entry);
+        location.siblings[position] = next;
+        location.entry = next;
+        break;
+      }
+      case 'move': {
+        const location = requireLocation(operation.entryId);
+        const parent = operation.parentId ? requireLocation(operation.parentId) : undefined;
+        if (parent && parent.rootId !== location.rootId) {
+          throw new MakaPluginRuntimeError(
+            'invalid_entry',
+            'Composition entries cannot move between roots',
+          );
+        }
+        for (let ancestor = parent; ancestor; ancestor = ancestor.parent) {
+          if (ancestor === location) {
+            throw new MakaPluginRuntimeError(
+              'dependency_cycle',
+              `Entry ${operation.entryId} cannot contain itself`,
+            );
+          }
+        }
+        location.siblings.splice(location.siblings.indexOf(location.entry), 1);
+        const siblings = parent
+          ? (parent.entry.children as MakaCompositionEntry[])
+          : rootEntries(location.rootId);
+        siblings.splice(
+          Math.min(operation.position ?? Infinity, siblings.length),
+          0,
+          location.entry,
+        );
+        location.parent = parent;
+        location.siblings = siblings;
+        break;
+      }
+      case 'remove': {
+        const location = requireLocation(operation.entryId);
+        location.siblings.splice(location.siblings.indexOf(location.entry), 1);
+        unindex(location.entry);
+        break;
+      }
+    }
+  }
+
+  return freezeCompositionState({
+    schemaVersion: 1,
+    generation: state.generation + 1,
+    roots: { profile, desktopUi, sessions },
+  });
+}
+
 export type MakaCompositionEntryStatus =
   | 'disabled'
   | 'pending'
@@ -125,20 +329,6 @@ export interface MakaPluginMountInspection {
   readonly diagnostic?: { readonly message: string };
 }
 
-export interface MakaRuntimeCompositionEntry {
-  readonly entryId: string;
-  readonly packageId: string;
-  readonly generation: number;
-  readonly contributions: readonly MakaPluginContribution[];
-}
-
-export interface MakaRuntimeCompositionSnapshot {
-  readonly schemaVersion: 1;
-  readonly rootId: string;
-  readonly digest: `sha256:${string}`;
-  readonly entries: readonly MakaRuntimeCompositionEntry[];
-}
-
 export interface MakaPluginMetadata {
   readonly rootId: MakaPluginRootId;
   readonly entryId: string;
@@ -202,6 +392,40 @@ export function validatePluginPackage(pkg: MakaPluginPackage): void {
       `Plugin package ${pkg.packageId} has no host or client plugin`,
     );
   }
+  if (!Array.isArray(pkg.contributions ?? []) || (pkg.contributions?.length ?? 0) > 1024) {
+    throw new MakaPluginRuntimeError(
+      'invalid_package',
+      `Plugin package ${pkg.packageId} has invalid contributions`,
+    );
+  }
+  const contributions = new Set<string>();
+  for (const contribution of pkg.contributions ?? []) {
+    if (
+      !contribution ||
+      typeof contribution !== 'object' ||
+      typeof contribution.id !== 'string' ||
+      contribution.id.length === 0 ||
+      contribution.id.length > 128 ||
+      /[\u0000-\u001f\u007f]/u.test(contribution.id) ||
+      typeof contribution.kind !== 'string' ||
+      contribution.kind.length === 0 ||
+      contribution.kind.length > 128 ||
+      /[\u0000-\u001f\u007f]/u.test(contribution.kind)
+    ) {
+      throw new MakaPluginRuntimeError(
+        'invalid_package',
+        `Plugin package ${pkg.packageId} has an invalid contribution`,
+      );
+    }
+    const identity = `${contribution.kind}\0${contribution.id}`;
+    if (contributions.has(identity)) {
+      throw new MakaPluginRuntimeError(
+        'invalid_package',
+        `Plugin package ${pkg.packageId} repeats contribution ${contribution.kind}:${contribution.id}`,
+      );
+    }
+    contributions.add(identity);
+  }
 }
 
 export function validateCompositionEntry(entry: MakaCompositionEntry): void {
@@ -378,6 +602,56 @@ export function isCanonicalPluginId(value: unknown): value is string {
 
 export const isCanonicalExtensionId = isCanonicalPluginId;
 
+function cloneCompositionEntry(entry: MakaCompositionEntry): MakaCompositionEntry {
+  return {
+    ...entry,
+    ...(entry.inject && !Array.isArray(entry.inject)
+      ? { inject: { ...entry.inject } }
+      : entry.inject
+        ? { inject: [...entry.inject] }
+        : {}),
+    ...(entry.isolate ? { isolate: { ...entry.isolate } } : {}),
+    ...(entry.intercept ? { intercept: { ...entry.intercept } } : {}),
+    children: (entry.children ?? []).map(cloneCompositionEntry),
+  };
+}
+
+function* walkCompositionEntry(entry: MakaCompositionEntry): Generator<MakaCompositionEntry> {
+  yield entry;
+  for (const child of entry.children ?? []) yield* walkCompositionEntry(child);
+}
+
+function freezeCompositionState(state: MakaCompositionState): MakaCompositionState {
+  const freezeEntry = (entry: MakaCompositionEntry): MakaCompositionEntry =>
+    Object.freeze({
+      ...entry,
+      ...(entry.inject && !Array.isArray(entry.inject)
+        ? { inject: Object.freeze({ ...entry.inject }) }
+        : entry.inject
+          ? { inject: Object.freeze([...entry.inject]) }
+          : {}),
+      ...(entry.isolate ? { isolate: Object.freeze({ ...entry.isolate }) } : {}),
+      ...(entry.intercept ? { intercept: Object.freeze({ ...entry.intercept }) } : {}),
+      children: Object.freeze((entry.children ?? []).map(freezeEntry)),
+    });
+  return Object.freeze({
+    schemaVersion: 1,
+    generation: state.generation,
+    roots: Object.freeze({
+      profile: Object.freeze(state.roots.profile.map(freezeEntry)),
+      desktopUi: Object.freeze(state.roots.desktopUi.map(freezeEntry)),
+      sessions: Object.freeze(
+        Object.fromEntries(
+          Object.entries(state.roots.sessions).map(([scopeId, entries]) => [
+            scopeId,
+            Object.freeze(entries.map(freezeEntry)),
+          ]),
+        ),
+      ),
+    }),
+  });
+}
+
 export function isCanonicalExtensionScopeId(value: unknown): value is string {
   return (
     typeof value === 'string' && value.length <= 128 && /^[A-Za-z0-9][A-Za-z0-9._:-]*$/u.test(value)


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@maka.apache.org
For additional commands, e-mail: commits-help@maka.apache.org