row331 r4: use approved scratch hireable aide fixture

This commit is contained in:
jason.woltje committed 2026-10-25 01:50:19 -05:00
1 parent 989a482ac4
commit 0965fe1ea5
3 files changed
+125 -3

No files matched your search

+41
View File
@@ -448,3 +448,44 @@ Digest correction: a026f563... identifies the frozen import graph (paths/edges),
pins SHA256(committed blob bytes) for45 changed paths at e0578794c; its digest is pins SHA256(committed blob bytes) for45 changed paths at e0578794c; its digest is
e4e0353dbd88e829caf4ce3f050443bd55740e1b8af50ed90522962b81d77f37. Its sourceCommit e4e0353dbd88e829caf4ce3f050443bd55740e1b8af50ed90522962b81d77f37. Its sourceCommit
anchor deliberately precedes the later receipt artifact, avoiding self-reference. anchor deliberately precedes the later receipt artifact, avoiding self-reference.
## 2026-10-25 — r4 fixture approved, static path check before push (sage-4453)
Copied the exact established aide fixture from chief-of-staff.test.mjs:1026-1033
into bootBusiness under rolesCopy(f.root) only: aide.md, roleVersion2 aide.json,
read tool, network api-only, withinRole message.send, credentials[], copied chief
hireable:['aide']. One comment explains both shipped hire gates. Changed only the
three sec-new hire requests to definition aide. sec-1/security-reviewer stays the
fire target; every assertion and timeout is unchanged. Repository roles/*.json and
product source are untouched. No test run.
Read-only path check completed before push:
- Broker.#chiefLifecycle checks the definition's eligibility, then invokes the same
instance.hire organization handler (broker:5100 onward).
- modelOrganization.wrap derives only business/agent identity from args.name and
unconditionally awaits modelKeys.ensure(instance) before invoking the writer
(model-keys:227-243); it does not choose a path by definition/harness/network/tools.
- ModelKeys.#issue:94-109 takes instance, rotation flag and optional current list;
it registers implicit model, GETs, PUTs, confirms GET and writes the model record.
It never reads a role definition or its declared credentials.
- Thus successful hire still must show GET/PUT/GET and valid sec-new model metadata;
failed-PUT hire still must refuse proxy-key-issue-failed before membership/file;
newly-hired preflight still calls runtime.modelPreflight for demo/sec-new.
- Runtime.modelPreflight:721-725 checks current role membership and calls the same
ModelKeys.preflight by instance; it is not the harness plug-in preflight. That
preflight uses the existing key, own sentinel and one /v1/models probe.
- Both security-reviewer and aide are credential-free, have network api-only and
no vars/harness/model overrides. They inherit the same fixture/system route. Aide
has fewer built-in tools and different authority solely to satisfy hire eligibility;
those fields are not inputs to this proxy issuance/preflight path. No real harness
is spawned in these three cases. No key-issuance assertion was weakened/skipped.
R4 runner retains probe-first/full262/test-config/4mutants with whole-file controls,
measured driver/child priority and start/end uptime, with identical test flags and
timeouts. Its receipt clear field now takes MOSAIC_GATE_CLEAR supplied at invocation
so preparation placeholders do not recur. Await separate CLEAR after288 processing
pair and Poe330 diagnostic. Existing27 passing probe cases are not rerun now.
Import-graph and262 path-list digests remain a026f563... and512d0c1c... respectively.
A new committed-blob candidate manifest will be generated for the r4 source tip;
it has its own content digest and sourceCommit anchor.
+73
View File
@@ -0,0 +1,73 @@
// sage-4453: whole-file r4 probe, then full gate; measured priority/load, unchanged test flags/timeouts.
import fs from 'node:fs';
import path from 'node:path';
import os from 'node:os';
import vm from 'node:vm';
import { createHash } from 'node:crypto';
import { execFileSync, spawn } from 'node:child_process';
const root=process.cwd(),home=path.join(root,'agents/magica/work/queue-331');
os.setPriority(0,19);
const archive=execFileSync('mktemp',['-d','/mnt/storage/scratch/tmp/XXXXXX'],{encoding:'utf8'}).trim();
const events=path.join(home,'r4-events.jsonl'),receipt=path.join(home,'r4-receipts.json');
const candidate=execFileSync('git',['rev-parse','HEAD'],{encoding:'utf8'}).trim();
fs.writeFileSync(events,'',{flag:'wx'});
const rows=[];
const uptime=()=>execFileSync('uptime',[],{encoding:'utf8'}).trim();
const logEvent=e=>fs.appendFileSync(events,JSON.stringify(e)+'\n');
const hash=b=>createHash('sha256').update(b).digest('hex');
async function step(name,command,args,timeout=0){
const temp=execFileSync('mktemp',['-d','/mnt/storage/scratch/tmp/XXXXXX'],{encoding:'utf8'}).trim();
fs.mkdirSync(path.join(temp,'home'));fs.mkdirSync(path.join(temp,'config'));
const env={...process.env,TMPDIR:temp,HOME:path.join(temp,'home'),MOSAIC_CONFIG:path.join(temp,'config/config.json')};
for(const key of ['OPENAI_API_KEY','ANTHROPIC_API_KEY','ANTHROPIC_AUTH_TOKEN','CLAUDE_CODE_OAUTH_TOKEN','OPENROUTER_API_KEY','ZAI_API_KEY','MOSAIC_BUS_CAP'])delete env[key];
os.setPriority(0,19);
const before={name,event:'start',at:new Date().toISOString(),uptime:uptime(),TMPDIR:temp,nice:os.getPriority(0)};
logEvent(before);
const file=path.join(archive,String(rows.length+1).padStart(3,'0')+'-'+name.replaceAll('/','_')+'.log');
const fd=fs.openSync(file,'wx',0o600);
const measuredDriverNice=os.getPriority(0);fs.writeSync(fd,'driverNice='+measuredDriverNice+'\n');
let timer,timedOut=false;
const child=spawn(command,args,{cwd:root,env,stdio:['ignore',fd,fd]});
let measuredChildNice=null;
if(child.pid){os.setPriority(child.pid,19);measuredChildNice=os.getPriority(child.pid);}
fs.writeSync(fd,'nice='+String(measuredChildNice)+'\n');fs.closeSync(fd);
if(timeout)timer=setTimeout(()=>{timedOut=true;child.kill('SIGTERM');},timeout);
const outcome=await new Promise(resolve=>{child.once('error',error=>resolve({rc:1,error:error.code}));child.once('close',(code,signal)=>resolve({rc:code??1,signal}));});
clearTimeout(timer);
const endLoad=uptime(),bytes=fs.readFileSync(file),text=bytes.toString();
const count=key=>Number(new RegExp('^# '+key+' (\\d+)$','m').exec(text)?.[1]??0);
const shell=/selftest: (\d+) passed, (\d+) failed/.exec(text);
const row={...before,measuredDriverNice,measuredChildNice,event:'end',endAt:new Date().toISOString(),endUptime:endLoad,...outcome,timedOut,
tests:shell?Number(shell[1])+Number(shell[2]):count('tests'),pass:shell?Number(shell[1]):count('pass'),fail:shell?Number(shell[2]):count('fail'),skipped:count('skipped'),cancelled:count('cancelled'),
failedNames:text.split('\n').filter(s=>s.startsWith('not ok ')).map(s=>s.replace(/^not ok \d+ - /,'')),log:{path:file,sha256:hash(bytes),bytes:bytes.length}};
rows.push(row);logEvent(row);fs.writeFileSync(receipt,JSON.stringify({clear:process.env.MOSAIC_GATE_CLEAR??'not supplied',candidate,archive,rows},null,2)+'\n');
process.stdout.write(`${name} rc=${row.rc} pass=${row.pass} fail=${row.fail} skip=${row.skipped} start=[${row.uptime}] end=[${endLoad}]\n`);
return row;
}
const testArgs=file=>['--test','--test-reporter=tap',path.join(root,file)];
const sourceFile=path.join(root,'packages/bus/src/model-keys.mjs'),original=fs.readFileSync(sourceFile,'utf8');
try{
const probe=await step('probe-model-keys',process.execPath,testArgs('packages/bus/tests/model-keys.test.mjs'));
if(probe.rc!==0)throw Error('RED whole-file model-keys probe; full gate not started');
const list=fs.readFileSync(path.join(home,'green-files.txt'),'utf8').trim().split('\n');
if(list.length!==262||list.includes('packages/cli/tests/case1-accept.test.mjs'))throw Error('frozen list mismatch');
for(const file of list){const row=await step(file,process.execPath,testArgs(file));if(row.rc!==0)throw Error('RED '+file);}
const shell=await step('scripts/test-config.sh','timeout',['-k','10','1800',path.join(root,'scripts/test-config.sh')]);
if(shell.rc!==0)throw Error('RED scripts/test-config.sh');
const helper=fs.readFileSync(path.join(home,'mutants.mjs'),'utf8');
const start=helper.indexOf('const cases = ')+14,end=helper.indexOf('\nos.setPriority',start);
const cases=vm.runInNewContext('('+helper.slice(start,end).trim().replace(/;$/,'')+')');
for(const m of cases){
if(original.split(m.from).length!==2)throw Error('mutation anchor not unique '+m.name);
let result;
try{fs.writeFileSync(sourceFile,original.replace(m.from,m.to));result=await step('mutant-'+m.name,process.execPath,testArgs('packages/bus/tests/model-keys.test.mjs'),180000);}
finally{fs.writeFileSync(sourceFile,original);}
const killed=result.rc!==0&&!result.timedOut&&result.failedNames.some(name=>name===m.failure);
logEvent({event:'mutant-result',name:m.name,killed,restoredSha256:hash(fs.readFileSync(sourceFile))});
if(!killed)throw Error('mutant not killed by named behavior '+m.name);
const positive=await step('positive-'+m.name,process.execPath,testArgs('packages/bus/tests/model-keys.test.mjs'),180000);
if(positive.rc!==0)throw Error('RED positive control '+m.name);
}
logEvent({event:'complete',at:new Date().toISOString(),uptime:uptime()});
}catch(error){logEvent({event:'stopped',reason:error.message,at:new Date().toISOString(),uptime:uptime()});process.stdout.write(error.message+'\n');process.exitCode=1;}
finally{if(fs.readFileSync(sourceFile,'utf8')!==original)fs.writeFileSync(sourceFile,original);}
+11 -3
View File
@@ -174,6 +174,14 @@ test('proxy-stop-failed: old proxy key and retiring record survive a failed grac
async function bootBusiness(f) { async function bootBusiness(f) {
const rolesDir = rolesCopy(f.root), system = systemFor(f.root), doc = businessDoc(f.root, 'demo'); const rolesDir = rolesCopy(f.root), system = systemFor(f.root), doc = businessDoc(f.root, 'demo');
// Aide is needed because shipped chief hireable:[] and security-reviewer has review.verdict outside HIRE_ALLOWED.
fs.writeFileSync(join(rolesDir, 'aide.md'), '# Aide\n');
writeJson(join(rolesDir, 'aide.json'), {
roleVersion: 2, name: 'aide', title: 'Aide', contract: 'aide.md', tools: ['read'], network: 'api-only',
authority: { withinRole: ['message.send'], crossRole: [] }, credentials: [],
});
const chiefFile = join(rolesDir, 'chief-of-staff.json');
writeJson(chiefFile, { ...JSON.parse(fs.readFileSync(chiefFile, 'utf8')), hireable: ['aide'] });
doc.plugins = { ...doc.plugins, harness: ['pi'] }; doc.plugins = { ...doc.plugins, harness: ['pi'] };
doc.roles['sec-1'] = { definition: 'security-reviewer' }; doc.launch.instances.push('sec-1'); doc.roles['sec-1'] = { definition: 'security-reviewer' }; doc.launch.instances.push('sec-1');
const file = writeJson(join(f.configDir, 'businesses', 'demo.json'), doc); const file = writeJson(join(f.configDir, 'businesses', 'demo.json'), doc);
@@ -222,7 +230,7 @@ test('proxy-revoke-revision-conflict: racing organization write keeps record, ne
}); });
test('bus hire issues and confirms implicit model key before publishing new membership', async t => { test('bus hire issues and confirms implicit model key before publishing new membership', async t => {
const f = await fixture(t); const b = await bootBusiness(f); const calls = f.state.calls.length; const f = await fixture(t); const b = await bootBusiness(f); const calls = f.state.calls.length;
const result = await b.bus.broker.request(b.chief, { verb: 'instance.hire', args: { name: 'sec-new', definition: 'security-reviewer', reason: 'fixture hire' } }); const result = await b.bus.broker.request(b.chief, { verb: 'instance.hire', args: { name: 'sec-new', definition: 'aide', reason: 'fixture hire' } });
assert.equal(typeof result.transaction, 'string'); assert.equal(typeof result.transaction, 'string');
assert.equal(JSON.parse(fs.readFileSync(b.file, 'utf8')).launch.instances.includes('sec-new'), true); assert.equal(JSON.parse(fs.readFileSync(b.file, 'utf8')).launch.instances.includes('sec-new'), true);
assert.equal(b.bus.credentials.modelRecord('demo/sec-new')?.state, 'valid'); assert.equal(b.bus.credentials.modelRecord('demo/sec-new')?.state, 'valid');
@@ -231,7 +239,7 @@ test('bus hire issues and confirms implicit model key before publishing new memb
test('proxy-key-issue-failed: bus hire failure publishes neither membership nor model file', async t => { test('proxy-key-issue-failed: bus hire failure publishes neither membership nor model file', async t => {
const f = await fixture(t); const b = await bootBusiness(f); f.state.failPut = true; const f = await fixture(t); const b = await bootBusiness(f); f.state.failPut = true;
const before = fs.readFileSync(b.file, 'utf8'); const before = fs.readFileSync(b.file, 'utf8');
await assert.rejects(b.bus.broker.request(b.chief, { verb: 'instance.hire', args: { name: 'sec-new', definition: 'security-reviewer', reason: 'fixture hire' } }), failCode('proxy-key-issue-failed')); await assert.rejects(b.bus.broker.request(b.chief, { verb: 'instance.hire', args: { name: 'sec-new', definition: 'aide', reason: 'fixture hire' } }), failCode('proxy-key-issue-failed'));
assert.equal(fs.readFileSync(b.file, 'utf8'), before); assert.equal(b.bus.credentials.modelRecord('demo/sec-new') === null, true); assert.equal(fs.readFileSync(b.file, 'utf8'), before); assert.equal(b.bus.credentials.modelRecord('demo/sec-new') === null, true);
}); });
test('proxy-open: removing sentinel after boot refuses the next launch before models probe', async t => { test('proxy-open: removing sentinel after boot refuses the next launch before models probe', async t => {
@@ -241,7 +249,7 @@ test('proxy-open: removing sentinel after boot refuses the next launch before mo
}); });
test('newly hired role can use runtime preflight without a broker restart', async t => { test('newly hired role can use runtime preflight without a broker restart', async t => {
const f = await fixture(t); const b = await bootBusiness(f); const f = await fixture(t); const b = await bootBusiness(f);
await b.bus.broker.request(b.chief, { verb: 'instance.hire', args: { name: 'sec-new', definition: 'security-reviewer', reason: 'fixture hire' } }); await b.bus.broker.request(b.chief, { verb: 'instance.hire', args: { name: 'sec-new', definition: 'aide', reason: 'fixture hire' } });
const proxy = await b.bus.modelPreflight({ business: 'demo', role: 'sec-new' }); const proxy = await b.bus.modelPreflight({ business: 'demo', role: 'sec-new' });
assert.equal(proxy.baseUrl, f.baseUrl); assert.equal(f.state.keys.includes(proxy.key), true); assert.equal(proxy.baseUrl, f.baseUrl); assert.equal(f.state.keys.includes(proxy.key), true);
}); });