Files
stack/packages/bus/tests/usage-broker.test.mjs
jason.woltjeandClaude Opus 5.5 70504d23a4 bus, cli, webui: token accounting per run, schema 3h usage_records (row 124, #1618)
Rocko's round 2 candidate e09313aba4d155a1c5af7bfb227ec397e96c0d57444782cd0b48593102bcc684
(38 paths, base 23533625d), approved by Dewey in #1618 comment 28923 (queue rev 1757).
Packet: agents/rocko/work/queue-124/r2/.

- Schema 3g to 3h: packages/bus/src/migrations/3g-3h.sql adds an append-only
  usage_records table; nothing earlier changes. usage_records is in timedTables.
- The transcript usage-source module reads token counts from Pi and Claude
  Code session transcripts and follows no symlink.
- `mosaic usage` in the CLI and a read-only usage section in the Console's
  Settings (one GET route; 400 on a query string).

Decision 123 go: Mos, mos-0737. Activation (3g to 3h) is a migrating run
with Jason present, in Mos's combined re-pin; landing changes nothing live.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-18 11:08:17 -05:00

31 lines
2.3 KiB
JavaScript

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';
test('REQ-LIMIT-4 usage protocol binds run identity, requires a delivered turn and isolates businesses', async t => {
const root = mkdtempSync(join(tmpdir(), 'usage-broker-'));
const store = new Store(root); t.after(() => { store.close(); rmSync(root, { recursive: true, force: true }); });
const businesses = { demo: { id: 'demo', human: 'jason', roles: { coder: { definition: 'coder', authority: { withinRole: [], crossRole: [] } } }, arbiters: { technical: 'coder', delivery: 'coder' } } };
const recorded = [];
const broker = new Broker({ store, businesses, usage: {
collect: async (...args) => { recorded.push(args); return { recorded: true }; },
view: business => ({ business }),
} });
const coder = broker.bindLaunch({ business: 'demo', role: 'coder', run: 'run1', harness: 'pi', provider: 'fixture', model: 'custom-model' });
broker.request(coder, { verb: 'role.claim' });
const human = broker.bindHuman({ business: 'demo', human: 'jason', via: 'cli', outsideAgent: true });
const { id } = broker.request(human, { verb: 'message.send', args: { to: 'coder', body: 'Work' } });
await assert.rejects(broker.request(coder, { verb: 'usage.begin', args: { turn: id } }), { code: 'not-recipient' });
broker.request(coder, { verb: 'message.receive' });
for (const phase of ['begin', 'end']) assert.deepEqual(await broker.request(coder, { verb: `usage.${phase}`, args: { turn: id } }), { recorded: true });
assert.equal(recorded.length, 2); assert.equal(recorded[0][0].run, 'run1');
assert.equal(recorded[0][0].provider, 'fixture'); assert.equal(recorded[0][0].model, 'custom-model');
await assert.rejects(broker.request(coder, { verb: 'usage.end', args: { turn: id, root: '/etc' } }), { code: 'invalid-request' });
await assert.rejects(broker.request(human, { verb: 'usage.begin', args: { turn: id } }), { code: 'agent-required' });
assert.deepEqual(broker.request(broker.bindReader({ business: 'demo' }), { verb: 'usage' }), { business: 'demo' });
assert.throws(() => broker.request(human, { verb: 'usage', args: { business: 'other' } }), /invalid-request/);
});