import test from 'node:test'; import assert from 'node:assert/strict'; import { mkdtempSync, readFileSync, rmSync } from 'node:fs'; import { tmpdir } from 'node:os'; import { join } from 'node:path'; import { fileURLToPath } from 'node:url'; import { Store } from '../src/store.mjs'; import { Broker } from '../src/broker.mjs'; // Row 141 (#1635, REQ-MSG-2): messages are addressed by an instance's name. The human sets names // through the CLI; the chief of staff sets them because its role file grants `instance.name` // within-role. The grant is read from the shipped roles/chief-of-staff.json, so removing it there // fails the chief's test. Instance keys differ from definitions here, so each refusal is its own. const shipped = (name) => JSON.parse(readFileSync(fileURLToPath(new URL(`../../../roles/${name}.json`, import.meta.url)), 'utf8')); const none = { authority: { withinRole: ['message.send'], crossRole: [] } }; const roles = { chief: { definition: 'chief-of-staff', authority: shipped('chief-of-staff').authority }, lead: { definition: 'pm', ...none }, dev: { definition: 'coder', authority: { withinRole: ['message.send'], crossRole: ['instance.name'] } }, }; const demo = () => ({ demo: { id: 'demo', human: 'jason', arbiters: { technical: 'chief', delivery: 'chief' }, roles, definitions: { reviewer: {} }, vars: { 'bus.tester': true }, }, }); function setup(t) { const root = mkdtempSync(join(tmpdir(), 'bus-names-')); const store = new Store(root); t.after(() => { store.close(); rmSync(root, { recursive: true, force: true }); }); const b = new Broker({ store, businesses: demo() }); const caps = { human: b.bindHuman({ business: 'demo', human: 'jason', via: 'cli', outsideAgent: true }) }; for (const role of Object.keys(roles)) { caps[role] = b.bindLaunch({ business: 'demo', role, run: `${role}-run`, harness: 'pi' }); b.request(caps[role], { verb: 'role.claim' }); } caps.reader = b.bindReader({ business: 'demo' }); caps.tester = b.bindTester({ business: 'demo' }); const call = (who, verb, args = {}) => b.request(caps[who], { verb, args }); return { b, store, caps, call }; } test('REQ-MSG-2: the chief of staff names an instance under its within-role grant, and the write is logged', (t) => { const { store, call } = setup(t); assert.ok(shipped('chief-of-staff').authority.withinRole.includes('instance.name'), 'the shipped chief file grants instance.name'); assert.deepEqual(call('chief', 'name.set', { instance: 'dev', name: 'rex' }), { instance: 'dev', name: 'rex' }); const [event, ...rest] = store .all("SELECT actor_role, subject, body FROM events WHERE kind='action.allowed' AND json_extract(body,'$.action')='instance.name'") .map((e) => ({ ...e, body: JSON.parse(e.body) })); assert.equal(rest.length, 0); assert.equal(event.actor_role, 'chief'); assert.equal(event.subject, 'dev'); assert.equal(event.body.class, 'within-role'); assert.equal(event.body.target, 'dev'); assert.deepEqual({ ...store.get('SELECT business, instance, name, by FROM instance_names') }, { business: 'demo', instance: 'dev', name: 'rex', by: 'chief-run', }); assert.deepEqual( call('chief', 'names').map(({ instance, name }) => ({ instance, name })), [{ instance: 'dev', name: 'rex' }], ); }); test('REQ-MSG-2: the human names an instance through the CLI', (t) => { const { store, call } = setup(t); assert.deepEqual(call('human', 'name.set', { instance: 'lead', name: 'patty' }), { instance: 'lead', name: 'patty' }); assert.equal(store.get('SELECT by FROM instance_names').by, 'jason'); assert.deepEqual( call('human', 'names').map(({ instance, name }) => ({ instance, name })), [{ instance: 'lead', name: 'patty' }], ); }); test('REQ-MSG-2: a role without the grant, or holding it cross-role, is refused not-authorized', (t) => { const { store, call } = setup(t); // lead holds no instance.name at all; dev holds it cross-role. Neither may set a name: the refusal // comes before #checkAuthority, so dev gets not-authorized, not decision-required, and name.set // takes no decision argument at all. assert.throws(() => call('lead', 'name.set', { instance: 'dev', name: 'rex' }), /not-authorized/); assert.throws(() => call('dev', 'name.set', { instance: 'dev', name: 'rex' }), /not-authorized/); assert.throws( () => call('dev', 'name.set', { instance: 'dev', name: 'rex', decision: '00000000-0000-4000-8000-000000000000' }), /invalid-request/, ); assert.throws(() => call('reader', 'name.set', { instance: 'dev', name: 'rex' }), /read-only/); assert.equal(store.get('SELECT count(*) AS n FROM instance_names').n, 0); // Row 175 (#1673): the tester sets a name like the human, recorded by `tester`. call('tester', 'name.set', { instance: 'dev', name: 'rex' }); assert.equal(store.get('SELECT by FROM instance_names').by, 'tester'); }); test('REQ-MSG-2: a name is unique in the business and is never an instance key or a role name', (t) => { const { store, call } = setup(t); call('human', 'name.set', { instance: 'dev', name: 'rex' }); assert.throws(() => call('human', 'name.set', { instance: 'lead', name: 'rex' }), /name-taken/); assert.throws(() => call('chief', 'name.set', { instance: 'lead', name: 'rex' }), /name-taken/); for (const key of ['chief', 'lead', 'human', 'tester']) assert.throws(() => call('human', 'name.set', { instance: 'dev', name: key }), /name-is-instance/, key); // A definition an instance uses, and one the business only defines. for (const definition of ['coder', 'chief-of-staff', 'reviewer']) assert.throws(() => call('human', 'name.set', { instance: 'dev', name: definition }), /name-is-role/, definition); for (const bad of ['', 'Rex', '_bus', 'a b', 'x'.repeat(65), 7]) assert.throws(() => call('human', 'name.set', { instance: 'dev', name: bad }), /invalid-request/, String(bad)); assert.throws(() => call('human', 'name.set', { instance: 'nobody', name: 'zed' }), /unknown-role/); // Renaming frees the old name for another instance. call('human', 'name.set', { instance: 'dev', name: 'rexy' }); call('human', 'name.set', { instance: 'lead', name: 'rex' }); assert.deepEqual( call('human', 'names').map(({ instance, name }) => ({ instance, name })), [{ instance: 'dev', name: 'rexy' }, { instance: 'lead', name: 'rex' }], ); // The store refuses a duplicate on its own, and the table is append-only. assert.throws( () => store.run("INSERT INTO instance_names(at,business,instance,name,by) VALUES('2026-01-01T00:00:00.000Z','demo','chief','rex','t')"), /unique in its business/, ); assert.throws(() => store.run("UPDATE instance_names SET name='zed'"), /append-only/); assert.throws(() => store.run('DELETE FROM instance_names'), /append-only/); }); test('REQ-MSG-2: a send by name reaches the instance and records both; a send by instance key is unchanged', (t) => { const { call } = setup(t); call('human', 'name.set', { instance: 'dev', name: 'rex' }); const byName = call('lead', 'message.send', { to: 'rex', body: 'by name' }); const byKey = call('lead', 'message.send', { to: 'dev', body: 'by key' }); const fromHuman = call('human', 'message.send', { to: 'rex', body: 'from the human' }); const got = call('dev', 'message.receive'); assert.deepEqual( got.map(({ id, to_role, to_name, body }) => ({ id, to_role, to_name, body })), [ { id: byName.id, to_role: 'dev', to_name: 'rex', body: 'by name' }, { id: byKey.id, to_role: 'dev', to_name: null, body: 'by key' }, { id: fromHuman.id, to_role: 'dev', to_name: 'rex', body: 'from the human' }, ], ); // The tester may send by name too; a name no instance holds is an unknown role. call('tester', 'message.send', { to: 'rex', body: '[mos test] by name' }); assert.equal(call('dev', 'message.receive')[0].to_role, 'dev'); assert.throws(() => call('lead', 'message.send', { to: 'nobody', body: 'x' }), /unknown-role/); // After a rename, the old name no longer reaches anyone. call('human', 'name.set', { instance: 'dev', name: 'rexy' }); assert.throws(() => call('lead', 'message.send', { to: 'rex', body: 'x' }), /unknown-role/); assert.equal(call('lead', 'message.send', { to: 'rexy', body: 'renamed' }).id.length, 36); }); test('REQ-MSG-2: an instance key beats a name that equals it, as when a later instance takes the key', (t) => { const { store, call } = setup(t); // name.set refuses this name; the store's trigger doesn't know the business, so a row stands in for // a name set before an instance with that key joined. store.run("INSERT INTO instance_names(at,business,instance,name,by) VALUES('2026-01-01T00:00:00.000Z','demo','dev','lead','jason')"); call('chief', 'message.send', { to: 'lead', body: 'to the key' }); const [m] = call('lead', 'message.receive'); assert.equal(m.body, 'to the key'); assert.equal(m.to_role, 'lead'); assert.equal(m.to_name, null); assert.deepEqual(call('dev', 'message.receive'), []); }); test('REQ-MSG-2: a role name beats a name that equals it, as when a later definition takes the word (sage-0590)', (t) => { const { store, call } = setup(t); // As above, rows stand in for names set before the business knew these definitions: one an // instance uses (coder) and one the business only defines (reviewer). Neither is an instance key. store.run("INSERT INTO instance_names(at,business,instance,name,by) VALUES('2026-01-01T00:00:00.000Z','demo','dev','reviewer','jason')"); store.run("INSERT INTO instance_names(at,business,instance,name,by) VALUES('2026-01-01T00:00:00.000Z','demo','lead','coder','jason')"); for (const word of ['reviewer', 'coder']) assert.throws(() => call('chief', 'message.send', { to: word, body: 'to the role' }), /unknown-role/, word); assert.deepEqual(call('dev', 'message.receive'), []); assert.deepEqual(call('lead', 'message.receive'), []); });