import test from 'node:test'; import assert from 'node:assert/strict'; import { mkdtempSync, readFileSync, rmSync } from 'node:fs'; import { join } from 'node:path'; import { tmpdir } from 'node:os'; import { Broker } from '../src/broker.mjs'; import { Store } from '../src/store.mjs'; import { citationWorld, citedBody, fixtureCite } from './citation-helpers.mjs'; test('C2-10c room.read carries exactly the thread check and current file last', async t => { const f = citationWorld(t, { definition: 'companion' }); const room = f.call(f.human, 'room.open', { project: f.store.get('SELECT id FROM projects').id }); const thread = room.threads[0].id; const agent = f.broker.bindLaunch({ ...f.launch, run: 'room-agent', thread }); f.call(agent, 'role.claim'); const sent = await f.call(agent, 'message.send', { to: 'human', body: citedBody([fixtureCite(f.commit)]) }); const [single] = await f.call(f.human, 'thread.messages', { thread }); const merged = await f.call(f.human, 'room.read', { project: room.project }); const same = merged.find(m => m.id === sent.id); assert.deepEqual(same.check, single.check); assert.deepEqual(same.check.citations, [{ scope: 'canon', agent: null, file: f.commit, last: f.commit }]); assert.equal(f.reads.length, 2, 'both read verbs route through last hydration'); }); test('C2-10c check hydration preserves unchecked rows and one broadcast with two addressees', t => { const root = mkdtempSync(join(tmpdir(), 'room-check-')), store = new Store(root); t.after(() => { store.close(); rmSync(root, { recursive: true, force: true }); }); const messaging = JSON.parse(readFileSync(new URL('../../../roles/companion.json', import.meta.url))).messaging; const role = { definition: 'companion', authority: { withinRole: ['message.send'], crossRole: [] } }; const broker = new Broker({ store, businesses: { demo: { id: 'demo', human: 'jason', vars: {}, arbiters: { technical: 'chief', delivery: 'chief' }, roles: {chief: { definition: 'chief-of-staff', authority: { withinRole: ['decision.resolve.technical', 'decision.resolve.delivery'], crossRole: [] } }, bean: role, chet: role }, definitions: { companion: { messaging } } } } }); const human = broker.bindHuman({ business: 'demo', human: 'jason', via: 'cli', outsideAgent: true }); const call = (verb, args) => broker.request(human, { verb, args }); const project = call('project.create', { name: 'Room' }).id; call('room.open', { project }); const receipt = call('room.send', { project, body: 'One broadcast.' }); const rows = call('room.read', { project }); assert.equal(rows.length, 1); assert.deepEqual(rows[0].ids, receipt.ids); assert.deepEqual(rows[0].to, ['bean', 'chet']); assert.equal(Object.hasOwn(rows[0], 'check'), false); assert.equal(rows[0].body, 'One broadcast.'); });