Files
stack/packages/bus/tests/p5-key-compatibility.test.mjs
jason.woltje a8d9eecf65 organization: move packages/business to packages/organization (rename r2 stage B1)
git mv packages/business -> packages/organization (@mosaic/organization). The
old package stays as one-line re-export shims of each moved module, with
src/business.mjs re-exporting src/organization-config.mjs and src/cli.mjs
forwarding to the moved executable. BusinessError is OrganizationConfigError
(one constructor, name kept BusinessError); OrganizationError stays distinct.
The bus adapter gains organization-context.mjs (busOrganization), with
business.mjs (busBusiness) as the same function.

Import consumers, manifests, the lockfile, scripts/mosaic, stack-copy.sh
COPY_PATHS (both roots), seat sandbox RUNNER_FILES and the copy closure
walker (organization-imports.mjs, both roots required) move to the new path.
v1 serialization, v1 writers and the stage A fixtures are unchanged; the stage
A contract tests stay where they were and pass as before.
2026-11-09 11:47:48 -06:00

69 lines
6.3 KiB
JavaScript

import test from 'node:test';
import assert from 'node:assert/strict';
import { mkdtempSync, rmSync, readFileSync } from 'node:fs';
import { tmpdir } from 'node:os';
import { join } from 'node:path';
import { Store } from '../src/store.mjs';
import { createLimits, modelUsageKey } from '../src/limits.mjs';
import * as token from '../../plugins/limit-check/token-limit/index.mjs';
import * as daily from '../../plugins/limit-check/daily-quota/index.mjs';
import { launchSettings } from '../../organization/src/launch-settings.mjs';
import { businessDoc, rolesCopy, writeJson, systemFor } from '../../organization/tests/helpers.mjs';
const key='abcdefabcdef',other='012345abcdef',since='2026-01-01T00:00:00.000Z';
const quota={limit:10,since,reset:'00:00',timeZone:'UTC'};
const native={at:'2026-10-26T12:00:00.000Z',run:'legacy-run',turn:'turn',account:key,modelKeyId:other,status:'known',input:10,output:0,cacheWrite:0,cacheRead:0};
test('P5 R1 plain twelve-hex account leaves retain matching and original account report even with another model ID',()=>{
const a={limits:{tokens:{keys:{[key]:{limit:10,since}}}},subject:{account:key,modelKeyId:other},records:[native]};
assert.equal(token.mayLaunch(a).allow,false);assert.equal(token.mustStop(a).stop,true);
assert.equal(token.report(a)[0].count,10);assert.deepEqual(token.report(a)[0].path,['tokens','keys',key]);
assert.equal(token.mayLaunch({...a,records:[{...native,input:9}]}).allow,true);
assert.deepEqual(daily.report({...a,now:native.at}),[]);
});
for(const proxy of [false,true])test(`P5 R1 legacy account core lookup stays independent of ${proxy?'unrelated proxy metadata':'missing proxy metadata'}`,async t=>{
const root=mkdtempSync(join(tmpdir(),'p5-legacy-')),store=new Store(root);t.after(()=>{store.close();rmSync(root,{recursive:true,force:true});});
let lookups=0;
const b={launch:{account:{name:key,credential:'FAKE_TOKEN_NAME'},limits:{tokens:{keys:{[key]:{limit:10,since}}}}},plugins:{'limit-check':['token-limit']}};
const limits=createLimits({store,read:()=>b,log:()=>{},keyForSubject:(...args)=>{lookups++;return proxy?modelUsageKey([{service:'model',instance:'demo/coder',keyId:other,retiring:[]}],new Map(),'demo',args[1]):null;}});
assert.deepEqual(await limits.mayLaunch('demo',{instance:'coder',account:key}),{allow:true});
store.run(`INSERT INTO usage_records(at,business,run,instance,account,turn,source,phase,status,cursor,input,output,cache_write,cache_read)
VALUES (?,'demo','legacy-run','coder',?,'turn','transcript','end','known',?,10,0,0,0)`,native.at,key,JSON.stringify({modelKeyId:other}));
const hit={path:['tokens','keys',key],limit:10,count:10,unknownTurns:0};
assert.deepEqual(await limits.mayLaunch('demo',{instance:'coder',account:key}),{allow:false,check:'token-limit',hit});
assert.deepEqual(await limits.mustStop('demo',{instance:'coder',account:key}),{stop:true,check:'token-limit',hit});
assert.equal(limits.report('demo')[0].count,10);assert.equal(lookups,0);
});
for(const leaf of [{limit:0,since},quota])test(`P5 R1 empty checks bypass model metadata for ${leaf.reset?'daily model':'legacy hex account'} leaves`,async t=>{
const root=mkdtempSync(join(tmpdir(),'p5-no-checks-')),store=new Store(root);t.after(()=>{store.close();rmSync(root,{recursive:true,force:true});});
let lookups=0;const limits=createLimits({store,read:()=>({plugins:{'limit-check':[]},launch:{limits:{tokens:{keys:{[key]:leaf}}}}}),log:()=>{},keyForSubject:()=>{lookups++;throw Error('MUST-NOT-LOOK-UP');}});
assert.deepEqual(await limits.mayLaunch('demo',{instance:'coder',account:key}),{allow:true});
assert.deepEqual(await limits.mustStop('demo',{instance:'coder',account:key}),{stop:false});assert.equal(lookups,0);
});
test('P5 R1 legacy hex account chief resets stay allowed; daily model old/new/removal/reset transitions stay human-only',t=>{
const root=mkdtempSync(join(tmpdir(),'p5-fence-'));t.after(()=>rmSync(root,{recursive:true,force:true}));
const rolesDir=rolesCopy(root),doc=businessDoc(root,'demo'),file=join(root,'businesses/demo.json');
doc.launch.account={name:key,credential:'FAKE_TOKEN_NAME'};doc.launch.limits={tokens:{keys:{[key]:{limit:10,since}}}};writeJson(file,doc);
let now='2026-10-26T12:00:00.000Z';const settings=launchSettings({dir:root,rolesDir,system:systemFor(root),now:()=>now});let v=settings.read('demo');
v=settings.set('demo',{revision:v.revision,reset:[['tokens','keys',key]]},'chief');
assert.equal(JSON.parse(readFileSync(file,'utf8')).launch.limits.tokens.keys[key].since,now);
const dailyLeaf={limit:10,reset:'00:00',timeZone:'UTC'};
assert.throws(()=>settings.set('demo',{revision:v.revision,limits:{tokens:{keys:{[key]:dailyLeaf}}}},'chief'),{code:'organization-model-quota-human-only'});
v=settings.set('demo',{revision:v.revision,limits:{tokens:{keys:{[key]:dailyLeaf}}}},'jason');now='2026-10-26T13:00:00.000Z';
for(const args of [{reset:[['tokens','keys',key]]},{limits:{}},{limits:{tokens:{keys:{[key]:{limit:10}}}}}])
assert.throws(()=>settings.set('demo',{revision:v.revision,...args},'chief'),{code:'organization-model-quota-human-only'});
v=settings.set('demo',{revision:v.revision,limits:{tokens:{keys:{[key]:{limit:10}}}}},'jason');
v=settings.set('demo',{revision:v.revision,reset:[['tokens','keys',key]]},'chief');
assert.equal(JSON.parse(readFileSync(file,'utf8')).launch.limits.tokens.keys[key].since,now);
});
test('P5 R1 daily model matching/report is separate from legacy account and schema refuses partial or invalid daily shapes',async()=>{
const {checkTokenLimits}=await import('../../organization/src/launch.mjs');
assert.deepEqual(checkTokenLimits({keys:{[key]:quota}}).keys[key],quota);
const args={limits:{tokens:{keys:{[key]:quota}}},records:[native],subject:{account:key,modelKeyId:other},now:native.at,lineages:[[key],[other]]};
assert.deepEqual(token.report(args),[]);
assert.equal(daily.mayLaunch(args).allow,true);assert.equal(daily.report(args)[0].count,0);
const owned={...args,subject:{account:'other-account',modelKeyId:key},records:[{...native,account:'other-account',modelKeyId:key}]};
assert.equal(daily.mayLaunch(owned).allow,false);assert.equal(daily.mustStop(owned).stop,true);assert.equal(daily.report(owned)[0].count,10);
for(const leaf of [{...quota,reset:'25:00'},{...quota,timeZone:'Mars/Phobos'},{limit:10,since,reset:'00:00'},{limit:10,since,timeZone:'UTC'}])
assert.throws(()=>checkTokenLimits({keys:{[key]:leaf}}));
});