* fix(#621): route plan-phase post-planning-gaps through gsd_run launcher The post-planning-gaps step in gsd-core/workflows/plan-phase.md invoked gsd-tools via a hardcoded `node "$HOME/.claude/gsd-core/bin/gsd-tools.cjs"` path twice on one line — for the gap-analysis call and its nested init.plan-phase phase_req_ids query — bypassing the gsd_run launcher that every other call in the workflow uses. On non-default install/runtime layouts (relocated/global installs, non-Claude runtimes) the hardcoded path does not resolve, so the assistant reported the gap-analysis tool as "not found" and fell back to a frontmatter-only coverage check even when a working install existed. #3668 fixed this class earlier in the file but missed this block. Route both invocations through gsd_run, matching the rest of the workflow. No hardcoded $HOME gsd-tools path remains in plan-phase.md. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * chore(#621): add changeset for plan-phase gsd_run gap-analysis fix Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * test(#621): update bug-2851 §13e guard for the gsd_run gap-analysis form The #621 fix migrates plan-phase.md's post-planning-gaps gap-analysis call from the hardcoded node "$HOME/.claude/gsd-core/bin/gsd-tools.cjs" form to the gsd_run launcher (the canonical resolvable form every other call in the file uses). bug-2851's §13e subtest pinned that line to the absolute-$HOME form and now asserts stale behavior. Update the §13e assertion to require `gsd_run gap-analysis` (still rejecting a regression to the hardcoded $HOME path), retitle it, and note the migration in the file header. The generic bare-`gsd-tools` sweeper test is unchanged — gsd_run is a resolvable launcher, not a bare gsd-tools call. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
85 lines
3.1 KiB
JavaScript
85 lines
3.1 KiB
JavaScript
// allow-test-rule: source-text-is-the-product
|
|
// The post-planning-gaps gap-analysis invocation is deployed workflow text the
|
|
// runtime executes; the contract is that it routes through the gsd_run launcher,
|
|
// not a hardcoded $HOME path (#621).
|
|
|
|
/**
|
|
* Regression test for #621: plan-phase gap-analysis must route through gsd_run
|
|
*
|
|
* Prior to the fix, line 1631 of plan-phase.md hardcoded:
|
|
* node "$HOME/.claude/gsd-core/bin/gsd-tools.cjs" gap-analysis ...
|
|
* twice on the same line, breaking non-default install layouts.
|
|
*
|
|
* After the fix, both invocations route through gsd_run (the launcher defined
|
|
* at line ~34 of the same file that resolves gsd-tools.cjs against
|
|
* RUNTIME_DIR / git-toplevel / PATH / $HOME in order).
|
|
*/
|
|
|
|
const { test, describe } = require('node:test');
|
|
const assert = require('node:assert/strict');
|
|
const fs = require('fs');
|
|
const path = require('path');
|
|
|
|
const WORKFLOW_PATH = path.join(
|
|
__dirname,
|
|
'..',
|
|
'gsd-core',
|
|
'workflows',
|
|
'plan-phase.md'
|
|
);
|
|
|
|
// ─── Fixture ──────────────────────────────────────────────────────────────────
|
|
|
|
const workflow = fs.readFileSync(WORKFLOW_PATH, 'utf8');
|
|
|
|
// ─── #621 regression: gap-analysis routes through gsd_run ────────────────────
|
|
|
|
describe('plan-phase workflow: post-planning-gaps gap-analysis uses gsd_run launcher (#621)', () => {
|
|
test('gap-analysis call routes through gsd_run, not hardcoded node path', () => {
|
|
assert.ok(
|
|
workflow.includes('gsd_run gap-analysis'),
|
|
'workflow must invoke gap-analysis via gsd_run, not a hardcoded node path'
|
|
);
|
|
});
|
|
|
|
test('inner phase_req_ids query also routes through gsd_run', () => {
|
|
assert.ok(
|
|
workflow.includes('gsd_run query init.plan-phase'),
|
|
'workflow must invoke the inner phase_req_ids query via gsd_run launcher'
|
|
);
|
|
});
|
|
|
|
test('no hardcoded node "$HOME/.claude/gsd-core/bin/gsd-tools.cjs" invocations remain (#621)', () => {
|
|
const hardcodedCount = (
|
|
workflow.match(/node "\$HOME\/\.claude\/gsd-core\/bin\/gsd-tools\.cjs"/g) || []
|
|
).length;
|
|
assert.strictEqual(
|
|
hardcodedCount,
|
|
0,
|
|
[
|
|
'#621 regression: workflow must not contain any hardcoded',
|
|
'node "$HOME/.claude/gsd-core/bin/gsd-tools.cjs" invocations;',
|
|
`found ${hardcodedCount}`,
|
|
].join(' ')
|
|
);
|
|
});
|
|
|
|
test('post-planning-gaps block still gates on workflow.post_planning_gaps and preserves required args', () => {
|
|
const hasGate = workflow.includes('workflow.post_planning_gaps');
|
|
const hasPhaseDir = workflow.includes('--phase-dir "${PHASE_DIR}"');
|
|
const hasPickArg = workflow.includes('--pick phase_req_ids');
|
|
assert.ok(
|
|
hasGate,
|
|
'workflow must still gate the gap-analysis step on workflow.post_planning_gaps config key'
|
|
);
|
|
assert.ok(
|
|
hasPhaseDir,
|
|
'gap-analysis invocation must still pass --phase-dir "${PHASE_DIR}"'
|
|
);
|
|
assert.ok(
|
|
hasPickArg,
|
|
'inner query must still pass --pick phase_req_ids to extract phase requirement IDs'
|
|
);
|
|
});
|
|
});
|