fix(workflows,docs): scrub stale /gsd-code-review-fix and /gsd-plan-milestone-gaps refs (#3029, #3034) (#3038)

* fix(workflows,docs): scrub stale /gsd-code-review-fix and /gsd-plan-milestone-gaps refs (#3029, #3034)

#2790 consolidated /gsd-code-review-fix into /gsd-code-review --fix and
deleted /gsd-plan-milestone-gaps in favor of inline gap planning as part
of /gsd-audit-milestone's output. The deletion was propagated through
some surfaces (#2950 covered help/do/settings/discuss-phase/etc.) but
several user-facing surfaces still emitted the old forms:

#3029 — /gsd-code-review-fix references in:
- agents/gsd-code-fixer.md (description, "Spawned by", recovery prose)
- get-shit-done/workflows/code-review.md (offer text)
- get-shit-done/workflows/execute-phase.md (offer text)
- get-shit-done/workflows/code-review-fix.md (internal retry hints)
- docs/INVENTORY.md (agent + workflow rows)
- docs/CONFIGURATION.md (workflow.code_review row)
- docs/USER-GUIDE.md (3 occurrences in walkthrough)
- docs/AGENTS.md (gsd-code-fixer agent stub)
- docs/FEATURES.md (commands list + REQ-REVIEW-04)

All replaced with /gsd-code-review --fix. Internal retry hints in the
workflow file itself updated to point at the new form. Release notes
(docs/RELEASE-*.md) and gsd-ns-review's "absorbed by" deletion note
left unchanged — historical/explanatory content.

#3034 — /gsd-plan-milestone-gaps references in:
- get-shit-done/workflows/audit-milestone.md (<offer_next> blocks for
  gaps_found and tech_debt: lines 281, 323)
- commands/gsd/complete-milestone.md (gaps_found pre-flight: lines 46, 57)

Replaced with inline closure path:
  /gsd-phase --insert <N> "Close gap: <REQ-ID> ..."
  /gsd-discuss-phase <N>
  /gsd-plan-phase <N>
  /gsd-execute-phase <N>

Plus a Nyquist-coverage hint pointing at /gsd-validate-phase /
/gsd-secure-phase for retroactive audit-chain hygiene gaps. The
gsd-ns-project SKILL.md "deleted by #2790" note is preserved
(it's the canonical pointer for future readers asking what
happened to the command).

Tests:
- tests/bug-3029-3034-stale-command-routes.test.cjs — parser-based
  assertions per fixed surface, plus a structural cross-check that
  gsd-ns-project keeps the deletion note. 15 tests, all green.
- 6905/6905 full suite passes.

Closes #3029
Closes #3034

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

* fix: address CR feedback on PR #3038 — argument order, structural tests, agent count

CR findings on PR #3038:

1. **docs/USER-GUIDE.md (Major)** — `--fix` examples used flag-first form
   (`/gsd-code-review --fix 3`), but the supported CLI grammar is
   phase-first (`/gsd-code-review 3 --fix`). The original sed-based
   replacement preserved the position of the `gsd-code-review-fix`
   token, producing the wrong order. Fixed in USER-GUIDE.md (3
   occurrences) and the same drift in the workflow surfaces:
   - get-shit-done/workflows/code-review-fix.md (2 retry hints)
   - get-shit-done/workflows/code-review.md (offer text)
   - get-shit-done/workflows/execute-phase.md (offer text)

2. **docs/AGENTS.md (Minor)** — internal count drift: line 483 said
   "Ten additional agents" but line 725 said "12 advanced/specialized".
   Filesystem reality: 33 agents total, 21 primary, 12 specialized
   (count of `### ` stubs in the Advanced and Specialized section).
   Updated lines 3, 13, 483 to use 12/33 and added the two missing
   names (doc-classifier, doc-synthesizer) to the inline list at
   line 13.

3. **tests:94 (Major refactor suggestion)** — `.includes()` token checks
   were source-grep style. Refactored to a typed-IR pattern: extract
   the SET of slash-command tokens via regex, assert membership on the
   parsed Set instead of substring scanning the raw file text. Added
   the `allow-test-rule` comment explaining the IR-build vs
   IR-assertion split per scripts/lint-no-source-grep.cjs convention.

4. **tests:130 (Major)** — replacement-path assertion was file-wide and
   could false-pass on generic mentions of "inline" elsewhere in the
   file. Refactored: `extractOfferBlocks(content)` returns the typed
   list of `<offer_next>` and "Pre-flight" blocks where the deleted
   command previously lived, and the assertion runs against those
   blocks specifically. Now requires `/gsd-phase --insert` or
   inline-audit prose to appear in the same offer block, not just
   somewhere in the file.

15/15 targeted tests pass. 6905/6905 full suite pass. Lints clean.

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

---------

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
Tom Boucher
2026-05-02 17:23:44 -04:00
committed by GitHub
parent 117b3ec009
commit 7714b5244b
13 changed files with 311 additions and 26 deletions

View File

@@ -0,0 +1,5 @@
---
type: Fixed
pr: 3029
---
**`/gsd-code-review-fix` and `/gsd-plan-milestone-gaps` no longer surface as "Unknown command"** — both were consolidated by #2790 (`/gsd-code-review --fix` and inline gap planning in `/gsd-audit-milestone` respectively), but several user-facing surfaces still emitted the old slash forms in their offer text. Fixed audit-milestone offer blocks, gsd-complete-milestone routing, code-review/execute-phase offer text, gsd-code-fixer agent role card, and the doc surfaces (USER-GUIDE, FEATURES, INVENTORY, AGENTS, CONFIGURATION). Closes #3029, closes #3034.

View File

@@ -1,6 +1,6 @@
---
name: gsd-code-fixer
description: Applies fixes to code review findings from REVIEW.md. Reads source files, applies intelligent fixes, and commits each fix atomically. Spawned by /gsd-code-review-fix.
description: Applies fixes to code review findings from REVIEW.md. Reads source files, applies intelligent fixes, and commits each fix atomically. Spawned by /gsd-code-review --fix.
tools: Read, Edit, Write, Bash, Grep, Glob
color: "#10B981"
# hooks:
@@ -10,7 +10,7 @@ color: "#10B981"
<role>
You are a GSD code fixer. You apply fixes to issues found by the gsd-code-reviewer agent.
Spawned by `/gsd-code-review-fix` workflow. You produce REVIEW-FIX.md artifact in the phase directory.
Spawned by `/gsd-code-review --fix` workflow. You produce REVIEW-FIX.md artifact in the phase directory.
Your job: Read REVIEW.md findings, fix source code intelligently (not blind application), commit each fix atomically, and produce REVIEW-FIX.md report.
@@ -295,7 +295,7 @@ cd "$wt"
Concrete steps:
1. Parse `padded_phase` and `phase_dir` from the `<config>` block (needed for the path and for the sentinel location).
2. Resolve the current branch: `branch=$(git branch --show-current)`. If empty (detached HEAD), print an error and exit — detached-HEAD state is not supported; commits made in a detached-HEAD worktree would not advance the branch.
3. **Recovery check (#2839, #2990):** If `${phase_dir}/.review-fix-recovery-pending.json` already exists, a prior run was interrupted. Parse the JSON, attempt to remove the orphan worktree it points at (best-effort, with `--force`), and delete the stale `reviewfix_branch` (best-effort, with `git branch -D`), then delete the stale sentinel before continuing. This makes a re-run of `/gsd-code-review-fix` self-healing.
3. **Recovery check (#2839, #2990):** If `${phase_dir}/.review-fix-recovery-pending.json` already exists, a prior run was interrupted. Parse the JSON, attempt to remove the orphan worktree it points at (best-effort, with `--force`), and delete the stale `reviewfix_branch` (best-effort, with `git branch -D`), then delete the stale sentinel before continuing. This makes a re-run of `/gsd-code-review --fix` self-healing.
4. Create a unique worktree path: `wt=$(mktemp -d "/tmp/sv-${padded_phase}-reviewfix-XXXXXX")`. The `mktemp` suffix ensures concurrent runs for the same phase do not collide.
5. Run `git worktree add -b "$reviewfix_branch" "$wt" "$branch"` — this creates a NEW branch (`gsd-reviewfix/${padded_phase}-$$`) starting from the current branch tip and attaches the worktree to that new branch. Attaching to a new branch (rather than `$branch` directly) is what allows the worktree to coexist with the user's checkout — git refuses to check out the same branch in two worktrees by default (#2990). Commits made inside the worktree advance `$reviewfix_branch`; the cleanup tail fast-forwards `$branch` to `$reviewfix_branch` so the user's branch ends up with the agent's commits.
6. **Write the recovery sentinel** at `${phase_dir}/.review-fix-recovery-pending.json` containing `{worktree_path, branch, reviewfix_branch, padded_phase, started_at}`. Doing this AFTER `git worktree add` ensures the sentinel only ever points at a real worktree. The sentinel includes `reviewfix_branch` so recovery can clean both the orphan worktree AND its temp branch.

View File

@@ -43,7 +43,10 @@ Output: Milestone archived (roadmap + requirements), PROJECT.md evolved, git tag
- Look for `.planning/v{{version}}-MILESTONE-AUDIT.md`
- If missing or stale: recommend `/gsd-audit-milestone` first
- If audit status is `gaps_found`: recommend `/gsd-plan-milestone-gaps` first
- If audit status is `gaps_found`: recommend closing the gaps inline
(the audit output already enumerates them — insert closure phases
via `/gsd-phase --insert <N>` plus the standard
discuss/plan/execute chain) before proceeding.
- If audit status is `passed`: proceed to step 1
```markdown
@@ -54,8 +57,11 @@ Output: Milestone archived (roadmap + requirements), PROJECT.md evolved, git tag
requirements coverage, cross-phase integration, and E2E flows.
{If audit has gaps:}
⚠ Milestone audit found gaps. Run `/gsd-plan-milestone-gaps` to create
phases that close the gaps, or proceed anyway to accept as tech debt.
⚠ Milestone audit found gaps. The audit output already enumerates the
unsatisfied requirements, cross-phase issues, and broken flows — insert
a closure phase per gap with `/gsd-phase --insert <N>` and run the
standard `/gsd-discuss-phase` → `/gsd-plan-phase` → `/gsd-execute-phase`
chain. Or proceed anyway to accept the gaps as tech debt.
{If audit passed:}
✓ Milestone audit passed. Proceeding with completion.

View File

@@ -1,6 +1,6 @@
# GSD Agent Reference
> Full role cards for 21 primary agents plus concise stubs for 10 advanced/specialized agents (31 shipped agents total). The `agents/` directory and [`docs/INVENTORY.md`](INVENTORY.md) are the authoritative roster; see [Architecture](ARCHITECTURE.md) for context.
> Full role cards for 21 primary agents plus concise stubs for 12 advanced/specialized agents (33 shipped agents total). The `agents/` directory and [`docs/INVENTORY.md`](INVENTORY.md) are the authoritative roster; see [Architecture](ARCHITECTURE.md) for context.
---
@@ -10,7 +10,7 @@ GSD uses a multi-agent architecture where thin orchestrators (workflow files) sp
### Agent Categories
> The table below covers the **21 primary agents** detailed in this section. Ten additional shipped agents (pattern-mapper, debug-session-manager, code-reviewer, code-fixer, ai-researcher, domain-researcher, eval-planner, eval-auditor, framework-selector, intel-updater) have concise stubs in the [Advanced and Specialized Agents](#advanced-and-specialized-agents) section below. For the authoritative 31-agent roster, see [`docs/INVENTORY.md`](INVENTORY.md) and the `agents/` directory.
> The table below covers the **21 primary agents** detailed in this section. Twelve additional shipped agents (pattern-mapper, debug-session-manager, code-reviewer, code-fixer, ai-researcher, domain-researcher, eval-planner, eval-auditor, framework-selector, intel-updater, doc-classifier, doc-synthesizer) have concise stubs in the [Advanced and Specialized Agents](#advanced-and-specialized-agents) section below. For the authoritative 33-agent roster, see [`docs/INVENTORY.md`](INVENTORY.md) and the `agents/` directory.
| Category | Count | Agents |
|----------|-------|--------|
@@ -480,7 +480,7 @@ Communication style, decision patterns, debugging approach, UX preferences, vend
## Advanced and Specialized Agents
Ten additional agents ship under `agents/gsd-*.md` and are used by specialty workflows (`/gsd-ai-integration-phase`, `/gsd-eval-review`, `/gsd-code-review`, `/gsd-code-review-fix`, `/gsd-debug`, `/gsd-intel`, `/gsd-select-framework`) and by the planner pipeline. Each carries full frontmatter in its agent file; the stubs below are concise by design. The authoritative roster (with spawner and primary-doc status per agent) lives in [`docs/INVENTORY.md`](INVENTORY.md).
Twelve additional agents ship under `agents/gsd-*.md` and are used by specialty workflows (`/gsd-ai-integration-phase`, `/gsd-eval-review`, `/gsd-code-review`, `/gsd-code-review --fix`, `/gsd-debug`, `/gsd-intel`, `/gsd-select-framework`, `/gsd-ingest-docs`) and by the planner pipeline. Each carries full frontmatter in its agent file; the stubs below are concise by design. The authoritative roster (with spawner and primary-doc status per agent) lives in [`docs/INVENTORY.md`](INVENTORY.md).
### gsd-pattern-mapper
@@ -548,7 +548,7 @@ Ten additional agents ship under `agents/gsd-*.md` and are used by specialty wor
| Property | Value |
|----------|-------|
| **Spawned by** | `/gsd-code-review-fix` |
| **Spawned by** | `/gsd-code-review --fix` |
| **Parallelism** | Single instance |
| **Tools** | Read, Edit, Write, Bash, Grep, Glob |
| **Model (balanced)** | Sonnet |

View File

@@ -199,7 +199,7 @@ All workflow toggles follow the **absent = enabled** pattern. If a key is missin
| `workflow.text_mode` | boolean | `false` | Replaces AskUserQuestion TUI menus with plain-text numbered lists. Required for Claude Code remote sessions (`/rc` mode) where TUI menus don't render. Can also be set per-session with `--text` flag on discuss-phase. Added in v1.28 |
| `workflow.use_worktrees` | boolean | `true` | When `false`, disables git worktree isolation for parallel execution. Users who prefer sequential execution or whose environment does not support worktrees can disable this. Added in v1.31 |
| `workflow.worktree_skip_hooks` | boolean | `false` | When `true`, executor agents in worktree mode pass `--no-verify` (skipping pre-commit hooks) and post-wave hook validation runs against the merged result instead. Opt-in escape hatch for projects whose hooks cannot run in agent worktrees. Default `false` runs hooks on every commit (#2924). |
| `workflow.code_review` | boolean | `true` | Enable `/gsd-code-review` and `/gsd-code-review-fix` commands. When `false`, the commands exit with a configuration gate message. Added in v1.34 |
| `workflow.code_review` | boolean | `true` | Enable `/gsd-code-review` and `/gsd-code-review --fix` commands. When `false`, the commands exit with a configuration gate message. Added in v1.34 |
| `workflow.code_review_depth` | string | `standard` | Default review depth for `/gsd-code-review`: `quick` (pattern-matching only), `standard` (per-file analysis), or `deep` (cross-file with import graphs). Can be overridden per-run with `--depth=`. Added in v1.34 |
| `workflow.plan_bounce` | boolean | `false` | Run external validation script against generated plans. When enabled, the plan-phase orchestrator pipes each PLAN.md through the script specified by `plan_bounce_script` and blocks on non-zero exit. Added in v1.36 |
| `workflow.plan_bounce_script` | string | (none) | Path to the external script invoked for plan bounce validation. Receives the PLAN.md path as its first argument. Required when `plan_bounce` is `true`. Added in v1.36 |

View File

@@ -2121,7 +2121,7 @@ Test suite that scans all agent, workflow, and command files for embedded inject
### 93. Code Review Pipeline
**Commands:** `/gsd-code-review`, `/gsd-code-review-fix`
**Commands:** `/gsd-code-review`, `/gsd-code-review --fix`
**Purpose:** Structured review of source files changed during a phase, with a separate auto-fix pass that commits each fix atomically.
@@ -2129,7 +2129,7 @@ Test suite that scans all agent, workflow, and command files for embedded inject
- REQ-REVIEW-01: `gsd-code-review` MUST scope files to the phase using SUMMARY.md and git diff fallback
- REQ-REVIEW-02: Review MUST support three depth levels: `quick`, `standard`, `deep`
- REQ-REVIEW-03: Findings MUST be severity-classified: Critical, Warning, Info
- REQ-REVIEW-04: `gsd-code-review-fix` MUST read REVIEW.md and fix Critical + Warning findings by default
- REQ-REVIEW-04: `gsd-code-review --fix` MUST read REVIEW.md and fix Critical + Warning findings by default
- REQ-REVIEW-05: Each fix MUST be committed atomically with a descriptive message
- REQ-REVIEW-06: `--auto` flag MUST enable fix + re-review iteration loop, capped at 3 iterations
- REQ-REVIEW-07: Feature MUST be gated by `workflow.code_review` config flag

View File

@@ -40,7 +40,7 @@ Full roster at `agents/gsd-*.md`. The "Primary doc" column flags whether [`docs/
| gsd-pattern-mapper | Maps new files to closest existing analogs; writes PATTERNS.md for the planner. | `/gsd-plan-phase` (between research and planning) | advanced stub |
| gsd-debug-session-manager | Runs the full `/gsd-debug` checkpoint-and-continuation loop in isolated context so main stays lean. | `/gsd-debug` | advanced stub |
| gsd-code-reviewer | Reviews source files for bugs, security issues, and code-quality problems; produces REVIEW.md. | `/gsd-code-review` | advanced stub |
| gsd-code-fixer | Applies fixes to REVIEW.md findings with atomic per-fix commits; produces REVIEW-FIX.md. | `/gsd-code-review-fix` | advanced stub |
| gsd-code-fixer | Applies fixes to REVIEW.md findings with atomic per-fix commits; produces REVIEW-FIX.md. | `/gsd-code-review --fix` | advanced stub |
| gsd-ai-researcher | Researches a chosen AI framework's official docs into implementation-ready guidance (AI-SPEC.md §3–§4b). | `/gsd-ai-integration-phase` | advanced stub |
| gsd-domain-researcher | Surfaces domain-expert evaluation criteria and failure modes for an AI system (AI-SPEC.md §1b). | `/gsd-ai-integration-phase` | advanced stub |
| gsd-eval-planner | Designs structured evaluation strategy for an AI phase (AI-SPEC.md §5–§7). | `/gsd-ai-integration-phase` | advanced stub |
@@ -179,7 +179,7 @@ Full roster at `get-shit-done/workflows/*.md`. Workflows are thin orchestrators
| `autonomous.md` | Drive milestone phases autonomously — all remaining, a range, or a single phase. | `/gsd-autonomous` |
| `check-todos.md` | List pending todos, allow selection, load context, and route to the appropriate action. | `/gsd-capture --list` |
| `cleanup.md` | Archive accumulated phase directories from completed milestones. | `/gsd-cleanup` |
| `code-review-fix.md` | Auto-fix issues from REVIEW.md via gsd-code-fixer with per-fix atomic commits. | `/gsd-code-review-fix` |
| `code-review-fix.md` | Auto-fix issues from REVIEW.md via gsd-code-fixer with per-fix atomic commits. | `/gsd-code-review --fix` |
| `code-review.md` | Review phase source changes via gsd-code-reviewer; produces REVIEW.md. | `/gsd-code-review` |
| `complete-milestone.md` | Mark a shipped version as complete — MILESTONES.md entry, PROJECT.md evolution, tag. | `/gsd-complete-milestone` |
| `diagnose-issues.md` | Orchestrate parallel debug agents to investigate UAT gaps and find root causes. | `/gsd-verify-work` (auto-diagnosis) |

View File

@@ -748,8 +748,8 @@ After executing a phase, run a structured code review before UAT:
The reviewer scopes files automatically using SUMMARY.md (preferred) or git diff fallback. Findings are classified as Critical, Warning, or Info in `{phase}-REVIEW.md`.
```bash
/gsd-code-review-fix 3 # Fix Critical + Warning findings atomically
/gsd-code-review-fix 3 --auto # Fix and re-review until clean (max 3 iterations)
/gsd-code-review 3 --fix # Fix Critical + Warning findings atomically
/gsd-code-review 3 --fix --auto # Fix and re-review until clean (max 3 iterations)
```
### Autonomous Audit-to-Fix
@@ -766,7 +766,7 @@ To run an audit and fix all auto-fixable issues in one pass:
The review step slots in after execution and before UAT:
```
/gsd-execute-phase N -> /gsd-code-review N -> /gsd-code-review-fix N -> /gsd-verify-work N
/gsd-execute-phase N -> /gsd-code-review N -> /gsd-code-review N --fix -> /gsd-verify-work N
```
---

View File

@@ -274,11 +274,22 @@ Phases needing validation: run `/gsd-validate-phase {N}` for each flagged phase.
## ▶ Next Up — [${PROJECT_CODE}] ${PROJECT_TITLE}
**Plan gap closure** — create phases to complete milestone
**Close the gaps inline** — gap planning happens as part of this audit's
output (see the Unsatisfied Requirements, Cross-Phase Issues, Broken Flows,
and Nyquist Coverage sections above). Insert one closure phase per gap (or
per group of related gaps) using the standard phase chain:
/clear then:
/gsd-plan-milestone-gaps
/gsd-phase --insert <N> "Close gap: <REQ-ID> — <description>"
/gsd-discuss-phase <N>
/gsd-plan-phase <N>
/gsd-execute-phase <N>
For Nyquist-coverage gaps flagged in the table above, prefer running
`/gsd-validate-phase <N>` for each flagged phase (and `/gsd-secure-phase
<N>` if SECURITY.md was flagged) before inserting a new closure phase —
they may close the gap retroactively without a new phase.
───────────────────────────────────────────────────────────────
@@ -316,11 +327,15 @@ All requirements met. No critical blockers. Accumulated tech debt needs review.
/gsd-complete-milestone {version}
**B. Plan cleanup phase** — address debt before completing
**B. Plan a cleanup phase** — address the debt above before completing.
Insert a closure phase using the standard chain:
/clear then:
/gsd-plan-milestone-gaps
/gsd-phase --insert <N> "Address tech debt: <area>"
/gsd-discuss-phase <N>
/gsd-plan-phase <N>
/gsd-execute-phase <N>
───────────────────────────────────────────────────────────────
</offer_next>

View File

@@ -223,7 +223,7 @@ Check if FIX_REPORT_PATH exists:
Either way:
```
Some fix commits may already exist in git history — check git log for fix(${PADDED_PHASE}) commits.
You can retry with /gsd-code-review-fix ${PHASE_ARG}.
You can retry with /gsd-code-review ${PHASE_ARG} --fix.
```
Exit workflow (skip auto loop).
@@ -398,7 +398,7 @@ if [ ! -f "${FIX_REPORT_PATH}" ]; then
echo "The fixer agent may have failed before completing."
echo "Check git log for any fix(${PADDED_PHASE}) commits."
echo ""
echo "Retry: /gsd-code-review-fix ${PHASE_ARG}"
echo "Retry: /gsd-code-review ${PHASE_ARG} --fix"
echo ""
echo "═══════════════════════════════════════════════════════════════"
exit 1

View File

@@ -471,7 +471,7 @@ If total findings > 0:
Full report: ${REVIEW_PATH}
Next steps:
/gsd-code-review-fix ${PHASE_NUMBER} — Auto-fix issues
/gsd-code-review ${PHASE_NUMBER} --fix — Auto-fix issues
cat ${REVIEW_PATH} — View full report
```

View File

@@ -1138,7 +1138,7 @@ REVIEW_STATUS=$(sed -n '/^---$/,/^---$/p' "$REVIEW_FILE" | grep "^status:" | hea
If REVIEW_STATUS is not "clean" and not "skipped" and not empty, display:
```
Code review found issues. Consider running:
/gsd-code-review-fix ${PHASE_NUMBER}
/gsd-code-review ${PHASE_NUMBER} --fix
```
**Error handling:** If the Skill invocation fails or throws, catch the error, display "Code review encountered an error (non-blocking): {error}" and proceed to next step. Review failures must never block execution.

View File

@@ -0,0 +1,259 @@
/**
* Bugs #3029 + #3034: stale slash-command references in shipped surfaces.
*
* Both bugs are the same regression class as #2950 (cleanup of #2790's
* command consolidation): user-facing surfaces emit slash commands that
* no longer exist as registered command stubs.
*
* - #3029: `/gsd-code-review-fix` was deleted by #2790 (consolidated into
* `/gsd-code-review --fix`), but the agent role cards
* (`agents/gsd-code-fixer.md`), several workflow offer blocks
* (`code-review.md`, `execute-phase.md`), and the doc surfaces
* (`USER-GUIDE.md`, `INVENTORY.md`, `AGENTS.md`, `FEATURES.md`,
* `CONFIGURATION.md`) still reference the deleted command. Users hit
* `Unknown command` when they follow the orchestrator's offer.
*
* - #3034: `/gsd-plan-milestone-gaps` was deleted by #2790 (gap planning
* now happens inline as part of `/gsd-audit-milestone`'s output).
* `audit-milestone.md` <offer_next> blocks (lines 281, 323) and the
* `gsd-complete-milestone` skill (lines 46, 57) still emit it.
*
* Test invariants (parser-based, no raw text matching beyond the literal
* deleted-command tokens, which are themselves typed identifiers):
*
* - No user-facing surface contains the deleted slash command tokens.
* - The replacement form is present on each fixed surface.
* - bug-2950-stale-command-refs's existing assertions are not
* regressed.
*
* Internal mentions are allowed:
* - `code-review-fix.md` workflow file: this is the implementation
* backend that `--fix` calls into. Internal references to the
* workflow basename (e.g. "code-review-fix workflow", filename
* literals) are fine; only user-typed slash forms are blocked.
* - Release notes (`docs/RELEASE-*.md`): historical record, immutable.
*/
// allow-test-rule: structural-IR parser for stale-command scrubs. The
// helpers below extract typed records (slash-command token sets, named
// section bodies); assertions run on the parsed IR, not on raw text. The
// .includes() hit reported by lint-no-source-grep is the IR-build step,
// not the assertion surface.
'use strict';
const { describe, test } = require('node:test');
const assert = require('node:assert/strict');
const fs = require('node:fs');
const path = require('node:path');
const ROOT = path.join(__dirname, '..');
function read(rel) {
return fs.readFileSync(path.join(ROOT, rel), 'utf-8');
}
/**
* Extract the set of slash-command tokens emitted by a markdown surface.
* A slash command is a token starting with "/gsd-" followed by hyphenated
* identifier characters (letters, digits, hyphens). Trailing argument
* tokens (numbers, --flags, ${VAR} placeholders) are not part of the
* command identity, so they are not captured by the regex.
*
* Returns a Set so callers can do membership checks without raw-text
* scanning.
*/
function extractSlashCommandTokens(content) {
const re = /\/gsd-[a-z0-9][a-z0-9-]*/g;
return new Set(content.match(re) || []);
}
/**
* Locate the body of an `<offer_next>` block in a workflow file (or, for
* complete-milestone, the `gaps_found` pre-flight code block). Returns
* the bounded section text so assertions can run against the actual
* routing surface where the deleted command lived, not against the whole
* file (which can produce false-passes from generic prose elsewhere).
*
* Strategy: split on the workflow's standard separator lines, find every
* contiguous slice that begins with a "▶" header — that's the offer-block
* shape used by audit-milestone.md. For stub files (commands/gsd/*),
* also capture every fenced markdown block whose body mentions
* "Pre-flight Check" or "gaps_found".
*/
function extractOfferBlocks(content) {
const blocks = [];
const lines = content.split('\n');
for (let i = 0; i < lines.length; i++) {
if (/^##?\s*▶\s+/.test(lines[i])) {
const start = i;
let end = lines.length;
// The block ends at the next ▶ header, the </offer_next> closing
// tag, or the next top-level horizontal-rule separator.
for (let j = i + 1; j < lines.length; j++) {
if (
/^##?\s*▶\s+/.test(lines[j]) ||
/<\/offer_next>/.test(lines[j]) ||
/^---$/.test(lines[j])
) {
end = j;
break;
}
}
blocks.push(lines.slice(start, end).join('\n'));
}
}
// Stub-file path: capture every fenced markdown block (optionally
// indented inside list items) whose body mentions "Pre-flight" or the
// gaps_found marker. Used by commands/gsd/complete-milestone.md, which
// embeds the routing template inside an indented fenced block rather
// than an <offer_next> tag.
const fenceRe = /^[ \t]*```markdown\s*$([\s\S]*?)^[ \t]*```\s*$/gm;
let m;
while ((m = fenceRe.exec(content)) !== null) {
if (/Pre-flight|gaps?[ -]found|gaps_found/i.test(m[1])) {
blocks.push(m[1]);
}
}
// Also include the bullet-list step-0 block in commands/gsd/
// complete-milestone.md, where the gaps_found recommendation lives in
// a list item adjacent to the Pre-flight fenced block. Capture every
// numbered-list step whose body mentions gaps_found.
const numberedStepRe = /^\d+\.\s+\*\*[^*]+\*\*[\s\S]*?(?=^\d+\.\s+\*\*|\Z)/gm;
let s;
while ((s = numberedStepRe.exec(content)) !== null) {
if (/gaps?[ -]found|gaps_found/i.test(s[0])) {
blocks.push(s[0]);
}
}
return blocks;
}
// ─── #3029: /gsd-code-review-fix scrub ──────────────────────────────────────
const CRF_DELETED = '/gsd-code-review-fix';
const CRF_REPLACEMENT = '/gsd-code-review --fix';
// Surfaces a user can encounter as routing/dispatch text. Each must not
// emit the deleted slash-command form.
const CRF_USER_FACING_SURFACES = [
'agents/gsd-code-fixer.md',
'get-shit-done/workflows/code-review.md',
'get-shit-done/workflows/execute-phase.md',
'docs/INVENTORY.md',
'docs/CONFIGURATION.md',
'docs/USER-GUIDE.md',
'docs/AGENTS.md',
'docs/FEATURES.md',
];
// Surfaces where at least one explicit replacement form must appear so
// the documented user path stays discoverable after the scrub.
const CRF_REPLACEMENT_SURFACES = [
'docs/USER-GUIDE.md',
'docs/FEATURES.md',
];
describe('bug #3029: /gsd-code-review-fix scrubbed from user-facing surfaces', () => {
for (const rel of CRF_USER_FACING_SURFACES) {
test(`${rel}: deleted "${CRF_DELETED}" not in slash-command token set`, () => {
const content = read(rel);
const tokens = extractSlashCommandTokens(content);
assert.equal(
tokens.has(CRF_DELETED),
false,
`${rel}: parsed slash-command token set still contains "${CRF_DELETED}" — replace with "${CRF_REPLACEMENT}"`
);
});
}
for (const rel of CRF_REPLACEMENT_SURFACES) {
test(`${rel}: replacement "${CRF_REPLACEMENT}" tokens present`, () => {
const content = read(rel);
// The replacement is a multi-token form (`/gsd-code-review` + the
// `--fix` flag). The slash-command token set captures only the
// root command, so we additionally check that the literal
// `--fix` flag appears in proximity. "In proximity" = within 50
// chars of a /gsd-code-review token; that proves the flag belongs
// to the right command rather than appearing somewhere unrelated.
const tokens = extractSlashCommandTokens(content);
assert.equal(
tokens.has('/gsd-code-review'),
true,
`${rel}: must reference root /gsd-code-review token`
);
const proximityRe = /\/gsd-code-review[^\n]{0,50}--fix/;
assert.ok(
proximityRe.test(content),
`${rel}: must document the "/gsd-code-review … --fix" form (root token + flag within 50 chars)`
);
});
}
});
// ─── #3034: /gsd-plan-milestone-gaps scrub ──────────────────────────────────
const PMG_DELETED = '/gsd-plan-milestone-gaps';
// The closure path is the user-facing replacement for gap planning. We
// don't pin the exact prose — the gsd-ns-project SKILL.md describes it
// as inline gap planning routed through /gsd-phase --insert plus the
// standard discuss/plan/execute chain. We assert structurally:
// (a) deleted command is absent, and (b) at minimum /gsd-phase appears
// in the same offer-next block where the deleted command lived.
const PMG_FIX_SURFACES = [
'get-shit-done/workflows/audit-milestone.md',
'commands/gsd/complete-milestone.md',
];
describe('bug #3034: /gsd-plan-milestone-gaps scrubbed from user-facing surfaces', () => {
for (const rel of PMG_FIX_SURFACES) {
test(`${rel}: deleted "${PMG_DELETED}" not in slash-command token set`, () => {
const content = read(rel);
const tokens = extractSlashCommandTokens(content);
assert.equal(
tokens.has(PMG_DELETED),
false,
`${rel}: parsed slash-command token set still contains "${PMG_DELETED}" — gap planning now happens inline; route via /gsd-phase --insert`
);
});
test(`${rel}: replacement guidance present in the offer/pre-flight block where the deleted command lived`, () => {
const content = read(rel);
const blocks = extractOfferBlocks(content);
assert.ok(
blocks.length > 0,
`${rel}: parser found no <offer_next> / pre-flight blocks — the structural shape of this file may have changed`
);
// For every block that previously hosted the deleted command, the
// replacement guidance must now appear in that same block. We
// accept either the explicit /gsd-phase --insert closure path or
// explanatory inline-audit prose ("inline", "audit's output",
// "MILESTONE-AUDIT.md").
const inlineProseRe = /inline|audit.*output|gap.*planning.*now|MILESTONE-AUDIT\.md/i;
const blocksWithReplacement = blocks.filter(
(b) => b.includes('/gsd-phase --insert') || inlineProseRe.test(b)
);
assert.ok(
blocksWithReplacement.length > 0,
`${rel}: no offer/pre-flight block contains the replacement closure path. ` +
`Expected at least one block to mention "/gsd-phase --insert" or inline-audit prose ` +
`(scoped check, not file-wide — see CR #3038)`
);
});
}
});
// ─── Cross-issue invariant: gsd-ns-project still documents the deletion ─────
describe('cross-check: gsd-ns-project keeps the deletion note', () => {
test('commands/gsd/ns-project.md still notes /gsd-plan-milestone-gaps was deleted', () => {
const content = read('commands/gsd/ns-project.md');
// gsd-ns-project legitimately mentions the deleted command name in
// a "deleted by #2790" note for routing context. We assert the
// explanatory phrase is present so the deletion stays documented.
assert.ok(
/gsd-plan-milestone-gaps.*deleted by #2790|deleted by #2790.*gsd-plan-milestone-gaps/s.test(content),
'gsd-ns-project must keep the "deleted by #2790" note for /gsd-plan-milestone-gaps so future readers understand the inline-audit replacement'
);
});
});