* Match `gsd-sdk query commit` in graphify auto-update hook (#3653) The PostToolUse Bash hook only substring-matched direct shell git ops in tool_input.command. `gsd-sdk query commit` invokes git via spawnSync, so the literal "git commit" never appears in the Bash tool's command string and the hook silently skipped every SDK-issued commit. Result: .planning/graphs/ drifted stale after every phase that closed via gsd-sdk query commit, with no error and no log. Gate 2 now also matches `gsd-sdk query commit`. Other SDK verbs (phase.complete, roadmap.update-plan-progress, state.begin-phase) do not invoke git themselves and remain non-matching to avoid spurious rebuilds per state mutation. Adds positive + negative matcher tests. * Fix changeset frontmatter for #3658 `type: Bug Fix` rejected by scripts/changeset/parse.cjs ALLOWED_TYPES (Keep a Changelog values: Added/Changed/Deprecated/Removed/Fixed/Security). Switch to `type: Fixed` and add `pr: 3658` required by MISSING_PR check. docs-lint now reports `ok_no_triggering_fragments` locally. * fix(#3658): bound graphify SDK commit matcher * fix(#3658): exempt release note docs lint
This commit is contained in:
@@ -389,6 +389,11 @@ describe('#3347 hook — HEAD-advancing command matchers',
|
||||
'git pull --ff-only',
|
||||
'git rebase --continue',
|
||||
'git cherry-pick abc123',
|
||||
// #3653 — `gsd-sdk query commit` invokes git via spawnSync('git', [...]),
|
||||
// so the substring "git commit" never appears in tool_input.command.
|
||||
// The hook must match the user-facing SDK invocation directly.
|
||||
'gsd-sdk query commit "docs: probe" --files .planning/STATE.md',
|
||||
'npx gsd-sdk query commit "docs: probe" --files .planning/STATE.md',
|
||||
]) {
|
||||
test(`dispatches on: ${cmd}`, (t) => {
|
||||
const tmpDir = createTempGitRepo({
|
||||
@@ -407,4 +412,50 @@ describe('#3347 hook — HEAD-advancing command matchers',
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
test('does NOT dispatch on SDK commit-to-subrepo prefix collision', (t) => {
|
||||
const tmpDir = createTempGitRepo({
|
||||
config: { graphify: { enabled: true, auto_update: true } },
|
||||
});
|
||||
t.after(() => cleanup(tmpDir));
|
||||
const mockBin = makeMockGraphifyBin(tmpDir, { sleepMs: 100 });
|
||||
const r = runHook(
|
||||
tmpDir,
|
||||
{
|
||||
tool_name: 'Bash',
|
||||
tool_input: {
|
||||
command: 'gsd-sdk query commit-to-subrepo "msg" --files packages/foo',
|
||||
},
|
||||
},
|
||||
{ pathPrepend: mockBin },
|
||||
);
|
||||
assert.strictEqual(r.status, 0);
|
||||
assert.ok(
|
||||
!fs.existsSync(path.join(tmpDir, '.planning/graphs/.last-build-status.json')),
|
||||
'must NOT dispatch for commit-to-subrepo, which does not advance the outer repo HEAD',
|
||||
);
|
||||
});
|
||||
|
||||
// #3653 — only the SDK `commit` verb invokes git internally. Other
|
||||
// `gsd-sdk query` verbs (phase.complete, roadmap.update-plan-progress,
|
||||
// state.begin-phase) mutate .md files but do NOT advance HEAD; matching
|
||||
// them would cause a spurious rebuild per state mutation.
|
||||
for (const cmd of [
|
||||
'gsd-sdk query phase.complete 109',
|
||||
'gsd-sdk query roadmap.update-plan-progress 109 W001',
|
||||
'gsd-sdk query state.begin-phase 110',
|
||||
]) {
|
||||
test(`does NOT dispatch on non-HEAD-advancing SDK verb: ${cmd}`, (t) => {
|
||||
const tmpDir = createTempGitRepo({
|
||||
config: { graphify: { enabled: true, auto_update: true } },
|
||||
});
|
||||
t.after(() => cleanup(tmpDir));
|
||||
const r = runHook(tmpDir, { tool_name: 'Bash', tool_input: { command: cmd } });
|
||||
assert.strictEqual(r.status, 0);
|
||||
assert.ok(
|
||||
!fs.existsSync(path.join(tmpDir, '.planning/graphs/.last-build-status.json')),
|
||||
`must NOT dispatch for non-HEAD-advancing SDK verb: ${cmd}`,
|
||||
);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user