fix(#2352): expand tilde paths in review scope before the deleted-file filter (#2419)

* fix(#2352): tilde-expand SUMMARY.md key-files paths before deleted-file filter

compute_file_scope's "Filter deleted files" step tested the literal `~/...`
value from SUMMARY.md key-files entries with `[ -f "$file" ]`, which bash
never tilde-expands (only a literal `~` in source text expands, not one
arriving as an already-expanded variable value). Real files recorded with a
`~/...` path were silently misclassified as deleted and dropped from
REVIEW_FILES, and a phase whose every recorded file used a tilde path hit the
empty-scope skip as a false negative.

Adds a tilde-normalization loop as step 1 of post-processing (all tiers),
before the deleted-file filter, rewriting a leading `~/` to `${HOME}/...` so
downstream existence checks, the empty-scope short-circuit, and the
FILES_TO_READ/CONFIG_FILES construction all see a real, openable path.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* chore(#2352): regenerate fixtures + lint gate-prep

* chore(#2352): add Fixed changeset fragment (pr 2419)

---------

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Tom Boucher
2026-07-18 21:29:58 -04:00
committed by GitHub
parent dd5a2211c9
commit 873bdf51e5
22 changed files with 223 additions and 23 deletions

View File

@@ -0,0 +1,5 @@
---
type: Fixed
pr: 2419
---
**`/code-review` no longer skips a phase whose SUMMARY.md records `~/`-prefixed file paths** — such a path was silently dropped as "deleted" (bash never tilde-expands a `~` that arrives as a variable's value), emptying the review scope and reporting "no source files changed" as a false success. Tilde paths are now expanded to `$HOME/…` before the deleted-file filter runs.

View File

@@ -247,7 +247,19 @@ fi
**Post-processing (all tiers):**
1. **Apply exclusions (per D-03):** Remove paths matching planning artifacts
1. **Expand tilde paths:** SUMMARY.md `key-files` entries may record a `~/...`-prefixed path (e.g. `~/.claude/gsd-core/workflows/verify-phase.md`). Bash only tilde-expands a literal `~` written in source text, never one arriving as the value of an already-expanded variable, so every later `[ -f "$file" ]` check must see a real, expanded path or it misclassifies the file as deleted.
```bash
EXPANDED_FILES=()
for file in "${REVIEW_FILES[@]}"; do
case "$file" in
"~/"*) file="${HOME}${file#\~}" ;;
esac
EXPANDED_FILES+=("$file")
done
REVIEW_FILES=("${EXPANDED_FILES[@]}")
```
2. **Apply exclusions (per D-03):** Remove paths matching planning artifacts
```bash
FILTERED_FILES=()
for file in "${REVIEW_FILES[@]}"; do
@@ -265,7 +277,7 @@ done
REVIEW_FILES=("${FILTERED_FILES[@]}")
```
2. **Filter deleted files:** Remove paths that don't exist on disk
3. **Filter deleted files:** Remove paths that don't exist on disk
```bash
EXISTING_FILES=()
DELETED_COUNT=0
@@ -283,7 +295,7 @@ if [ $DELETED_COUNT -gt 0 ]; then
fi
```
3. **Deduplicate:** Remove duplicate paths (portable — bash 3.2+ compatible, handles spaces in paths)
4. **Deduplicate:** Remove duplicate paths (portable — bash 3.2+ compatible, handles spaces in paths)
```bash
DEDUPED=()
while IFS= read -r line; do
@@ -292,7 +304,7 @@ done < <(printf '%s\n' "${REVIEW_FILES[@]}" | sort -u)
REVIEW_FILES=("${DEDUPED[@]}")
```
4. **Sort:** Alphabetical sort for reproducible agent input (already sorted by sort -u above)
5. **Sort:** Alphabetical sort for reproducible agent input (already sorted by sort -u above)
**Log final scope and warn if large:**
```bash

View File

@@ -25,6 +25,8 @@ const { describe, test } = require('node:test');
const assert = require('node:assert/strict');
const fs = require('node:fs');
const path = require('node:path');
const { spawnSync } = require('node:child_process');
const { createTempDir, cleanup } = require('./helpers.cjs');
const ROOT = path.resolve(__dirname, '..');
const WORKFLOW_PATH = path.join(ROOT, 'gsd-core', 'workflows', 'code-review.md');
@@ -347,3 +349,184 @@ describe('Reviewer contract — gsd-code-reviewer.md label-equivalence', () => {
);
});
});
// ---------------------------------------------------------------------------
// BUG 4 (#2352) — compute_file_scope must tilde-expand `~/...`-prefixed
// SUMMARY.md key-files entries BEFORE the "Filter deleted files" existence
// check. Bash only tilde-expands a literal `~` written in source text, never
// one arriving as the value of an already-expanded variable — so a real file
// recorded as `~/.claude/gsd-core/workflows/verify-phase.md` was silently
// misclassified as deleted and dropped from REVIEW_FILES, and a phase whose
// every recorded file used a `~/...` path hit the empty-scope skip
// ("No source files changed ... Skipping review.") as a false negative.
//
// Tested both ways: a docs-parity assertion (cross-platform, pure fs read)
// that the normalization block exists in the deployed workflow text, and a
// behavioral test that extracts the actual "Expand tilde paths" +
// "Filter deleted files" bash blocks from code-review.md and executes them
// via a real bash subprocess against planted files under a fresh HOME.
// ---------------------------------------------------------------------------
describe('Bug 4 (#2352) — compute_file_scope tilde-path expansion', () => {
// Docs-parity: the workflow .md must contain the tilde-normalization block
// as step 1 of "Post-processing (all tiers)", ahead of the deleted-file
// filter, so what we behaviorally test below is what is actually deployed.
test('code-review.md contains a tilde-expansion block ahead of the deleted-file filter', () => {
const src = fs.readFileSync(WORKFLOW_PATH, 'utf8');
const postProcessingIdx = src.indexOf('**Post-processing (all tiers):**');
assert.ok(postProcessingIdx !== -1, 'code-review.md must have a "Post-processing (all tiers)" section');
const expandIdx = src.indexOf('EXPANDED_FILES=()', postProcessingIdx);
assert.ok(expandIdx !== -1, 'Post-processing must contain an EXPANDED_FILES=() tilde-expansion loop');
const caseIdx = src.indexOf('case "$file" in', postProcessingIdx);
assert.ok(caseIdx !== -1 && caseIdx < expandIdx + 400, 'tilde-expansion loop must use a case "$file" in match');
assert.ok(
src.slice(caseIdx, caseIdx + 200).includes('"~/"*)') &&
src.slice(caseIdx, caseIdx + 200).includes('${HOME}${file#\\~}'),
'tilde-expansion loop must rewrite a leading ~/ to ${HOME}/... via ${file#\\~}'
);
const deletedFilterIdx = src.indexOf('DELETED_COUNT=0', postProcessingIdx);
assert.ok(deletedFilterIdx !== -1, 'Post-processing must still contain the deleted-file filter');
assert.ok(
expandIdx < deletedFilterIdx,
'tilde-expansion loop must run BEFORE the deleted-file filter, not after'
);
});
// Extract the tilde-expansion fence and the (non-adjacent — the exclusions
// filter sits between them) deleted-file-filter fence from the
// "Post-processing (all tiers)" section of code-review.md — the exact
// snippets the runtime executes, located by content anchor rather than
// position so an intervening step doesn't silently swap in the wrong
// block — and glue them behind a synthetic REVIEW_FILES=("$@") seed for
// direct execution. The exclusions filter itself is intentionally skipped
// here: it only matches relative planning-artifact paths and is orthogonal
// to tilde expansion (see code-review.md step 2, "Apply exclusions").
function extractPostProcessingScript() {
const src = fs.readFileSync(WORKFLOW_PATH, 'utf8');
const postProcessingIdx = src.indexOf('**Post-processing (all tiers):**');
assert.ok(postProcessingIdx !== -1, 'code-review.md must have a "Post-processing (all tiers)" section');
function fenceContaining(marker) {
const markerIdx = src.indexOf(marker, postProcessingIdx);
assert.ok(markerIdx !== -1, `expected to find "${marker}" in the Post-processing section`);
const fenceStart = src.lastIndexOf('```bash', markerIdx);
assert.ok(fenceStart !== -1 && fenceStart > postProcessingIdx, `no \`\`\`bash fence before "${marker}"`);
const bodyStart = src.indexOf('\n', fenceStart) + 1;
const fenceEnd = src.indexOf('\n```', bodyStart);
assert.ok(fenceEnd !== -1, `unterminated \`\`\`bash fence containing "${marker}"`);
return src.slice(bodyStart, fenceEnd);
}
const tildeBlock = fenceContaining('EXPANDED_FILES=()');
const deletedBlock = fenceContaining('DELETED_COUNT=0');
return [
'REVIEW_FILES=("$@")',
tildeBlock,
deletedBlock,
'printf "%s\\n" "${REVIEW_FILES[@]}"',
'echo "REVIEW_FILES_COUNT=${#REVIEW_FILES[@]}"',
'echo "DELETED_COUNT=$DELETED_COUNT"',
].join('\n');
}
function runPostProcessing(homeDir, files) {
const script = extractPostProcessingScript();
// "bash" as $0 so the real REVIEW_FILES entries land in "$@" from $1.
return spawnSync('bash', ['-c', script, 'bash', ...files], {
encoding: 'utf8',
env: { ...process.env, HOME: homeDir },
});
}
let tmpHome;
test('setup: plant a fresh HOME with a real file', { skip: process.platform === 'win32' }, () => {
tmpHome = createTempDir('gsd-2352-home-');
fs.mkdirSync(path.join(tmpHome, '.claude', 'gsd-core', 'workflows'), { recursive: true });
fs.writeFileSync(
path.join(tmpHome, '.claude', 'gsd-core', 'workflows', 'verify-phase.md'),
'# real file\n',
'utf8'
);
});
test(
'AC1: a ~/-prefixed path to a real file survives and is not counted deleted',
{ skip: process.platform === 'win32' },
() => {
const result = runPostProcessing(tmpHome, ['~/.claude/gsd-core/workflows/verify-phase.md']);
assert.equal(result.status, 0, `snippet exited ${result.status}; stderr=${result.stderr}`);
assert.match(
result.stdout,
new RegExp(path.join(tmpHome, '.claude', 'gsd-core', 'workflows', 'verify-phase.md').replace(/[/\\.]/g, '\\$&')),
`expected expanded absolute path in surviving REVIEW_FILES; got: ${JSON.stringify(result.stdout)}`
);
assert.match(result.stdout, /DELETED_COUNT=0/, `expected DELETED_COUNT=0; got: ${JSON.stringify(result.stdout)}`);
assert.match(
result.stdout,
/REVIEW_FILES_COUNT=1/,
`expected the tilde path to survive into REVIEW_FILES; got: ${JSON.stringify(result.stdout)}`
);
}
);
test(
'AC2: a ~/-prefixed path to a non-existent file is still correctly excluded as deleted',
{ skip: process.platform === 'win32' },
() => {
const result = runPostProcessing(tmpHome, ['~/.claude/gsd-core/workflows/does-not-exist.md']);
assert.equal(result.status, 0, `snippet exited ${result.status}; stderr=${result.stderr}`);
assert.match(result.stdout, /DELETED_COUNT=1/, `expected DELETED_COUNT=1; got: ${JSON.stringify(result.stdout)}`);
assert.match(
result.stdout,
/REVIEW_FILES_COUNT=0/,
`expected the missing tilde path to be dropped; got: ${JSON.stringify(result.stdout)}`
);
}
);
test(
'AC3: a phase where every recorded file is a real ~/-prefixed path does not empty the scope',
{ skip: process.platform === 'win32' },
() => {
const result = runPostProcessing(tmpHome, ['~/.claude/gsd-core/workflows/verify-phase.md']);
assert.equal(result.status, 0, `snippet exited ${result.status}; stderr=${result.stderr}`);
const countMatch = result.stdout.match(/REVIEW_FILES_COUNT=(\d+)/);
assert.ok(countMatch, `expected a REVIEW_FILES_COUNT line; got: ${JSON.stringify(result.stdout)}`);
assert.ok(
Number(countMatch[1]) > 0,
'an all-tilde real-file scope must not reduce to zero (would trigger the empty-scope skip)'
);
}
);
test(
'AC4: mixed tilde + missing ordinary relative path resolve independently',
{ skip: process.platform === 'win32' },
() => {
const result = runPostProcessing(tmpHome, [
'~/.claude/gsd-core/workflows/verify-phase.md',
'this/relative/path/does-not-exist.md',
]);
assert.equal(result.status, 0, `snippet exited ${result.status}; stderr=${result.stderr}`);
assert.match(result.stdout, /DELETED_COUNT=1/, `expected exactly 1 deleted; got: ${JSON.stringify(result.stdout)}`);
assert.match(
result.stdout,
/REVIEW_FILES_COUNT=1/,
`expected only the tilde path to survive; got: ${JSON.stringify(result.stdout)}`
);
assert.doesNotMatch(
result.stdout,
/this\/relative\/path\/does-not-exist\.md/,
'the missing ordinary relative path must not survive into REVIEW_FILES'
);
}
);
test('teardown: remove the temp HOME', { skip: process.platform === 'win32' }, () => {
cleanup(tmpHome);
});
});

View File

@@ -217,7 +217,7 @@
"gsd-core/workflows/check-todos.md": "5a62092df800ad7c",
"gsd-core/workflows/cleanup.md": "12c8fd85d3010fe6",
"gsd-core/workflows/code-review-fix.md": "60640e633b0a124b",
"gsd-core/workflows/code-review.md": "5c40505c01871153",
"gsd-core/workflows/code-review.md": "2d9943e121908327",
"gsd-core/workflows/complete-milestone.md": "aaf272074acec69d",
"gsd-core/workflows/debug.md": "0b802b267d0ca2d1",
"gsd-core/workflows/diagnose-issues.md": "c8c41993c277363c",

View File

@@ -288,7 +288,7 @@
"gsd-core/workflows/check-todos.md": "bdeaf43f9c61e0cc",
"gsd-core/workflows/cleanup.md": "0daa2f2720c111f1",
"gsd-core/workflows/code-review-fix.md": "2e113d1f4350a075",
"gsd-core/workflows/code-review.md": "334c90c401f291f8",
"gsd-core/workflows/code-review.md": "2aa1957579f50a87",
"gsd-core/workflows/complete-milestone.md": "c1f91b77f4ace7f2",
"gsd-core/workflows/debug.md": "98c8ed5af882ef8f",
"gsd-core/workflows/diagnose-issues.md": "6cc3900891dfb927",

View File

@@ -287,7 +287,7 @@
"gsd-core/workflows/check-todos.md": "8f2c6b27f18cc5e2",
"gsd-core/workflows/cleanup.md": "bfbab4b981d39544",
"gsd-core/workflows/code-review-fix.md": "78c716068ccdf820",
"gsd-core/workflows/code-review.md": "2d21452eb0449fdd",
"gsd-core/workflows/code-review.md": "595f0d9c7f475809",
"gsd-core/workflows/complete-milestone.md": "9962377cddee50d7",
"gsd-core/workflows/debug.md": "80c413b3a9877433",
"gsd-core/workflows/diagnose-issues.md": "db6a599674efbc4d",

View File

@@ -216,7 +216,7 @@
"gsd-core/workflows/check-todos.md": "6c2a43d1d3e86589",
"gsd-core/workflows/cleanup.md": "0daa2f2720c111f1",
"gsd-core/workflows/code-review-fix.md": "722416b71b31c5fc",
"gsd-core/workflows/code-review.md": "506412604f767adc",
"gsd-core/workflows/code-review.md": "14682c0ba32d5dc6",
"gsd-core/workflows/complete-milestone.md": "dcf1182398efb1ca",
"gsd-core/workflows/debug.md": "b4c658c9608d08e2",
"gsd-core/workflows/diagnose-issues.md": "75ffc381ac3059ff",

View File

@@ -220,7 +220,7 @@
"gsd-core/workflows/check-todos.md": "32fdf33f5dc8bdde",
"gsd-core/workflows/cleanup.md": "b0ebfc48792b407b",
"gsd-core/workflows/code-review-fix.md": "e4549af672e74e6f",
"gsd-core/workflows/code-review.md": "a65e3e869508f89e",
"gsd-core/workflows/code-review.md": "2f9cacacbc862af3",
"gsd-core/workflows/complete-milestone.md": "c0808127038a8f86",
"gsd-core/workflows/debug.md": "870682af53182a6c",
"gsd-core/workflows/diagnose-issues.md": "e616d0d730328d68",

View File

@@ -288,7 +288,7 @@
"gsd-core/workflows/check-todos.md": "bdeaf43f9c61e0cc",
"gsd-core/workflows/cleanup.md": "0daa2f2720c111f1",
"gsd-core/workflows/code-review-fix.md": "2e113d1f4350a075",
"gsd-core/workflows/code-review.md": "334c90c401f291f8",
"gsd-core/workflows/code-review.md": "2aa1957579f50a87",
"gsd-core/workflows/complete-milestone.md": "c1f91b77f4ace7f2",
"gsd-core/workflows/debug.md": "98c8ed5af882ef8f",
"gsd-core/workflows/diagnose-issues.md": "77d98ac07c4a26ff",

View File

@@ -323,7 +323,7 @@
"gsd-core/workflows/check-todos.md": "b2b103e8638e760a",
"gsd-core/workflows/cleanup.md": "5d48d64664222a3e",
"gsd-core/workflows/code-review-fix.md": "ae7f9c6b39a23c12",
"gsd-core/workflows/code-review.md": "eadada9e0a89adf2",
"gsd-core/workflows/code-review.md": "8ac44419de9d2ab5",
"gsd-core/workflows/complete-milestone.md": "017df7443bd08da5",
"gsd-core/workflows/debug.md": "63691293c0bc0294",
"gsd-core/workflows/diagnose-issues.md": "e38bb21d06dff077",

View File

@@ -218,7 +218,7 @@
"gsd-core/workflows/check-todos.md": "be9b50b5f28d7504",
"gsd-core/workflows/cleanup.md": "8233b05ebf011bec",
"gsd-core/workflows/code-review-fix.md": "fda53892ae4b17fc",
"gsd-core/workflows/code-review.md": "f1c045ec4d33abc8",
"gsd-core/workflows/code-review.md": "d58b02fb3a6160a8",
"gsd-core/workflows/complete-milestone.md": "470cf39261400ee2",
"gsd-core/workflows/debug.md": "37c900b9f6c11663",
"gsd-core/workflows/diagnose-issues.md": "42acbe2a43fc886e",

View File

@@ -288,7 +288,7 @@
"gsd-core/workflows/check-todos.md": "1a67337d1630848f",
"gsd-core/workflows/cleanup.md": "db47963f103c2748",
"gsd-core/workflows/code-review-fix.md": "c57af378033b1b58",
"gsd-core/workflows/code-review.md": "32c37bcbec8b8698",
"gsd-core/workflows/code-review.md": "8d7d2de8781fb3f9",
"gsd-core/workflows/complete-milestone.md": "1400a4856f592f3e",
"gsd-core/workflows/debug.md": "fb9e5ecb5027b98e",
"gsd-core/workflows/diagnose-issues.md": "cd582747131726e3",

View File

@@ -217,7 +217,7 @@
"gsd-core/workflows/check-todos.md": "ea9a303c48a5d752",
"gsd-core/workflows/cleanup.md": "6c488059fc152a49",
"gsd-core/workflows/code-review-fix.md": "5e396494a79c3f19",
"gsd-core/workflows/code-review.md": "64a62562611f7f2b",
"gsd-core/workflows/code-review.md": "cf7735c3643d9190",
"gsd-core/workflows/complete-milestone.md": "f1866541148dc291",
"gsd-core/workflows/debug.md": "a8132ea4480a4730",
"gsd-core/workflows/diagnose-issues.md": "385096674965c043",

View File

@@ -288,7 +288,7 @@
"gsd-core/workflows/check-todos.md": "ed4b4eb12be222d7",
"gsd-core/workflows/cleanup.md": "c5f1bf186395d67d",
"gsd-core/workflows/code-review-fix.md": "722416b71b31c5fc",
"gsd-core/workflows/code-review.md": "506412604f767adc",
"gsd-core/workflows/code-review.md": "14682c0ba32d5dc6",
"gsd-core/workflows/complete-milestone.md": "59753bf44d4300da",
"gsd-core/workflows/debug.md": "e88c2d430c3625b6",
"gsd-core/workflows/diagnose-issues.md": "210b5b313e8a559a",

View File

@@ -281,7 +281,7 @@
"gsd-core/workflows/check-todos.md": "bdeaf43f9c61e0cc",
"gsd-core/workflows/cleanup.md": "0daa2f2720c111f1",
"gsd-core/workflows/code-review-fix.md": "2e113d1f4350a075",
"gsd-core/workflows/code-review.md": "334c90c401f291f8",
"gsd-core/workflows/code-review.md": "2aa1957579f50a87",
"gsd-core/workflows/complete-milestone.md": "c1f91b77f4ace7f2",
"gsd-core/workflows/debug.md": "98c8ed5af882ef8f",
"gsd-core/workflows/diagnose-issues.md": "67c058fc7ae6026b",

View File

@@ -288,7 +288,7 @@
"gsd-core/workflows/check-todos.md": "6526b64ee88c7d2e",
"gsd-core/workflows/cleanup.md": "94d771d26f62dc86",
"gsd-core/workflows/code-review-fix.md": "adb9388bb157610c",
"gsd-core/workflows/code-review.md": "ae6bcbd1575aeec4",
"gsd-core/workflows/code-review.md": "8ff9884096ae8341",
"gsd-core/workflows/complete-milestone.md": "614299b2c08e66c3",
"gsd-core/workflows/debug.md": "161be2a77ffce47a",
"gsd-core/workflows/diagnose-issues.md": "2971c699d52f1b85",

View File

@@ -184,7 +184,7 @@
"gsd-core/workflows/check-todos.md": "bdeaf43f9c61e0cc",
"gsd-core/workflows/cleanup.md": "0daa2f2720c111f1",
"gsd-core/workflows/code-review-fix.md": "2e113d1f4350a075",
"gsd-core/workflows/code-review.md": "334c90c401f291f8",
"gsd-core/workflows/code-review.md": "2aa1957579f50a87",
"gsd-core/workflows/complete-milestone.md": "c1f91b77f4ace7f2",
"gsd-core/workflows/debug.md": "98c8ed5af882ef8f",
"gsd-core/workflows/diagnose-issues.md": "d6d978fddfd5da8d",

View File

@@ -217,7 +217,7 @@
"gsd-core/workflows/check-todos.md": "ec8c22920f6b2df1",
"gsd-core/workflows/cleanup.md": "6a18b165752e3087",
"gsd-core/workflows/code-review-fix.md": "f3725ae9d685bed2",
"gsd-core/workflows/code-review.md": "29125604bed2c467",
"gsd-core/workflows/code-review.md": "6076e252b0d315f4",
"gsd-core/workflows/complete-milestone.md": "40085d32b15805c8",
"gsd-core/workflows/debug.md": "09b6bad63939bb82",
"gsd-core/workflows/diagnose-issues.md": "652ae26975f82242",

View File

@@ -217,7 +217,7 @@
"gsd-core/workflows/check-todos.md": "0dda8236355e8c9c",
"gsd-core/workflows/cleanup.md": "82f65f5214ecd748",
"gsd-core/workflows/code-review-fix.md": "f2761f7f8c4a5674",
"gsd-core/workflows/code-review.md": "47663a2922756c5e",
"gsd-core/workflows/code-review.md": "c5311718997f7681",
"gsd-core/workflows/complete-milestone.md": "6e918b72bd885426",
"gsd-core/workflows/debug.md": "04b29e0ba18603b6",
"gsd-core/workflows/diagnose-issues.md": "9274b11a3db98c65",

View File

@@ -217,7 +217,7 @@
"gsd-core/workflows/check-todos.md": "afc840fceb07bf99",
"gsd-core/workflows/cleanup.md": "93c14107979a4428",
"gsd-core/workflows/code-review-fix.md": "b99b1f20bb27c291",
"gsd-core/workflows/code-review.md": "faa87faf07ae765a",
"gsd-core/workflows/code-review.md": "ac70888b14a21aaf",
"gsd-core/workflows/complete-milestone.md": "f463bf4e86ac26f6",
"gsd-core/workflows/debug.md": "830c309b48c35c8c",
"gsd-core/workflows/diagnose-issues.md": "447072aa72385271",

View File

@@ -288,7 +288,7 @@
"gsd-core/workflows/check-todos.md": "bdeaf43f9c61e0cc",
"gsd-core/workflows/cleanup.md": "0daa2f2720c111f1",
"gsd-core/workflows/code-review-fix.md": "2e113d1f4350a075",
"gsd-core/workflows/code-review.md": "334c90c401f291f8",
"gsd-core/workflows/code-review.md": "2aa1957579f50a87",
"gsd-core/workflows/complete-milestone.md": "c1f91b77f4ace7f2",
"gsd-core/workflows/debug.md": "98c8ed5af882ef8f",
"gsd-core/workflows/diagnose-issues.md": "aa8d787db8f3c46c",

View File

@@ -12,7 +12,7 @@
"check-todos.md": 9475,
"cleanup.md": 9941,
"code-review-fix.md": 24320,
"code-review.md": 31916,
"code-review.md": 32504,
"complete-milestone.md": 31071,
"debug.md": 19031,
"diagnose-issues.md": 12864,