Files
stack/packages/cli/tests/proxy-launch-order.test.mjs

286 lines
19 KiB
JavaScript

// Vikunja #774 F1 (row 332 review): with system.proxy set, a launch that can never start refuses in
// the first check, before authorizeLaunch, the workspace and checkouts, and the P2 modelPreflight
// that may issue a key. The first check predicts the route from the harness preflights on a
// stand-in key (R2); only the session proxy key match waits for the admitted key, in the final
// check. Real launcher, bus runtime and runner (managed P2 fixture).
import test from 'node:test';
import assert from 'node:assert/strict';
import fs from 'node:fs';
import { join } from 'node:path';
import { DatabaseSync } from 'node:sqlite';
import { PENDING_ADMISSION_KEY } from '../src/launcher.mjs';
import { sandboxProblem } from '../../seat/src/sandbox.mjs';
import { workspaceDir } from '../../seat/src/session.mjs';
import { managedLaunchFixture } from './model-managed-launch-fixture.mjs';
const skip = sandboxProblem() ?? false;
function editBusiness(f, update) {
const path = join(f.root, 'config', 'businesses', 'acme.json');
const document = JSON.parse(fs.readFileSync(path, 'utf8'));
update(document);
fs.writeFileSync(path, JSON.stringify(document) + '\n', { mode: 0o600 });
}
// A capability the bus issued to a claimed chief, as a launched chief holds.
function chief(f) {
const cap = f.bus.broker.bindLaunch({ business: 'acme', role: 'chief', run: 'chief-774', harness: f.f.doc.roles.chief.vars.harness });
f.bus.broker.request(cap, { verb: 'role.claim' });
return cap;
}
// The refusal came from the first check: nothing after it ran.
function refusedFirst(f, before, preflights, bindings = 0, instance = 'coder') {
assert.equal(f.trace.preflightAttempts, preflights, 'no modelPreflight for a launch the first check refuses');
assert.deepEqual(f.trace.ops.slice(before).filter(op => ['authorizeLaunch', 'credentialStatus', 'modelPreflight'].includes(op)), [],
'no authorizeLaunch, credentialStatus or modelPreflight after the first check');
assert.equal(fs.existsSync(join(workspaceDir(f.f.dataRoot, 'acme', instance), 'stack')), false, 'no checkout clone or fetch');
assert.equal(f.trace.bindings.length, bindings, 'no runner bound for the refused launch');
}
const refusal = (f, code) => f.launchLog().filter(e => e.event === 'refused' && e.code === code);
const claudeCoder = doc => {
doc.launch.models['claude-opus-5-5'].provider = 'anthropic';
doc.roles.coder.vars.model = 'claude-opus-5-5';
};
test('#774 F1 proxy capacity-full refuses in the first check: no modelPreflight, checkout or authorizeLaunch; the ordinary launch before it goes live', { skip, timeout: 60000 }, async t => {
const f = await managedLaunchFixture(t);
const cap = chief(f);
const ordinary = await f.launcher.fromSession(cap, 'reviewer');
assert.equal(ordinary.ok, true, JSON.stringify(ordinary));
assert.ok(f.sessions().find(s => s.run === ordinary.result.run)?.live, 'the ordinary proxy launch is live');
assert.equal(f.trace.preflightAttempts, 1, 'the ordinary proxy launch makes one P2 admission');
editBusiness(f, doc => { doc.launch.limits.total = 1; });
const before = f.trace.ops.length;
assert.deepEqual(await f.launcher.fromSession(cap, 'coder'), { ok: false, error: 'capacity-full' });
refusedFirst(f, before, 1, 1);
assert.deepEqual(refusal(f, 'capacity-full').map(e => e.limit), [{ scope: 'total', limit: 1, running: 1 }]);
f.valueFree();
});
test('#774 F1 proxy limit-reached refuses in the first check: no modelPreflight, checkout or authorizeLaunch', { skip, timeout: 60000 }, async t => {
const f = await managedLaunchFixture(t);
editBusiness(f, doc => {
doc.plugins = { ...doc.plugins, 'limit-check': ['token-limit'] };
doc.launch.limits.tokens = { instances: { coder: { limit: 0, since: '2026-10-18T00:00:00.000Z' } } };
});
const before = f.trace.ops.length;
assert.deepEqual(await f.launcher.fromSession(chief(f), 'coder'), { ok: false, error: 'limit-reached' });
refusedFirst(f, before, 0);
assert.equal(refusal(f, 'limit-reached')[0]?.limit?.check, 'token-limit');
assert.equal(f.runDirectories().length, 0);
f.valueFree();
});
test('#774 F1 proxy sandbox-unavailable refuses in the first check: no modelPreflight, checkout or authorizeLaunch', { skip, timeout: 60000 }, async t => {
const f = await managedLaunchFixture(t, { bwrap: '/nonexistent-774/bwrap' });
const before = f.trace.ops.length;
assert.deepEqual(await f.launcher.fromSession(chief(f), 'coder'), { ok: false, error: 'sandbox-unavailable' });
refusedFirst(f, before, 0);
assert.equal(f.runDirectories().length, 0);
f.valueFree();
});
test('#774 F1 proxy launch.account declared with an upstream credential refuses in the first check, before modelPreflight', { skip, timeout: 60000 }, async t => {
const f = await managedLaunchFixture(t, { harness: 'claude-code' });
editBusiness(f, doc => {
claudeCoder(doc);
doc.launch.account = { name: 'jason-max', credential: 'CLAUDE_CODE_OAUTH_TOKEN' };
});
const before = f.trace.ops.length;
assert.deepEqual(await f.launcher.fromSession(chief(f), 'coder'), { ok: false, error: 'account-credential-missing' });
refusedFirst(f, before, 0);
assert.equal(refusal(f, 'account-credential-missing')[0]?.why, 'account jason-max needs the declared proxy credential');
assert.equal(f.runDirectories().length, 0);
f.valueFree();
});
// The key match needs the admitted key, so it stays in the final check: after modelPreflight,
// before newRun and spawn. The fixture makes P2 admit a key equal to the account name.
test('#774 F1 proxy session key equal to launch.account.name still refuses account-is-credential in the final check', { skip, timeout: 60000 }, async t => {
const f = await managedLaunchFixture(t, { harness: 'claude-code', admit: value => ({ ...value, key: 'jason-max' }) });
editBusiness(f, doc => {
claudeCoder(doc);
doc.launch.account = { name: 'jason-max', credential: 'proxy' };
});
assert.deepEqual(await f.launcher.fromSession(chief(f), 'coder'), { ok: false, error: 'account-is-credential' });
assert.equal(f.trace.preflightAttempts, 1, 'the first check passed and P2 admitted a key');
assert.equal(f.trace.ops.filter(op => op === 'authorizeLaunch').length, 1);
assert.equal(refusal(f, 'account-is-credential')[0]?.why, 'launch.account.name is the value of session proxy key; it names the account, never its credential');
assert.equal(f.trace.bindings.length, 0);
assert.equal(f.sessions().length, 0);
assert.equal(f.runDirectories().length, 0, 'refused before newRun');
f.valueFree();
});
// Row 333: under a daily key quota the bus refuses mayLaunch key-quota-no-model-key for an agent
// with no model key. In the first check that is the one answer that waits for P2 to issue a key.
test('#774 F1 proxy launch of an agent with no key yet passes the first check under a daily key quota, and both checks ask mayLaunch', { skip, timeout: 60000 }, async t => {
const f = await managedLaunchFixture(t);
editBusiness(f, doc => {
doc.plugins = { ...doc.plugins, 'limit-check': ['token-limit'] };
doc.launch.limits.tokens = { keys: { '000000000774': { limit: 1000000, since: '2026-10-18T00:00:00.000Z', reset: '00:00', timeZone: 'UTC' } } };
});
assert.equal(f.bus.credentials.modelRecord('acme/chief'), null, 'chief holds no model key yet');
const answer = await f.launcher.launchPm();
assert.ok(f.sessions().find(s => s.run === answer.run)?.live, 'the launch goes live');
assert.equal(f.trace.successfulPreflights, 1);
assert.equal(f.trace.ops.filter(op => op === 'mayLaunch').length, 2, 'mayLaunch in the first and the final check');
f.valueFree();
});
// #774 R2: the first check gates the route the final check picks. The coder's primary is the real
// claude-code module on claude-opus-5-5 (provider anthropic); MOSAIC_CLAUDE_BIN decides whether its
// preflight passes. The stated fallback is pi on glm-5.3-flash (provider zai).
const NO_CLAUDE = '/nonexistent-774/claude';
const NO_CLAUDE_WHY = `MOSAIC_CLAUDE_BIN ${NO_CLAUDE} isn't an executable file at an absolute path`;
const routed = (t, bin) => managedLaunchFixture(t, { harness: 'claude-code', extra: ['pi'], real: ['claude-code'], hostEnv: { MOSAIC_CLAUDE_BIN: bin } });
const withFallback = (doc, harness = 'pi', model = 'glm-5.3-flash') => {
claudeCoder(doc);
doc.roles.coder.vars = { ...doc.roles.coder.vars, 'fallback.harness': harness, 'fallback.model': model, 'fallback.thinking': 'high' };
};
const full = (doc, provider, model) => { doc.launch.limits.models = { ...doc.launch.limits.models, [provider]: { ...doc.launch.limits.models?.[provider], [model]: 0 } }; };
const launched = (f, run) => f.launchLog().find(e => e.event === 'launch' && e.run === run);
test('#774 R2 a healthy primary at capacity zero refuses capacity-full in the first check, though the fallback has room', { skip, timeout: 60000 }, async t => {
const f = await routed(t, process.execPath);
editBusiness(f, doc => { withFallback(doc); full(doc, 'anthropic', 'claude-opus-5-5'); });
const before = f.trace.ops.length;
assert.deepEqual(await f.launcher.fromSession(chief(f), 'coder'), { ok: false, error: 'capacity-full' });
assert.deepEqual(refusal(f, 'capacity-full').map(e => e.limit), [{ scope: 'model', limit: 0, running: 0, provider: 'anthropic', model: 'claude-opus-5-5' }]);
refusedFirst(f, before, 0);
assert.equal(f.runDirectories().length, 0);
f.valueFree();
});
test('#774 R2 a failed primary preflight with a stated fallback launches on the fallback, route fallback, reason harness-binary-missing', { skip, timeout: 60000 }, async t => {
const f = await routed(t, NO_CLAUDE);
editBusiness(f, doc => withFallback(doc));
const answer = await f.launcher.fromSession(chief(f), 'coder');
assert.equal(answer.ok, true, JSON.stringify(answer));
assert.deepEqual(answer.result, { run: answer.result.run, instance: 'coder', harness: 'pi', model: 'glm-5.3-flash' });
assert.ok(f.sessions().find(s => s.run === answer.result.run)?.live, 'the fallback launch is live');
const event = launched(f, answer.result.run);
assert.deepEqual([event?.harness, event?.route, event?.routeReason, event?.provider, event?.model], ['pi', 'fallback', 'harness-binary-missing', 'zai', 'glm-5.3-flash']);
assert.equal(f.trace.successfulPreflights, 1);
assert.equal(f.trace.ops.filter(op => op === 'authorizeLaunch').length, 1);
f.valueFree();
});
test('#774 R2 a failed primary preflight at capacity zero still launches on the fallback: the first check gates the predicted route', { skip, timeout: 60000 }, async t => {
const f = await routed(t, NO_CLAUDE);
editBusiness(f, doc => { withFallback(doc); full(doc, 'anthropic', 'claude-opus-5-5'); });
const answer = await f.launcher.fromSession(chief(f), 'coder');
assert.equal(answer.ok, true, JSON.stringify(answer));
assert.ok(f.sessions().find(s => s.run === answer.result.run)?.live, 'the fallback launch is live');
const event = launched(f, answer.result.run);
assert.deepEqual([event?.harness, event?.route, event?.routeReason], ['pi', 'fallback', 'harness-binary-missing']);
assert.equal(refusal(f, 'capacity-full').length, 0);
f.valueFree();
});
test('#774 R2 a failed primary preflight and a fallback at capacity zero refuse capacity-full for the fallback in the first check', { skip, timeout: 60000 }, async t => {
const f = await routed(t, NO_CLAUDE);
editBusiness(f, doc => { withFallback(doc); full(doc, 'zai', 'glm-5.3-flash'); });
const before = f.trace.ops.length;
assert.deepEqual(await f.launcher.fromSession(chief(f), 'coder'), { ok: false, error: 'capacity-full' });
assert.deepEqual(refusal(f, 'capacity-full').map(e => e.limit), [{ scope: 'model', limit: 0, running: 0, provider: 'zai', model: 'glm-5.3-flash' }]);
refusedFirst(f, before, 0);
assert.equal(f.runDirectories().length, 0);
f.valueFree();
});
test('#774 R2 when both preflights fail the first check refuses with the final check\'s combined code and message', { skip, timeout: 60000 }, async t => {
const f = await routed(t, NO_CLAUDE);
editBusiness(f, doc => withFallback(doc, 'claude-code', 'claude-sonnet-5-5'));
const before = f.trace.ops.length;
assert.deepEqual(await f.launcher.fromSession(chief(f), 'coder'), { ok: false, error: 'harness-binary-missing' });
assert.deepEqual(refusal(f, 'harness-binary-missing').map(e => e.why), [`fallback claude-code: ${NO_CLAUDE_WHY} (primary claude-code: ${NO_CLAUDE_WHY})`]);
refusedFirst(f, before, 0);
assert.equal(f.runDirectories().length, 0);
f.valueFree();
});
test('#774 R2 a failed primary preflight with no fallback refuses harness-binary-missing in the first check', { skip, timeout: 60000 }, async t => {
const f = await routed(t, NO_CLAUDE);
editBusiness(f, claudeCoder);
const before = f.trace.ops.length;
assert.deepEqual(await f.launcher.fromSession(chief(f), 'coder'), { ok: false, error: 'harness-binary-missing' });
assert.deepEqual(refusal(f, 'harness-binary-missing').map(e => e.why), [NO_CLAUDE_WHY]);
refusedFirst(f, before, 0);
assert.equal(f.runDirectories().length, 0);
f.valueFree();
});
// Both preflights of the first check saw the stand-in key; none of it reaches the evidence.
test('#774 R2 the stand-in key never reaches the launch log, the authorization record, session.json or the data root', { skip, timeout: 60000 }, async t => {
assert.equal(typeof PENDING_ADMISSION_KEY === 'string' && PENDING_ADMISSION_KEY.length > 0, true);
const f = await routed(t, NO_CLAUDE);
editBusiness(f, doc => withFallback(doc));
const answer = await f.launcher.fromSession(chief(f), 'coder');
assert.equal(answer.ok, true, JSON.stringify(answer));
assert.ok(f.sessions().find(s => s.run === answer.result.run)?.live, 'the fallback launch is live');
const absent = (what, value) => assert.equal(String(value).includes(PENDING_ADMISSION_KEY), false, `the stand-in key reached ${what}`);
const log = f.launchLog();
assert.ok(launched(f, answer.result.run), 'the launch log holds the launch');
absent('the launch log', JSON.stringify(log));
const db = new DatabaseSync(join(f.f.dataRoot, 'bus', 'bus.sqlite'), { readOnly: true });
let events;
try { events = db.prepare('SELECT kind, subject, body FROM events ORDER BY seq').all(); } finally { db.close(); }
assert.equal(events.filter(e => e.kind === 'action.allowed' && JSON.parse(e.body).action === 'role.launch').length, 1, 'one authorization record for the launch');
absent('the bus events', JSON.stringify(events));
const session = join(f.runDirectories().find(d => d.endsWith(`/${answer.result.run}`)), 'session.json');
assert.ok(fs.existsSync(session), 'the run has a session.json');
absent('session.json', fs.readFileSync(session, 'utf8'));
absent('the host log', JSON.stringify(f.logs));
absent('the trace', JSON.stringify(f.trace));
// Every regular file under the data root, the bus database and its WAL included.
const files = fs.readdirSync(f.f.dataRoot, { recursive: true, withFileTypes: true }).filter(e => e.isFile()).map(e => join(e.parentPath, e.name));
assert.ok(files.length > 0);
for (const file of files) {
let bytes;
try { bytes = fs.readFileSync(file); } catch (e) { if (e.code === 'ENOENT') continue; throw e; }
absent(file, bytes);
}
f.valueFree();
});
test('a removed catalogue model is refused by final admission before newRun', { skip, timeout: 60000 }, async t => {
let reads=0;
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 modelCatalogue={invalidate(){},read:async()=>({status:'ready',observedAt:'2026-11-06T00:00:00.000Z',models:++reads===1?[offered]:[],notices:[]})};
const f=await managedLaunchFixture(t,{modelCatalogue});
editBusiness(f,doc=>{doc.plugins['model-provider']=['cliproxy'];doc.launch.models['zai-fixture-id']={provider:'zai',model:'fixture-id',module:'cliproxy',upstream:'zai'};doc.roles.coder.vars.model='zai-fixture-id';});
const result=await f.launcher.fromSession(chief(f),'coder');
assert.deepEqual(result,{ok:false,error:'model-provider-unavailable'});
assert.equal(reads,2);assert.equal(f.trace.preflightAttempts,1);assert.equal(f.runDirectories().length,0);assert.equal(f.trace.bindings.length,0);
});
test('fixture catalogue route persists, launches, and then refuses after model removal', { skip, timeout: 60000 }, async t => {
let present=true;
const offered={key:'zai-fixture-id',module:'cliproxy',upstream:'zai',provider:'zai',model:'fixture-id',label:'z.ai / fixture-id',available:true,reason:null,harnesses:['pi']};
const modelCatalogue={invalidate(){},read:async()=>({status:'ready',observedAt:'2026-11-06T00:00:00.000Z',models:present?[offered]:[],notices:[]})};
const f=await managedLaunchFixture(t,{modelCatalogue});
editBusiness(f,doc=>{doc.plugins['model-provider']=['cliproxy'];});
const human=f.bus.broker.bindHuman({business:'acme',human:'jason',via:'cli',outsideAgent:true});
const before=await f.bus.broker.request(human,{verb:'routes'});
assert.equal(before.models.includes(offered.key),false);assert.equal(before.catalogue.models[0].key,offered.key);
const route={harness:'pi',model:offered.key,thinking:'low',fallback:null};
await f.bus.broker.request(human,{verb:'routes.set',args:{revision:before.revision,routes:{coder:route,reviewer:route}}});
const doc=JSON.parse(fs.readFileSync(join(f.root,'config/businesses/acme.json'),'utf8'));
assert.deepEqual(doc.launch.models[offered.key],{provider:'zai',model:'fixture-id',module:'cliproxy',upstream:'zai'});
const cap=chief(f);const launched=await f.launcher.fromSession(cap,'coder');
assert.equal(launched.ok,true,JSON.stringify(launched));
const session=f.sessions().find(x=>x.run===launched.result.run);assert.equal(session.provider,'zai');assert.equal(session.model,'fixture-id');
present=false;const after=await f.bus.broker.request(human,{verb:'routes'});
assert.equal(after.instances.reviewer.model,offered.key);assert.equal(after.catalogue.models.length,0);
assert.deepEqual(await f.launcher.fromSession(cap,'reviewer'),{ok:false,error:'model-provider-unavailable'});
});
test('business revision changed during final limit check refuses before creating a run', { skip, timeout: 60000 }, async t => {
let currentModel='fixture-old';
const modelCatalogue={invalidate(){},read:async()=>({status:'ready',observedAt:'2026-11-06T00:00:00.000Z',models:[{key:`zai-${currentModel}`,module:'cliproxy',upstream:'zai',provider:'zai',model:currentModel,label:currentModel,available:true,reason:null,harnesses:['pi']}],notices:[]})};
const f=await managedLaunchFixture(t,{modelCatalogue});
editBusiness(f,doc=>{doc.plugins['model-provider']=['cliproxy'];doc.launch.models['legacy-fixture']={provider:'zai',model:'fixture-old'};doc.roles.coder.vars.model='legacy-fixture';});
const human=f.bus.broker.bindHuman({business:'acme',human:'jason',via:'cli',outsideAgent:true});
const original=f.bus.mayLaunch; let count=0;
f.bus.mayLaunch=async request=>{const answer=await original(request);if(++count===2){currentModel='fixture-new';const view=f.bus.broker.request(human,{verb:'limits'});const models=structuredClone(view.models);models['legacy-fixture'].model=currentModel;await f.bus.broker.request(human,{verb:'limits.set',args:{revision:view.revision,models}});}return answer;};
assert.deepEqual(await f.launcher.fromSession(chief(f),'coder'),{ok:false,error:'model-provider-unavailable'});
assert.equal(f.runDirectories().length,0);assert.equal(f.trace.bindings.length,0);
});