// P5 end-to-end within one process: only fresh fake config, credentials and loopback HTTP. import test from 'node:test'; import assert from 'node:assert/strict'; import http from 'node:http'; import { createHash, randomBytes } from 'node:crypto'; import { mkdtempSync, mkdirSync, writeFileSync, readFileSync, rmSync } from 'node:fs'; import { tmpdir } from 'node:os'; import { join } from 'node:path'; import { startBroker } from '../src/runtime.mjs'; import { Registry } from '../../seat/src/session.mjs'; import { startTimeOf } from '../../seat/src/proc.mjs'; import { businessDoc, rolesCopy, systemFor, writeJson } from '../../organization/tests/helpers.mjs'; const hash=s=>createHash('sha256').update(s).digest('hex').slice(0,12); test('P5 real runtime binds stack usage to issued key, daily stops at stack count and human-only telemetry settings pass broker contract',async t=>{ const root=mkdtempSync(join(tmpdir(),'p5-runtime-')),config=join(root,'config'),data=join(root,'data'); mkdirSync(config,{mode:0o700});mkdirSync(data,{mode:0o700});const rolesDir=rolesCopy(config),doc=businessDoc(config,'demo'); doc.plugins={'usage-source':['transcript'],'limit-check':['daily-quota'],harness:['pi']}; writeJson(join(config,'businesses/demo.json'),doc);mkdirSync(join(config,'secrets'),{recursive:true,mode:0o700}); writeFileSync(join(config,'secrets/proxy-management.key'),'p5-fake-management',{mode:0o600}); new Registry(data); let keys=[`msk-${hash(config)}-sentinel-${randomBytes(32).toString('base64url')}`],queue=[],calls=[]; const server=http.createServer(async(req,res)=>{ calls.push(req.url); if(req.url==='/v8/management/config/access/api-keys') { if(req.method==='PUT'){let b='';for await(const c of req)b+=c;keys=JSON.parse(b);res.end('{"status":"ok"}');} else res.end(JSON.stringify(keys));return; } if(req.url==='/v8/management/observability/usage/queue?count=100'){res.end(JSON.stringify(queue));queue=[];return;} res.writeHead(keys.includes(req.headers.authorization?.slice(7))?200:401);res.end('{}'); }); await new Promise(r=>server.listen(0,'127.0.0.1',r));let bus; t.after(async()=>{await bus?.close();await new Promise(r=>server.close(r));rmSync(root,{recursive:true,force:true});}); bus=await startBroker({dataRoot:data,businesses:{demo:{id:'demo',human:'jason',plugins:doc.plugins,arbiters:{technical:'chief',delivery:'chief'},roles:{chief: { definition: 'chief-of-staff', authority: { withinRole: ['decision.resolve.technical', 'decision.resolve.delivery'], crossRole: [] } }, coder:{definition:'coder',authority:{withinRole:[],crossRole:[]}}}}}, organization:{dir:config,rolesDir,system:systemFor(config)},proxy:{port:server.address().port,binary:'/fixture-unused'}}); assert.equal(calls.some(p=>p.includes('usage/queue')),false); const model=await bus.modelPreflight({business:'demo',role:'coder'}),keyId=hash(model.key); const human=bus.broker.bindHuman({business:'demo',human:'jason',via:'cli',outsideAgent:true}); let limits=bus.broker.request(human,{verb:'limits'}); bus.broker.request(human,{verb:'limits.set',args:{revision:limits.revision,limits:{tokens:{keys:{[keyId]:{limit:2,reset:'00:00',timeZone:'UTC'}}}}}}); assert.equal((await bus.mayLaunch({business:'demo',instance:'coder',provider:'fixture',model:'fake'})).allow,true); const dir=join(root,'transcript');mkdirSync(dir); const {cap}=bus.bindLaunch({business:'demo',role:'coder',run:'p5-run',harness:'pi',modelKeyId:keyId,transcript:dir,pid:process.pid,startTime:startTimeOf(process.pid)}); bus.broker.request(cap,{verb:'role.claim'}); const {id}=bus.broker.request(human,{verb:'message.send',args:{to:'coder',body:'fake work'}}); bus.broker.request(cap,{verb:'message.receive'}); await bus.broker.request(cap,{verb:'usage.begin',args:{turn:id}}); writeFileSync(join(dir,'s.jsonl'),JSON.stringify({type:'message',id:'fake',message:{role:'assistant',usage:{input:2,output:0,cacheWrite:0,cacheRead:0}}})+'\n'); await bus.broker.request(cap,{verb:'usage.end',args:{turn:id}}); const view=bus.broker.request(human,{verb:'usage'});assert.equal(view.byKey[0].modelKeyId,keyId);assert.equal(view.byKey[0].input,2); assert.equal((await bus.mayLaunch({business:'demo',instance:'coder',provider:'fixture',model:'fake'})).allow,false); assert.throws(()=>bus.broker.request(cap,{verb:'message.receive'}),{code:'not-holder'}); let plugins=bus.broker.request(human,{verb:'plugins'}); plugins=bus.broker.request(human,{verb:'plugins.set',args:{revision:plugins.revision,plugins:{usage:'cliproxy-queue'},usage:{cliproxyQueue:{pollSeconds:7}}}}); assert.equal(plugins.plugins.usage,'cliproxy-queue');assert.equal(plugins.usage.cliproxyQueue.pollSeconds,7); const history=readFileSync(join(config,'businesses/.history/demo/changes.jsonl'),'utf8'); for(const value of [model.key,'p5-fake-management'])assert.equal(JSON.stringify([view,history]).includes(value),false); }); // Row 333 R4 (#1831): the writer the runtime builds keeps a moved quota's since through the runtime's // own key lineage lookup. The runtime keeps its ModelKeys inside, so the move follows a re-issue: the // fake proxy stops listing A and the next preflight issues B with A among its earlier ids. test('R4 real runtime: a quota spent on A and moved to B with no reset still refuses the next launch', async t => { const root=mkdtempSync(join(tmpdir(),'p5-runtime-')),config=join(root,'config'),data=join(root,'data'); mkdirSync(config,{mode:0o700});mkdirSync(data,{mode:0o700});const rolesDir=rolesCopy(config),doc=businessDoc(config,'demo'); doc.plugins={'usage-source':['transcript'],'limit-check':['daily-quota'],harness:['pi']}; writeJson(join(config,'businesses/demo.json'),doc);mkdirSync(join(config,'secrets'),{recursive:true,mode:0o700}); writeFileSync(join(config,'secrets/proxy-management.key'),'p5-fake-management',{mode:0o600}); new Registry(data); let keys=[`msk-${hash(config)}-sentinel-${randomBytes(32).toString('base64url')}`]; const server=http.createServer(async(req,res)=>{ if(req.url==='/v8/management/config/access/api-keys') { if(req.method==='PUT'){let b='';for await(const c of req)b+=c;keys=JSON.parse(b);res.end('{"status":"ok"}');} else res.end(JSON.stringify(keys));return; } if(req.url==='/v8/management/observability/usage/queue?count=100'){res.end('[]');return;} res.writeHead(keys.includes(req.headers.authorization?.slice(7))?200:401);res.end('{}'); }); await new Promise(r=>server.listen(0,'127.0.0.1',r));let bus; t.after(async()=>{await bus?.close();await new Promise(r=>server.close(r));rmSync(root,{recursive:true,force:true});}); bus=await startBroker({dataRoot:data,businesses:{demo:{id:'demo',human:'jason',plugins:doc.plugins,arbiters:{technical:'chief',delivery:'chief'},roles:{chief: { definition: 'chief-of-staff', authority: { withinRole: ['decision.resolve.technical', 'decision.resolve.delivery'], crossRole: [] } }, coder:{definition:'coder',authority:{withinRole:[],crossRole:[]}}}}}, organization:{dir:config,rolesDir,system:systemFor(config)},proxy:{port:server.address().port,binary:'/fixture-unused'}}); const stored=()=>JSON.parse(readFileSync(join(config,'businesses/demo.json'),'utf8')).launch.limits.tokens.keys; const may=async()=>(await bus.mayLaunch({business:'demo',instance:'coder',provider:'fixture',model:'fake'})).allow; const a=await bus.modelPreflight({business:'demo',role:'coder'}),A=hash(a.key); const human=bus.broker.bindHuman({business:'demo',human:'jason',via:'cli',outsideAgent:true}); const leaf={limit:2,reset:'00:00',timeZone:'UTC'}; let limits=bus.broker.request(human,{verb:'limits'}); limits=bus.broker.request(human,{verb:'limits.set',args:{revision:limits.revision,limits:{tokens:{keys:{[A]:{...leaf}}}}}}); const since=stored()[A].since;assert.equal(await may(),true); // The agent spends the whole allowance on A. const dir=join(root,'transcript');mkdirSync(dir); const {cap}=bus.bindLaunch({business:'demo',role:'coder',run:'r4-run',harness:'pi',modelKeyId:A,transcript:dir,pid:process.pid,startTime:startTimeOf(process.pid)}); bus.broker.request(cap,{verb:'role.claim'}); const {id}=bus.broker.request(human,{verb:'message.send',args:{to:'coder',body:'fake work'}}); bus.broker.request(cap,{verb:'message.receive'}); await bus.broker.request(cap,{verb:'usage.begin',args:{turn:id}}); writeFileSync(join(dir,'s.jsonl'),JSON.stringify({type:'message',id:'fake',message:{role:'assistant',usage:{input:2,output:0,cacheWrite:0,cacheRead:0}}})+'\n'); await bus.broker.request(cap,{verb:'usage.end',args:{turn:id}}); assert.equal(await may(),false); // The proxy loses A, so the next preflight issues B; then the human moves the unchanged quota to B. keys=keys.filter(k=>k!==a.key); const b=await bus.modelPreflight({business:'demo',role:'coder'}),B=hash(b.key);assert.notEqual(B,A); await new Promise(r=>setTimeout(r,20)); // a fresh `now` would fall after the turn's record limits=bus.broker.request(human,{verb:'limits'}); bus.broker.request(human,{verb:'limits.set',args:{revision:limits.revision,limits:{tokens:{keys:{[B]:{...leaf}}}}}}); assert.deepEqual(stored(),{[B]:{...leaf,since}}); const report=bus.broker.request(human,{verb:'limits'}); assert.equal(JSON.stringify(report).includes(a.key)||JSON.stringify(report).includes(b.key),false); assert.equal(await may(),false); });