import { describe, it, expect } from 'vitest'; import { mkdtempSync } from 'node:fs'; import { tmpdir } from 'node:os'; import { join } from 'node:path'; import { pushVerdict, drainVerdicts, markSurfaced, readPendingAck, clearPendingAck } from './verdict-surface-store.mjs'; const dir = () => mkdtempSync(join(tmpdir(), 'vsurf-')); describe('verdict-surface-store', () => { it('push → drain one-shot (drain чистит)', () => { const d = dir(); pushVerdict('s1', { outcome: 'NO-GO', gate: 'judge' }, d); expect(drainVerdicts('s1', d)).toHaveLength(1); expect(drainVerdicts('s1', d)).toHaveLength(0); }); it('пер-сессия: чужие не видны', () => { const d = dir(); pushVerdict('s1', { outcome: 'GO' }, d); expect(drainVerdicts('s2', d)).toHaveLength(0); }); it('pending-ack: mark → read → clear', () => { const d = dir(); markSurfaced('s1', ['NO-GO'], d); expect(readPendingAck('s1', d)).toEqual(['NO-GO']); clearPendingAck('s1', d); expect(readPendingAck('s1', d)).toBeNull(); }); it('fail-quiet: битый baseDir не кидает', () => { expect(() => drainVerdicts('s1', '\0bad')).not.toThrow(); expect(drainVerdicts('s1', '\0bad')).toEqual([]); }); }); import { writeStage, readSnapshot } from './verdict-surface-store.mjs'; describe('verdict-surface-store снимок стадий (видимость «всё в лоб»)', () => { it('writeStage pending → читается через readSnapshot по hash', () => { const d = dir(); writeStage('s1', { stage: 'mentor:plan', hash: 'h1', status: 'pending', ts: 1 }, d); expect(readSnapshot('s1', 'h1', d)['mentor:plan'].status).toBe('pending'); }); it('завершение перезаписывает pending на исход (та же стадия+hash)', () => { const d = dir(); writeStage('s1', { stage: 'mentor:plan', hash: 'h1', status: 'pending', ts: 1 }, d); writeStage('s1', { stage: 'mentor:plan', hash: 'h1', status: 'NO-GO', reason: 'переделай', ts: 2 }, d); const snap = readSnapshot('s1', 'h1', d); expect(snap['mentor:plan'].status).toBe('NO-GO'); expect(snap['mentor:plan'].reason).toBe('переделай'); }); it('разные стадии одного hash сосуществуют', () => { const d = dir(); writeStage('s1', { stage: 'router', hash: 'h1', status: 'recommend', ts: 1 }, d); writeStage('s1', { stage: 'judge:plan', hash: 'h1', status: 'GO', ts: 2 }, d); const snap = readSnapshot('s1', 'h1', d); expect(snap.router.status).toBe('recommend'); expect(snap['judge:plan'].status).toBe('GO'); }); it('неизвестный hash → пустой объект', () => { const d = dir(); expect(readSnapshot('s1', 'nope', d)).toEqual({}); }); it('fail-quiet: битый baseDir не кидает (снимок)', () => { expect(() => writeStage('s1', { stage: 'router', hash: 'h', status: 'GO' }, '\0bad')).not.toThrow(); expect(readSnapshot('s1', 'h', '\0bad')).toEqual({}); }); });