import assert from 'node:assert/strict'; import { mkdtemp, rm } from 'node:fs/promises'; import os from 'node:os'; import path from 'node:path'; import test from 'node:test'; import { CardStateDatabase } from '../scripts/lib/card_state_db.mjs'; test('card state survives closing and reopening SQLite', async () => { const directory = await mkdtemp(path.join(os.tmpdir(), 'stem-card-state-')); const file = path.join(directory, 'state.sqlite3'); const state = { schema: 'stem-card-navigation.v2', revision: 7, selected_at: '2026-07-17T12:00:00.000Z', snapshot_ref: 'task04.alloc5.cursor' }; try { const first = new CardStateDatabase(file); first.write('navigation', state); first.close(); const second = new CardStateDatabase(file); assert.deepEqual(second.read('navigation'), state); assert.equal(second.read('missing'), null); second.close(); } finally { await rm(directory, { recursive: true, force: true }); } }); test('audit log is append-only, ordered and keeps navigation timestamps', async () => { const directory = await mkdtemp(path.join(os.tmpdir(), 'stem-card-audit-')); const file = path.join(directory, 'state.sqlite3'); try { const database = new CardStateDatabase(file); const navigation = { task: { id: 'task04' }, block: { id: 'allocator-flow' }, phase: { id: 'alloc5' }, step: { id: 'alloc5-commit' }, snapshot_ref: 'task04.alloc5.commit' }; const first = database.appendEvent({ eventType: 'navigation.activate', actor: 'nvim', navigation, occurredAt: '2026-07-17T12:00:00.000Z', payload: { source: 'F2' } }); const second = database.appendEvent({ eventType: 'checkpoint.ready', actor: 'nvim', navigation, occurredAt: '2026-07-17T12:00:01.000Z' }); assert.equal(second.id, first.id + 1); assert.deepEqual( database.listEvents({ afterId: first.id, limit: 10 }).map(event => event.event_type), ['checkpoint.ready'] ); assert.equal(database.listEvents()[0].snapshot_ref, navigation.snapshot_ref); database.close(); } finally { await rm(directory, { recursive: true, force: true }); } });