train S3: merge #3698 at 395df002ec v1.92.64.0

This commit is contained in:
garrytan committed 2000-01-01 00:00:00 +00:00
commit 6ee3272f58
11 files changed
+204 -18

No files matched your search

+124 -2
View File
@@ -182,7 +182,7 @@ function host(dir: string, env: NodeJS.ProcessEnv, o: { output?: (title: string)
if (mode === 'after') throw new Error('create result lost');
return { tasks: [{ index, title: t.title }], ...(rejected ? { rejected: [{ index, error: 'cap' }] } : {}) };
},
start: async ({ indices }: { indices: number[] }) => { starts.push(indices); for (const i of indices) subs.get(String(i))!.status = 'working'; return { started: indices.map(index => ({ index })), rejected: [] }; },
start: async ({ indices, model }: { indices: number[]; model?: unknown }) => { starts.push(indices); for (const i of indices) { const s = subs.get(String(i))!; s.status = 'working'; if (model) s.model = model; } return { started: indices.map(index => ({ index })), rejected: [] }; },
list: async () => { advance(); return { tasks: [...subs].map(([p, s]) => ({ path: p, title: s.title, status: s.status })), total: subs.size }; },
get: async ({ path: p }: { path: string }) => ({ path: p, status: subs.get(p)!.status, summary: subs.get(p)!.summary }),
},
@@ -338,7 +338,7 @@ describe('Capy pass program (fake host, real bins)', () => {
const h = host(dir, env);
const base = { base: 'main', out, pass: 'x7p1', planFlags: ['--depth-floor', 'full'] };
expect(await runPass(h, base)).toContain('NEXT: judge (Phase 4)');
expect(await runPass(h, { ...base, stage: 'voices' })).toContain("STOP: the outside voice needs input.models['outside-voice']");
expect(await runPass(h, { ...base, stage: 'voices', laneModel: undefined })).toContain("STOP: the outside voice needs input.models['outside-voice']");
expect(h.creates.some(c => c.title.startsWith('ship x7p1 ') && /adversarial|outside/.test(c.title))).toBe(false);
const models = { 'outside-voice': { model_id: 'openai/gpt-6.1-sol' }, 'adversarial-native': { model_id: 'anthropic/claude-opus-5-5', reasoning_mode: 'high' } };
expect(await runPass(h, { ...base, stage: 'voices', models })).toContain('NEXT: judge the voices');
@@ -346,6 +346,128 @@ describe('Capy pass program (fake host, real bins)', () => {
expect(h.creates.find(c => c.title === 'ship x7p1 adversarial-native')!.model).toEqual(models['adversarial-native']);
}, 240_000);
// Value: protects=Step 11's outside voice is never the native voice's or the lane's model family; fails_when=the STOP checks only that some model was given (lib/capy-review-pass.js before GSTA-167 PR B), so a Claude outside voice beside a Claude native voice runs as "outside";
// why_new=GSTA-167 plan R2 (autoplan-20261031135232); seam=none; no_claim=which family pairs find more
test('a same-family explicit outside voice STOPs before either voice is created', async () => {
const { dir, env } = repo();
const h = host(dir, env);
const base = { base: 'main', out: path.join(dir, '.state/run/p1'), pass: 'x14p1', planFlags: ['--depth-floor', 'full'] };
expect(await runPass(h, base)).toContain('NEXT: judge (Phase 4)');
expect(await runPass(h, { ...base, stage: 'voices', models: { 'outside-voice': { model_id: 'anthropic/claude-sonnet-5-5', reasoning_mode: 'medium' } } }))
.toContain("STOP: the outside voice anthropic/claude-sonnet-5-5 is the anthropic family, the same as the lane model; Step 11 needs input.models['outside-voice'] from another family");
expect(await runPass(h, { ...base, stage: 'voices', models: { 'outside-voice': { model_id: 'openai/gpt-6.1-sol', reasoning_mode: 'medium' }, 'adversarial-native': { model_id: 'openai/gpt-6-astra', reasoning_mode: 'high' } } }))
.toContain('STOP: the outside voice openai/gpt-6.1-sol is the openai family, the same as the native voice');
expect(h.creates.some(c => /^ship x14p1 (adversarial-native|outside-voice)$/.test(c.title))).toBe(false);
}, 240_000);
// Value: protects=a Step 11 rerun on one manifest keeps refusing a same-family outside voice, including one queued at the subagent cap that tools.subagent.start would pick up; fails_when=the family check runs only on the first render, so a resumed or queued voice starts unchecked;
// why_new=GSTA-167 plan R2; seam=none; no_claim=the host's cap timing
test('a Step 11 rerun on one manifest still refuses a same-family outside voice, rendered or queued', async () => {
const same = { 'outside-voice': { model_id: 'anthropic/claude-sonnet-5-5', reasoning_mode: 'medium' } };
const refused = /STOP: the outside voice anthropic\/claude-sonnet-5-5 is the anthropic family/;
const { dir, env } = repo();
const h = host(dir, env);
const base = { base: 'main', out: path.join(dir, '.state/run/p1'), pass: 'x15p1', planFlags: ['--depth-floor', 'full'] };
expect(await runPass(h, base)).toContain('NEXT: judge (Phase 4)');
expect(await runPass(h, { ...base, stage: 'voices', models: same })).toMatch(refused);
expect(await runPass(h, { ...base, stage: 'voices', models: same })).toMatch(refused);
expect(h.creates.some(c => /^ship x15p1 (adversarial-native|outside-voice)$/.test(c.title))).toBe(false);
const b = repo();
const h2 = host(b.dir, b.env, { reject: t => t.endsWith('outside-voice') });
const base2 = { ...base, out: path.join(b.dir, '.state/run/p1'), pass: 'x18p1' };
expect(await runPass(h2, base2)).toContain('NEXT: judge (Phase 4)');
expect(await runPass(h2, { ...base2, stage: 'voices', budgetMs: 1 })).toMatch(/DISPATCHED: outside-voice path=\d+ queued/);
const starts = h2.starts.length;
const recorded = path.join(base2.out, 'voice-models.json');
const kept = fs.readFileSync(recorded, 'utf8');
fs.rmSync(recorded);
expect(await runPass(h2, { ...base2, stage: 'voices', models: same })).toMatch(refused);
expect(h2.starts.length).toBe(starts);
fs.writeFileSync(recorded, kept);
const resumed = await runPass(h2, { ...base2, stage: 'voices', models: same });
expect(resumed).toContain('OUTSIDE_VOICE: openai/gpt-6.1-sol reasoning=medium as dispatched, started from the queue (certified configuration)');
expect(h2.creates.find(c => c.title === 'ship x18p1 outside-voice')!.model).toEqual({ model_id: 'openai/gpt-6.1-sol', reasoning_mode: 'medium' });
}, 300_000);
// Value: protects=a queued outside voice resumes on the models recorded when the voices were dispatched, so changed rerun inputs cannot pair it with a native voice of its own family; fails_when=the rerun's input decides the queued voice's model and the native family (outside-voice finding on #3698: two OpenAI voices started);
// why_new=/ship Step 11 review of #3698; seam=none; no_claim=inputs that change between reruns on purpose
test('a queued outside voice resumes on its dispatched model, checked against the dispatched native family', async () => {
const { dir, env } = repo();
const h = host(dir, env, { reject: t => t.endsWith('outside-voice') });
const base = { base: 'main', out: path.join(dir, '.state/run/p1'), pass: 'x19p1', planFlags: ['--depth-floor', 'full'] };
expect(await runPass(h, base)).toContain('NEXT: judge (Phase 4)');
const first = { 'adversarial-native': { model_id: 'openai/gpt-6-astra', reasoning_mode: 'high' }, 'outside-voice': { model_id: 'google/gemini-4-argon', reasoning_mode: 'medium' } };
expect(await runPass(h, { ...base, stage: 'voices', models: first, budgetMs: 1 })).toMatch(/DISPATCHED: outside-voice path=\d+ queued/);
const res = await runPass(h, { ...base, stage: 'voices' });
expect(res).not.toContain('STOP:');
expect(res).toContain('OUTSIDE_VOICE: google/gemini-4-argon reasoning=medium as dispatched, started from the queue; outside the certified configuration');
expect(h.creates.find(c => c.title === 'ship x19p1 outside-voice')!.model).toEqual(first['outside-voice']);
expect(h.creates.find(c => c.title === 'ship x19p1 adversarial-native')!.model).toEqual(first['adversarial-native']);
}, 300_000);
// Value: protects=a lane whose family is unknown or not Anthropic gets no default outside voice, and an explicit one cannot skip the family check; fails_when=the pin applies to a lane it was not certified for, or an outside voice runs with nothing to compare its family to;
// why_new=GSTA-167 plan R2; seam=none; no_claim=an OpenAI lane's pairing, which is uncertified
test('a missing lane identity STOPs the outside voice: none given, or given with nothing to compare its family to', async () => {
const { dir, env } = repo();
const h = host(dir, env);
const base = { base: 'main', out: path.join(dir, '.state/run/p1'), pass: 'x16p1', planFlags: ['--depth-floor', 'full'] };
expect(await runPass(h, base)).toContain('NEXT: judge (Phase 4)');
const none = "STOP: the outside voice needs input.models['outside-voice'] (a model of another family); none was given";
expect(await runPass(h, { ...base, stage: 'voices', laneModel: undefined })).toContain(none);
expect(await runPass(h, { ...base, stage: 'voices', laneModel: 'openai/gpt-6.1-sol' })).toContain(none);
expect(await runPass(h, { ...base, stage: 'voices', laneModel: undefined, models: { 'outside-voice': { model_id: 'openai/gpt-6.1-sol', reasoning_mode: 'medium' } } }))
.toContain('STOP: the outside voice openai/gpt-6.1-sol cannot be checked against another family: neither input.laneModel nor a native voice model was given');
expect(await runPass(h, { ...base, stage: 'voices', models: { 'outside-voice': { model_id: 'claude-sonnet-5-5' } } }))
.toContain('STOP: the outside voice claude-sonnet-5-5 has no provider prefix, so its family cannot be checked');
expect(await runPass(h, { ...base, stage: 'voices', models: { 'outside-voice': { model_id: 'Anthropic/claude-sonnet-5-5' } } }))
.toContain('STOP: the outside voice Anthropic/claude-sonnet-5-5 is the anthropic family, the same as the lane model');
expect(await runPass(h, { ...base, stage: 'voices', laneModel: 'claude-opus-5-5', models: { 'outside-voice': { model_id: 'openai/gpt-6.1-sol' } } }))
.toContain('STOP: the outside voice openai/gpt-6.1-sol cannot be checked against another family: the lane model claude-opus-5-5 has no provider prefix and no native voice model was given');
expect(h.creates.some(c => /^ship x16p1 (adversarial-native|outside-voice)$/.test(c.title))).toBe(false);
}, 240_000);
const certified = { model_id: 'openai/gpt-6.1-sol', reasoning_mode: 'medium' };
async function voicesRun(dir: string, env: NodeJS.ProcessEnv, sub: string, models?: Record<string, unknown>) {
const out = path.join(dir, '.state/run', sub);
const h = host(dir, env);
const base = { base: 'main', out, pass: 'x17p1', planFlags: ['--depth-floor', 'full'] };
expect(await runPass(h, base)).toContain('NEXT: judge (Phase 4)');
const res = await runPass(h, { ...base, stage: 'voices', ...(models ? { models } : {}) });
const m = JSON.parse(fs.readFileSync(path.join(out, 'pass-manifest.json'), 'utf8')) as Manifest;
for (const r of m.readers) expect(h.creates.find(c => c.title === r.title)!.prompt).toBe(fs.readFileSync(r.file!, 'utf8'));
const shas = Object.fromEntries(h.creates.map(c => [c.title, promptHash(c.prompt.split(out).join('<out>'))]));
return { res, shas, models: Object.fromEntries(h.creates.map(c => [c.title, c.model])) };
}
// Value: protects=an Anthropic lane's Step 11 gets the certified outside voice (openai/gpt-6.1-sol at medium, as rounds 3-6 and A3668 ran) without naming it, and every brief goes out byte for byte as it does with that model named; fails_when=the lane must pick the outside voice (gpt-6-astra in 6c/7e/8g), or the pin changes any reader's brief or another reader's model;
// why_new=GSTA-167 plan R2; seam=none; no_claim=the certified pair's recall, which arm-L6 measured
test('an anthropic lane defaults the outside voice to the certified model, with every brief byte-identical to naming it', async () => {
const { dir, env } = repo();
const pinned = await voicesRun(dir, env, 'pin');
expect(pinned.res).toContain('OUTSIDE_VOICE: openai/gpt-6.1-sol reasoning=medium default for an anthropic lane (certified configuration)');
expect(pinned.res).toContain('NEXT: judge the voices');
expect(pinned.models['ship x17p1 outside-voice']).toEqual(certified);
const named = await voicesRun(dir, env, 'named', { 'outside-voice': certified });
expect(named.res).toContain('OUTSIDE_VOICE: openai/gpt-6.1-sol reasoning=medium given (certified configuration)');
expect(named.shas).toEqual(pinned.shas);
expect(named.models).toEqual(pinned.models);
}, 300_000);
// Value: protects=an explicit cross-family override is accepted but its pass output says it is outside the certified configuration; fails_when=a changed outside-voice model or reasoning passes silently as if certified;
// why_new=GSTA-167 plan R2; seam=none; no_claim=the uncertified configuration's recall
test('an explicit outside-voice override with changed reasoning runs and is recorded as uncertified, other briefs unchanged', async () => {
const { dir, env } = repo();
const high = { model_id: 'openai/gpt-6.1-sol', reasoning_mode: 'high' };
const over = await voicesRun(dir, env, 'over', { 'outside-voice': high });
expect(over.res).toContain('OUTSIDE_VOICE: openai/gpt-6.1-sol reasoning=high given; outside the certified configuration (openai/gpt-6.1-sol at medium beside an anthropic lane)');
expect(over.res).toContain('NEXT: judge the voices');
expect(over.models['ship x17p1 outside-voice']).toEqual(high);
const named = await voicesRun(dir, env, 'named', { 'outside-voice': certified });
expect(over.shas).toEqual(named.shas);
for (const t of Object.keys(named.models)) if (t !== 'ship x17p1 outside-voice') expect(over.models[t]).toEqual(named.models[t]);
}, 300_000);
test('an audit reader marked first settles before any specialist starts; its output is returned, never merged', async () => {
const { dir, env } = repo();
const out = path.join(dir, '.state/run/p1');
+2 -2
View File
@@ -222,11 +222,11 @@ describe('variant G: the call plan, observe budget, waits and audit readers (GST
// Value: protects=audits that cannot block (Steps 7, 8, 14.5) run on a small model at low effort with their sections' own briefs, and skip their reader when --audit decides them; fails_when=an audit reader inherits the lane's model and effort (#36: the coverage audit alone was 2.45M at Opus), or an audit brief is paraphrased;
// why_new=audit model routing is new; seam=none; no_claim=the audits' recall
test('audit readers run on a small model at low effort, named for Capy, and Phase 3 dispatches only what READER names', () => {
expect(flat(doc)).toContain('Audit readers (Steps 7, 8, 14.5) cannot block, so each runs on a small model at low effort; their findings go to the PR body');
expect(flat(doc)).toContain('Audit readers (Steps 7, 8, 14.5) cannot block, so each runs at low effort on a small model, Step 14.5 once on Sonnet 5.5; findings go to the PR body');
expect(flat(doc)).toContain('`Coverage:` and Step 8\'s line come from `--audit` when no reader ran');
const capy = read('capy/skill/gstack/SKILL.md');
expect(capy).toContain('model: { model_id: "anthropic/claude-sonnet-5-5", reasoning_mode: "low" }');
expect(capy).toContain('`anthropic/claude-haiku-5-5` also fits');
expect(capy).toContain('(14.5 once)');
});
// Value: protects=Step 9.2.1's report-only probes run in the parent's own Phase 4 program, as the section says, with its Reads in Phase 3, and