import test from 'node:test'; import assert from 'node:assert/strict'; import { mkdtempSync, rmSync } from 'node:fs'; import { tmpdir } from 'node:os'; import { join } from 'node:path'; import { Store } from '../src/store.mjs'; import { Broker } from '../src/broker.mjs'; function fixture(t) { const root = mkdtempSync(join(tmpdir(), 'comment-cursors-')); const store = new Store(root); const roles = { pm: { authority: { withinRole: ['message.send'], crossRole: [] } } }; const b = new Broker({ store, businesses: { demo: { id: 'demo', human: 'jason', arbiters: { technical: 'pm', delivery: 'pm' }, roles }, other: { id: 'other', human: 'jason', arbiters: { technical: 'pm', delivery: 'pm' }, roles }, } }); t.after(() => { store.close(); rmSync(root, { recursive: true, force: true }); }); return { store, b, record: (commentCursors, extra = {}) => b.recordTask({ business: 'demo', commentCursors, ...extra }) }; } test('comment cursors isolate businesses, move only forward and remain append-only', t => { const { store, b, record } = fixture(t); record([{ task_id: 7, last_comment: 11 }]); record([{ task_id: 7, last_comment: 15 }]); b.recordTask({ business: 'other', commentCursors: [{ task_id: 7, last_comment: 2 }] }); assert.deepEqual(b.taskView('demo', 'comments').cursors.map(c => ({ ...c })), [{ task_id: 7, last_comment: 15 }]); assert.deepEqual(b.taskView('other', 'comments').cursors.map(c => ({ ...c })), [{ task_id: 7, last_comment: 2 }]); for (const last_comment of [11, 15]) assert.throws(() => record([{ task_id: 7, last_comment }]), /must advance/); for (const sql of [ 'UPDATE task_comment_cursors SET last_comment=20 WHERE seq=1', 'DELETE FROM task_comment_cursors WHERE seq=1', "INSERT OR REPLACE INTO task_comment_cursors VALUES(1,'demo',7,20)", ]) assert.throws(() => store.run(sql), /append-only/); assert.equal(store.get('SELECT count(*) n FROM task_comment_cursors').n, 3); }); test('only trusted sync writes validated cursors; events and cursor share rollback', t => { const { store, b, record } = fixture(t); const cap = b.bindLaunch({ business: 'demo', role: 'pm', run: 'pm-run', harness: 'pi' }); for (const x of [null, {}, { task_id: 0, last_comment: 1 }, { task_id: 1, last_comment: 0 }, { task_id: 1, last_comment: 1.5 }, { task_id: 1, last_comment: 2 ** 53 }, { task_id: 1, last_comment: 1, extra: true }]) { assert.throws(() => record([x]), e => e.code === 'invalid-request'); } assert.throws(() => record([{ task_id: 1, last_comment: 1 }], { cap }), e => e.code === 'agent-required'); assert.throws(() => record([{ task_id: 1, last_comment: 1 }], { events: [{ kind: 'human.input', body: {} }], }), e => e.code === 'reserved-event'); assert.equal(store.get('SELECT count(*) n FROM task_comment_cursors').n, 0); });