90 lines
6.5 KiB
JavaScript
90 lines
6.5 KiB
JavaScript
// Row 126 (#1620, REQ-LIMIT-2, REQ-LIMIT-4): the account a run spends. bindLaunch keeps it on the
|
|
// session, out of session.launched's body; usage records carry it; mayLaunch and mustStop pass it
|
|
// to the shipped daily-quota through the real loader. A run with no account is null throughout.
|
|
import test from 'node:test';
|
|
import assert from 'node:assert/strict';
|
|
import { mkdtempSync, rmSync, mkdirSync } 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';
|
|
|
|
const SINCE = '2026-10-18T07:00:00.000Z';
|
|
const DAILY = ['tokens', 'daily', 'jason-max'];
|
|
const ROLES = { coder: { definition: 'coder', authority: { withinRole: [], crossRole: [] } } };
|
|
|
|
async function setup(t, limit = 0) {
|
|
const { startBroker } = await import('../src/runtime.mjs');
|
|
const { businessDoc, rolesCopy, systemFor, writeJson } = await import('../../organization/tests/helpers.mjs');
|
|
const root = mkdtempSync(join(tmpdir(), 'mosaic-daily-quota-')), rolesDir = rolesCopy(root), doc = businessDoc(root, 'demo');
|
|
doc.plugins = { 'limit-check': ['daily-quota'], harness: ['pi', 'claude-code'] };
|
|
doc.launch.account = { name: 'jason-max', credential: 'CLAUDE_CODE_OAUTH_TOKEN' };
|
|
doc.launch.limits = { ...doc.launch.limits,
|
|
tokens: { daily: { 'jason-max': { limit, since: SINCE, reset: '05:00', timeZone: 'America/Chicago' } } } };
|
|
writeJson(join(root, 'businesses/demo.json'), 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: [] } }, ...ROLES }, definitions: { coder: {} }, projects: { stack: { root: '/nonexistent' } } } },
|
|
organization: { dir: root, rolesDir, system: systemFor(root) } });
|
|
t.after(async () => { await bus.close(); rmSync(root, { recursive: true, force: true }); });
|
|
return { bus, human: bus.broker.bindHuman({ business: 'demo', human: 'jason', via: 'cli', outsideAgent: true }) };
|
|
}
|
|
|
|
async function turn(broker, human, cap) {
|
|
const { id } = broker.request(human, { verb: 'message.send', args: { to: 'coder', body: 'work' } });
|
|
broker.request(cap, { verb: 'message.receive' });
|
|
await broker.request(cap, { verb: 'usage.begin', args: { turn: id } });
|
|
await broker.request(cap, { verb: 'usage.end', args: { turn: id } });
|
|
}
|
|
|
|
test('REQ-LIMIT-2 runtime: limits counts the daily quota, and mayLaunch refuses only the account at it', async t => {
|
|
const { bus, human } = await setup(t);
|
|
const [row] = bus.broker.request(human, { verb: 'limits' }).tokens;
|
|
assert.deepEqual({ path: row.path, limit: row.limit, since: row.since, status: row.status, check: row.check, count: row.count },
|
|
{ path: DAILY, limit: 0, since: SINCE, status: 'counted', check: 'daily-quota', count: 0 });
|
|
assert.deepEqual(await bus.mayLaunch({ business: 'demo', instance: 'coder', provider: 'anthropic', model: 'opus', account: 'jason-max' }),
|
|
{ allow: false, check: 'daily-quota', hit: { path: DAILY, limit: 0, count: 0, unknownTurns: 0 } });
|
|
// A pi launch has no account, so no daily quota covers it; the op may also leave it out.
|
|
assert.deepEqual(await bus.mayLaunch({ business: 'demo', instance: 'coder', provider: 'zai', model: 'glm', account: null }), { allow: true });
|
|
assert.deepEqual(await bus.mayLaunch({ business: 'demo', instance: 'coder', provider: 'zai', model: 'glm' }), { allow: true });
|
|
});
|
|
|
|
test('REQ-LIMIT-4 runtime: a run bound with the account writes it on its usage records and stops at the quota', async t => {
|
|
const { bus, human } = await setup(t);
|
|
const { broker } = bus;
|
|
const coder = broker.bindLaunch({ business: 'demo', role: 'coder', run: 'run1', harness: 'claude-code', provider: 'anthropic', model: 'opus', account: 'jason-max' });
|
|
broker.request(coder, { verb: 'role.claim' });
|
|
await turn(broker, human, coder);
|
|
assert.deepEqual(broker.request(human, { verb: 'usage' }).byAccount.map(r => r.account), ['jason-max']);
|
|
assert.throws(() => broker.request(coder, { verb: 'message.receive' }), { code: 'not-holder' });
|
|
assert.deepEqual(bus.endLaunch({ business: 'demo', run: 'run1', reason: 'exited', exitCode: 22 }),
|
|
{ released: false, limit: 'limit: daily-quota tokens.daily.jason-max limit 0 count 0' });
|
|
});
|
|
|
|
test('REQ-LIMIT-4 runtime: a run bound without an account records null and the daily quota never stops it', async t => {
|
|
const { bus, human } = await setup(t);
|
|
const { broker } = bus;
|
|
const coder = broker.bindLaunch({ business: 'demo', role: 'coder', run: 'run1', harness: 'pi', provider: 'zai', model: 'glm' });
|
|
broker.request(coder, { verb: 'role.claim' });
|
|
await turn(broker, human, coder);
|
|
assert.deepEqual(broker.request(human, { verb: 'usage' }).byAccount.map(r => r.account), [null]);
|
|
assert.deepEqual(broker.request(coder, { verb: 'message.receive' }), []);
|
|
});
|
|
|
|
test('REQ-LIMIT-4 bindLaunch keeps the account off session.launched, refuses one that is not an identifier, and takes null as none', t => {
|
|
const root = mkdtempSync(join(tmpdir(), 'mosaic-daily-bind-'));
|
|
const store = new Store(root);
|
|
t.after(() => { store.close(); rmSync(root, { recursive: true, force: true }); });
|
|
const broker = new Broker({ store, 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: [] } }, ...ROLES }, definitions: { coder: {} }, projects: { stack: { root: '/nonexistent' } } } } });
|
|
const base = { business: 'demo', role: 'coder', harness: 'claude-code', provider: 'anthropic', model: 'opus' };
|
|
for (const [i, account] of ['Jason Max', '', 5, {}, '-x'].entries())
|
|
assert.throws(() => broker.bindLaunch({ ...base, run: `bad${i}`, account }), { code: 'invalid-request' }, JSON.stringify(account));
|
|
assert.ok(broker.bindLaunch({ ...base, run: 'none', account: null }));
|
|
assert.ok(broker.bindLaunch({ ...base, run: 'run1', account: 'jason-max' }));
|
|
// The body is what it was before row 126, so a rebind after a broker restart compares the same.
|
|
const { body } = store.get("SELECT body FROM events WHERE kind='session.launched' AND subject='run1'");
|
|
assert.deepEqual(JSON.parse(body), { harness: 'claude-code', address: null, pid: null, startTime: null });
|
|
});
|