Files
stack/packages/bus/tests/routes-verb.test.mjs
jason.woltje cfe7535533 fix(autonomy): account quota coverage reads the harness module's countsAccount, not a name (#1873)
authorityBudgetCovered named claude-code to decide whether an account
quota covers every future launch, which fails the row 65 scan. The bus
host now passes each harness module's own countsAccount answer, read
once with its levels in harnessLevels, through autonomyHost to the
broker. Without the lookup no account quota counts (fail closed); the
provider/model branch is unchanged.
2026-11-11 13:39:44 -06:00

222 lines
19 KiB
JavaScript

// Row 65 (#1558, REQ-PLUG-2, mos-0840): routes and routes.set, the Console's routing table, are
// human-only broker actions outside ORGANIZATION_KEYS, so neither organization.set nor the chief of
// staff's change_organization sends a routes key. The chief reaches a route only through the
// assistant's vars (Q169), and that write runs the same checks (chief-of-staff.test). A new launch
// binds only on a harness its business switches on; a run an earlier broker bound binds again unchanged.
import test from 'node:test';
import assert from 'node:assert/strict';
import { mkdtempSync, mkdirSync, 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, ORGANIZATION_KEYS } from '../src/broker.mjs';
const chiefAuthority = JSON.parse(readFileSync(fileURLToPath(new URL('../../../roles/chief-of-staff.json', import.meta.url)), 'utf8')).authority;
const none = { authority: { withinRole: ['message.send'], crossRole: [] } };
const biz = () => ({
demo: {
id: 'demo', human: 'jason', arbiters: { technical: 'pm', delivery: 'chief' }, definitions: {},
roles: { chief: { definition: 'chief-of-staff', authority: chiefAuthority }, pm: { definition: 'pm', ...none } },
projects: { stack: { root: '/nonexistent' } }, vars: { 'bus.tester': true },
},
});
const ROUTE = { harness: 'pi', model: 'sonnet', thinking: 'low', fallback: null };
const SET = { revision: 'a'.repeat(64), routes: { pm: ROUTE } };
function scratch(t, prefix) {
const root = mkdtempSync(join(tmpdir(), prefix));
t.after(() => rmSync(root, { recursive: true, force: true }));
return root;
}
test('row 65: routes and routes.set refuse every non-human session, the chief of staff included, the tester may read and set, and each passes the verified actor', (t) => {
const store = new Store(scratch(t, 'routes-verb-'));
t.after(() => store.close());
const calls = [];
const b = new Broker({ store, businesses: biz(), organization: (id, verb, args, actor) => (calls.push([id, verb, args, actor]), { ok: true }) });
const human = b.bindHuman({ business: 'demo', human: 'jason', via: 'cli', outsideAgent: true });
const tester = b.bindTester({ business: 'demo' });
const caps = { reader: b.bindReader({ business: 'demo' }) };
for (const role of ['chief', 'pm']) {
caps[role] = b.bindLaunch({ business: 'demo', role, run: `${role}-run`, harness: 'pi' });
b.request(caps[role], { verb: 'role.claim' });
}
// Row 176 (#1674): the tester reads routes as well as setting them.
assert.deepEqual(b.request(tester, { verb: 'routes', args: {} }), { ok: true });
for (const [who, cap] of Object.entries(caps))
for (const verb of ['routes', 'routes.set'])
assert.throws(() => b.request(cap, { verb, args: verb === 'routes' ? {} : SET }), /human-required/, `${who} ${verb}`);
// The chief of staff holds organization.change, but organization.set takes ORGANIZATION_KEYS
// only: a routes key is refused before the writer, so change_organization can't send one.
assert.equal(ORGANIZATION_KEYS.includes('routes'), false);
for (const args of [SET, { revision: SET.revision, routes: SET.routes, instances: { pm: 'sonnet' } }])
assert.throws(() => b.request(caps.chief, { verb: 'organization.set', args }), /invalid-request/);
assert.equal(calls.length, 1);
assert.throws(() => b.request(human, { verb: 'routes.set', args: { ...SET, actor: 'forged' } }), /invalid-request/);
assert.throws(() => b.request(human, { verb: 'routes.set', args: { revision: SET.revision } }), /invalid-request/);
assert.throws(() => b.request(human, { verb: 'routes.set', args: { routes: SET.routes } }), /invalid-request/);
assert.throws(() => b.request(human, { verb: 'routes', args: { x: 1 } }), /invalid-request/);
assert.equal(calls.length, 1);
b.request(human, { verb: 'routes' });
b.request(human, { verb: 'routes.set', args: SET });
assert.throws(() => b.request(tester, { verb: 'routes.set', args: { ...SET, actor: 'forged' } }), /invalid-request/);
b.request(tester, { verb: 'routes.set', args: SET });
assert.deepEqual(calls, [['demo', 'routes', {}, 'tester'], ['demo', 'routes', {}, 'jason'], ['demo', 'routes.set', SET, 'jason'], ['demo', 'routes.set', SET, 'tester']]);
});
test('row 65: a new launch binds only on a switched-on harness with a module name, and a run an earlier broker bound binds again after its harness is switched off', (t) => {
const store = new Store(scratch(t, 'routes-harness-on-'));
t.after(() => store.close());
const asked = [];
const first = new Broker({ store, businesses: biz(), harnessOn: (id, name) => (asked.push([id, name]), name === 'pi') });
assert.throws(() => first.bindLaunch({ business: 'demo', role: 'pm', run: 'off-run', harness: 'claude-code' }), /invalid-harness/);
for (const harness of ['', 'Pi', '../pi', 'pi/x', 7])
assert.throws(() => first.bindLaunch({ business: 'demo', role: 'pm', run: 'bad-run', harness }), /invalid-harness/, String(harness));
const cap = first.bindLaunch({ business: 'demo', role: 'pm', run: 'pi-run', harness: 'pi' });
first.request(cap, { verb: 'role.claim' });
// The name check runs before the file is asked; the switched-on check asks for the bind's business.
assert.deepEqual(asked, [['demo', 'claude-code'], ['demo', 'pi']]);
// A second broker over the same store, with nothing switched on: the old run binds unchanged, and
// a new run on the same harness doesn't.
const second = new Broker({ store, businesses: biz(), harnessOn: () => false });
assert.equal(typeof second.bindLaunch({ business: 'demo', role: 'pm', run: 'pi-run', harness: 'pi' }), 'string');
assert.throws(() => second.bindLaunch({ business: 'demo', role: 'pm', run: 'new-run', harness: 'pi' }), /invalid-harness/);
// A broker given no harnessOn switches every module name on, as before row 65.
const store2 = new Store(scratch(t, 'routes-harness-default-'));
t.after(() => store2.close());
new Broker({ store: store2, businesses: biz() }).bindLaunch({ business: 'demo', role: 'pm', run: 'any-run', harness: 'fixture' });
assert.throws(() => new Broker({ store: store2, businesses: biz(), harnessOn: 'yes' }), /harnessOn must be a function/);
});
test('row 65 runtime: harnessLevels answers each module in the tree, and null for a name with no module', async () => {
const { harnessLevels } = await import('../src/runtime.mjs');
const logged = [];
const levels = await harnessLevels({ log: (e) => logged.push(e) });
assert.deepEqual(levels('pi'), ['off', 'minimal', 'low', 'medium', 'high', 'xhigh', 'max']);
assert.deepEqual(levels('claude-code'), ['low', 'medium', 'high', 'xhigh', 'max']);
for (const name of ['cursor', '', '../pi']) assert.equal(levels(name), null, name);
// AU (#1873): each module's own countsAccount answer, read once with its levels.
assert.deepEqual([levels.countsAccount('pi'), levels.countsAccount('claude-code')], [false, true]);
for (const name of ['cursor', '', '../pi']) assert.equal(levels.countsAccount(name), null, name);
assert.deepEqual(logged, []);
});
test('row 65 runtime: routes and routes.set reach the organization file with the human as actor, a new bind reads plugins.harness, and each refusal keeps the bytes and logs nothing', async (t) => {
const { startBroker } = await import('../src/runtime.mjs');
const { businessDoc, rolesCopy, systemFor, writeJson } = await import('../../organization/tests/helpers.mjs');
const root = scratch(t, 'routes-runtime-');
const rolesDir = rolesCopy(root);
const doc = businessDoc(root, 'demo');
doc.plugins = { ...doc.plugins, harness: ['pi', 'claude-code'] };
for (const r of Object.values(doc.roles)) r.vars = { harness: 'pi', model: 'claude-sonnet-5-5', thinking: 'high', ...r.vars };
const file = join(root, 'businesses/demo.json');
writeJson(file, doc);
mkdirSync(join(root, 'data'), { mode: 0o700 });
const bus = await startBroker({ dataRoot: join(root, 'data'), businesses: { demo: { id: 'demo', human: 'jason', arbiters: { technical: 'chief', delivery: 'chief' }, roles: {chief: { definition: 'chief-of-staff', authority: { withinRole: ['decision.resolve.technical', 'decision.resolve.delivery'], crossRole: [] } }, coder: { authority: { withinRole: [], crossRole: [] } } } } }, organization: { dir: root, rolesDir, system: systemFor(root) } });
t.after(() => bus.close());
const human = bus.broker.bindHuman({ business: 'demo', human: 'jason', via: 'cli', outsideAgent: true });
const log = () => readFileSync(join(root, 'businesses/.history/demo/changes.jsonl'), 'utf8').trim().split('\n').filter(Boolean).map(JSON.parse);
const view = bus.broker.request(human, { verb: 'routes' });
assert.deepEqual(view.harnesses, ['pi', 'claude-code']);
assert.deepEqual(view.levels.pi, ['off', 'minimal', 'low', 'medium', 'high', 'xhigh', 'max']);
assert.deepEqual(view.instances.coder, { harness: 'pi', model: 'claude-sonnet-5-5', thinking: 'high', fallback: null });
const route = { harness: 'pi', model: 'claude-opus-5-5', thinking: 'minimal', fallback: { harness: 'pi', model: 'glm-5.3-flash', thinking: 'off' } };
const saved = bus.broker.request(human, { verb: 'routes.set', args: { revision: view.revision, routes: { coder: route } } });
assert.deepEqual(saved.instances.coder, route);
const vars = JSON.parse(readFileSync(file, 'utf8')).roles.coder.vars;
assert.deepEqual([vars.model, vars.thinking, vars['fallback.harness'], vars['fallback.model'], vars['fallback.thinking'], vars['limits.network']], ['claude-opus-5-5', 'minimal', 'pi', 'glm-5.3-flash', 'off', 'none']);
assert.equal(log().at(-1).actor, 'jason');
// harnessOn reads the file as it stands: pi and claude-code are on, and cursor isn't.
bus.broker.bindLaunch({ business: 'demo', role: 'coder', run: 'pi-run', harness: 'pi' });
assert.throws(() => bus.broker.bindLaunch({ business: 'demo', role: 'coder', run: 'cursor-run', harness: 'cursor' }), /invalid-harness/);
const before = readFileSync(file, 'utf8');
const entries = log().length;
const code = (routes, revision = saved.revision) => { try { bus.broker.request(human, { verb: 'routes.set', args: { revision, routes } }); } catch (e) { return e.code; } return null; };
const coder = (more) => ({ coder: { ...route, ...more } });
assert.equal(code(coder({ harness: 'cursor', thinking: 'low' })), 'harness-off');
assert.equal(code(coder({ fallback: { harness: 'cursor', model: 'glm-5.3-flash', thinking: 'low' } })), 'harness-off');
// claude-code has no minimal or off; a level no harness applies fails the file's own check.
assert.equal(code(coder({ harness: 'claude-code' })), 'thinking-unsupported');
assert.equal(code(coder({ fallback: { harness: 'claude-code', model: 'glm-5.3-flash', thinking: 'off' } })), 'thinking-unsupported');
assert.equal(code(coder({ thinking: 'ultra' })), 'invalid-request');
assert.equal(code(coder({ fallback: { harness: 'pi', model: 'glm-5.3-flash' } })), 'organization-partial-fallback');
assert.equal(code(coder({ fallback: { harness: 'pi', model: 'glm-5.3-flash', thinking: null } })), 'organization-partial-fallback');
// A model the table lacks comes back as unknown-model, so the Console can say so (dewey N1).
assert.equal(code(coder({ model: 'ghost' })), 'unknown-model');
assert.equal(code(coder({ fallback: { harness: 'pi', model: 'ghost', thinking: 'off' } })), 'unknown-model');
assert.equal(code({ ghost: route }), 'organization-unknown-instance');
assert.equal(code({ coder: route }), 'organization-no-change');
assert.equal(code(coder({ thinking: 'low' }), view.revision), 'revision-conflict');
assert.equal(readFileSync(file, 'utf8'), before);
assert.equal(log().length, entries, 'a refused write logs nothing');
});
test('fixture provider catalogue appears in actual routes and materializes the selected model', async t => {
const { startBroker } = await import('../src/runtime.mjs');
const { businessDoc, rolesCopy, systemFor, writeJson } = await import('../../organization/tests/helpers.mjs');
const root = scratch(t, 'routes-catalogue-'), rolesDir = rolesCopy(root), doc = businessDoc(root, 'demo');
doc.plugins = { ...doc.plugins, harness: ['pi'], 'model-provider': ['cliproxy'] };
for (const r of Object.values(doc.roles)) r.vars = { harness: 'pi', model: Object.keys(doc.launch.models)[0], thinking: 'high', ...r.vars };
const file = join(root, 'businesses/demo.json'); writeJson(file, doc); mkdirSync(join(root, 'data'), { mode: 0o700 });
const offered={ key:'zai-fixture-id',module:'cliproxy',upstream:'zai',provider:'zai',model:'fixture-id',label:'fixture-id',available:true,reason:null,harnesses:['pi'] };
const catalogues={ read:async()=>({status:'ready',observedAt:'2026-11-06T00:00:00.000Z',models:[offered],notices:[]}),invalidate:()=>{} };
const bus = await startBroker({ dataRoot: join(root, 'data'), businesses: { demo: { id:'demo',human:'jason',arbiters:{technical:'chief',delivery:'chief'},roles:{chief: { definition: 'chief-of-staff', authority: { withinRole: ['decision.resolve.technical', 'decision.resolve.delivery'], crossRole: [] } }, coder:{authority:{withinRole:[],crossRole:[]}}} } }, organization:{dir:root,rolesDir,system:systemFor(root)}, modelCatalogue:catalogues });
t.after(() => bus.close());
const human=bus.broker.bindHuman({business:'demo',human:'jason',via:'cli',outsideAgent:true});
const before=await bus.broker.request(human,{verb:'routes'});
assert.equal(before.catalogue.models[0].key,'zai-fixture-id');
assert.equal(before.models.includes('zai-fixture-id'),false);
const saved=await bus.broker.request(human,{verb:'routes.set',args:{revision:before.revision,routes:{coder:{harness:'pi',model:'zai-fixture-id',thinking:'low',fallback:null}}}});
assert.equal(saved.instances.coder.model,'zai-fixture-id');
assert.equal(JSON.parse(readFileSync(file,'utf8')).launch.models['zai-fixture-id'].model,'fixture-id');
});
for (const writer of ['limits.set','organization.set','instances.set']) test(`${writer} selects only available compatible existing provider models`, async t => {
const { startBroker } = await import('../src/runtime.mjs');
const { businessDoc, rolesCopy, systemFor, writeJson } = await import('../../organization/tests/helpers.mjs');
const root=scratch(t,'provider-writer-'),rolesDir=rolesCopy(root),doc=businessDoc(root,'demo');
doc.plugins={...doc.plugins,harness:['pi','claude-code'],'model-provider':['cliproxy']};
doc.launch.models['fixture-persisted']={provider:'zai',model:'fixture-id',module:'cliproxy',upstream:'zai'};
doc.roles.coder.vars={...doc.roles.coder.vars,harness:'pi',thinking:'low'};
writeJson(join(root,'businesses/demo.json'),doc);mkdirSync(join(root,'data'),{mode:0o700});
let mode='absent';
const offered={key:'fixture-persisted',module:'cliproxy',upstream:'zai',provider:'zai',model:'fixture-id',label:'fixture',available:true,reason:null,harnesses:['pi']};
const catalogue={read:async()=>({status:'ready',observedAt:'2026-11-06T00:00:00.000Z',models:mode==='absent'?[]:[{...offered,harnesses:mode==='incompatible'?['claude-code']:['pi']}],notices:[]}),invalidate(){}};
const bus=await startBroker({dataRoot:join(root,'data'),businesses:{demo:{id:'demo',human:'jason',arbiters:{technical:'chief',delivery:'chief'},roles:{coder:{authority:{withinRole:[],crossRole:[]}},chief:{definition:'chief-of-staff',authority:chiefAuthority}}}},organization:{dir:root,rolesDir,system:systemFor(root)},modelCatalogue:catalogue});t.after(()=>bus.close());
const human=bus.broker.bindHuman({business:'demo',human:'jason',via:'cli',outsideAgent:true});
const cap=writer==='organization.set'?bus.broker.bindLaunch({business:'demo',role:'chief',run:'provider-chief',harness:'pi'}):human;
if(writer==='organization.set')bus.broker.request(cap,{verb:'role.claim'});
const view=bus.broker.request(human,{verb:'limits'});
const args=writer==='instances.set'?{revision:view.revision,instance:'coder',op:'change',vars:{...doc.roles.coder.vars,model:'fixture-persisted'}}:{revision:view.revision,instances:{coder:'fixture-persisted'}};
await assert.rejects(Promise.resolve().then(()=>bus.broker.request(cap,{verb:writer,args})),{code:'model-provider-unavailable'});
mode='incompatible';await assert.rejects(Promise.resolve().then(()=>bus.broker.request(cap,{verb:writer,args})),{code:'model-harness-incompatible'});
mode='available';const result=await bus.broker.request(cap,{verb:writer,args});assert.ok(result.transaction);
assert.equal(JSON.parse(readFileSync(join(root,'businesses/demo.json'),'utf8')).roles.coder.vars.model,'fixture-persisted');
});
test('legacy routes follow enabled module mappings while unchanged unavailable selections remain saveable', async t => {
const {startBroker}=await import('../src/runtime.mjs');const {businessDoc,rolesCopy,systemFor,writeJson}=await import('../../organization/tests/helpers.mjs');
const root=scratch(t,'legacy-catalogue-'),rolesDir=rolesCopy(root),doc=businessDoc(root,'demo');
doc.plugins={...doc.plugins,harness:['pi','claude-code'],'model-provider':['cliproxy']};
doc.launch.models['legacy-one']={provider:'anthropic',model:'fixture-one'};doc.launch.models['legacy-two']={provider:'zai',model:'fixture-two'};
doc.roles.coder.vars={...doc.roles.coder.vars,harness:'pi',model:'legacy-one',thinking:'low'};
doc.roles.reviewer.vars={...doc.roles.reviewer.vars,harness:'pi',model:'legacy-one',thinking:'low'};
writeJson(join(root,'businesses/demo.json'),doc);mkdirSync(join(root,'data'),{mode:0o700});
let state='ready';const offered={key:'zai-fixture-two',module:'cliproxy',upstream:'zai',provider:'zai',model:'fixture-two',label:'fixture',available:true,reason:null,harnesses:['pi']};
const catalogue={read:async()=>({status:state,observedAt:'2026-11-06T00:00:00.000Z',models:[offered],notices:[]}),invalidate(){}};
const bus=await startBroker({dataRoot:join(root,'data'),businesses:{demo:{id:'demo',human:'jason',arbiters:{technical:'chief',delivery:'chief'},roles:{chief: { definition: 'chief-of-staff', authority: { withinRole: ['decision.resolve.technical', 'decision.resolve.delivery'], crossRole: [] } }, coder:{authority:{withinRole:[],crossRole:[]}}}}},organization:{dir:root,rolesDir,system:systemFor(root)},modelCatalogue:catalogue});t.after(()=>bus.close());
const human=bus.broker.bindHuman({business:'demo',human:'jason',via:'cli',outsideAgent:true});const request=(verb,args)=>bus.broker.request(human,{verb,args});
let view=await request('routes');assert.deepEqual(view.catalogue.legacy['legacy-one'],{module:'cliproxy',upstream:'claude',model:'fixture-one'});
const pick=(harness,model,fallback=null)=>({harness,model,thinking:'low',fallback});
await assert.rejects(request('routes.set',{revision:view.revision,routes:{coder:pick('claude-code','legacy-two')}}),{code:'model-harness-incompatible'});
await assert.rejects(request('routes.set',{revision:view.revision,routes:{coder:pick('pi','legacy-two',{harness:'pi',model:'legacy-one',thinking:'low'})}}),{code:'model-provider-unavailable'});
const saved=await request('routes.set',{revision:view.revision,routes:{coder:pick('pi','legacy-two')}});assert.equal(saved.instances.reviewer.model,'legacy-one');
state='unavailable';view=await request('routes');await assert.rejects(request('routes.set',{revision:view.revision,routes:{coder:pick('pi','legacy-one')}}),{code:'model-provider-unavailable'});
});
test('the tester cannot switch a model-provider plugin', t => {
const store=new Store(scratch(t,'provider-switch-'));t.after(()=>store.close());
const b=new Broker({store,businesses:biz(),organization:()=>({ok:true})});const tester=b.bindTester({business:'demo'});
assert.throws(()=>b.request(tester,{verb:'plugins.set',args:{revision:'a'.repeat(64),plugins:{'model-provider':['fixture']}}}),{code:'human-required'});
});