fix(#3533): effort inherit — expressible, omitted at writers, never re-added (#3541)

This commit is contained in:
Tom Boucher
2026-08-15 07:00:44 -04:00
committed by GitHub
parent 500df8e37f
commit 50d5368add
10 changed files with 284 additions and 8 deletions

View File

@@ -3726,6 +3726,85 @@ description: Executes GSD phase plans
Body of the agent.
`;
describe('#3533 effort sync: inherit means the key must not exist', () => {
test('10d: sync does not re-add a hand-stripped key when inherit is configured', () => {
const tmpDir = makeTmpDir('effort-sync-inherit-absent-');
const agentsDir = makeAgentsDir(tmpDir);
fs.writeFileSync(path.join(agentsDir, 'gsd-executor.md'), AGENT_WITHOUT_EFFORT);
// Tier standard -> inherit.
writePlanningConfig(tmpDir, { routing_tier_defaults: { light: 'high', standard: 'inherit', heavy: 'xhigh' } });
const { cmdEffortSync } = require('../gsd-core/bin/lib/commands.cjs');
const result = captureOutput(() =>
cmdEffortSync(tmpDir, false, { dryRun: false, configDir: tmpDir, runtime: 'claude' })
);
assert.equal(result.synced, 0, `absent key + inherit is IN SYNC, not drift: ${JSON.stringify(result.changes)}`);
assert.equal(result.changes.length, 0, 'no change may be reported for an absent key under inherit');
const after = fs.readFileSync(path.join(agentsDir, 'gsd-executor.md'), 'utf8');
assert.ok(!/^effort:/m.test(after), 'the effort: key must NOT be re-added');
cleanup(tmpDir);
});
test('10d: sync strips the key when inherit is configured and a value is present', () => {
const tmpDir = makeTmpDir('effort-sync-inherit-strip-');
const agentsDir = makeAgentsDir(tmpDir);
// Fixture carries its own name so the survivor assertion below is
// satisfiable (AGENT_WITH_EFFORT names gsd-planner — wrong file).
fs.writeFileSync(path.join(agentsDir, 'gsd-executor.md'), AGENT_WITH_EFFORT.replace('name: gsd-planner', 'name: gsd-executor'));
writePlanningConfig(tmpDir, { default: 'inherit' });
const { cmdEffortSync } = require('../gsd-core/bin/lib/commands.cjs');
const result = captureOutput(() =>
cmdEffortSync(tmpDir, false, { dryRun: false, configDir: tmpDir, runtime: 'claude' })
);
assert.equal(result.synced, 1);
assert.equal(result.changes[0].agent, 'gsd-executor');
assert.equal(result.changes[0].from, 'medium');
assert.equal(result.changes[0].to, null, 'to: null is the typed IR for omission');
const after = fs.readFileSync(path.join(agentsDir, 'gsd-executor.md'), 'utf8');
assert.ok(!/^effort:/m.test(after), 'the effort: line must be stripped');
assert.ok(after.includes('name: gsd-executor'), 'every other frontmatter line survives');
assert.ok(after.includes('Body of the agent.'), 'the body survives');
cleanup(tmpDir);
});
test('10d: strip preserves CRLF files and leaves comments and sibling keys intact', () => {
const tmpDir = makeTmpDir('effort-sync-inherit-crlf-');
const agentsDir = makeAgentsDir(tmpDir);
const crlfAgent = [
'---',
'name: gsd-executor',
'# a hand comment that must survive',
'effort: high',
'description: Executes GSD phase plans',
'---',
'Body.',
'',
].join('\r\n');
const agentPath = path.join(agentsDir, 'gsd-executor.md');
fs.writeFileSync(agentPath, crlfAgent);
writePlanningConfig(tmpDir, { agent_overrides: { 'gsd-executor': 'inherit' } });
const { cmdEffortSync } = require('../gsd-core/bin/lib/commands.cjs');
const result = captureOutput(() =>
cmdEffortSync(tmpDir, false, { dryRun: false, configDir: tmpDir, runtime: 'claude' })
);
assert.equal(result.synced, 1, `expected one strip: ${JSON.stringify(result.changes)}`);
const after = fs.readFileSync(agentPath, 'utf8');
assert.ok(!/^effort:/m.test(after), 'effort line gone');
assert.ok(after.includes('\r\n'), 'CRLF endings preserved');
assert.ok(after.includes('# a hand comment that must survive'), 'comment preserved');
assert.ok(/^description: Executes GSD phase plans\r?$/m.test(after), 'sibling key preserved');
cleanup(tmpDir);
});
});
describe('feat-488: effort sync command', () => {
test('dry-run mode reports pending changes without writing files', () => {
const tmpDir = makeTmpDir('effort-sync-dry-');