import { describe, expect, it, vi } from 'vitest'; import { InMemoryInteractionCoordinationPort, type InteractionCoordinationPort, type Handoff, } from '@mosaicstack/coord'; import type { RuntimeProviderRequestContext } from '../agent/runtime-provider-registry.service.js'; import { InteractionCoordinationService, type InteractionCoordinationConfig, type InteractionCoordinationGatewayError, } from './interaction-coordination.service.js'; const context: RuntimeProviderRequestContext = { actorScope: { userId: 'operator-1', tenantId: 'tenant-a' }, channelId: 'cli', correlationId: 'corr-1', }; const config: InteractionCoordinationConfig = { interactionAgentId: 'Nova', orchestrationAgentId: 'Conductor', }; function service( port: InteractionCoordinationPort = new InMemoryInteractionCoordinationPort(), options: { config?: InteractionCoordinationConfig; handoffIdFactory?: () => string; } = {}, ): InteractionCoordinationService { return new InteractionCoordinationService( port, options.config ?? config, options.handoffIdFactory ?? (() => 'handoff-1'), ); } describe('InteractionCoordinationService authority boundary', (): void => { it('derives identity and actor/tenant scope server-side, then round-trips the native adapter', async (): Promise => { const adapter = new InMemoryInteractionCoordinationPort(); const coordination = service(adapter); await expect( coordination.handoff( { idempotencyKey: 'request-1', summary: 'Implement the requested feature' }, context, ), ).resolves.toEqual({ handoffId: 'handoff-1', targetAgentId: 'Conductor', status: 'queued', correlationId: 'corr-1', }); adapter.recordActivity('handoff-1', 'running', 'Orchestrator accepted the request'); adapter.recordResult('handoff-1', 'completed', 'Merged by orchestrator'); const followUpContext = { ...context, correlationId: 'corr-2' }; await expect(coordination.observe('handoff-1', followUpContext)).resolves.toMatchObject({ targetAgentId: 'Conductor', status: 'completed', }); await expect(coordination.result('handoff-1', followUpContext)).resolves.toMatchObject({ targetAgentId: 'Conductor', status: 'completed', summary: 'Merged by orchestrator', }); }); it('fails closed without calling a port when the interaction requester is unconfigured', async (): Promise => { const adapter = new InMemoryInteractionCoordinationPort(); const handoff = vi.spyOn(adapter, 'handoff'); const coordination = service(adapter, { config: { interactionAgentId: '', orchestrationAgentId: 'Conductor' }, }); await expect( coordination.handoff( { idempotencyKey: 'request-1', summary: 'Implement the requested feature' }, context, ), ).rejects.toMatchObject({ code: 'unconfigured_requester', } satisfies Partial); expect(handoff).not.toHaveBeenCalled(); }); it('rejects self-delegation configuration before delivering work', async (): Promise => { const adapter = new InMemoryInteractionCoordinationPort(); const handoff = vi.spyOn(adapter, 'handoff'); const coordination = service(adapter, { config: { interactionAgentId: 'Nova', orchestrationAgentId: 'Nova' }, }); await expect( coordination.handoff( { idempotencyKey: 'request-1', summary: 'Implement the requested feature' }, context, ), ).rejects.toThrow('Interaction and orchestration identities must differ'); expect(handoff).not.toHaveBeenCalled(); }); it('denies cross-tenant observe and result before calling the adapter', async (): Promise => { const adapter = new InMemoryInteractionCoordinationPort(); const observe = vi.spyOn(adapter, 'observe'); const result = vi.spyOn(adapter, 'result'); const coordination = service(adapter); await coordination.handoff( { idempotencyKey: 'request-1', summary: 'Implement the requested feature' }, context, ); const otherTenant = { ...context, actorScope: { ...context.actorScope, tenantId: 'tenant-b' }, }; await expect(coordination.observe('handoff-1', otherTenant)).rejects.toMatchObject({ code: 'cross_tenant_forbidden', } satisfies Partial); await expect(coordination.result('handoff-1', otherTenant)).rejects.toMatchObject({ code: 'cross_tenant_forbidden', } satisfies Partial); expect(observe).not.toHaveBeenCalled(); expect(result).not.toHaveBeenCalled(); }); it('scopes idempotency by actor and joins concurrent retries without duplicate delivery', async (): Promise => { let handoffSequence = 0; let release: (() => void) | undefined; const delivered = new Promise((resolve: () => void): void => { release = resolve; }); const adapter: InteractionCoordinationPort = { handoff: vi.fn(async (handoff: Handoff) => { await delivered; return { handoffId: handoff.handoffId, targetAgentId: handoff.targetAgentId, status: 'queued' as const, correlationId: handoff.scope.correlationId, }; }), observe: vi.fn(), result: vi.fn(), }; const coordination = service(adapter, { handoffIdFactory: (): string => `handoff-${++handoffSequence}`, }); const request = { idempotencyKey: 'request-1', summary: 'Implement the requested feature' }; const first = coordination.handoff(request, context); const retry = coordination.handoff(request, context); expect(adapter.handoff).toHaveBeenCalledTimes(1); release?.(); await expect(Promise.all([first, retry])).resolves.toEqual([ expect.objectContaining({ handoffId: 'handoff-1' }), expect.objectContaining({ handoffId: 'handoff-1' }), ]); await expect( coordination.handoff(request, { ...context, actorScope: { ...context.actorScope, userId: 'operator-2' }, }), ).resolves.toMatchObject({ handoffId: 'handoff-2' }); expect(adapter.handoff).toHaveBeenCalledTimes(2); }); it('rejects idempotency-key payload drift and malformed handoff input before delivery', async (): Promise => { const adapter = new InMemoryInteractionCoordinationPort(); const handoff = vi.spyOn(adapter, 'handoff'); const coordination = service(adapter); await coordination.handoff( { idempotencyKey: 'request-1', summary: 'Implement the requested feature' }, context, ); await expect( coordination.handoff({ idempotencyKey: 'request-1', summary: 'Different work' }, context), ).rejects.toMatchObject({ code: 'handoff_conflict', } satisfies Partial); await expect( coordination.handoff({ idempotencyKey: 'request-2', summary: '' }, context), ).rejects.toMatchObject({ code: 'invalid_request', } satisfies Partial); await expect( coordination.handoff({ idempotencyKey: 'request-3', summary: 'x'.repeat(2_049) }, context), ).rejects.toMatchObject({ code: 'invalid_request', } satisfies Partial); expect(handoff).toHaveBeenCalledTimes(1); }); it('fails closed when the port reports a target that drifts from configuration', async (): Promise => { const adapter: InteractionCoordinationPort = { handoff: vi.fn(async (handoff: Handoff) => ({ handoffId: handoff.handoffId, targetAgentId: 'Unexpected', status: 'accepted' as const, correlationId: handoff.scope.correlationId, })), observe: vi.fn(), result: vi.fn(), }; await expect( service(adapter).handoff( { idempotencyKey: 'request-1', summary: 'Implement the requested feature' }, context, ), ).rejects.toMatchObject({ code: 'target_drift' }); }); });