/** * Retrieval Reflex resolve IPC round-trip tests (#1981, T3/T5). */ import { describe, test, expect, afterEach } from 'bun:test'; import { mkdtempSync, rmSync, existsSync } from 'node:fs'; import { tmpdir } from 'node:os'; import { join } from 'node:path'; import { resolveSocketPath, startResolveIpcServer, resolveViaIpc, IPC_UNAVAILABLE, } from '../../src/core/context/resolve-ipc.ts'; import type { PointerBlock } from '../../src/core/context/retrieval-reflex.ts'; const servers: Array<{ close: () => void }> = []; afterEach(() => { for (const s of servers.splice(0)) { try { s.close(); } catch { /* noop */ } } }); function tmpDir(): string { return mkdtempSync(join(tmpdir(), 'rr-ipc-')); } describe('resolve IPC', () => { test('round-trip: client gets the pointer block the server returns', async () => { const dir = tmpDir(); const sock = resolveSocketPath(dir); const block: PointerBlock = { pointers: [{ display: 'Alice', slug: 'people/alice', source_id: 'default', synopsis: 'x', arm: 'alias', confidence: 0.9 }], text: 'BLOCK', }; const server = await startResolveIpcServer(sock, async (req) => { expect(req.candidates[0].query).toBe('Alice'); return block; }); expect(server).not.toBeNull(); servers.push(server!); const got = await resolveViaIpc(sock, { candidates: [{ display: 'Alice', query: 'Alice' }] }); expect(got).not.toBe(IPC_UNAVAILABLE); expect((got as PointerBlock).text).toBe('BLOCK'); rmSync(dir, { recursive: true, force: true }); }); test('absent socket → IPC_UNAVAILABLE (caller falls through ladder)', async () => { const dir = tmpDir(); const got = await resolveViaIpc(resolveSocketPath(dir), { candidates: [{ display: 'A', query: 'A' }] }); expect(got).toBe(IPC_UNAVAILABLE); rmSync(dir, { recursive: true, force: true }); }); test('server returning null relays as null (resolved, nothing found)', async () => { const dir = tmpDir(); const sock = resolveSocketPath(dir); const server = await startResolveIpcServer(sock, async () => null); servers.push(server!); const got = await resolveViaIpc(sock, { candidates: [{ display: 'A', query: 'A' }] }); expect(got).toBeNull(); rmSync(dir, { recursive: true, force: true }); }); test('stale socket file is cleaned up so a fresh server can bind', async () => { const dir = tmpDir(); const sock = resolveSocketPath(dir); const s1 = await startResolveIpcServer(sock, async () => null); servers.push(s1!); s1!.close(); // bind again at the same path — startResolveIpcServer must unlink the stale file const s2 = await startResolveIpcServer(sock, async () => null); expect(s2).not.toBeNull(); servers.push(s2!); expect(existsSync(sock)).toBe(true); rmSync(dir, { recursive: true, force: true }); }); });