import { describe, expect, it, vi } from 'vitest'; import type { RuntimeScope, RuntimeStreamEvent } from '@mosaicstack/types'; import { type MatrixRuntimeSession, type MatrixRuntimeTransport, MatrixNativeRuntimeProvider, type MatrixReadAuthority, type MatrixWriteAuthority, } from './matrix-native-runtime-provider.js'; const scope: RuntimeScope = { actorId: 'operator-1', tenantId: 'tenant-a', channelId: 'matrix-control', correlationId: 'corr-1', }; const session: MatrixRuntimeSession = { id: 'native-1', runtimeId: '@worker:example.test', state: 'active', createdAt: '2026-07-13T00:00:00.000Z', updatedAt: '2026-07-13T00:00:00.000Z', }; function transport(): MatrixRuntimeTransport { return { health: vi.fn(async () => ({ status: 'healthy' as const, checkedAt: '2026-07-13T00:00:00.000Z', })), listSessions: vi.fn(async () => [session]), verifySession: vi.fn(async (sessionId) => { if (sessionId !== session.id) throw new Error('unexpected session'); return session; }), stream: vi.fn(async function* (): AsyncIterable { yield { type: 'message.delta', sessionId: 'native-1', cursor: 'cursor-1', occurredAt: '2026-07-13T00:00:00.000Z', content: 'hello', }; }), send: vi.fn(async () => undefined), terminate: vi.fn(async () => undefined), }; } function readAuthority(): MatrixReadAuthority { return { canRead: vi.fn(async () => true) }; } function writeAuthority(): MatrixWriteAuthority { return { canWrite: vi.fn(async () => true), assertAuthorized: vi.fn(async () => undefined), }; } describe('MatrixNativeRuntimeProvider contract boundary', (): void => { it('advertises the concrete Matrix operations and returns only normalized sessions', async (): Promise => { const provider = new MatrixNativeRuntimeProvider({ transport: transport(), readAuthority: readAuthority(), }); await expect(provider.capabilities(scope)).resolves.toEqual({ supported: [ 'session.list', 'session.tree', 'session.stream', 'session.send', 'session.attach', 'session.terminate', ], }); await expect(provider.listSessions(scope)).resolves.toEqual([ expect.objectContaining({ id: 'native-1', providerId: 'runtime.matrix' }), ]); }); it('binds read attachments to immutable scope and rejects control mode before transport access', async (): Promise => { const matrix = transport(); const provider = new MatrixNativeRuntimeProvider({ transport: matrix, readAuthority: readAuthority(), attachmentIdFactory: () => 'attachment-1', now: () => new Date('2026-07-13T00:00:00.000Z'), }); await expect(provider.attach('native-1', 'control', scope)).rejects.toMatchObject({ code: 'forbidden', }); expect(matrix.verifySession).not.toHaveBeenCalled(); await provider.attach('native-1', 'read', scope); await expect( provider.detach('attachment-1', { ...scope, tenantId: 'other' }), ).rejects.toMatchObject({ code: 'forbidden', }); }); it('validates messages and applies exact Matrix authority after bound-session verification', async (): Promise => { const matrix = transport(); const writes = writeAuthority(); const provider = new MatrixNativeRuntimeProvider({ transport: matrix, readAuthority: readAuthority(), writeAuthority: writes, }); await expect( provider.sendMessage('native-1', { content: '', idempotencyKey: 'msg-1' }, scope), ).rejects.toMatchObject({ code: 'invalid_request', }); expect(matrix.verifySession).not.toHaveBeenCalled(); await provider.sendMessage('native-1', { content: 'hello', idempotencyKey: 'msg-1' }, scope); expect(writes.assertAuthorized).toHaveBeenCalledWith({ operation: 'session.send', sessionId: 'native-1', scope, }); expect(matrix.send).toHaveBeenCalledWith( 'native-1', { content: 'hello', idempotencyKey: 'msg-1' }, scope, ); }); it('streams only after exact read authorization', async (): Promise => { const matrix = transport(); const provider = new MatrixNativeRuntimeProvider({ transport: matrix, readAuthority: readAuthority(), }); await expect(collect(provider.streamSession('native-1', 'cursor-0', scope))).resolves.toEqual([ expect.objectContaining({ type: 'message.delta', sessionId: 'native-1' }), ]); expect(matrix.stream).toHaveBeenCalledWith('native-1', 'cursor-0', scope); }); }); async function collect(stream: AsyncIterable): Promise { const values: RuntimeStreamEvent[] = []; for await (const value of stream) values.push(value); return values; }