// Row 65 (#1558, REQ-PLUG-2, Q156): the launcher takes a launch's route from the instance's // harness, model and thinking vars and its harness from the plug-in loader. A stub host answers // the ops, as in launch-limit-checks: mayLaunch records the route's provider, model and account, // and authorizeLaunch stops the launch before anything spawns. The fixture modules live in a // scratch plug-in tree; no core file names them. import test from 'node:test'; import assert from 'node:assert/strict'; import {readFileSync} from 'node:fs'; import {createLauncher} from '../src/launcher.mjs'; import {initializeControl} from '../../processing-control/src/state.mjs'; import {fakeHarnesses,fixture,tmp,withoutHostCredentials} from './helpers.mjs'; import {launchLogFile,SESSION_CREDENTIALS} from '../../seat/src/session.mjs'; const PI=JSON.stringify(new URL('../../plugins/harness/pi/index.mjs',import.meta.url).href); // down fails its preflight; sparse takes one thinking level; metered spends launch.account; broken // lacks the kind's exports; throws throws from its preflight. Each is the pi module otherwise. const MODULES={ down:`export * from ${PI};\nexport const preflight = () => ({ code: "fixture-down", message: "fixture preflight fails" });\n`, sparse:`export * from ${PI};\nexport const levels = () => ["low"];\n`, metered:`export * from ${PI};\nexport const countsAccount = () => true;\n`, broken:'export const interfaceVersion = 1;\nexport const adapter = () => "/nowhere";\n', throws:`export * from ${PI};\nexport function preflight() { throw new Error("fixture preflight threw"); }\n`, }; const ON=['pi','claude-code','down','sparse','metered','broken','throws','absent']; // vars are the coder's whole agent vars; edit changes the rest of the file. async function setup(t,vars,{on=ON,edit=doc=>doc,env:more={},modelAdmission=null}={}){ const root=tmp(t),f=fixture(root,'acme',doc=>{doc.roles.coder.vars=vars;doc.plugins={...doc.plugins,harness:on};return edit(doc);}),ops=[]; initializeControl(f.dataRoot); withoutHostCredentials(f.env,{piKey:true}); Object.assign(f.env,more); const host={business:'acme',beforeClose:()=>{},op:async x=>{ ops.push(x); if(x.op==='identity')return {business:'acme',role:'pm'}; if(x.op==='mayLaunch')return {allow:true}; if(x.op==='modelAdmission' && modelAdmission) return modelAdmission; if(x.op==='authorizeLaunch')throw Object.assign(Error('fixture authorization stop'),{code:'fixture-policy'}); return {}; }}; const makeLoader=await fakeHarnesses(t,{pi:null,'claude-code':null},write=>{for(const [name,body] of Object.entries(MODULES))write('harness',name,body);write('model-provider','cliproxy',`export * from ${JSON.stringify(new URL('../../plugins/model-provider/cliproxy/index.mjs',import.meta.url).href)};`);}); // The system config's execution keys are set and must never reach a route. const system={...JSON.parse(readFileSync(f.config,'utf8'))}; system.execution={...system.execution,adapter:'pi',model:'glm-5.3-flash'}; const launcher=createLauncher({host,system,env:f.env,makeLoader,bwrap:'/usr/bin/true',log:()=>{}}); const events=()=>readFileSync(launchLogFile(f.dataRoot,'acme'),'utf8').trim().split('\n').map(l=>JSON.parse(l)); const launch=()=>launcher.fromSession('fixture-cap','coder'); const may=()=>ops.filter(x=>x.op==='mayLaunch').map(({provider,model,account})=>({provider,model,account})); return {launch,ops,may,last:()=>events().at(-1)}; } const route=(harness,model,thinking)=>({harness,model,thinking}); const fallback=(harness,model,thinking)=>({'fallback.harness':harness,'fallback.model':model,'fallback.thinking':thinking}); const SONNET={provider:'zai',model:'claude-sonnet-5-5',account:null}, FLASH={provider:'zai',model:'glm-5.3-flash',account:null}; test('row 65 a passing primary is the route: its provider and model reach mayLaunch, and a stated fallback is never used',async t=>{ const s=await setup(t,{...route('pi','claude-sonnet-5-5','high'),...fallback('down','glm-5.3-flash','low')}); assert.equal((await s.launch()).error,'fixture-policy'); assert.deepEqual(s.may(),[SONNET]); }); test('row 65 a failed primary preflight takes the stated fallback, and the limit checks see the fallback route',async t=>{ const s=await setup(t,{...route('down','claude-sonnet-5-5','high'),...fallback('pi','glm-5.3-flash','low')}); assert.equal((await s.launch()).error,'fixture-policy'); assert.deepEqual(s.may(),[FLASH]); }); test('row 65 a failed primary with no fallback refuses with the preflight code and never asks mayLaunch',async t=>{ const s=await setup(t,route('down','claude-sonnet-5-5','high')); assert.deepEqual(await s.launch(),{ok:false,error:'fixture-down'}); assert.equal(s.last().why,'fixture preflight fails'); assert.deepEqual(s.may(),[]); }); test('row 65 a fallback whose own preflight fails refuses with its code and names both reasons',async t=>{ const s=await setup(t,{...route('down','claude-sonnet-5-5','high'),...fallback('down','glm-5.3-flash','low')}); assert.deepEqual(await s.launch(),{ok:false,error:'fixture-down'}); assert.equal(s.last().why,'fallback down: fixture preflight fails (primary down: fixture preflight fails)'); assert.deepEqual(s.may(),[]); }); test('row 65 the fallback route spends launch.account when its module counts the account',async t=>{ const env=Object.fromEntries(SESSION_CREDENTIALS.flat().map(k=>[k,''])); Object.assign(env,{ANTHROPIC_AUTH_TOKEN:'stand-in',ANTHROPIC_BASE_URL:'http://127.0.0.1:9'}); const s=await setup(t,{...route('down','claude-sonnet-5-5','high'),...fallback('metered','glm-5.3-flash','low')},{env,edit:doc=>{doc.launch.account={name:'proxy-login',credential:'ANTHROPIC_AUTH_TOKEN+ANTHROPIC_BASE_URL'};return doc;}}); assert.equal((await s.launch()).error,'fixture-policy'); assert.deepEqual(s.may(),[{...FLASH,account:'proxy-login'}]); }); test('row 65 a missing harness, model or thinking var refuses no-route naming it, and the system execution keys never fill it',async t=>{ for(const missing of ['harness','model','thinking']){ const vars=route('pi','claude-sonnet-5-5','high');delete vars[missing]; const s=await setup(t,vars); assert.deepEqual(await s.launch(),{ok:false,error:'no-route'},missing); assert.equal(s.last().why,`instance coder: no ${missing} var`); assert.deepEqual(s.may(),[],missing); } }); test('row 65 a harness that is not switched on refuses harness-off, primary or fallback, and an off primary never falls back',async t=>{ const cases=[ [route('pi','claude-sonnet-5-5','high'),'pi'], [{...route('pi','claude-sonnet-5-5','high'),...fallback('down','glm-5.3-flash','low')},'down'], [{...route('down','claude-sonnet-5-5','high'),...fallback('pi','glm-5.3-flash','low')},'down'], ]; for(const [vars,off] of cases){ const s=await setup(t,vars,{on:ON.filter(n=>n!==off)}); assert.deepEqual(await s.launch(),{ok:false,error:'harness-off'},off); assert.equal(s.last().why,`harness ${off} isn't switched on in plugins.harness`); assert.deepEqual(s.may(),[],off); } // A file with no plugins.harness at all refuses the same way. const s=await setup(t,route('pi','claude-sonnet-5-5','high'),{on:undefined,edit:doc=>{delete doc.plugins.harness;return doc;}}); assert.deepEqual(await s.launch(),{ok:false,error:'harness-off'}); }); test('row 65 the loader refusing a module refuses harness-refused and names it; a module that throws refuses harness-failed',async t=>{ for(const [name,reason] of [['broken',/^harness broken: missing-export: /],['absent',/^harness absent: /]]){ const s=await setup(t,route(name,'claude-sonnet-5-5','high')); assert.deepEqual(await s.launch(),{ok:false,error:'harness-refused'},name); assert.match(s.last().why,reason); } const s=await setup(t,route('throws','claude-sonnet-5-5','high')); assert.deepEqual(await s.launch(),{ok:false,error:'harness-failed'}); assert.equal(s.last().why,'harness throws preflight: threw Error without a system code'); }); test('row 65 a thinking level the route harness does not apply refuses thinking-unsupported, on the primary or a fallback taken',async t=>{ // A refused fallback names the primary's failure too, so the reason it was tried stays visible. for(const [vars,why] of [ [route('sparse','claude-sonnet-5-5','high'),'harness sparse takes thinking low, not high'], [{...route('down','claude-sonnet-5-5','high'),...fallback('sparse','glm-5.3-flash','high')},'harness sparse takes thinking low, not high (primary down: fixture preflight fails)'], ]){ const s=await setup(t,vars); assert.deepEqual(await s.launch(),{ok:false,error:'thinking-unsupported'}); assert.equal(s.last().why,why); assert.deepEqual(s.may(),[]); } // A fallback the loader refuses names both too. const refused=await setup(t,{...route('down','claude-sonnet-5-5','high'),...fallback('broken','glm-5.3-flash','high')}); assert.deepEqual(await refused.launch(),{ok:false,error:'harness-refused'}); assert.match(refused.last().why,/^harness broken: missing-export: .* \(primary down: fixture preflight fails\)$/); // claude-code has no off: its module's own levels refuse it. const s=await setup(t,route('claude-code','claude-sonnet-5-5','off')); assert.deepEqual(await s.launch(),{ok:false,error:'thinking-unsupported'}); assert.equal(s.last().why,'harness claude-code takes thinking low, medium, high, xhigh, max, not off'); }); test('module-backed unavailable selection refuses before run creation',async t=>{ const s=await setup(t,route('pi','zai-fixture-id','low'),{edit:doc=>{doc.plugins['model-provider']=['cliproxy'];doc.launch.models['zai-fixture-id']={provider:'zai',model:'fixture-id',module:'cliproxy',upstream:'zai'};return doc;}}); assert.deepEqual(await s.launch(),{ok:false,error:'model-provider-unavailable'}); assert.equal(s.ops.some(op=>op.op==='modelAdmission'),true); assert.deepEqual(s.may(),[{provider:'zai',model:'fixture-id',account:null}]); }); test('a proxy uncertainty refusal survives launcher admission without creating a run',async t=>{ const s=await setup(t,route('pi','zai-fixture-id','low'),{modelAdmission:{allow:false,code:'proxy-uncertain'},edit:doc=>{doc.plugins['model-provider']=['cliproxy'];doc.launch.models['zai-fixture-id']={provider:'zai',model:'fixture-id',module:'cliproxy',upstream:'zai'};return doc;}}); assert.deepEqual(await s.launch(),{ok:false,error:'proxy-uncertain'}); assert.equal(s.last().code,'proxy-uncertain'); });