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

(maka) 01/01: fix(desktop): issue live peer routes for shared sessions

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

M4n5ter pushed a commit to branch fix/session-share-peer-route-liveness
in repository https://gitbox.apache.org/repos/asf/maka.git

commit 3c72a81961eb182e7b6fb9134f2bd1fc0febbed2
Author: Wang <m4...@gmail.com>
AuthorDate: Tue Sep 1 15:21:34 2026 +0800

    fix(desktop): issue live peer routes for shared sessions
---
 .../runtime-host-local-remote-access.test.ts       | 94 ++++++++++++++++++++--
 .../__tests__/runtime-host-profile-service.test.ts | 45 ++++++++++-
 apps/desktop/src/main/runtime-host-boot.ts         |  3 +
 apps/desktop/src/main/runtime-host-client.ts       |  5 ++
 .../src/main/runtime-host-local-remote-access.ts   | 30 ++++++-
 .../src/main/runtime-host-profile-service.ts       | 48 ++++++++---
 .../src/__tests__/peer-listener.test.ts            | 28 +++++++
 .../runtime-host/src/__tests__/peer-native.test.ts | 16 +++-
 .../runtime-host/src/__tests__/protocol.test.ts    | 30 +++++++
 packages/runtime-host/src/client/connection.ts     |  8 +-
 packages/runtime-host/src/client/host-profile.ts   | 11 ++-
 packages/runtime-host/src/client/peer-client.ts    |  4 +
 packages/runtime-host/src/peer-mesh/node.ts        | 19 ++++-
 packages/runtime-host/src/peer-mesh/owner.ts       |  4 +
 packages/runtime-host/src/protocol/host-status.ts  | 46 +++++++++++
 packages/runtime-host/src/protocol/index.ts        |  4 +-
 packages/runtime-host/src/protocol/operations.ts   |  1 +
 .../runtime-host/src/server/execution-service.ts   |  3 +
 packages/runtime-host/src/server/host-kernel.ts    | 10 +++
 packages/runtime-host/src/server/listener-set.ts   | 21 +++--
 packages/runtime-host/src/server/peer-listener.ts  |  4 +
 21 files changed, 396 insertions(+), 38 deletions(-)

diff --git a/apps/desktop/src/main/__tests__/runtime-host-local-remote-access.test.ts b/apps/desktop/src/main/__tests__/runtime-host-local-remote-access.test.ts
index 9e502095c6..c6f2e90813 100644
--- a/apps/desktop/src/main/__tests__/runtime-host-local-remote-access.test.ts
+++ b/apps/desktop/src/main/__tests__/runtime-host-local-remote-access.test.ts
@@ -44,17 +44,36 @@ test('enabling remote access hands the same root to one managed service before D
   const handlers = new Map<string, Parameters<Electron.IpcMain['handle']>[1]>();
   let retired = false;
   let resumed = false;
+  const peer = {
+    peerId: '12D3KooWpeer',
+    routeHints: ['/ip4/192.0.2.1/udp/41000/quic-v1'],
+    coordinationRelays: [],
+  };
+  const livePeer = {
+    ...peer,
+    coordinationRelays: ['/dns4/relay.example/udp/443/quic-v1/p2p/12D3KooWrelay'],
+  };
   const manager = {
     async retireOwnedLocalHost() {
       retired = true;
       return { kind: 'retired' as const, resume: () => { resumed = true; } };
     },
+    async waitUntilReady(profileId: string) {
+      assert.equal(profileId, 'local');
+    },
+    current(profileId: string) {
+      assert.equal(profileId, 'local');
+      return {
+        candidate: {
+          client: {
+            async status() {
+              return { peerEndpoint: livePeer };
+            },
+          },
+        },
+      };
+    },
   } as unknown as RuntimeHostDesktopManager;
-  const peer = {
-    peerId: '12D3KooWpeer',
-    routeHints: ['/ip4/192.0.2.1/udp/41000/quic-v1'],
-    coordinationRelays: [],
-  };
   const deploymentId = '11111111-1111-4111-8111-111111111111';
   const operator = {
     async runSetup(input: {
@@ -123,7 +142,7 @@ test('enabling remote access hands the same root to one managed service before D
   assert.deepEqual(decodeRuntimeHostOwnerConnectionCode(result.connectionCode), {
     name: decodeRuntimeHostOwnerConnectionCode(result.connectionCode).name,
     rootId: 'a'.repeat(64),
-    transport: { kind: 'libp2p-direct', ...peer },
+    transport: { kind: 'libp2p-direct', ...livePeer },
     credential: 'pending-credential',
   });
   const lifecycle = JSON.parse(
@@ -134,6 +153,69 @@ test('enabling remote access hands the same root to one managed service before D
   assert.equal(lifecycle.deploymentId, deploymentId);
 });
 
+test('shares the running Local Host endpoint instead of its persisted startup routes', async (t) => {
+  const base = await mkdtemp(join(tmpdir(), 'maka-local-live-peer-share-'));
+  t.after(() => rm(base, { recursive: true, force: true }));
+  const clientDataRoot = join(base, 'client');
+  const rootPath = join(clientDataRoot, 'workspaces', 'default');
+  const rootId = 'a'.repeat(64);
+  await mkdir(rootPath, { recursive: true });
+  await writeManagedLifecycle(clientDataRoot, rootPath, rootId);
+  const configuredPeer = {
+    peerId: '12D3KooWpeer',
+    routeHints: ['/ip4/192.0.2.1/udp/41000/quic-v1'],
+    coordinationRelays: [],
+  };
+  const livePeer = {
+    ...configuredPeer,
+    coordinationRelays: ['/dns4/relay.example/udp/443/quic-v1/p2p/12D3KooWrelay'],
+  };
+  const service = createDesktopLocalRuntimeHostRemoteAccess({
+    ipcMain: { handle() {}, removeHandler() {} },
+    clientDataRoot,
+    rootPath,
+    rootId,
+    directPeerAvailable: true,
+    manager: () =>
+      ({
+        current() {
+          return {
+            candidate: {
+              client: {
+                async status() {
+                  return { peerEndpoint: livePeer };
+                },
+              },
+            },
+          };
+        },
+      }) as unknown as RuntimeHostDesktopManager,
+    resolveSetupPackage: async () => ({ kind: 'npm', specifier: 'maka-agent@0.2.0' }),
+    operator: {
+      async runPeer() {
+        return {
+          kind: 'result' as const,
+          action: 'status' as const,
+          status: {
+            state: 'enabled' as const,
+            serviceState: 'running',
+            rootId,
+            ...configuredPeer,
+          },
+        };
+      },
+      async close() {},
+    } as unknown as ReturnType<typeof createDesktopRuntimeHostLocalOperator>,
+  });
+  t.after(() => service.close());
+
+  const target = await service.createCollaborationConnectionTarget();
+  assert.deepEqual(target, {
+    name: target.name,
+    transport: { kind: 'libp2p-direct', ...livePeer },
+  });
+});
+
 test('revokes the one Local sharing authority without changing peer connectivity', async (t) => {
   const base = await mkdtemp(join(tmpdir(), 'maka-local-shared-access-revoke-'));
   t.after(() => rm(base, { recursive: true, force: true }));
diff --git a/apps/desktop/src/main/__tests__/runtime-host-profile-service.test.ts b/apps/desktop/src/main/__tests__/runtime-host-profile-service.test.ts
index d99b90a262..12a9886d42 100644
--- a/apps/desktop/src/main/__tests__/runtime-host-profile-service.test.ts
+++ b/apps/desktop/src/main/__tests__/runtime-host-profile-service.test.ts
@@ -716,12 +716,27 @@ test("keeps a managed Direct route on the SSH profile credential authority", asy
   await managedServices.save(MANAGED_PROFILE, MANAGED_SERVICE);
   const startup = await resolveDesktopRuntimeHostStartup(root, { catalog });
   const activated: ResolvedRuntimeHostProfile[] = [];
+  const livePeer = {
+    peerId: "12D3KooWpeer",
+    routeHints: ["/ip4/192.0.2.9/udp/44002/quic-v1"],
+    coordinationRelays: ["/dns4/relay.example/udp/443/quic-v1/p2p/12D3KooWrelay"],
+  };
+  let exposeReadyState = false;
   const service = createDesktopRuntimeHostProfileService({
     clientDataRoot: root,
     startup,
     catalog,
     managedServices,
-    states: () => [connectingLocal()],
+    states: () =>
+      exposeReadyState
+        ? [
+            connectingLocal(),
+            readyWithPeerEndpoint(
+              { profile: MANAGED_PROFILE, credential: "owner-token" },
+              livePeer,
+            ),
+          ]
+        : [connectingLocal()],
     enable: async (target) => {
       activated.push(target);
     },
@@ -755,10 +770,15 @@ test("keeps a managed Direct route on the SSH profile credential authority", asy
     routeHints: ["/ip4/192.0.2.8/udp/44001/quic-v1"],
     coordinationRelays: [],
   });
+  exposeReadyState = true;
   assert.deepEqual(
     await service.resolveCollaborationConnectionTarget(MANAGED_PROFILE),
-    { name: MANAGED_PROFILE.name, transport: direct.profile.transport },
+    {
+      name: MANAGED_PROFILE.name,
+      transport: { kind: "libp2p-direct", ...livePeer },
+    },
   );
+  exposeReadyState = false;
   assert.equal((await catalog.resolve(MANAGED_PROFILE.id)).credential, "owner-token");
 
   const beforeRejectedRemoval = {
@@ -1602,6 +1622,27 @@ function ready(target: ResolvedRuntimeHostProfile): RuntimeHostDesktopTargetStat
   };
 }
 
+function readyWithPeerEndpoint(
+  target: ResolvedRuntimeHostProfile,
+  peerEndpoint: {
+    readonly peerId: string;
+    readonly routeHints: readonly string[];
+    readonly coordinationRelays: readonly string[];
+  },
+): RuntimeHostDesktopTargetState {
+  return {
+    epoch: `epoch-${target.profile.id}`,
+    target,
+    readiness: "ready",
+    candidate: {
+      client: {
+        hostId: target.profile.kind === "remote" ? target.profile.rootId : ROOT_ID,
+        status: async () => ({ peerEndpoint }),
+      },
+    } as never,
+  };
+}
+
 function unavailable(
   target: ResolvedRuntimeHostProfile,
   error: Error,
diff --git a/apps/desktop/src/main/runtime-host-boot.ts b/apps/desktop/src/main/runtime-host-boot.ts
index 21d1726c53..9f66062ae3 100644
--- a/apps/desktop/src/main/runtime-host-boot.ts
+++ b/apps/desktop/src/main/runtime-host-boot.ts
@@ -268,6 +268,9 @@ if (runtimeHostPeerConfiguration) {
       ...runtimeHostPeerConfiguration,
       dataRoot: join(userDataDir, 'peer-mesh'),
       endpointKind: 'client',
+      onBackgroundReconcileError: (error) => {
+        console.error('[runtime-host] Peer Mesh background synchronization failed:', error);
+      },
     });
     runtimeHostPeerClient = runtimeHostPeerOwner.client;
     runtimeHostPeerMesh = runtimeHostPeerOwner.mesh;
diff --git a/apps/desktop/src/main/runtime-host-client.ts b/apps/desktop/src/main/runtime-host-client.ts
index 10a68c65e0..035043e23d 100644
--- a/apps/desktop/src/main/runtime-host-client.ts
+++ b/apps/desktop/src/main/runtime-host-client.ts
@@ -84,6 +84,7 @@ import {
   type MemoryQueryInput,
   type MemoryQueryResult,
   type GoalControlAction,
+  type HostStatusResult,
   type GoalProjection,
   type OperationInput,
   type OperationOutput,
@@ -295,6 +296,10 @@ export class DesktopRuntimeHostClient {
     return this.#connectionClosed || this.#closeTask ? 'unavailable' : 'ready';
   }
 
+  status(): Promise<HostStatusResult> {
+    return this.connection.status();
+  }
+
   finalizeAccessCredential(
     timeoutMs?: number,
   ): Promise<OperationOutput<'access.credential.finalize'>> {
diff --git a/apps/desktop/src/main/runtime-host-local-remote-access.ts b/apps/desktop/src/main/runtime-host-local-remote-access.ts
index 4ade5c5610..3623734975 100644
--- a/apps/desktop/src/main/runtime-host-local-remote-access.ts
+++ b/apps/desktop/src/main/runtime-host-local-remote-access.ts
@@ -339,11 +339,14 @@ export function createDesktopLocalRuntimeHostRemoteAccess(input: {
       };
       const completed = await finishSetup(setup, 'request');
       if (completed.kind === 'active_tasks') return completed;
+      const manager = requireManager(input.manager);
+      await manager.waitUntilReady('local');
+      const livePeer = await readLivePeer(localClient(input.manager), completed.peer);
       return enabledResult(
         encodeRuntimeHostOwnerConnectionCode({
           name: hostName(),
           rootId: completed.managed.rootId,
-          transport: { kind: 'libp2p-direct', ...completed.peer },
+          transport: { kind: 'libp2p-direct', ...livePeer },
           credential: completed.credential,
         }),
       );
@@ -515,9 +518,10 @@ export function createDesktopLocalRuntimeHostRemoteAccess(input: {
       );
       const peer = await readPeer(input.operator, managed);
       if (!peer) throw new Error('Remote access is not enabled on this computer');
+      const livePeer = await readLivePeer(localClient(input.manager), peer);
       return {
         name: hostName(),
-        transport: { kind: 'libp2p-direct' as const, ...peer },
+        transport: { kind: 'libp2p-direct' as const, ...livePeer },
       };
     });
 
@@ -968,6 +972,7 @@ async function issueConnectionCode(
   peer: LocalPeerDescriptor,
   client: DesktopRuntimeHostClient,
 ): Promise<string> {
+  const livePeer = await readLivePeer(client, peer);
   const prepared = await client.request('access.credential.prepare', {
     principalKind: 'remote_owner',
     principalId: LOCAL_REMOTE_ACCESS_PRINCIPAL_ID,
@@ -984,11 +989,30 @@ async function issueConnectionCode(
   return encodeRuntimeHostOwnerConnectionCode({
     name: hostName(),
     rootId,
-    transport: { kind: 'libp2p-direct', ...peer },
+    transport: { kind: 'libp2p-direct', ...livePeer },
     credential,
   });
 }
 
+async function readLivePeer(
+  client: DesktopRuntimeHostClient,
+  configured: LocalPeerDescriptor,
+): Promise<LocalPeerDescriptor> {
+  const endpoint = (await client.status()).peerEndpoint;
+  if (!endpoint) {
+    throw new Error('Runtime Host Direct peer is not available');
+  }
+  if (endpoint.peerId !== configured.peerId) {
+    throw new Error('Runtime Host Direct peer identity changed');
+  }
+  return requireEnabledPeer({
+    state: 'enabled',
+    peerId: endpoint.peerId,
+    routeHints: endpoint.routeHints,
+    coordinationRelays: endpoint.coordinationRelays,
+  });
+}
+
 async function hasSharedAccess(
   operator: DesktopRuntimeHostLocalOperator,
   target: LocalServiceTarget,
diff --git a/apps/desktop/src/main/runtime-host-profile-service.ts b/apps/desktop/src/main/runtime-host-profile-service.ts
index 33bb1380f7..a310141439 100644
--- a/apps/desktop/src/main/runtime-host-profile-service.ts
+++ b/apps/desktop/src/main/runtime-host-profile-service.ts
@@ -920,23 +920,49 @@ export function createDesktopRuntimeHostProfileService(input: {
         if (profile.kind !== 'remote') {
           throw new Error('This Runtime Host does not expose a shareable peer endpoint');
         }
-        if (profile.transport.kind !== 'ssh') {
+        if (profile.transport.kind !== 'ssh' && profile.transport.kind !== 'libp2p-direct') {
           return { name: profile.name, transport: profile.transport };
         }
-        const direct = (await catalog.read()).profiles.find(
-          (candidate) => candidate.id === managedDirectPeerProfileId(profile.id),
-        );
-        if (
-          !direct ||
-          direct.kind !== 'remote' ||
-          direct.rootId !== profile.rootId ||
-          direct.transport.kind !== 'libp2p-direct'
-        ) {
+        let configuredPeerId: string | undefined;
+        if (profile.transport.kind === 'libp2p-direct') {
+          configuredPeerId = profile.transport.peerId;
+        } else {
+          const direct = (await catalog.read()).profiles.find(
+            (candidate) => candidate.id === managedDirectPeerProfileId(profile.id),
+          );
+          if (
+            direct?.kind === 'remote' &&
+            direct.rootId === profile.rootId &&
+            direct.transport.kind === 'libp2p-direct'
+          ) {
+            configuredPeerId = direct.transport.peerId;
+          }
+        }
+        if (!configuredPeerId) {
           throw new Error(
             'Enable Direct peer access for this Runtime Host before sharing its Sessions',
           );
         }
-        return { name: profile.name, transport: direct.transport };
+        const active = input.states().find((state) => state.target.profile.id === profile.id);
+        if (!active || active.readiness !== 'ready') {
+          throw new Error('Connect this Runtime Host before sharing its Sessions');
+        }
+        const endpoint = (await active.candidate.client.status()).peerEndpoint;
+        if (!endpoint) {
+          throw new Error('Runtime Host Direct peer is not available');
+        }
+        if (configuredPeerId !== endpoint.peerId) {
+          throw new Error('Runtime Host Direct peer identity changed');
+        }
+        return {
+          name: profile.name,
+          transport: {
+            kind: 'libp2p-direct' as const,
+            peerId: endpoint.peerId,
+            routeHints: endpoint.routeHints,
+            coordinationRelays: endpoint.coordinationRelays,
+          },
+        };
       });
     },
     resolveManagedAccess(profileId) {
diff --git a/packages/runtime-host/src/__tests__/peer-listener.test.ts b/packages/runtime-host/src/__tests__/peer-listener.test.ts
index 2a5d900895..e6ec103e18 100644
--- a/packages/runtime-host/src/__tests__/peer-listener.test.ts
+++ b/packages/runtime-host/src/__tests__/peer-listener.test.ts
@@ -21,6 +21,7 @@ import assert from 'node:assert/strict';
 import { setImmediate as waitForImmediate } from 'node:timers/promises';
 import { test } from 'node:test';
 import { createRuntimeHostPeerListener } from '../server/peer-listener.js';
+import { createRuntimeHostListenerSet } from '../server/listener-set.js';
 import type { RuntimeHostPeerClient } from '../client/peer-client.js';
 import type { RuntimeHostPeerNativeStream } from '../transport/peer-native.js';
 
@@ -122,6 +123,33 @@ test('bounds active application streams from one authenticated peer', async () =
   await listener.cleanup();
 });
 
+test('projects newly accepted coordination relays from the running peer endpoint', async () => {
+  let coordinationRelays: readonly string[] = [];
+  const peer = {
+    ...peerWith([]),
+    identity: () => ({
+      peerId: 'peer',
+      listenAddresses: ['/ip4/192.0.2.1/udp/41000/quic-v1'],
+      coordinationRelays,
+    }),
+  };
+  const listener = createRuntimeHostPeerListener(peer, {} as never, () => {});
+  const listeners = createRuntimeHostListenerSet(
+    {
+      kind: 'local_ipc',
+      endpoint: 'local',
+      closeAdmission: async () => undefined,
+      cleanup: async () => undefined,
+    },
+    [listener],
+  );
+
+  assert.deepEqual(listeners.peerListeners[0]?.coordinationRelays, []);
+  coordinationRelays = ['/dns4/relay.example/udp/443/quic-v1/p2p/12D3KooWrelay'];
+  assert.deepEqual(listeners.peerListeners[0]?.coordinationRelays, coordinationRelays);
+  await listeners.cleanup();
+});
+
 function peerWith(streams: RuntimeHostPeerNativeStream[]): RuntimeHostPeerClient {
   return {
     identity: () => ({ peerId: 'peer', listenAddresses: [], coordinationRelays: [] }),
diff --git a/packages/runtime-host/src/__tests__/peer-native.test.ts b/packages/runtime-host/src/__tests__/peer-native.test.ts
index fc12167100..ce5627cf97 100644
--- a/packages/runtime-host/src/__tests__/peer-native.test.ts
+++ b/packages/runtime-host/src/__tests__/peer-native.test.ts
@@ -72,7 +72,7 @@ module.exports = {
       connect: ({ requestId, peerId, routeHints, coordinationRelays, transitRelayPeerIds }) => {
         stats.requests.push({ requestId, peerId, routeHints, coordinationRelays, transitRelayPeerIds });
         if (peerId === 'unreachable') return Promise.reject(Object.assign(new Error('transit_unavailable: no approved route'), { code: 'GenericFailure' }));
-        if (peerId === 'ready' || peerId === 'fallback') return Promise.resolve(stream);
+        if (peerId === 'ready' || peerId === 'fallback' || peerId === 'self-contained') return Promise.resolve(stream);
         return new Promise((resolve, reject) => pending.set(requestId, { resolve, reject }));
       },
       connectMeshControl: ({ requestId, peerId, routeHints, coordinationRelays, transitRelayPeerIds }) => {
@@ -100,11 +100,13 @@ module.exports = {
 `,
     );
     let routesPrepared = false;
+    const preparedPeerIds: string[] = [];
     const client = createRuntimeHostPeerClient({
       nativePath,
       keyPath: join(directory, 'peer.key'),
       routeResolver: {
         prepareRoutes: async (peerId) => {
+          preparedPeerIds.push(peerId);
           routesPrepared = true;
           if (peerId === 'fallback') throw new Error('Mesh refresh failed');
         },
@@ -151,6 +153,11 @@ module.exports = {
     await assert.rejects(client.connect(peerConnectInput('unreachable')), (failure: unknown) => {
       return failure instanceof RuntimeHostPeerError && failure.code === 'transit_unavailable';
     });
+    await client.connect({
+      ...peerConnectInput('self-contained'),
+      coordinationRelays: ['/memory/explicit-relay'],
+    });
+    assert.equal(preparedPeerIds.includes('self-contained'), false);
     assert.deepEqual(native.default.stats, {
       starts: 1,
       closes: 0,
@@ -197,6 +204,13 @@ module.exports = {
           coordinationRelays: ['/memory/relay'],
           transitRelayPeerIds: ['transit-peer'],
         },
+        {
+          requestId: 7,
+          peerId: 'self-contained',
+          routeHints: ['/memory/discovered', '/memory/1'],
+          coordinationRelays: ['/memory/relay', '/memory/explicit-relay'],
+          transitRelayPeerIds: ['transit-peer'],
+        },
       ],
       cancellations: [1, 1],
     });
diff --git a/packages/runtime-host/src/__tests__/protocol.test.ts b/packages/runtime-host/src/__tests__/protocol.test.ts
index db9f2d70f6..3bbe698872 100644
--- a/packages/runtime-host/src/__tests__/protocol.test.ts
+++ b/packages/runtime-host/src/__tests__/protocol.test.ts
@@ -1924,6 +1924,36 @@ describe('Runtime Host bootstrap protocol', () => {
     );
   });
 
+  test('publishes a bounded live Direct peer endpoint through Host status', () => {
+    const status = {
+      hostEpoch: 'epoch-1',
+      compositionId: 'maka.interactive',
+      compositionRevision: '1',
+      state: 'ready',
+      connections: 1,
+      activeOperations: 0,
+      activeResidencies: 0,
+      peerEndpoint: {
+        peerId: '12D3KooWhost',
+        routeHints: ['/ip4/192.0.2.1/udp/41000/quic-v1'],
+        coordinationRelays: ['/dns4/relay.example/udp/443/quic-v1/p2p/12D3KooWrelay'],
+      },
+    };
+    assert.deepEqual(HOST_BOOTSTRAP_OPERATION_SPECS['host.status'].decodeOutput(status), status);
+    assert.throws(() =>
+      HOST_BOOTSTRAP_OPERATION_SPECS['host.status'].decodeOutput({
+        ...status,
+        peerEndpoint: {
+          ...status.peerEndpoint,
+          coordinationRelays: [
+            status.peerEndpoint.coordinationRelays[0],
+            status.peerEndpoint.coordinationRelays[0],
+          ],
+        },
+      }),
+    );
+  });
+
   test('keeps Runtime Host logs within the diagnostics operation contract', () => {
     for (let index = 0; index < 257; index += 1) {
       runtimeHostLogBuffer.append('info', `entry ${index}`);
diff --git a/packages/runtime-host/src/client/connection.ts b/packages/runtime-host/src/client/connection.ts
index 109cb47b99..4ec10ddae1 100644
--- a/packages/runtime-host/src/client/connection.ts
+++ b/packages/runtime-host/src/client/connection.ts
@@ -196,6 +196,7 @@ export type ConnectRemoteRuntimeHostResult =
         | 'unreachable'
         | 'connect_failed'
         | 'handshake_failed'
+        | 'handshake_timed_out'
         | 'root_mismatch'
         | 'composition_mismatch';
     };
@@ -1035,11 +1036,13 @@ export async function connectRuntimeHostMessageTransport(
 ): Promise<ConnectRemoteRuntimeHostResult> {
   let resourceTransferred = false;
   let timer: ReturnType<typeof setTimeout> | undefined;
+  let handshakeTimedOut = false;
   try {
     const normalized = normalizeConnectRuntimeHostInput(input);
     const compositionId = requireHostCompositionId(input.compositionId);
     const expectedRootId = requireHostRootId(input.expectedRootId);
     timer = setTimeout(() => {
+      handshakeTimedOut = true;
       input.transport.abort(new Error('Timed out handshaking with Runtime Host'));
     }, normalized.handshakeTimeoutMs);
     const result = await exchangeRuntimeHostHandshake({
@@ -1067,7 +1070,10 @@ export async function connectRuntimeHostMessageTransport(
     if (error instanceof RuntimeHostCompositionMismatchError) {
       return { kind: 'unavailable', reason: 'composition_mismatch' };
     }
-    return { kind: 'unavailable', reason: 'handshake_failed' };
+    return {
+      kind: 'unavailable',
+      reason: handshakeTimedOut ? 'handshake_timed_out' : 'handshake_failed',
+    };
   } finally {
     if (timer) clearTimeout(timer);
     if (!resourceTransferred) await input.connectionResource?.close().catch(() => undefined);
diff --git a/packages/runtime-host/src/client/host-profile.ts b/packages/runtime-host/src/client/host-profile.ts
index ea0a72ac9c..feab8c1fd6 100644
--- a/packages/runtime-host/src/client/host-profile.ts
+++ b/packages/runtime-host/src/client/host-profile.ts
@@ -71,6 +71,7 @@ const PROFILE_ID_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$/;
 const PEER_ID_MAX_BYTES = 160;
 const PEER_ADDRESS_MAX_BYTES = 2 * 1024;
 const PEER_ROUTE_MAX = 16;
+const DEFAULT_PEER_HANDSHAKE_TIMEOUT_MS = 5_000;
 const PROFILE_CREDENTIAL_RECORD_PREFIX = 'maka-runtime-host-profile-credential-v1:';
 const PROFILE_INCARNATION_ID_MAX_BYTES = 128;
 export const RUNTIME_HOST_ACCESS_CREDENTIAL_MAX_BYTES = 8 * 1024;
@@ -588,6 +589,7 @@ export async function connectPeerRuntimeHost(input: {
   readonly onConnectionPhase?: (phase: RuntimeHostConnectionPhase) => void;
 }): Promise<RuntimeHostConnection> {
   input.signal?.throwIfAborted();
+  const handshakeTimeoutMs = input.handshakeTimeoutMs ?? DEFAULT_PEER_HANDSHAKE_TIMEOUT_MS;
   const stream = await input.peerClient.connect(
     {
       peerId: input.transport.peerId,
@@ -608,7 +610,7 @@ export async function connectPeerRuntimeHost(input: {
     await writeRuntimeHostPeerAuthentication(stream, input.credential);
     const authentication = await readRuntimeHostPeerAuthenticationResult(
       stream,
-      input.handshakeTimeoutMs,
+      handshakeTimeoutMs,
     );
     if (!authentication.accepted) {
       throw new RuntimeHostProfileConnectionError(
@@ -628,9 +630,7 @@ export async function connectPeerRuntimeHost(input: {
         max: RUNTIME_HOST_PROTOCOL_VERSION,
       },
       clientInstanceId: input.clientInstanceId,
-      ...(input.handshakeTimeoutMs === undefined
-        ? {}
-        : { handshakeTimeoutMs: input.handshakeTimeoutMs }),
+      handshakeTimeoutMs,
       ...(stream.path ? { peerPath: stream.path } : {}),
     });
     input.signal?.throwIfAborted();
@@ -700,6 +700,9 @@ export function remoteRuntimeHostUnavailableError(
     case 'unreachable':
       message = `${subject} could not reach its endpoint`;
       break;
+    case 'handshake_timed_out':
+      message = `${subject} timed out while establishing its protocol session`;
+      break;
     default:
       message = `${subject} is unavailable (${reason})`;
   }
diff --git a/packages/runtime-host/src/client/peer-client.ts b/packages/runtime-host/src/client/peer-client.ts
index 543efdb2f0..e8f639141f 100644
--- a/packages/runtime-host/src/client/peer-client.ts
+++ b/packages/runtime-host/src/client/peer-client.ts
@@ -226,6 +226,10 @@ class RuntimeHostPeerClientImpl implements RuntimeHostPeerClient {
     signal: AbortSignal | undefined,
   ): Promise<void> {
     if (!this.#routeResolver?.prepareRoutes) return;
+    // A freshly issued target with both direct hints and coordination relays is
+    // already self-contained. Cached Mesh state can still enrich the actual
+    // dial below, but a stale control plane must not delay this explicit path.
+    if (input.routeHints.length > 0 && (input.coordinationRelays?.length ?? 0) > 0) return;
     const deadline = AbortSignal.timeout(Math.min(10_000, input.directDeadlineMs));
     const operationSignal = signal ? AbortSignal.any([signal, deadline]) : deadline;
     try {
diff --git a/packages/runtime-host/src/peer-mesh/node.ts b/packages/runtime-host/src/peer-mesh/node.ts
index d49068723e..2e16e5469c 100644
--- a/packages/runtime-host/src/peer-mesh/node.ts
+++ b/packages/runtime-host/src/peer-mesh/node.ts
@@ -224,6 +224,7 @@ export async function openPeerMeshNode(input: {
   readonly peer: PeerMeshTransport;
   readonly endpointKind?: 'client' | 'host';
   readonly now?: () => number;
+  readonly onBackgroundReconcileError?: (error: unknown) => void;
 }): Promise<PeerMeshNode> {
   const store = await openPeerMeshStateStore(input.dataRoot, input.peer.identity().peerId);
   const node = new PeerMeshNodeImpl({ ...input, store });
@@ -241,6 +242,7 @@ class PeerMeshNodeImpl implements PeerMeshNode {
   readonly #peer: PeerMeshTransport;
   readonly #endpointKind: 'client' | 'host' | undefined;
   readonly #now: () => number;
+  readonly #onBackgroundReconcileError: ((error: unknown) => void) | undefined;
   readonly #activeControlStreams = new Set<RuntimeHostPeerNativeStream>();
   readonly #lifetime = new AbortController();
   #admissionTail = Promise.resolve();
@@ -256,11 +258,13 @@ class PeerMeshNodeImpl implements PeerMeshNode {
     readonly peer: PeerMeshTransport;
     readonly endpointKind?: 'client' | 'host';
     readonly now?: () => number;
+    readonly onBackgroundReconcileError?: (error: unknown) => void;
   }) {
     this.#store = input.store;
     this.#peer = input.peer;
     this.#endpointKind = input.endpointKind;
     this.#now = input.now ?? Date.now;
+    this.#onBackgroundReconcileError = input.onBackgroundReconcileError;
   }
 
   async initialize(): Promise<void> {
@@ -910,8 +914,21 @@ class PeerMeshNodeImpl implements PeerMeshNode {
   }
 
   async #runReconciliation(signal: AbortSignal): Promise<void> {
+    let failureReported = false;
     while (!signal.aborted) {
-      await this.reconcile(signal).catch(() => undefined);
+      try {
+        await this.reconcile(signal);
+        failureReported = false;
+      } catch (error) {
+        if (!signal.aborted && !failureReported) {
+          failureReported = true;
+          try {
+            this.#onBackgroundReconcileError?.(error);
+          } catch {
+            // Diagnostics cannot control Peer Mesh reconciliation.
+          }
+        }
+      }
       await delay(RECONCILE_INTERVAL_MS, undefined, { signal }).catch(() => undefined);
     }
   }
diff --git a/packages/runtime-host/src/peer-mesh/owner.ts b/packages/runtime-host/src/peer-mesh/owner.ts
index 5bde0a8d10..035ab2a46b 100644
--- a/packages/runtime-host/src/peer-mesh/owner.ts
+++ b/packages/runtime-host/src/peer-mesh/owner.ts
@@ -44,6 +44,7 @@ export async function openRuntimeHostPeerMeshOwner(input: {
   readonly coordinationRelays?: readonly string[];
   readonly automaticRelayDiscovery?: boolean;
   readonly webRtcStunUrls?: readonly string[];
+  readonly onBackgroundReconcileError?: (error: unknown) => void;
 }): Promise<RuntimeHostPeerMeshOwner> {
   let mesh: PeerMeshNode | undefined;
   let resolverMesh: PeerMeshNode | undefined;
@@ -77,6 +78,9 @@ export async function openRuntimeHostPeerMeshOwner(input: {
       dataRoot: join(input.dataRoot, client.identity().peerId),
       peer: client,
       endpointKind: input.endpointKind,
+      ...(input.onBackgroundReconcileError
+        ? { onBackgroundReconcileError: input.onBackgroundReconcileError }
+        : {}),
     });
     resolverMesh = mesh;
   } catch (error) {
diff --git a/packages/runtime-host/src/protocol/host-status.ts b/packages/runtime-host/src/protocol/host-status.ts
index 4aac3a9603..a28ef97438 100644
--- a/packages/runtime-host/src/protocol/host-status.ts
+++ b/packages/runtime-host/src/protocol/host-status.ts
@@ -51,6 +51,9 @@ export type HostUpgradePrepareResult =
 export const HOST_DIAGNOSTICS_RESULT_MAX_BYTES = 72 * 1024;
 export const HOST_DIAGNOSTIC_LOG_MAX_ENTRIES = 256;
 export const HOST_DIAGNOSTIC_LOG_MAX_ENTRY_BYTES = 10 * 1024;
+const HOST_PEER_ID_MAX_BYTES = 160;
+const HOST_PEER_ADDRESS_MAX_BYTES = 2 * 1024;
+const HOST_PEER_ROUTE_MAX = 16;
 
 export interface HostStatusResult {
   hostEpoch: string;
@@ -60,6 +63,13 @@ export interface HostStatusResult {
   connections: number;
   activeOperations: number;
   activeResidencies: number;
+  peerEndpoint?: HostPeerEndpoint;
+}
+
+export interface HostPeerEndpoint {
+  readonly peerId: string;
+  readonly routeHints: readonly string[];
+  readonly coordinationRelays: readonly string[];
 }
 
 export interface HostDiagnosticsResult extends HostStatusResult {
@@ -100,12 +110,26 @@ export const HOST_BOOTSTRAP_OPERATION_SPECS = {
   }),
 } as const;
 
+function decodePeerAddresses(value: unknown, label: string): readonly string[] {
+  if (!Array.isArray(value) || value.length > HOST_PEER_ROUTE_MAX) {
+    throw invalidProtocolFrame(`Invalid ${label}`);
+  }
+  const addresses = value.map((address) =>
+    requireString(address, label, HOST_PEER_ADDRESS_MAX_BYTES),
+  );
+  if (new Set(addresses).size !== addresses.length) {
+    throw invalidProtocolFrame(`Duplicate ${label}`);
+  }
+  return Object.freeze(addresses);
+}
+
 function decodeEmptyHostInput(value: unknown, label: string): HostStatusInput {
   requireExactRecord(value, label, []);
   return {};
 }
 
 function decodeHostStatusResult(value: unknown): HostStatusResult {
+  const valueRecord = requireRecord(value, 'host.status result');
   const record = requireExactRecord(value, 'host.status result', [
     'hostEpoch',
     'compositionId',
@@ -114,6 +138,7 @@ function decodeHostStatusResult(value: unknown): HostStatusResult {
     'connections',
     'activeOperations',
     'activeResidencies',
+    ...(valueRecord.peerEndpoint === undefined ? [] : ['peerEndpoint']),
   ]);
   return decodeHostStatusFields(record);
 }
@@ -124,6 +149,7 @@ function decodeHostDiagnosticsResult(value: unknown): HostDiagnosticsResult {
     'host.diagnostics.query result',
     HOST_DIAGNOSTICS_RESULT_MAX_BYTES,
   );
+  const valueRecord = requireRecord(value, 'host.diagnostics.query result');
   const record = requireExactRecord(value, 'host.diagnostics.query result', [
     'hostEpoch',
     'compositionId',
@@ -132,6 +158,7 @@ function decodeHostDiagnosticsResult(value: unknown): HostDiagnosticsResult {
     'connections',
     'activeOperations',
     'activeResidencies',
+    ...(valueRecord.peerEndpoint === undefined ? [] : ['peerEndpoint']),
     'compositionModules',
     'residencies',
     'protocolVersion',
@@ -262,6 +289,25 @@ function decodeHostStatusFields(record: Record<string, unknown>): HostStatusResu
     connections: requireCount(record.connections, 'connections'),
     activeOperations: requireCount(record.activeOperations, 'activeOperations'),
     activeResidencies: requireCount(record.activeResidencies, 'activeResidencies'),
+    ...(record.peerEndpoint === undefined
+      ? {}
+      : { peerEndpoint: decodeHostPeerEndpoint(record.peerEndpoint) }),
+  };
+}
+
+function decodeHostPeerEndpoint(value: unknown): HostPeerEndpoint {
+  const record = requireExactRecord(value, 'Runtime Host peer endpoint', [
+    'peerId',
+    'routeHints',
+    'coordinationRelays',
+  ]);
+  return {
+    peerId: requireString(record.peerId, 'Runtime Host peer id', HOST_PEER_ID_MAX_BYTES),
+    routeHints: decodePeerAddresses(record.routeHints, 'Runtime Host peer route hints'),
+    coordinationRelays: decodePeerAddresses(
+      record.coordinationRelays,
+      'Runtime Host peer coordination relays',
+    ),
   };
 }
 
diff --git a/packages/runtime-host/src/protocol/index.ts b/packages/runtime-host/src/protocol/index.ts
index c85b20e2c4..edddd73fe5 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 = 86 as const;
+export const RUNTIME_HOST_COMPATIBILITY_EPOCH = 87 as const;
+// 87: Host status publishes the live Direct peer endpoint so newly issued
+// connection invitations do not preserve stale startup routes.
 // 86: Client Capability accepted frames carry typed admission evidence used to
 // enforce Session Grant scopes. Older peers cannot preserve that boundary.
 // 85: Plugin package and Entry composition operations become Host-owned protocol
diff --git a/packages/runtime-host/src/protocol/operations.ts b/packages/runtime-host/src/protocol/operations.ts
index 1f6f900805..f87902936e 100644
--- a/packages/runtime-host/src/protocol/operations.ts
+++ b/packages/runtime-host/src/protocol/operations.ts
@@ -71,6 +71,7 @@ export type {
   HostDiagnosticsResult,
   HostActivitySnapshot,
   HostLifecycleState,
+  HostPeerEndpoint,
   HostStatusInput,
   HostStatusResult,
   HostUpgradePrepareInput,
diff --git a/packages/runtime-host/src/server/execution-service.ts b/packages/runtime-host/src/server/execution-service.ts
index 1ae258c3ff..baf69cdbc4 100644
--- a/packages/runtime-host/src/server/execution-service.ts
+++ b/packages/runtime-host/src/server/execution-service.ts
@@ -99,6 +99,9 @@ export async function startExecutionRuntimeHostService(
           ...options.peer,
           dataRoot: options.peer.meshDataRoot,
           endpointKind: 'host',
+          onBackgroundReconcileError: (error) => {
+            console.error('[runtime-host] Peer Mesh background synchronization failed:', error);
+          },
         });
       } catch (error) {
         console.error(
diff --git a/packages/runtime-host/src/server/host-kernel.ts b/packages/runtime-host/src/server/host-kernel.ts
index e86705ce28..491e663212 100644
--- a/packages/runtime-host/src/server/host-kernel.ts
+++ b/packages/runtime-host/src/server/host-kernel.ts
@@ -825,6 +825,7 @@ export class RuntimeHostKernel {
   }
 
   #statusSnapshot(): HostStatusResult {
+    const peer = this.peerListeners[0];
     return {
       hostEpoch: this.hostEpoch,
       compositionId: this.compositionDescriptor.id,
@@ -833,6 +834,15 @@ export class RuntimeHostKernel {
       connections: this.#acceptedTransports.size,
       activeOperations: this.#activeOperations,
       activeResidencies: this.#residencies.activeCount,
+      ...(peer
+        ? {
+            peerEndpoint: {
+              peerId: peer.peerId,
+              routeHints: peer.listenAddresses,
+              coordinationRelays: peer.coordinationRelays,
+            },
+          }
+        : {}),
     };
   }
 
diff --git a/packages/runtime-host/src/server/listener-set.ts b/packages/runtime-host/src/server/listener-set.ts
index c26508e581..cdc48047e5 100644
--- a/packages/runtime-host/src/server/listener-set.ts
+++ b/packages/runtime-host/src/server/listener-set.ts
@@ -46,11 +46,13 @@ export interface RuntimeHostPeerListener extends RuntimeHostListener {
   readonly kind: 'libp2p_direct';
   readonly peerId: string;
   readonly listenAddresses: readonly string[];
+  readonly coordinationRelays: readonly string[];
 }
 
 export interface RuntimeHostPeerListenerDescriptor {
   readonly peerId: string;
   readonly listenAddresses: readonly string[];
+  readonly coordinationRelays: readonly string[];
 }
 
 export type RuntimeHostListenerKind = 'local_ipc' | 'websocket' | 'libp2p_direct';
@@ -135,14 +137,17 @@ export function createRuntimeHostListenerSet(
         .filter((listener) => listener.kind === 'websocket')
         .map((listener) => listener.endpoint),
     ),
-    peerListeners: Object.freeze(
-      additional.filter(isRuntimeHostPeerListener).map((listener) =>
-        Object.freeze({
-          peerId: listener.peerId,
-          listenAddresses: Object.freeze([...listener.listenAddresses]),
-        }),
-      ),
-    ),
+    get peerListeners() {
+      return Object.freeze(
+        additional.filter(isRuntimeHostPeerListener).map((listener) =>
+          Object.freeze({
+            peerId: listener.peerId,
+            listenAddresses: Object.freeze([...listener.listenAddresses]),
+            coordinationRelays: Object.freeze([...listener.coordinationRelays]),
+          }),
+        ),
+      );
+    },
     closeAdmission: () => settleListeners(listeners, (listener) => listener.closeAdmission()),
     cleanup: () => settleListeners([...listeners].reverse(), (listener) => listener.cleanup()),
   };
diff --git a/packages/runtime-host/src/server/peer-listener.ts b/packages/runtime-host/src/server/peer-listener.ts
index 750f40bcce..3907669793 100644
--- a/packages/runtime-host/src/server/peer-listener.ts
+++ b/packages/runtime-host/src/server/peer-listener.ts
@@ -120,6 +120,10 @@ class RuntimeHostPeerListener implements RuntimeHostPeerListenerContract {
       .catch(captureFailure);
   }
 
+  get coordinationRelays(): readonly string[] {
+    return this.#client.identity().coordinationRelays;
+  }
+
   closeAdmission(): Promise<void> {
     this.#closeAdmissionTask ??= (async () => {
       this.#admitting = false;


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