fix(test): skill-validation renders codex host into an out-dir

Its 3 in-place --host codex regeneration sites collapse into one
module-level --out-dir render; assertions untouched. TREE_MUTATING
entry deleted.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Garry Tan
2026-08-29 05:32:59 +00:00
co-authored by Claude Fable 5
parent 1f6da056fe
commit 4409ca392f
2 changed files with 33 additions and 19 deletions
-1
View File
@@ -391,7 +391,6 @@ export const TREE_MUTATING: Record<string, string> = {
'test/catalog-mode-full.test.ts': 'regenerates ALL SKILL.md in full-catalog mode, then restores', 'test/catalog-mode-full.test.ts': 'regenerates ALL SKILL.md in full-catalog mode, then restores',
'test/spec-template-sync.test.ts': 'regenerates all SKILL.md in place to compare spec/SKILL.md', 'test/spec-template-sync.test.ts': 'regenerates all SKILL.md in place to compare spec/SKILL.md',
'test/gen-skill-docs-idempotency.test.ts': 'regenerates all SKILL.md twice to prove idempotency', 'test/gen-skill-docs-idempotency.test.ts': 'regenerates all SKILL.md twice to prove idempotency',
'test/skill-validation.test.ts': 'regenerates .agents/ (codex host) artifacts in place (3 sites)',
'test/gbrain-detection-override.test.ts': 'test/gbrain-detection-override.test.ts':
'regenerates SKILL.md in place with --respect-detection (gbrain variant), then git-restores — readers see inflated skeletons mid-window', 'regenerates SKILL.md in place with --respect-detection (gbrain variant), then git-restores — readers see inflated skeletons mid-window',
'test/host-config.test.ts': 'test/host-config.test.ts':
+33 -18
View File
@@ -1,12 +1,36 @@
import { describe, test, expect } from 'bun:test'; import { describe, test, expect, afterAll } from 'bun:test';
import { validateSkill, extractRemoteSlugPatterns, extractWeightsFromTable } from './helpers/skill-parser'; import { validateSkill, extractRemoteSlugPatterns, extractWeightsFromTable } from './helpers/skill-parser';
import { ALL_COMMANDS, COMMAND_DESCRIPTIONS, READ_COMMANDS, WRITE_COMMANDS, META_COMMANDS } from '../browse/src/commands'; import { ALL_COMMANDS, COMMAND_DESCRIPTIONS, READ_COMMANDS, WRITE_COMMANDS, META_COMMANDS } from '../browse/src/commands';
import { SNAPSHOT_FLAGS } from '../browse/src/snapshot'; import { SNAPSHOT_FLAGS } from '../browse/src/snapshot';
import * as fs from 'fs'; import * as fs from 'fs';
import * as os from 'os';
import * as path from 'path'; import * as path from 'path';
const ROOT = path.resolve(import.meta.dir, '..'); const ROOT = path.resolve(import.meta.dir, '..');
// ─── Codex-host render isolation ─────────────────────────────
// .agents/ is gitignored and regenerated. This file used to regenerate it IN
// PLACE at three sites (a tree-mutating hazard for concurrent readers).
// Render the codex host ONCE into a module-level out-dir instead; every
// codex-artifact assertion reads from here. Out-dir renders are byte-
// identical to in-place external-host renders (pinned by
// test/gen-skill-docs-out-dir.test.ts).
const CODEX_OUT = fs.mkdtempSync(path.join(os.tmpdir(), 'gstack-skillval-codex-'));
{
const render = Bun.spawnSync(
['bun', 'run', 'scripts/gen-skill-docs.ts', '--host', 'codex', '--out-dir', CODEX_OUT],
{ cwd: ROOT, stdout: 'pipe', stderr: 'pipe' },
);
if (render.exitCode !== 0) {
throw new Error(
`gen-skill-docs --host codex --out-dir failed (exit ${render.exitCode}):\n${render.stderr.toString()}`,
);
}
}
afterAll(() => {
fs.rmSync(CODEX_OUT, { recursive: true, force: true });
});
// Carved-skill aware (v2 plan T9 / Phase B): a carved skill is a skeleton SKILL.md // Carved-skill aware (v2 plan T9 / Phase B): a carved skill is a skeleton SKILL.md
// plus sections/*.md. Read the union so validations of content that moved into a // plus sections/*.md. Read the union so validations of content that moved into a
// section still hold. For an uncarved skill (no sections dir) this is just the // section still hold. For an uncarved skill (no sections dir) this is just the
@@ -1556,15 +1580,12 @@ describe('Codex skill', () => {
}); });
test('codex-host ship/review do NOT contain adversarial review step', () => { test('codex-host ship/review do NOT contain adversarial review step', () => {
// .agents/ is gitignored — generate on demand // Codex artifacts come from the module-level out-dir render (CODEX_OUT).
Bun.spawnSync(['bun', 'run', 'scripts/gen-skill-docs.ts', '--host', 'codex'], { const shipContent = fs.readFileSync(path.join(CODEX_OUT, '.agents', 'skills', 'gstack-ship', 'SKILL.md'), 'utf-8');
cwd: ROOT, stdout: 'pipe', stderr: 'pipe',
});
const shipContent = fs.readFileSync(path.join(ROOT, '.agents', 'skills', 'gstack-ship', 'SKILL.md'), 'utf-8');
expect(shipContent).not.toContain('codex review --base'); expect(shipContent).not.toContain('codex review --base');
expect(shipContent).not.toContain('CODEX_REVIEWS'); expect(shipContent).not.toContain('CODEX_REVIEWS');
const reviewContent = fs.readFileSync(path.join(ROOT, '.agents', 'skills', 'gstack-review', 'SKILL.md'), 'utf-8'); const reviewContent = fs.readFileSync(path.join(CODEX_OUT, '.agents', 'skills', 'gstack-review', 'SKILL.md'), 'utf-8');
expect(reviewContent).not.toContain('codex review --base'); expect(reviewContent).not.toContain('codex review --base');
expect(reviewContent).not.toContain('codex_reviews'); expect(reviewContent).not.toContain('codex_reviews');
expect(reviewContent).not.toContain('CODEX_REVIEWS'); expect(reviewContent).not.toContain('CODEX_REVIEWS');
@@ -1609,12 +1630,9 @@ describe('Codex skill', () => {
}); });
test('codex-host document-release does NOT contain the Codex doc review', () => { test('codex-host document-release does NOT contain the Codex doc review', () => {
// .agents/ is gitignored — generate on demand (codex never invokes itself) // Codex never invokes itself; artifacts come from the CODEX_OUT render.
Bun.spawnSync(['bun', 'run', 'scripts/gen-skill-docs.ts', '--host', 'codex'], {
cwd: ROOT, stdout: 'pipe', stderr: 'pipe',
});
const content = fs.readFileSync( const content = fs.readFileSync(
path.join(ROOT, '.agents', 'skills', 'gstack-document-release', 'SKILL.md'), 'utf-8'); path.join(CODEX_OUT, '.agents', 'skills', 'gstack-document-release', 'SKILL.md'), 'utf-8');
expect(content).not.toContain('Codex Documentation Review'); expect(content).not.toContain('Codex Documentation Review');
expect(content).not.toContain('codex-doc-review'); expect(content).not.toContain('codex-doc-review');
}); });
@@ -1841,12 +1859,9 @@ describe('Doc inventory cross-check', () => {
// ─── Codex Skill Validation ────────────────────────────────── // ─── Codex Skill Validation ──────────────────────────────────
describe('Codex skill validation', () => { describe('Codex skill validation', () => {
const AGENTS_DIR = path.join(ROOT, '.agents', 'skills'); // .agents/ is gitignored (v0.11.2.0) — read from the module-level out-dir
// render (CODEX_OUT) instead of regenerating the live tree in place.
// .agents/ is gitignored (v0.11.2.0) — generate on demand for tests const AGENTS_DIR = path.join(CODEX_OUT, '.agents', 'skills');
Bun.spawnSync(['bun', 'run', 'scripts/gen-skill-docs.ts', '--host', 'codex'], {
cwd: ROOT, stdout: 'pipe', stderr: 'pipe',
});
// Discover all shared skills with templates. // Discover all shared skills with templates.
// Host-exclusive outside-voice skills are intentionally omitted here: // Host-exclusive outside-voice skills are intentionally omitted here: