import { describe, it } from 'node:test';
import { strict as assert } from 'node:assert';
import { mkdtempSync, mkdirSync, rmSync, writeFileSync } from 'node:fs';
import { tmpdir } from 'node:os';
import { join } from 'node:path';
import {
  InMemoryBroker,
  InMemoryTransport,
  MatrixActor,
  MatrixRuntime,
  RequestReply,
  subscribeRuntimePresence,
} from '@open-matrix/core';
import { decideMatrixPlacementBind } from '@open-matrix/contracts/placement';

import {
  heartbeatRunnerRuntime,
  registerRunnerBindings,
  registerRunnerRuntime,
  shouldRegisterRuntimeInventoryClaim,
} from '../../src/utils/runner-control-plane.js';
import { ServiceRegistryActor } from '@open-matrix/system-platform';
import { BindingsRegistryActor } from '@open-matrix/system-bindings';
import { installRunnerPlacementPolicy } from '../../src/utils/runner-placement-policy.js';
import type { ILoadedMatrixServiceManifest } from '../../src/utils/service-manifest.js';

const runtimePresenceManifest: ILoadedMatrixServiceManifest = {
  packageDir: '/tmp/runtime-presence-package',
  packageName: '@open-matrix/runtime-presence-test',
  packageNamespace: 'runtime-presence-test',
  manifestPath: '/tmp/runtime-presence-package/matrix.json',
  entryPath: '/tmp/runtime-presence-package/dist/index.js',
  exportName: 'RuntimePresenceTestActor',
  kind: 'factory',
  overrides: {},
  root: 'SPACE-RUNNER',
  mount: 'runtime-presence-test',
  packageRoot: {
    mount: 'runtime-presence-test',
    accepts: ['runtime-presence.ping'],
  },
  packageComponents: [],
  serviceInstance: {
    id: 'runtime-presence-runner',
    packageName: '@open-matrix/runtime-presence-test',
    class: 'RuntimePresenceTestActor',
    rootKind: 'package-root',
    autoStart: true,
    registrationSource: 'matrix-service',
  },
};

class PlacementGatewayActor extends MatrixActor {
  static override description = 'Placement gateway test actor';
}

class PlacementCredentialBridgeActor extends MatrixActor {
  static override description = 'Placement credential bridge test actor';
}

class FakeAuthorityActor extends MatrixActor {
  static override accepts = {
    'fake.ping': {},
  };

  onFakePing(): { ok: true; actor: 'authority' } {
    return { ok: true, actor: 'authority' };
  }
}

class FakeDeviceActor extends MatrixActor {
  static override accepts = {
    'fake.ping': {},
  };

  onFakePing(): { ok: true; actor: 'device' } {
    return { ok: true, actor: 'device' };
  }
}

describe('runner control plane', () => {
  it('keeps ephemeral runtime mounts out of the logical registry', () => {
    assert.equal(
      shouldRegisterRuntimeInventoryClaim('RUNTIME-HOST-CHAT', 'system.runtimes.RUNTIME-HOST-CHAT'),
      false,
    );
    assert.equal(
      shouldRegisterRuntimeInventoryClaim('RUNTIME-HOST-CHAT', 'system.runtimes.RUNTIME-HOST-CHAT.control'),
      false,
    );
    assert.equal(
      shouldRegisterRuntimeInventoryClaim('RUNTIME-BROWSER-1234', 'system.runtimes.RUNTIME-BROWSER-1234.director'),
      false,
    );
  });

  it('continues to register canonical actor mounts', () => {
    assert.equal(shouldRegisterRuntimeInventoryClaim('RUNTIME-HOST-CHAT', 'chat'), true);
    assert.equal(shouldRegisterRuntimeInventoryClaim('RUNTIME-HOST-CHAT', 'chat.conversation'), true);
    assert.equal(shouldRegisterRuntimeInventoryClaim('RUNTIME-HOST-SYSTEM', 'system.runtimes'), true);
  });

  it('publishes runtime presence when registering a runner runtime', async () => {
    const runtime = new MatrixRuntime({
      transport: new InMemoryTransport(new InMemoryBroker(), {
        name: 'runner-presence-test',
        root: 'SPACE-RUNNER',
      }),
      logging: false,
    });
    const observed: string[] = [];
    const unsubscribe = subscribeRuntimePresence(
      runtime.getRootContext(),
      'SPACE-RUNNER',
      (record, event) => {
        observed.push(`${event}:${record.runtimeId}:${record.app ?? ''}:${record.health?.status ?? ''}`);
      },
    );

    try {
      await registerRunnerRuntime(
        runtime,
        runtimePresenceManifest,
        undefined,
        undefined,
        'runtime-presence-test',
      );

      // Slice 1b: runtime directory authority is system.runtimes
      // (RuntimeManagerActor). registerRunnerRuntime publishes presence on the
      // bus; subscribers like RuntimeManagerActor observe and serve it via
      // runtimes.list. There is no longer a `kind: 'runtime'` registry claim.
      assert.deepEqual(observed, ['announce:runtime-presence-runner:@open-matrix/runtime-presence-test:ok']);
    } finally {
      unsubscribe();
      await runtime.shutdown();
    }
  });

  it('marks linked-device control-plane calls for broker protocol request replies', async () => {
    const runtime = new MatrixRuntime({
      transport: new InMemoryTransport(new InMemoryBroker(), {
        name: 'runner-linked-authority-test',
        root: 'test-user-1',
      }),
      logging: false,
    });

    try {
      const registration = await registerRunnerRuntime(
        runtime,
        runtimePresenceManifest,
        {
          packageDir: '/tmp/runtime-presence-package',
          envName: 'hivecast',
          environmentPath: '/tmp/runtime-presence-package/.matrix/hivecast.environment.json',
          environment: {
            name: 'hivecast',
            runtime: {
              root: 'test-user-1',
              runtimeId: 'runtime-presence-runner',
            },
            nats: {
              mode: 'external',
              url: 'nats://dev-platform:4222',
              credentialsRef: 'file:/var/lib/hivecast/credentials/hivecast-nats.json',
            },
            host: {
              matrixDir: '/var/lib/hivecast',
            },
          },
        },
        {
          envName: 'hivecast',
          root: 'test-user-1',
          mode: 'external',
          url: 'nats://dev-platform:4222',
          credentialsRef: 'file:/var/lib/hivecast/credentials/hivecast-nats.json',
        },
        'runtime-presence-test',
      );

      assert.equal(registration.controlTargetRoot, 'test-user-1');
      assert.equal(registration.protocolRequest, true);
    } finally {
      await runtime.shutdown();
    }
  });

  it('reclaim re-issues registry.claim after the registry actor was wiped (simulates SYSTEM restart)', async () => {
    // This test pins the production failure mode that motivated the reclaim()
    // closure on IRunnerRuntimeRegistration / IRunnerBindingRegistration:
    //
    //   1. Runner registers, registry stores claim in its in-memory _claims Map
    //   2. SYSTEM runtime restarts (deploy, supervisor bounce). Its _claims
    //      starts empty
    //   3. Runner's 10s heartbeat calls registry.claim.renew → registry has
    //      no record → returns { renewed: 0 }
    //   4. Without reclaim, the runner's original 45s-TTL claim expires and
    //      the runtime vanishes from registry.query
    //
    // The fix: heartbeatRunnerRuntime / renewRunnerBindings return
    // { known: false } / { refreshed: 0 } when the registry forgot us, and
    // the heartbeat tick calls registration.reclaim() to re-issue claims.
    const home = mkdtempSync(join(tmpdir(), 'runner-reclaim-test-'));
    writeFileSync(join(home, 'matrix.json'), JSON.stringify({
      name: '@open-matrix/reclaim-test',
      root: {
        type: 'ReclaimTestRootActor',
        mount: 'reclaim-test',
      },
      components: [],
    }));
    const reclaimManifest: ILoadedMatrixServiceManifest = {
      ...runtimePresenceManifest,
      packageDir: home,
      packageName: '@open-matrix/reclaim-test',
      packageNamespace: 'reclaim-test',
      manifestPath: join(home, 'matrix.json'),
      entryPath: join(home, 'dist/index.js'),
      packageRoot: {
        mount: 'reclaim-test',
        accepts: ['reclaim.ping'],
      },
      serviceInstance: {
        ...runtimePresenceManifest.serviceInstance,
        id: 'reclaim-test-runner',
        packageName: '@open-matrix/reclaim-test',
      },
    };
    const runtime = new MatrixRuntime({
      transport: new InMemoryTransport(new InMemoryBroker(), {
        name: 'runner-reclaim-test',
        root: 'SPACE-RECLAIM',
      }),
      logging: false,
    });

    const queryRegistry = async () => await RequestReply.execute(
      runtime.getRootContext(),
      'system.registry',
      'registry.query',
      { kind: 'actor', includeStale: true },
      { timeoutMs: 5_000 },
    ) as { entries?: Array<{ mount?: string; providerRuntimeId?: string }> };

    const queryBindings = async () => await RequestReply.execute(
      runtime.getRootContext(),
      'system.bindings',
      'bindings.list',
      {},
      { timeoutMs: 5_000 },
    ) as { ok?: boolean; count?: number; bindings?: Array<{ binding?: string }> };

    try {
      const runtimeRegistration = await registerRunnerRuntime(
        runtime,
        reclaimManifest,
        undefined,
        undefined,
        'reclaim-test',
      );
      const bindingRegistration = await registerRunnerBindings(
        runtime,
        reclaimManifest,
        undefined,
        runtimeRegistration.runtimeId,
        'reclaim-test',
      );

      // Sanity: both registries know about us before wipe.
      const beforeWipeRegistry = await queryRegistry();
      const beforeRegistryMounts = new Set((beforeWipeRegistry.entries ?? []).map((e) => e.mount));
      assert.ok(beforeRegistryMounts.size > 0, 'system.registry should have at least one claim before wipe');
      const beforeWipeBindings = await queryBindings();
      const beforeBindingMounts = new Set((beforeWipeBindings.bindings ?? []).map((b) => b.binding));
      assert.ok(beforeBindingMounts.size > 0, 'system.bindings should have at least one binding before wipe');

      // Simulate SYSTEM restart: tear down BOTH registries and replace them
      // with fresh ones. Their _claims / _bindings maps start empty —
      // exactly the state the production registries are in right after a
      // SYSTEM bounce.
      await runtime.remove('system.registry');
      await runtime.remove('system.bindings');
      await runtime.createSupervised(ServiceRegistryActor, 'system.registry');
      await runtime.createSupervised(BindingsRegistryActor, 'system.bindings');

      const afterWipeRegistry = await queryRegistry();
      assert.deepEqual(
        afterWipeRegistry.entries ?? [],
        [],
        'system.registry should be empty after wipe (production failure mode)',
      );
      const afterWipeBindings = await queryBindings();
      assert.deepEqual(
        afterWipeBindings.bindings ?? [],
        [],
        'system.bindings should be empty after wipe (production failure mode)',
      );

      // Reclaim should restore every server-side record we published at
      // registration time. After both calls the registries see us again.
      const runtimeReclaim = await runtimeRegistration.reclaim();
      assert.ok(
        runtimeReclaim.inventoryClaimCount >= 0,
        'runtime reclaim returns the count of inventory claims re-issued',
      );
      const bindingReclaim = await bindingRegistration.reclaim();
      assert.ok(
        bindingReclaim.registryClaimCount >= 1,
        'binding reclaim re-issues at least the canonical package-root registry claim',
      );
      assert.ok(
        bindingReclaim.bindingsRegisteredCount >= 1,
        'binding reclaim re-issues at least the canonical package-root bindings.register',
      );
      assert.equal(
        bindingReclaim.registryClaimCount,
        bindingReclaim.bindingsRegisteredCount,
        'every canonical binding produces exactly one registry.claim AND one bindings.register; reclaim must restore them in lockstep',
      );

      const afterReclaimRegistry = await queryRegistry();
      const afterReclaimRegistryMounts = new Set((afterReclaimRegistry.entries ?? []).map((e) => e.mount));
      assert.ok(
        afterReclaimRegistryMounts.size >= beforeRegistryMounts.size,
        `reclaim should restore all registry claims (had ${beforeRegistryMounts.size}, now ${afterReclaimRegistryMounts.size})`,
      );
      assert.ok(
        afterReclaimRegistryMounts.has('reclaim-test'),
        'canonical package-root registry claim should be reclaimed',
      );

      const afterReclaimBindings = await queryBindings();
      const afterReclaimBindingMounts = new Set((afterReclaimBindings.bindings ?? []).map((b) => b.binding));
      assert.deepEqual(
        afterReclaimBindingMounts,
        beforeBindingMounts,
        'reclaim should restore every bindings.register record (otherwise canonical lookups break silently)',
      );
    } finally {
      await runtime.shutdown();
      rmSync(home, { recursive: true, force: true });
    }
  });

  it('publishes placement metadata for runtime inventory and registry claims', async () => {
    const home = mkdtempSync(join(tmpdir(), 'runner-placement-manifest-'));
    const manifestPath = join(home, 'matrix.json');
    writeFileSync(manifestPath, JSON.stringify({
      name: '@open-matrix/placement-test',
      root: {
        type: 'PlacementRootActor',
        mount: 'system',
      },
      components: [
        {
          type: 'PlacementRegistryActor',
          mount: 'system.registry',
          placement: { cardinality: 'authority-singleton' },
        },
        {
          type: 'PlacementGatewayActor',
          mount: 'system.gateway',
          placement: { cardinality: 'device-local-control' },
        },
        {
          type: 'PlacementCredentialBridgeActor',
          mount: 'system.security.credential-bridge',
          placement: { cardinality: 'device-singleton' },
        },
      ],
    }));

    const manifest: ILoadedMatrixServiceManifest = {
      ...runtimePresenceManifest,
      packageDir: home,
      packageName: '@open-matrix/placement-test',
      packageNamespace: 'system',
      manifestPath,
      entryPath: join(home, 'dist/index.js'),
      serviceInstance: {
        ...runtimePresenceManifest.serviceInstance,
        id: 'placement-test-runner',
        packageName: '@open-matrix/placement-test',
      },
    };
    const runtime = new MatrixRuntime({
      transport: new InMemoryTransport(new InMemoryBroker(), {
        name: 'runner-placement-test',
        root: 'SPACE-RUNNER',
      }),
      logging: false,
    });

    try {
      await runtime.createSupervised(PlacementGatewayActor, 'system.gateway');
      await runtime.createSupervised(PlacementCredentialBridgeActor, 'system.security.credential-bridge');

      const registration = await registerRunnerRuntime(
        runtime,
        manifest,
        undefined,
        undefined,
        'system',
      );

      const inventoryByMount = new Map(
        (registration.presence.inventory ?? []).map((entry) => [entry.mount, entry]),
      );
      assert.equal(inventoryByMount.get('system.registry')?.placement?.cardinality, 'authority-singleton');
      assert.equal(inventoryByMount.get('system.registry')?.placement?.claimMode, 'authoritative');
      assert.equal(inventoryByMount.get('system.registry')?.placement?.logicalMount, 'system.registry');
      assert.equal(inventoryByMount.get('system.registry')?.placement?.physicalMount, 'system.registry');
      assert.equal(inventoryByMount.get('system.registry')?.placement?.callable, true);
      assert.equal(inventoryByMount.get('system.gateway')?.placement?.cardinality, 'device-local-control');
      assert.equal(inventoryByMount.get('system.gateway')?.placement?.claimMode, 'local-only');
      assert.equal(inventoryByMount.get('system.security.credential-bridge')?.placement?.cardinality, 'device-singleton');
      assert.equal(inventoryByMount.get('system.security.credential-bridge')?.placement?.claimMode, 'local-only');

      const actorEntries = await RequestReply.execute(
        runtime.getRootContext(),
        'system.registry',
        'registry.query',
        { namespaceRoot: 'SPACE-RUNNER', kind: 'actor' },
        { timeoutMs: 5_000 },
      ) as {
        entries?: Array<{
          mount?: string;
          claim?: { mode?: string };
          placement?: {
            cardinality?: string;
            claimMode?: string;
            logicalMount?: string;
            physicalMount?: string;
            callable?: boolean;
          };
          metadata?: { placement?: { callable?: boolean } };
        }>;
      };

      const byMount = new Map((actorEntries.entries ?? []).map((entry) => [entry.mount, entry]));
      assert.equal(byMount.get('system.registry')?.claim?.mode, 'authoritative');
      assert.equal(byMount.get('system.registry')?.placement?.cardinality, 'authority-singleton');
      assert.equal(byMount.get('system.registry')?.placement?.claimMode, 'authoritative');
      assert.equal(byMount.get('system.registry')?.placement?.callable, true);
      assert.equal(byMount.get('system.registry')?.metadata?.placement?.callable, true);
      assert.equal(byMount.get('system.gateway')?.claim?.mode, 'local-only');
      assert.equal(byMount.get('system.gateway')?.placement?.cardinality, 'device-local-control');
      assert.equal(byMount.get('system.gateway')?.placement?.callable, true);
      assert.equal(byMount.get('system.security.credential-bridge')?.claim?.mode, 'local-only');
      assert.equal(byMount.get('system.security.credential-bridge')?.placement?.cardinality, 'device-singleton');
    } finally {
      await runtime.shutdown();
      rmSync(home, { recursive: true, force: true });
    }
  });

  it('blocks manifest authority-singleton actors before inbox bind on standby topology', async () => {
    const home = mkdtempSync(join(tmpdir(), 'runner-placement-denial-'));
    writeFileSync(join(home, 'matrix.json'), JSON.stringify({
      name: '@open-matrix/placement-denial-test',
      components: [
        {
          type: 'FakeAuthorityActor',
          mount: 'system.fakeAuthority',
          placement: {
            cardinality: 'authority-singleton',
          },
        },
        {
          type: 'FakeDeviceActor',
          mount: 'system.fakeDevice',
          placement: {
            cardinality: 'device-local-control',
          },
        },
      ],
    }));

    const manifest: ILoadedMatrixServiceManifest = {
      ...runtimePresenceManifest,
      packageDir: home,
      packageName: '@open-matrix/placement-denial-test',
      packageNamespace: 'system',
      manifestPath: join(home, 'matrix.json'),
      entryPath: join(home, 'dist/index.js'),
      packageComponents: [
        {
          mount: 'system.fakeAuthority',
          accepts: ['fake.ping'],
        },
        {
          mount: 'system.fakeDevice',
          accepts: ['fake.ping'],
        },
      ],
      serviceInstance: {
        ...runtimePresenceManifest.serviceInstance,
        id: 'placement-denial-runner',
        packageName: '@open-matrix/placement-denial-test',
      },
    };
    const runtime = new MatrixRuntime({
      transport: new InMemoryTransport(new InMemoryBroker(), {
        name: 'runner-placement-denial-test',
        root: 'SPACE-HIVECAST-LAB',
      }),
      logging: false,
    });

    try {
      installRunnerPlacementPolicy({
        runtime,
        manifest,
        environment: {
          packageDir: home,
          envName: 'standby',
          environmentPath: join(home, '.matrix', 'standby.environment.json'),
          environment: {
            name: 'standby',
            runtime: {
              root: 'SPACE-HIVECAST-LAB',
              runtimeId: 'placement-denial-runner',
            },
            topology: {
              kind: 'linked-device',
              roles: {
                authorityCoordinator: {
                  active: false,
                  reason: 'linked-device-standby',
                },
              },
              authority: {
                authorityRoot: 'SPACE-HIVECAST-LAB',
              },
            },
          },
        },
        runtimeId: 'placement-denial-runner',
        authorityRoot: 'SPACE-HIVECAST-LAB',
      });

      await assert.rejects(
        () => runtime.createSupervised(FakeAuthorityActor, 'system.fakeAuthority'),
        /SINGLETON_MOUNT_NOT_OWNED/,
      );
      await runtime.createSupervised(FakeDeviceActor, 'system.fakeDevice');

      const registration = await registerRunnerRuntime(
        runtime,
        manifest,
        undefined,
        undefined,
        'system',
      );
      const bindings = await registerRunnerBindings(
        runtime,
        manifest,
        undefined,
        registration.runtimeId,
        'system',
      );

      assert.equal(runtime.hasComponent('system.fakeAuthority'), false);
      assert.equal(runtime.hasComponent('system.fakeDevice'), true);
      assert.equal(bindings.bindings.some((binding) => binding.localMount === 'system.fakeAuthority'), false);
      assert.equal(bindings.bindings.some((binding) => binding.localMount === 'system.fakeDevice'), true);
      await assert.rejects(
        () => RequestReply.execute(
          runtime.getRootContext(),
          'system.fakeAuthority',
          'fake.ping',
          {},
          { timeoutMs: 150 },
        ),
      );
      const deviceReply = await RequestReply.execute(
        runtime.getRootContext(),
        'system.fakeDevice',
        'fake.ping',
        {},
        { timeoutMs: 5_000 },
      ) as { ok?: boolean; actor?: string };
      assert.deepEqual(deviceReply, { ok: true, actor: 'device' });

      const inventoryByMount = new Map(
        (registration.presence.inventory ?? []).map((entry) => [entry.mount, entry]),
      );
      assert.equal(inventoryByMount.get('system.fakeAuthority')?.placement?.cardinality, 'authority-singleton');
      assert.equal(inventoryByMount.get('system.fakeAuthority')?.placement?.callable, false);
      assert.equal(
        inventoryByMount.get('system.fakeAuthority')?.placement?.standbyReason,
        'SINGLETON_MOUNT_NOT_OWNED',
      );
      assert.equal(inventoryByMount.get('system.fakeDevice')?.placement?.cardinality, 'device-local-control');
      assert.equal(inventoryByMount.get('system.fakeDevice')?.placement?.claimMode, 'local-only');
      assert.equal(inventoryByMount.get('system.fakeDevice')?.placement?.callable, true);

      // Slice 1b: query without namespaceRoot filter because
      // registerRuntimeInventoryClaims writes claims with manifest.root as the
      // namespaceRoot, while presence uses the transport root. The substrate
      // truth here is "system.fakeDevice is claimed by this runtime" — the
      // test does not need to assert which namespaceRoot the claim is stored
      // under (that's a separate pre-existing inconsistency the workstream
      // does not address).
      const actorEntries = await RequestReply.execute(
        runtime.getRootContext(),
        'system.registry',
        'registry.query',
        { kind: 'actor', includeStale: true },
        { timeoutMs: 5_000 },
      ) as {
        entries?: Array<{
          mount?: string;
          placement?: {
            cardinality?: string;
            claimMode?: string;
            callable?: boolean;
          };
        }>;
      };
      const byMount = new Map((actorEntries.entries ?? []).map((entry) => [entry.mount, entry]));
      assert.equal(byMount.has('system.fakeAuthority'), false);
      assert.equal(byMount.get('system.fakeDevice')?.placement?.cardinality, 'device-local-control');
      assert.equal(byMount.get('system.fakeDevice')?.placement?.claimMode, 'local-only');
      assert.equal(byMount.get('system.fakeDevice')?.placement?.callable, true);
    } finally {
      await runtime.shutdown();
      rmSync(home, { recursive: true, force: true });
    }
  });

  it('uses authority leases to fence active authority-singleton placement', () => {
    const activeLease = {
      version: 1 as const,
      authorityRoot: 'SPACE-HIVECAST-LAB',
      leaseId: 'lease-active',
      ownerNodeId: 'owner-a',
      placementEpoch: 2,
      acquiredAt: '2026-05-09T00:00:00.000Z',
      heartbeatAt: '2026-05-09T00:00:00.000Z',
      expiresAt: '2026-05-09T00:05:00.000Z',
      status: 'active' as const,
      scope: 'local-home' as const,
      leaseAuthority: 'local' as const,
      source: 'local-file' as const,
    };

    assert.equal(decideMatrixPlacementBind({
      authorityRoot: 'SPACE-HIVECAST-LAB',
      mount: 'system.registry',
      cardinality: 'authority-singleton',
      authorityCoordinatorActive: true,
      ownerNodeId: 'owner-a',
      authorityLease: activeLease,
    }).allowed, true);

    const nonOwned = decideMatrixPlacementBind({
      authorityRoot: 'SPACE-HIVECAST-LAB',
      mount: 'system.registry',
      cardinality: 'authority-singleton',
      authorityCoordinatorActive: true,
      ownerNodeId: 'owner-b',
      authorityLease: activeLease,
    });
    assert.equal(nonOwned.allowed, false);
    assert.equal(nonOwned.reason, 'AUTHORITY_COORDINATOR_LEASE_NOT_OWNED');

    const fenced = decideMatrixPlacementBind({
      authorityRoot: 'SPACE-HIVECAST-LAB',
      mount: 'system.registry',
      cardinality: 'authority-singleton',
      authorityCoordinatorActive: true,
      ownerNodeId: 'owner-a',
      authorityLease: {
        ...activeLease,
        status: 'fenced',
        reason: 'LEASE_FORCED',
      },
    });
    assert.equal(fenced.allowed, false);
    assert.equal(fenced.reason, 'AUTHORITY_COORDINATOR_LEASE_NOT_OWNED');

    assert.equal(decideMatrixPlacementBind({
      authorityRoot: 'SPACE-HIVECAST-LAB',
      mount: 'system.registry',
      cardinality: 'authority-singleton',
      authorityCoordinatorActive: true,
      ownerNodeId: 'owner-a',
    }).allowed, true);
  });

  it('claims webapp surfaces in system.registry for shell launchers', async () => {
    const runtime = new MatrixRuntime({
      transport: new InMemoryTransport(new InMemoryBroker(), {
        name: 'runner-webapp-surface-test',
        root: 'SPACE-RUNNER',
      }),
      logging: false,
    });

    try {
      const registration = await registerRunnerRuntime(
        runtime,
        runtimePresenceManifest,
        undefined,
        undefined,
        'runtime-presence-test',
        undefined,
        undefined,
        {
          appName: 'director',
          routePrefix: '/apps/director/',
          displayName: 'Director',
          icon: 'director',
          navOrder: 20,
          description: 'Matrix actor hierarchy explorer',
          shells: ['platform', 'edge'],
          assetMount: 'system.runtimes.runtime-presence-runner.http',
        },
      );
      const appEntries = await RequestReply.execute(
        runtime.getRootContext(),
        'system.registry',
        'registry.query',
        { namespaceRoot: 'SPACE-RUNNER', kind: 'app', openable: true },
        { timeoutMs: 5_000 },
      ) as {
        entries?: Array<{
          mount?: string;
          app?: { appName?: string; route?: string; title?: string; icon?: string; openable?: boolean };
          metadata?: { source?: string; assetMount?: string; routeKind?: string; description?: string; navOrder?: number; shells?: string[] };
          placement?: { runtimeId?: string; packageRef?: string };
        }>;
      };

      assert.ok(registration.inventoryClaimCount >= 1);
      assert.deepEqual(appEntries.entries?.map((entry) => entry.mount), ['director']);
      assert.equal(appEntries.entries?.[0]?.app?.appName, 'director');
      assert.equal(appEntries.entries?.[0]?.app?.title, 'Director');
      assert.equal(appEntries.entries?.[0]?.app?.icon, 'director');
      assert.equal(appEntries.entries?.[0]?.app?.route, '/apps/director/');
      assert.equal(appEntries.entries?.[0]?.app?.openable, true);
      assert.equal(appEntries.entries?.[0]?.metadata?.source, 'runner-webapp-surface');
      assert.equal(appEntries.entries?.[0]?.metadata?.description, 'Matrix actor hierarchy explorer');
      assert.equal(appEntries.entries?.[0]?.metadata?.navOrder, 20);
      assert.deepEqual(appEntries.entries?.[0]?.metadata?.shells, ['platform', 'edge']);
      assert.equal(appEntries.entries?.[0]?.metadata?.routeKind, 'matrix-asset-endpoint');
      assert.equal(appEntries.entries?.[0]?.metadata?.assetMount, 'system.runtimes.runtime-presence-runner.http');
      assert.equal(appEntries.entries?.[0]?.placement?.runtimeId, 'runtime-presence-runner');
      assert.equal(appEntries.entries?.[0]?.placement?.packageRef, '@open-matrix/runtime-presence-test');

      await runtime.remove('system.registry');
      await runtime.createSupervised(ServiceRegistryActor, 'system.registry');

      const afterWipe = await RequestReply.execute(
        runtime.getRootContext(),
        'system.registry',
        'registry.query',
        { namespaceRoot: 'SPACE-RUNNER', kind: 'app', openable: true },
        { timeoutMs: 5_000 },
      ) as { entries?: Array<{ mount?: string }> };
      assert.deepEqual(afterWipe.entries ?? [], []);

      const heartbeat = await heartbeatRunnerRuntime(runtime, registration);
      assert.equal(heartbeat?.known, false);
      const reclaimed = await registration.reclaim();
      assert.ok(
        reclaimed.inventoryClaimCount >= 1,
        'webapp runtime reclaim re-issues the app-surface registry claim after a SYSTEM restart',
      );

      const reclaimedAppEntries = await RequestReply.execute(
        runtime.getRootContext(),
        'system.registry',
        'registry.query',
        { namespaceRoot: 'SPACE-RUNNER', kind: 'app', openable: true },
        { timeoutMs: 5_000 },
      ) as { entries?: Array<{ mount?: string; metadata?: { source?: string } }> };
      assert.deepEqual(reclaimedAppEntries.entries?.map((entry) => entry.mount), ['director']);
      assert.equal(reclaimedAppEntries.entries?.[0]?.metadata?.source, 'runner-webapp-surface');
    } finally {
      await runtime.shutdown();
    }
  });

  it('projects Host identity into Service Registry placement', async () => {
    const home = mkdtempSync(join(tmpdir(), 'runner-host-placement-'));
    mkdirSync(join(home, 'credentials'), { recursive: true });
    writeFileSync(join(home, 'credentials', 'hivecast-install.json'), JSON.stringify({
      version: 1,
      installId: 'install_test000000000003',
      hostName: 'Test Device',
    }));
    writeFileSync(join(home, 'credentials', 'hivecast-link.json'), JSON.stringify({
      version: 1,
      hostId: 'install_test000000000003',
      hostName: 'Test Device',
      deviceSlug: 'test-device',
    }));
    const runtime = new MatrixRuntime({
      transport: new InMemoryTransport(new InMemoryBroker(), {
        name: 'runner-host-placement-test',
        root: 'SPACE-RUNNER',
      }),
      logging: false,
    });
    runtime.registerService('matrix-host-home', home);
    const observed: Array<{
      runtimeId: string;
      metadata?: Record<string, unknown>;
    }> = [];
    const unsubscribe = subscribeRuntimePresence(
      runtime.getRootContext(),
      'SPACE-RUNNER',
      (record) => {
        observed.push({
          runtimeId: record.runtimeId,
          ...(record.metadata ? { metadata: record.metadata } : {}),
        });
      },
    );

    try {
      await registerRunnerRuntime(
        runtime,
        runtimePresenceManifest,
        undefined,
        undefined,
        'runtime-presence-test',
        undefined,
        undefined,
        {
          appName: 'director',
          routePrefix: '/apps/director/',
          assetMount: 'system.runtimes.runtime-presence-runner.http',
        },
      );

      const appEntries = await RequestReply.execute(
        runtime.getRootContext(),
        'system.registry',
        'registry.query',
        { namespaceRoot: 'SPACE-RUNNER', kind: 'app', openable: true },
        { timeoutMs: 5_000 },
      ) as {
        entries?: Array<{
          placement?: { deviceId?: string; hostId?: string };
          metadata?: { deviceId?: string; hostId?: string; hostName?: string; deviceSlug?: string };
        }>;
      };

      // Slice 1b: real registry app claim still carries Host identity.
      assert.equal(appEntries.entries?.[0]?.placement?.deviceId, 'install_test000000000003');
      assert.equal(appEntries.entries?.[0]?.placement?.hostId, 'install_test000000000003');
      assert.equal(appEntries.entries?.[0]?.metadata?.hostName, 'Test Device');
      assert.equal(appEntries.entries?.[0]?.metadata?.deviceSlug, 'test-device');
      // Runtime identity in this test is now asserted via presence (the
      // runtime directory authority), not via a registry kind=runtime claim.
      assert.equal(observed[0]?.metadata?.deviceId, 'install_test000000000003');
      assert.equal(observed[0]?.metadata?.hostName, 'Test Device');
    } finally {
      unsubscribe();
      await runtime.shutdown();
      rmSync(home, { recursive: true, force: true });
    }
  });

  it('does not require Host placement before a fresh local install has identity files', async () => {
    const home = mkdtempSync(join(tmpdir(), 'runner-host-placement-empty-'));
    mkdirSync(join(home, 'credentials'), { recursive: true });
    const runtime = new MatrixRuntime({
      transport: new InMemoryTransport(new InMemoryBroker(), {
        name: 'runner-host-placement-empty-test',
        root: 'SPACE-RUNNER',
      }),
      logging: false,
    });
    runtime.registerService('matrix-host-home', home);

    try {
      await registerRunnerRuntime(
        runtime,
        runtimePresenceManifest,
        undefined,
        undefined,
        'runtime-presence-test',
        undefined,
        undefined,
        {
          appName: 'director',
          routePrefix: '/apps/director/',
          assetMount: 'system.runtimes.runtime-presence-runner.http',
        },
      );

      const appEntries = await RequestReply.execute(
        runtime.getRootContext(),
        'system.registry',
        'registry.query',
        { namespaceRoot: 'SPACE-RUNNER', kind: 'app', openable: true },
        { timeoutMs: 5_000 },
      ) as {
        entries?: Array<{
          placement?: { deviceId?: string; hostId?: string };
          metadata?: { deviceId?: string; hostId?: string };
        }>;
      };

      assert.equal(appEntries.entries?.[0]?.placement?.deviceId, undefined);
      assert.equal(appEntries.entries?.[0]?.placement?.hostId, undefined);
      assert.equal(appEntries.entries?.[0]?.metadata?.deviceId, undefined);
      assert.equal(appEntries.entries?.[0]?.metadata?.hostId, undefined);
    } finally {
      await runtime.shutdown();
      rmSync(home, { recursive: true, force: true });
    }
  });
});
