mirror of
https://github.com/glittercowboy/get-shit-done
synced 2026-04-25 17:25:23 +02:00
test: destroy 9 config-schema.cjs/core.cjs source-grep tests, replace with behavioral config-set (#2696)
* test: destroy 9 config-schema.cjs/core.cjs source-grep tests, add behavioral config-set tests (#2691, #2693)
Replace source-grep theater with config-set behavioral tests:
- execute-phase-wave: config-set workflow.use_worktrees replaces VALID_CONFIG_KEYS grep
- inline-plan-threshold: delete redundant source-grep (behavioral test at L36 already covered it)
- plan-bounce: config-set for plan_bounce / plan_bounce_script / plan_bounce_passes replaces 3 key-presence greps
- code-review: config-set for code_review / code_review_depth replaces 2 greps; removes CONFIG_PATH constant
- thinking-partner: config-set features.thinking_partner replaces two greps (config-schema.cjs AND core.cjs)
Behavioral tests survive refactors (no path constants, no file reads). The config-schema.cjs →
core.cjs migration commit 990c3e64 happened because these tests groped source paths.
Add allow-test-rule: source-text-is-the-product annotations to legitimate product-content tests:
autonomous-allowed-tools, agent-frontmatter, agent-skills-awareness, bug-2334, bug-2346,
execute-phase-wave (MD reads), plan-bounce (workflow reads). Annotations explain WHY text
inspection is the right level of testing for AI instruction files.
Closes #2691
Closes #2693
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* test: address CodeRabbit findings on #2696
- agent-frontmatter.test.cjs: move allow-test-rule annotation from block comment
to standalone // line comment so rule scanners can detect it
- thinking-partner.test.cjs: strengthen config-set test with config-get read-back
assertion to verify the value was persisted, not just accepted (exit 0)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* test: tighten thinking_partner config assertion per CodeRabbit (#2696)
Replace config-get output substring check (includes('true') false-positive
risk) with a direct JSON read of .planning/config.json, asserting the
exact persisted value via strictEqual. This also validates the config file
was created, catching silent key-acceptance without persistence.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,3 +1,7 @@
|
||||
// allow-test-rule: source-text-is-the-product
|
||||
// Agent .md files are the installed AI agents — their frontmatter and body text IS what
|
||||
// Claude Code loads at runtime. Checking text content IS checking the deployed contract.
|
||||
|
||||
/**
|
||||
* GSD Agent Frontmatter Tests
|
||||
*
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
// allow-test-rule: source-text-is-the-product
|
||||
// Agent .md files are the installed AI agents — the "Project skills" block IS the deployed
|
||||
// instruction. Checking text content IS checking what runs in production.
|
||||
'use strict';
|
||||
|
||||
const { describe, test } = require('node:test');
|
||||
|
||||
@@ -12,6 +12,9 @@ const assert = require('node:assert/strict');
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
// allow-test-rule: source-text-is-the-product
|
||||
// commands/gsd/autonomous.md is the installed command — its frontmatter is what Claude Code
|
||||
// reads at runtime to enforce allowed-tools. Checking text content IS checking the contract.
|
||||
describe('commands/gsd/autonomous.md allowed-tools', () => {
|
||||
test('includes Agent in allowed-tools list', () => {
|
||||
const filePath = path.join(__dirname, '..', 'commands', 'gsd', 'autonomous.md');
|
||||
|
||||
@@ -19,6 +19,9 @@ const path = require('path');
|
||||
|
||||
const WORKFLOW_PATH = path.join(__dirname, '..', 'get-shit-done', 'workflows', 'quick.md');
|
||||
|
||||
// allow-test-rule: source-text-is-the-product
|
||||
// quick.md is the AI instruction workflow — the `command -v gsd-sdk` guard IS the fix.
|
||||
// There is no behavioral equivalent: the check runs inside the AI agent, not in gsd-tools.
|
||||
describe('bug #2334: quick workflow gsd-sdk pre-flight check', () => {
|
||||
let content;
|
||||
|
||||
|
||||
@@ -21,6 +21,9 @@ const path = require('path');
|
||||
|
||||
const AGENTS_DIR = path.join(__dirname, '..', 'agents');
|
||||
|
||||
// allow-test-rule: source-text-is-the-product
|
||||
// The <critical_rules> block in agent .md files IS the fix — it is the AI instruction that
|
||||
// prevents unbounded Read loops. There is no behavioral equivalent without a live LLM run.
|
||||
describe('bug #2346: agent read loop guards', () => {
|
||||
|
||||
describe('gsd-ui-checker', () => {
|
||||
|
||||
@@ -28,7 +28,6 @@ const { runGsdTools, createTempProject, cleanup } = require('./helpers.cjs');
|
||||
const AGENTS_DIR = path.join(__dirname, '..', 'agents');
|
||||
const COMMANDS_DIR = path.join(__dirname, '..', 'commands', 'gsd');
|
||||
const WORKFLOWS_DIR = path.join(__dirname, '..', 'get-shit-done', 'workflows');
|
||||
const CONFIG_PATH = path.join(__dirname, '..', 'get-shit-done', 'bin', 'lib', 'config-schema.cjs');
|
||||
|
||||
// Plugin directory resolution (cross-platform safe)
|
||||
const PLUGIN_WORKFLOWS_DIR = process.env.GSD_PLUGIN_ROOT || path.join(os.homedir(), '.claude', 'get-shit-done', 'workflows');
|
||||
@@ -271,18 +270,24 @@ describe('CR-WORKFLOW: code review workflow structure', () => {
|
||||
// --- CR-CONFIG: config key registration ---
|
||||
|
||||
describe('CR-CONFIG: config key registration', () => {
|
||||
test('config.cjs contains workflow.code_review key', () => {
|
||||
const content = fs.readFileSync(CONFIG_PATH, 'utf-8');
|
||||
|
||||
assert.ok(content.includes('workflow.code_review'),
|
||||
'config.cjs missing workflow.code_review key registration');
|
||||
test('config-set accepts workflow.code_review', () => {
|
||||
const tmpDir = createTempProject();
|
||||
try {
|
||||
const result = runGsdTools('config-set workflow.code_review true', tmpDir);
|
||||
assert.ok(result.success, `config-set should accept workflow.code_review: ${result.error}`);
|
||||
} finally {
|
||||
cleanup(tmpDir);
|
||||
}
|
||||
});
|
||||
|
||||
test('config.cjs contains workflow.code_review_depth key', () => {
|
||||
const content = fs.readFileSync(CONFIG_PATH, 'utf-8');
|
||||
|
||||
assert.ok(content.includes('workflow.code_review_depth'),
|
||||
'config.cjs missing workflow.code_review_depth key registration');
|
||||
test('config-set accepts workflow.code_review_depth', () => {
|
||||
const tmpDir = createTempProject();
|
||||
try {
|
||||
const result = runGsdTools('config-set workflow.code_review_depth standard', tmpDir);
|
||||
assert.ok(result.success, `config-set should accept workflow.code_review_depth: ${result.error}`);
|
||||
} finally {
|
||||
cleanup(tmpDir);
|
||||
}
|
||||
});
|
||||
|
||||
test('gsd-tools config-get workflow.code_review succeeds', () => {
|
||||
|
||||
@@ -12,12 +12,17 @@ const { test, describe } = require('node:test');
|
||||
const assert = require('node:assert/strict');
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const { runGsdTools, createTempProject, cleanup } = require('./helpers.cjs');
|
||||
|
||||
const COMMAND_PATH = path.join(__dirname, '..', 'commands', 'gsd', 'execute-phase.md');
|
||||
const WORKFLOW_PATH = path.join(__dirname, '..', 'get-shit-done', 'workflows', 'execute-phase.md');
|
||||
const COMMANDS_DOC_PATH = path.join(__dirname, '..', 'docs', 'COMMANDS.md');
|
||||
const HELP_PATH = path.join(__dirname, '..', 'get-shit-done', 'workflows', 'help.md');
|
||||
|
||||
// allow-test-rule: source-text-is-the-product
|
||||
// The workflow and command .md files are the installed AI instructions — their text content
|
||||
// IS what executes. String presence tests guard against accidental deletion of critical clauses.
|
||||
// See #2692 for the missing behavioral test for --wave N argument parsing.
|
||||
describe('execute-phase command: --wave flag', () => {
|
||||
test('command file exists', () => {
|
||||
assert.ok(fs.existsSync(COMMAND_PATH), 'commands/gsd/execute-phase.md should exist');
|
||||
@@ -128,7 +133,6 @@ describe('use_worktrees config: cross-workflow structural coverage', () => {
|
||||
const DIAGNOSE_PATH = path.join(__dirname, '..', 'get-shit-done', 'workflows', 'diagnose-issues.md');
|
||||
const EXECUTE_PLAN_PATH = path.join(__dirname, '..', 'get-shit-done', 'workflows', 'execute-plan.md');
|
||||
const PLANNING_CONFIG_PATH = path.join(__dirname, '..', 'get-shit-done', 'references', 'planning-config.md');
|
||||
const CONFIG_CJS_PATH = path.join(__dirname, '..', 'get-shit-done', 'bin', 'lib', 'config-schema.cjs');
|
||||
|
||||
test('quick workflow reads USE_WORKTREES from config', () => {
|
||||
const content = fs.readFileSync(QUICK_PATH, 'utf-8');
|
||||
@@ -174,11 +178,14 @@ describe('use_worktrees config: cross-workflow structural coverage', () => {
|
||||
);
|
||||
});
|
||||
|
||||
test('config.cjs includes workflow.use_worktrees in VALID_CONFIG_KEYS', () => {
|
||||
const content = fs.readFileSync(CONFIG_CJS_PATH, 'utf-8');
|
||||
assert.ok(
|
||||
content.includes("'workflow.use_worktrees'"),
|
||||
'config.cjs VALID_CONFIG_KEYS should include workflow.use_worktrees'
|
||||
);
|
||||
test('config-set accepts workflow.use_worktrees', () => {
|
||||
// allow-test-rule: behavioral — exercises config-set validation, not source text
|
||||
const tmpDir = createTempProject();
|
||||
try {
|
||||
const result = runGsdTools('config-set workflow.use_worktrees true', tmpDir);
|
||||
assert.ok(result.success, `config-set should accept workflow.use_worktrees: ${result.error}`);
|
||||
} finally {
|
||||
cleanup(tmpDir);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -20,7 +20,6 @@ const { runGsdTools, createTempProject, cleanup } = require('./helpers.cjs');
|
||||
const repoRoot = path.resolve(__dirname, '..');
|
||||
const executePlanPath = path.join(repoRoot, 'get-shit-done', 'workflows', 'execute-plan.md');
|
||||
const planningConfigPath = path.join(repoRoot, 'get-shit-done', 'references', 'planning-config.md');
|
||||
const configCjsPath = path.join(repoRoot, 'get-shit-done', 'bin', 'lib', 'config-schema.cjs');
|
||||
|
||||
describe('inline_plan_threshold config key (#1979)', () => {
|
||||
let tmpDir;
|
||||
@@ -43,15 +42,6 @@ describe('inline_plan_threshold config key (#1979)', () => {
|
||||
assert.ok(result.success, `config-set should accept 0: ${result.error}`);
|
||||
});
|
||||
|
||||
test('VALID_CONFIG_KEYS in config.cjs contains workflow.inline_plan_threshold', () => {
|
||||
const content = fs.readFileSync(configCjsPath, 'utf-8');
|
||||
assert.match(
|
||||
content,
|
||||
/['"]workflow\.inline_plan_threshold['"]/,
|
||||
'workflow.inline_plan_threshold must be in VALID_CONFIG_KEYS'
|
||||
);
|
||||
});
|
||||
|
||||
test('planning-config.md documents workflow.inline_plan_threshold', () => {
|
||||
const content = fs.readFileSync(planningConfigPath, 'utf-8');
|
||||
assert.match(
|
||||
|
||||
@@ -15,35 +15,41 @@ const { test, describe } = require('node:test');
|
||||
const assert = require('node:assert/strict');
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const { runGsdTools, createTempProject, cleanup } = require('./helpers.cjs');
|
||||
|
||||
const GSD_ROOT = path.join(__dirname, '..', 'get-shit-done');
|
||||
const CONFIG_CJS_PATH = path.join(GSD_ROOT, 'bin', 'lib', 'config-schema.cjs');
|
||||
const CONFIG_TEMPLATE_PATH = path.join(GSD_ROOT, 'templates', 'config.json');
|
||||
const PLAN_PHASE_PATH = path.join(GSD_ROOT, 'workflows', 'plan-phase.md');
|
||||
|
||||
describe('Plan Bounce: config keys', () => {
|
||||
test('workflow.plan_bounce is in VALID_CONFIG_KEYS', () => {
|
||||
const content = fs.readFileSync(CONFIG_CJS_PATH, 'utf-8');
|
||||
assert.ok(
|
||||
content.includes("'workflow.plan_bounce'"),
|
||||
'VALID_CONFIG_KEYS should contain workflow.plan_bounce'
|
||||
);
|
||||
test('config-set accepts workflow.plan_bounce', () => {
|
||||
const tmpDir = createTempProject();
|
||||
try {
|
||||
const result = runGsdTools('config-set workflow.plan_bounce true', tmpDir);
|
||||
assert.ok(result.success, `config-set should accept workflow.plan_bounce: ${result.error}`);
|
||||
} finally {
|
||||
cleanup(tmpDir);
|
||||
}
|
||||
});
|
||||
|
||||
test('workflow.plan_bounce_script is in VALID_CONFIG_KEYS', () => {
|
||||
const content = fs.readFileSync(CONFIG_CJS_PATH, 'utf-8');
|
||||
assert.ok(
|
||||
content.includes("'workflow.plan_bounce_script'"),
|
||||
'VALID_CONFIG_KEYS should contain workflow.plan_bounce_script'
|
||||
);
|
||||
test('config-set accepts workflow.plan_bounce_script', () => {
|
||||
const tmpDir = createTempProject();
|
||||
try {
|
||||
const result = runGsdTools('config-set workflow.plan_bounce_script ./bounce.sh', tmpDir);
|
||||
assert.ok(result.success, `config-set should accept workflow.plan_bounce_script: ${result.error}`);
|
||||
} finally {
|
||||
cleanup(tmpDir);
|
||||
}
|
||||
});
|
||||
|
||||
test('workflow.plan_bounce_passes is in VALID_CONFIG_KEYS', () => {
|
||||
const content = fs.readFileSync(CONFIG_CJS_PATH, 'utf-8');
|
||||
assert.ok(
|
||||
content.includes("'workflow.plan_bounce_passes'"),
|
||||
'VALID_CONFIG_KEYS should contain workflow.plan_bounce_passes'
|
||||
);
|
||||
test('config-set accepts workflow.plan_bounce_passes', () => {
|
||||
const tmpDir = createTempProject();
|
||||
try {
|
||||
const result = runGsdTools('config-set workflow.plan_bounce_passes 2', tmpDir);
|
||||
assert.ok(result.success, `config-set should accept workflow.plan_bounce_passes: ${result.error}`);
|
||||
} finally {
|
||||
cleanup(tmpDir);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -76,6 +82,9 @@ describe('Plan Bounce: config template defaults', () => {
|
||||
});
|
||||
});
|
||||
|
||||
// allow-test-rule: source-text-is-the-product
|
||||
// plan-phase.md is the installed AI workflow instruction — its text content IS what executes.
|
||||
// String presence tests guard against accidental deletion of bounce step clauses.
|
||||
describe('Plan Bounce: plan-phase.md step 12.5', () => {
|
||||
let content;
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ const { describe, test } = require('node:test');
|
||||
const assert = require('node:assert/strict');
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const { runGsdTools, createTempProject, cleanup } = require('./helpers.cjs');
|
||||
|
||||
const GSD_ROOT = path.join(__dirname, '..', 'get-shit-done');
|
||||
|
||||
@@ -66,27 +67,24 @@ describe('Thinking Partner Integration (#1726)', () => {
|
||||
|
||||
// Config tests
|
||||
describe('Config integration', () => {
|
||||
test('features.thinking_partner is in VALID_CONFIG_KEYS', () => {
|
||||
const configSrc = fs.readFileSync(
|
||||
path.join(GSD_ROOT, 'bin', 'lib', 'config-schema.cjs'),
|
||||
'utf-8'
|
||||
);
|
||||
assert.ok(
|
||||
configSrc.includes("'features.thinking_partner'"),
|
||||
'VALID_CONFIG_KEYS should contain features.thinking_partner'
|
||||
);
|
||||
});
|
||||
|
||||
test('features is in KNOWN_TOP_LEVEL section containers', () => {
|
||||
const coreSrc = fs.readFileSync(
|
||||
path.join(GSD_ROOT, 'bin', 'lib', 'core.cjs'),
|
||||
'utf-8'
|
||||
);
|
||||
// The KNOWN_TOP_LEVEL set should include 'features' in section containers
|
||||
assert.ok(
|
||||
coreSrc.includes("'features'"),
|
||||
'KNOWN_TOP_LEVEL should contain features as a section container'
|
||||
);
|
||||
test('config-set accepts features.thinking_partner', () => {
|
||||
// Exercises VALID_CONFIG_KEYS membership and KNOWN_TOP_LEVEL acceptance in one call.
|
||||
// Replaces two source-grep tests that read config-schema.cjs and core.cjs (see #2691).
|
||||
const tmpDir = createTempProject();
|
||||
try {
|
||||
const setResult = runGsdTools('config-set features.thinking_partner true', tmpDir);
|
||||
assert.ok(setResult.success, `config-set should accept features.thinking_partner: ${setResult.error}`);
|
||||
const configPath = path.join(tmpDir, '.planning', 'config.json');
|
||||
assert.ok(fs.existsSync(configPath), 'config-set should create .planning/config.json');
|
||||
const config = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
|
||||
assert.strictEqual(
|
||||
config.features?.thinking_partner,
|
||||
true,
|
||||
'config-set should persist features.thinking_partner=true'
|
||||
);
|
||||
} finally {
|
||||
cleanup(tmpDir);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user