From f0ef9063d5fdc64d45b02af21b72982fa29d79b3 Mon Sep 17 00:00:00 2001 From: 0xdhx Date: Thu, 6 Aug 2026 16:38:53 -0500 Subject: [PATCH] test(#2665): restore the three agent-skills tests this PR deleted Commit 2bed9fd8 ("replace the hand-synced TEST_ENV_BASE copies with the canonical import") also removed markLocalGsdInstall and three behavioural tests from tests/agent-skills.test.cjs -- 79 lines, no replacement, and no mention in the commit message or the PR body: - unconfigured Codex reads its local companion agent from a descendant cwd - workstream runtime selects the local Codex companion when root config differs - unconfigured Claude remains empty when a local Codex companion exists RULESET.TESTS.delete-bad-tests permits deleting a bad test only when it is replaced with compliant tests in the same PR. Nothing was replaced, and these were not bad tests -- they were collateral in a mechanical edit. A silent net loss of behavioural coverage inside a PR whose subject is test hygiene is the one thing that should not pass here, and the reviewer was right to block on it. Restored verbatim. They need no adaptation to the canonical TEST_ENV_BASE import: they pass their env explicitly, and an explicit env still spreads last over the base. The file goes 80 -> 83 tests, all green. Non-vacuity checked rather than assumed: dropping the local-install marker the first two depend on fails both. The third is a negative assertion and correctly stays green, which is why it is named here rather than counted as covered. Addresses review finding: Blocker 1. --- tests/agent-skills.test.cjs | 60 +++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/tests/agent-skills.test.cjs b/tests/agent-skills.test.cjs index ac2c52eae..9da0ad0f1 100644 --- a/tests/agent-skills.test.cjs +++ b/tests/agent-skills.test.cjs @@ -49,6 +49,13 @@ function readConfig(tmpDir) { return JSON.parse(fs.readFileSync(configPath, 'utf-8')); } +function markLocalGsdInstall(tmpDir) { + fs.writeFileSync( + path.join(tmpDir, '.codex', 'gsd-file-manifest.json'), + JSON.stringify({ files: {} }), + ); +} + // Run agent-skills with --json for typed IR assertions function runAgentSkillsJson(args, tmpDir, env) { // Insert --json after 'agent-skills' subcommand @@ -106,6 +113,59 @@ describe('agent-skills command', () => { assert.strictEqual(r.ir.block, ''); }); + test('unconfigured Codex reads its local companion agent from a descendant cwd', () => { + const agentsDir = path.join(tmpDir, '.codex', 'agents'); + const descendant = path.join(tmpDir, 'src', 'feature'); + const localPersona = '# Local Codex executor\nUse the project-local agent.\n'; + fs.mkdirSync(agentsDir, { recursive: true }); + fs.mkdirSync(descendant, { recursive: true }); + fs.writeFileSync(path.join(agentsDir, 'gsd-executor.md'), localPersona); + markLocalGsdInstall(tmpDir); + writeConfig(tmpDir, { runtime: 'codex' }); + + const r = runAgentSkillsJson(['agent-skills', 'gsd-executor'], descendant, { + HOME: tmpDir, + USERPROFILE: tmpDir, + CODEX_HOME: path.join(tmpDir, 'global-codex'), + GSD_RUNTIME: '', + }); + assert.ok(r.success, `Command failed: ${r.error}`); + assert.strictEqual(r.ir.block, localPersona); + }); + + test('workstream runtime selects the local Codex companion when root config differs', () => { + const agentsDir = path.join(tmpDir, '.codex', 'agents'); + const localPersona = '# Local Codex executor\nUse the overridden runtime.\n'; + fs.mkdirSync(agentsDir, { recursive: true }); + fs.writeFileSync(path.join(agentsDir, 'gsd-executor.md'), localPersona); + markLocalGsdInstall(tmpDir); + writeConfig(tmpDir, { runtime: 'claude' }); + const workstreamDir = path.join(tmpDir, '.planning', 'workstreams', 'feature-x'); + fs.mkdirSync(workstreamDir, { recursive: true }); + fs.writeFileSync(path.join(workstreamDir, 'config.json'), JSON.stringify({ runtime: 'codex' })); + + const r = runAgentSkillsJson(['agent-skills', 'gsd-executor'], tmpDir, { + HOME: tmpDir, + USERPROFILE: tmpDir, + CODEX_HOME: path.join(tmpDir, 'global-codex'), + GSD_RUNTIME: '', + GSD_WORKSTREAM: 'feature-x', + }); + assert.ok(r.success, `Command failed: ${r.error}`); + assert.strictEqual(r.ir.block, localPersona); + }); + + test('unconfigured Claude remains empty when a local Codex companion exists', () => { + const agentsDir = path.join(tmpDir, '.codex', 'agents'); + fs.mkdirSync(agentsDir, { recursive: true }); + fs.writeFileSync(path.join(agentsDir, 'gsd-executor.md'), '# Local Codex executor\n'); + writeConfig(tmpDir, { runtime: 'claude' }); + + const r = runAgentSkillsJson(['agent-skills', 'gsd-executor'], tmpDir, { GSD_RUNTIME: 'claude' }); + assert.ok(r.success, `Command failed: ${r.error}`); + assert.strictEqual(r.ir.block, ''); + }); + test('returns block containing agent_skills XML for configured agent', () => { const skillDir = path.join(tmpDir, 'skills', 'test-skill'); fs.mkdirSync(skillDir, { recursive: true });