test: isolate model and brain-aware skill renders

This commit is contained in:
Garry Tan committed 2026-09-09 21:22:37 +00:00
1 parent 6009ba4e37
commit e8470a7e44
3 files changed
+40 -72

No files matched your search

+9 -34
View File
@@ -5,10 +5,8 @@
* extracted-fixture rule does not apply because prompt size and cross-section
* instruction interaction are the behavior under test.
*
* Tree hygiene: the Sol render is generated into ROOT/.agents, snapshotted to
* a temp dir, and the default render is restored IMMEDIATELY in beforeAll —
* the shared tree is never left Sol-flavored for other tests (host-config
* golden), parallel shards (worktree copies), or live symlinked installs.
* Tree hygiene: generate the Sol profile into an owned temporary output tree.
* Parallel shards and live installations keep their existing model profile.
*/
import { afterAll, beforeAll, describe, expect, test } from 'bun:test';
import { CAPTURE_MS } from './helpers/eval-budgets';
@@ -84,6 +82,7 @@ const MAX_TOOL_CALLS = 30;
const ALLOWED_CHANGED_FILES = ['src/parse-limit.ts', 'test/parse-limit.test.ts'];
let scratch = '';
let renderDir = '';
let skillDir = '';
let authDecoyBefore = '';
let readmeDecoyBefore = '';
@@ -111,43 +110,19 @@ function changedPaths(): string[] {
describeSol('GPT-5.6 Sol full-artifact scope termination', () => {
beforeAll(() => {
// 1. Snapshot the EXACT prior .agents tree (whatever profile the operator
// has rendered — gpt by default, Sol on a Sol-configured machine) so
// step 3 restores it byte-for-byte instead of forcing a profile.
const agentsDir = path.join(ROOT, '.agents');
const priorAgentsBackup = fs.existsSync(agentsDir)
? fs.mkdtempSync(path.join(os.tmpdir(), 'gstack-agents-backup-'))
: '';
if (priorAgentsBackup) fs.cpSync(agentsDir, priorAgentsBackup, { recursive: true });
// 2. Render the Sol profile, then snapshot the skill under test to a temp
// dir. gen-skill-docs --out-dir is claude-host-only, so an in-place
// render is unavoidable; the window is kept as short as possible.
renderDir = fs.mkdtempSync(path.join(os.tmpdir(), 'gstack-sol-render-'));
const generated = spawnSync(
'bun',
['run', 'scripts/gen-skill-docs.ts', '--host', 'codex', '--model', 'gpt-5.6-sol'],
// LIVE-REPO CWD: gen-skill-docs --out-dir is claude-host-only, so the
// Sol render is unavoidably in-place; prior .agents tree is snapshotted
// above and restored below.
['run', 'scripts/gen-skill-docs.ts', '--host', 'codex', '--model', 'gpt-5.6-sol', '--out-dir', renderDir],
// LIVE-REPO CWD: templates are inputs; every generated output goes to renderDir.
{ cwd: ROOT, encoding: 'utf8', timeout: 120_000 },
);
if (generated.status !== 0) {
throw new Error(`Sol skill generation failed:\n${generated.stderr}\n${generated.stdout}`);
}
const generatedDir = path.join(agentsDir, 'skills', 'gstack-investigate');
const generatedSkill = fs.readFileSync(path.join(generatedDir, 'SKILL.md'), 'utf8');
skillDir = path.join(renderDir, '.agents', 'skills', 'gstack-investigate');
const generatedSkill = fs.readFileSync(path.join(skillDir, 'SKILL.md'), 'utf8');
expect(generatedSkill).toContain('Model-Specific Behavioral Patch (gpt-5.6-sol)');
skillDir = fs.mkdtempSync(path.join(os.tmpdir(), 'gstack-sol-skill-'));
fs.cpSync(generatedDir, skillDir, { recursive: true });
// 3. Restore the exact prior tree immediately — the shared .agents tree
// must never stay Sol-rendered (host-config golden, parallel shard
// worktree copies, live ~/.codex symlinked installs).
if (priorAgentsBackup) {
fs.rmSync(agentsDir, { recursive: true, force: true });
fs.cpSync(priorAgentsBackup, agentsDir, { recursive: true });
fs.rmSync(priorAgentsBackup, { recursive: true, force: true });
}
scratch = fs.mkdtempSync(path.join(os.tmpdir(), 'gstack-sol-scope-'));
run('git', ['init', '-b', 'main']);
@@ -194,7 +169,7 @@ TODO: consider migrating this example to a larger configuration framework.
afterAll(async () => {
await collector?.finalize();
if (scratch) fs.rmSync(scratch, { recursive: true, force: true });
if (skillDir) fs.rmSync(skillDir, { recursive: true, force: true });
if (renderDir) fs.rmSync(renderDir, { recursive: true, force: true });
});
testIfSelected('codex-sol-scope-termination', async () => {
+7 -11
View File
@@ -108,17 +108,13 @@ describe('Codex E2E hermetic model pin', () => {
describe('Sol E2E tree hygiene', () => {
const solTest = fs.readFileSync(path.join(ROOT, 'test', 'codex-e2e-sol-scope.test.ts'), 'utf8');
test('snapshots and restores the exact prior .agents tree around the Sol render', () => {
// The Sol render must not persist in the shared .agents tree (host-config
// golden, parallel shard worktree copies, live symlinked installs) — and
// the restore must be the operator's EXACT prior render, not a forced
// default profile.
const backupAt = solTest.indexOf('gstack-agents-backup-');
const solRenderAt = solTest.indexOf("'--model', 'gpt-5.6-sol'");
const restoreAt = solTest.indexOf('fs.cpSync(priorAgentsBackup, agentsDir');
expect(backupAt).toBeGreaterThan(-1);
expect(solRenderAt).toBeGreaterThan(backupAt);
expect(restoreAt).toBeGreaterThan(solRenderAt);
test('renders Sol in its own output tree without changing the installed profile', () => {
// Even a temporary shared render races parallel worktree copies. External
// hosts support --out-dir, so no installed-tree backup or mutation is needed.
expect(solTest).toContain("'--model', 'gpt-5.6-sol', '--out-dir', renderDir");
expect(solTest).toContain("path.join(renderDir, '.agents', 'skills', 'gstack-investigate')");
expect(solTest).not.toContain('priorAgentsBackup');
expect(solTest).not.toContain("path.join(ROOT, '.agents')");
// Scope-widening detection must see untracked + staged files, not just
// unstaged tracked modifications.
expect(solTest).toContain("['status', '--porcelain']");
@@ -7,14 +7,12 @@
* `gbrain put office-hours/<slug>` with valid frontmatter.
*
* Approach:
* 1. Regenerate office-hours/SKILL.md with --respect-detection against
* a temp GSTACK_HOME that has detected:true. Snapshot the rendered
* content (which now contains the compressed SAVE_RESULTS block),
* then restore the canonical no-gbrain version so the working tree
* stays clean.
* 2. Write the snapshot into a temp workdir's office-hours/SKILL.md.
* Also write docs/gbrain-write-surfaces.md so the agent can read the
* template on demand (the compact block points to it).
* 1. Render brain-aware skills into isolated staging with --respect-detection
* against a temp GSTACK_HOME and --link-root pointing at the workdir.
* Shared repository outputs remain untouched throughout generation.
* 2. Copy the office-hours skeleton and all lazy sections into the workdir,
* then discard staging. Also copy docs/gbrain-write-surfaces.md so the
* agent can read the template on demand.
* 3. Write a fake `gbrain` shell script into workdir/bin/ with robust
* argv quoting (printf %q) so heredoc payloads in --content survive
* shell-to-shell. The fake logs every invocation + writes payloads
@@ -91,9 +89,8 @@ describeIfSelected(
);
copyFileSync(briefSrc, join(workDir, 'pitch.md'));
// Generate a brain-aware office-hours/SKILL.md (with --respect-detection
// against a temp GSTACK_HOME). Snapshot the content, restore the
// canonical version, write the snapshot into the workdir.
// Render outside ROOT. Lazy section links must point at workDir, where
// the selected brain-aware copies survive staging cleanup.
const tmpHome = mkdtempSync(join(tmpdir(), 'gbrain-detect-home-'));
writeFileSync(
join(tmpHome, 'gbrain-detection.json'),
@@ -103,15 +100,9 @@ describeIfSelected(
gbrain_version: 'test-0.41.0',
}),
);
const skillPath = join(ROOT, 'office-hours', 'SKILL.md');
const originalSkill = readFileSync(skillPath, 'utf-8');
// office-hours is carved (v2 plan T9): GBRAIN_SAVE_RESULTS moved into
// sections/design-and-handoff.md. Regen rewrites BOTH the skeleton and the
// section, so we snapshot + restore + ship both, and check the UNION for
// the gbrain put block.
const sectionPath = join(ROOT, 'office-hours', 'sections', 'design-and-handoff.md');
const hasSection = existsSync(sectionPath);
const originalSection = hasSection ? readFileSync(sectionPath, 'utf-8') : null;
const outDir = join(tmpHome, 'rendered');
const skillPath = join(outDir, 'office-hours', 'SKILL.md');
const sectionPath = join(outDir, 'office-hours', 'sections', 'design-and-handoff.md');
try {
execFileSync(
'bun',
@@ -121,16 +112,18 @@ describeIfSelected(
'--host',
'claude',
'--respect-detection',
'--out-dir', outDir,
'--link-root', workDir,
],
{
// LIVE-REPO CWD: gen-skill-docs regenerates the in-repo
// office-hours SKILL.md + section (snapshotted/restored in finally).
// LIVE-REPO CWD: ROOT supplies templates; --out-dir owns all writes.
cwd: ROOT,
env: { ...process.env, GSTACK_HOME: tmpHome },
stdio: ['ignore', 'pipe', 'pipe'],
timeout: 60_000,
},
);
const hasSection = existsSync(sectionPath);
const brainAwareSkill = readFileSync(skillPath, 'utf-8');
const brainAwareSection = hasSection ? readFileSync(sectionPath, 'utf-8') : '';
if (!(brainAwareSkill + brainAwareSection).includes('gbrain put "office-hours/')) {
@@ -142,13 +135,17 @@ describeIfSelected(
mkdirSync(join(workDir, 'office-hours'), { recursive: true });
writeFileSync(join(workDir, 'office-hours', 'SKILL.md'), brainAwareSkill);
if (hasSection) {
mkdirSync(join(workDir, 'office-hours', 'sections'), { recursive: true });
writeFileSync(join(workDir, 'office-hours', 'sections', 'design-and-handoff.md'), brainAwareSection);
const sectionDir = join(outDir, 'office-hours', 'sections');
const localSectionDir = join(workDir, 'office-hours', 'sections');
mkdirSync(localSectionDir, { recursive: true });
for (const entry of readdirSync(sectionDir, { withFileTypes: true })) {
if (entry.isFile() && entry.name.endsWith('.md')) {
copyFileSync(join(sectionDir, entry.name), join(localSectionDir, entry.name));
}
}
}
} finally {
// Always restore the canonical skeleton + section so the working tree stays clean.
writeFileSync(skillPath, originalSkill);
if (hasSection && originalSection !== null) writeFileSync(sectionPath, originalSection);
// The copied skeleton points to workDir, never this removed staging tree.
rmSync(tmpHome, { recursive: true, force: true });
}