enhance(#4139): Phase 6 — the lazily-read remainder and the artifact templates (#4540)

* enhance(#4406): the lazily-read remainder and the artifact templates

ADR-4139 Decision 3, Phase 6 of the #4139 Compact Content epic. Covers stream 1b
(gsd-core/workflows/<name>/{modes,steps,templates}/*.md) and stream 4
(gsd-core/templates/**) with a variant-swap mechanism, confirmed with the user:
two independent, complete files per covered path (canonical + .compact.md
sibling), with the gate picking which one gets Read at the call site. This is
a different shape from Phase 5's spine+detail partition, and is safe here
specifically because these files are already reached only by a runtime Read —
a missed Read already means zero overlay content today, with or without
workflow.compact_content, so selecting between two independently-complete
files introduces no new failure mode (documented in
gsd-core/references/compact-content-gate.md's new "Streams 1b and 4" section).

Disposition, after inspecting every candidate rather than trusting a byte-size
threshold (same rigor Phase 5 applied to review.md):

- Stream 1b: 1 of 78 files compacted (help/modes/full.md, a user-facing
  reference doc emitted verbatim, not orchestrator instruction). The other 9
  size-threshold candidates are dominated by fail-closed guards, exact CLI
  invocations, or output-format contracts (AskUserQuestion blocks) — recorded
  not-worth-compacting, same reasoning as Phase 5's review.md.
- Stream 4: a ground-truth reachability audit replaced the initial size-only
  candidate list. Two files (summary.md, user-setup.md) got compact variants;
  a third (spec.md) was drafted, then dropped after discovering its only two
  call sites are eager @-includes, not a runtime Read — stream-1 material
  hiding under gsd-core/templates/, not stream-4's actual mechanism. summary.md
  itself has 3 eager call sites and only 1 genuine runtime-Read call site
  (execute-plan.md); only that one was wired, so the compact variant's savings
  apply to the sequential single-plan execution path only.
- Discovered while auditing reachability: 12 gsd-core/templates/** files with
  zero references anywhere in workflow/agent/command prose, compiled source,
  or tests — dead scaffolding predating this phase. Deleted in this same PR
  per this repo's no-defer policy, after re-verifying against a computed
  path.join(...) pattern (not just a plain-string search) that nearly caused
  two genuinely load-bearing templates (user-profile.md, dev-preferences.md)
  to be misclassified as dead.

New checker (tests/helpers/compact-content-variant.cjs): registration,
reachability, protected-content-preserved, size-smaller — replacing Phase
3/5's disjointness/completeness checks, which assume a partition rather than
two deliberately-overlapping documents. The reachability check's own
"unprefixed match" guard had a real bug (rejected the repo's own
`~/.claude/gsd-core/...` convention), caught by running it against the
already-wired help/modes/full.compact.md pair rather than only synthetic
fixtures — fixed to anchor on the nearest `gsd-core` path segment instead.

Template consumer parity (tests/compact-content-template-variant-parity.test.cjs):
proves each compact variant's `## File Template` fenced block — the actual
output-format contract a generated SUMMARY.md/USER-SETUP.md is parsed
against — is byte-identical to the canonical file, then runs the one real
deterministic consumer (gsd-core/bin/lib/coverage.cjs's classifyContent,
backing `gsd-tools uat classify-coverage`) against content built from that
shared contract.

Added a sibling benchmark script (scripts/benchmark-compact-content-variants.cjs)
rather than extending the existing spine/detail one — different data shape,
and the existing script's own contract deliberately isolates it from a
test-only helper's shape changing.

Emitted-drift acknowledgement: not needed. Every changed/added path in this
diff is hand-authored and present in the diff itself, so diffEmitted's
attribution loop resolves `via` to the path's own source before reaching the
ack-lookup branch (same reasoning Phase 5 verified for its own diff).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

* enhance(#4406): address code-review findings on the variant-swap gate

- docs/CONFIGURATION.md and gsd-core/references/planning-config.md's
  workflow.compact_content entries described only the spine+detail mechanism
  (Phase 5) and were missing this phase's variant-swap mechanism and its
  benchmark:compact-content-variants script entirely — required since this
  PR's changeset is type Added (CLAUDE.md's "Missing Docs for Changesets"
  rule). Both now describe both mechanisms and which call sites are wired.
- Added the missing RED^-1/no-op fixture for checkProtectedContentPreserved:
  a canonical file with zero <!-- gsd:protected --> blocks must be a
  no-op, not a violation — the only branch of that function the existing
  fixtures didn't exercise.
- Collapsed findCompactFiles/findMarkdownFiles in
  tests/helpers/compact-content-variant.cjs into one findFilesWithSuffix
  helper — the two were identical recursive walks differing only in the
  extension predicate (minor Duplicated-Code finding).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

* fix(#4406): restore copilot-instructions.md, a false-positive dead-template classification

gsd-test caught this, not static analysis: 10 real failures in
tests/copilot-install.test.cjs, tests/installer-migration-install.integration.test.cjs,
and tests/repo-layout.test.cjs — all downstream of bin/install.js's Copilot install
path, which does
fs.readFileSync(path.join(targetDir, 'gsd-core', 'templates', 'copilot-instructions.md'))
after copying gsd-core/templates/** into the target project, then merges it into both
.github/copilot-instructions.md and (local installs) AGENTS.md. The reachability audit
that flagged this file as dead checked src/*.cts and gsd-core/bin/*.cjs but never the
repo-root bin/install.js — a separately maintained installer bundle outside the
src/-to-gsd-core/bin/lib/ compiled-output convention. The fs.existsSync guard around
that read degrades to a silent skip rather than a crash when the template is missing,
which is why this surfaced only once the real E2E install test ran, not from any
static check.

Re-verified the remaining 11 deleted filenames against bin/install.js specifically
(plain substring and quoted-filename search) before trusting that list — all 11 have
zero hits there, confirmed dead by the same standard this one file failed.

Regenerated the installer emitted-tree goldens (tests/fixtures/install-tree/*.json) to
reflect the restored file, and corrected the "Removed" changeset (jolly-lynx-sprint.md)
and the phase design doc from 12 to 11 deleted files.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Emitted-Drift-Ack-Growth: execute-plan.md — call-site wiring for the summary.md and user-setup.md .compact.md variants
Emitted-Drift-Ack-Growth: help.md — call-site wiring for full.compact.md, same variant-resolution rule

* docs(#4406): backfill changeset PR numbers

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

* fix(#4406): resolve removed-but-needed lint findings on the dead-template deletion

CI's own full-test matrix (not gsd-test's matrix, which does not run this
check) caught 4 more false-positive dead-template classifications via
tests/removed-but-needed-lint.test.cjs / scripts/lint-removed-but-needed.cjs
— a literal, word-boundary basename check across .github/workflows/,
gsd-core/, and docs/ (excluding docs/adr/** and docs/research/**) for every
file a PR deletes. It has no semantic awareness, so a deleted template's
basename colliding with something else entirely still fires:

- claude-md.md: gsd-core/templates/README.md had a stale table row claiming
  /gsd-profile reads this template to generate CLAUDE.md. Verified false (no
  code reads it anywhere, same search that already covered bin/install.js) —
  fixed the row to *(inline)*, matching every other command-generated
  artifact in that table. File stays deleted.
- codebase/testing.md: collided with docs/guides/testing.md, an illustrative
  example row in docs-update.md's sample output table (an unrelated real
  generated-docs path). Swapped the example topic to "contributing" — the
  row is illustrative, any topic works. File stays deleted.
- codebase/architecture.md, codebase/stack.md: collided with docs/reference/
  planning-artifacts.md's directory listing of a user's own generated
  .planning/codebase/architecture.md and stack.md output — the same
  semantic mismatch already investigated and dismissed as unrelated earlier
  in this phase's audit, now caught by a gate instead of judgment. That
  listing repeats across 5 locale copies of the doc.
- continue-here.md: collided with the real .continue-here.md pause-work
  artifact, referenced across 15+ locale and workflow files.

For the last two, the lint's own error message offers "restore the file or
update every consumer in the same commit." Rewording 15+ files across
languages I cannot verify translation quality for, to shave 2 already-tiny
templates that were merely presumed dead, is disproportionate to this PR's
actual scope — restored codebase/architecture.md, codebase/stack.md, and
continue-here.md instead, and corrected docs/ARCHITECTURE.md's Templates
section accordingly.

Final confirmed-dead set: claude-md.md, codebase/concerns.md,
codebase/conventions.md, codebase/integrations.md, codebase/structure.md,
codebase/testing.md, debug-subagent-prompt.md, discovery.md — 8 files, down
from the original 12. Verified locally: GSD_REMOVED_BUT_NEEDED_BASE=next
node scripts/lint-removed-but-needed.cjs now passes clean.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Emitted-Drift-Ack-Growth: docs-update.md — swapped an illustrative example-table topic (testing -> contributing) to avoid a removed-but-needed basename collision with the deleted codebase/testing.md template; net +10 bytes

* fix(#4406): split codex-config.test.cjs to fix a genuine Windows CI timeout

Root cause of the `full test (windows-latest, 24, shard 2/3)` failure the
user asked to be actually fixed, not just re-run past: PR #4497 (landed
2026-09-07, one day before this PR's CI run) isolated
tests/codex-config.test.cjs into its own dedicated chunk because its
measured weight (17.87, ~45% of the post-cut Windows budget) made it unsafe
to share a chunk with any other file. That isolation was necessary but not
sufficient — even alone, with zero companion-file contention, the file's
real Windows execution time sits right at the 600s per-chunk ceiling. Two
independent CI runs on two unrelated PRs (this one and #4154) were both
killed within ~1.4s of the identical 600000ms mark — not random contention,
a deterministic near-miss the isolation fix couldn't address because it
never reduced the file's own cost, only removed the risk of a companion
file's cost stacking on top of it (which the PR #4497 comment explicitly
anticipated: "if a future profiling pass genuinely speeds up
codex-config.test.cjs itself, this isolation can be revisited").

The file itself explains why it's this heavy: 11,262 lines / 433 tests / 79
describe blocks, accumulated over dozens of bug-fix PRs (#2695, #2760,
#3245, #3285, #3346, #3426, #3427, #3562, #3566, #3582, #3808, and more),
several of which are explicitly documented as "folded" in from separate
files that were never actually split back out ("Verified non-duplicate
against both the pre-existing target and the other three folded sources").

Split into 4 files by top-level AST statement boundaries (never a naive
column-0 regex — an early attempt at that overcounted 79 apparent
"describe(" matches when only 21 are genuinely top-level; the rest are
nested inside a handful of large folded-in blocks, which a regex can't tell
apart from real top-level statements). Verified lossless twice: the split
script asserts byte-for-byte reconstruction of every source character, and
independently, total test()/describe() call counts match exactly between
the original file and the sum across all 4 new files (433/79 both sides).
Each new file carries the complete original shared header (imports/helpers)
for safety; per-file unused-import warnings from that duplication are
resolved via ESLint-precise alias renames (`{ foo: _foo }`, the standard
form for an intentionally-unused destructured binding — never a bare `{
_foo }`, which would destructure a different, nonexistent property).

No change needed to scripts/run-tests.cjs's ISOLATED_HEAVY_FILES or its
pinned test in tests/run-tests-harness.test.cjs: the file that keeps the
original name (tests/codex-config.test.cjs) is now only ~28% of the
original's size and safely isolated in its own chunk as before; the other
three new files re-enter normal weight-balanced packing, none individually
close to disproportionate. Confirmed no other file hardcodes the hardcoded
filename anywhere that would silently stop these tests from running (the
CI test-selection scripts determine scope algorithmically, not by literal
filename).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

---------

Co-authored-by: sim <sim@local>
Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Tom Boucher
2026-09-08 14:31:04 -04:00
committed by GitHub
parent 66dbb104a0
commit a27cb6b2fa
52 changed files with 10865 additions and 10511 deletions

View File

@@ -0,0 +1,5 @@
---
type: Removed
pr: 4540
---
**Removed 8 unreferenced planning-artifact scaffolding templates under `gsd-core/templates/`** (`claude-md.md`, four of the seven `codebase/` brownfield-mapping templates — `concerns.md`, `conventions.md`, `integrations.md`, `structure.md` — plus `debug-subagent-prompt.md` and `discovery.md`) — confirmed, file by file, to have zero references anywhere in workflow prose, agent/command definitions, compiled source, or tests, and (for the deleted set specifically) no surviving basename reference anywhere in the tree either. `codebase/architecture.md`, `codebase/stack.md`, and `continue-here.md` were kept: their basenames collide with unrelated, genuinely live concepts documented across many files (a user's generated `.planning/codebase/*.md` output, and the real `.continue-here.md` pause-work artifact), so deleting them would have required rewording numerous translated docs to describe something else entirely.

View File

@@ -0,0 +1,5 @@
---
type: Added
pr: 4540
---
**`workflow.compact_content` now also covers lazily-read workflow fragments and planning-artifact templates.** With the key on, `help --full`'s reference doc and generated `SUMMARY.md`/`USER-SETUP.md` templates resolve to a terser `.compact.md` sibling at the point of their existing `Read` — two independent, complete files, picked per the same shared gate Phase 5 introduced (`gsd-core/references/compact-content-gate.md`). With the key off (default), nothing changes.

View File

@@ -277,7 +277,7 @@ Markdown templates for all planning artifacts. Used by `gsd-tools.cjs template f
- `DEBUG.md` — Debug session tracking template - `DEBUG.md` — Debug session tracking template
- `UI-SPEC.md`, `UAT.md`, `VALIDATION.md` — Specialized verification templates - `UI-SPEC.md`, `UAT.md`, `VALIDATION.md` — Specialized verification templates
- `discussion-log.md` — Discussion audit trail template - `discussion-log.md` — Discussion audit trail template
- `codebase/` — Brownfield mapping templates (stack, architecture, conventions, concerns, structure, testing, integrations) - `codebase/` — Brownfield mapping templates (architecture, stack)
- `research-project/` — Research output templates (SUMMARY, STACK, FEATURES, ARCHITECTURE, PITFALLS) - `research-project/` — Research output templates (SUMMARY, STACK, FEATURES, ARCHITECTURE, PITFALLS)
### Hooks (`hooks/`) ### Hooks (`hooks/`)

View File

@@ -517,7 +517,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.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. **Branch-divergence note:** when your branch has diverged from `origin/HEAD`, GSD auto-degrades to sequential and prints a warning. See [`worktree.baseRef`](#worktree-settings) to restore parallel execution on a diverged branch. **Per-runtime note:** whether this key can be honored depends on the runtime's declared `dispatch.isolation` capability, not on its name (#2584). Runtimes whose own harness isolates each executor (**Claude Code**, **Cursor**) run parallel worktrees natively; runtimes exposing a headless exec with an explicit working directory (**Codex**, **OpenCode**, **Kimi**, **Kimi Code**) get worktrees GSD itself creates and merges — where a dispatch site can only drive the harness model, those hosts degrade to sequential with a warning rather than aborting. Every other runtime declares no isolation primitive, and forcing `use_worktrees: true` there still fails closed before any executor dispatch. `/gsd-health` reports such a value as warning `W025` (#2486). **Default on a non-Claude install:** if a worktree-capable non-Claude host is not isolating as described above, check whether the install stamped this key's default to `false` and set an explicit `use_worktrees: true`. See [Executor isolation per runtime](#executor-isolation-per-runtime). | | `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. **Branch-divergence note:** when your branch has diverged from `origin/HEAD`, GSD auto-degrades to sequential and prints a warning. See [`worktree.baseRef`](#worktree-settings) to restore parallel execution on a diverged branch. **Per-runtime note:** whether this key can be honored depends on the runtime's declared `dispatch.isolation` capability, not on its name (#2584). Runtimes whose own harness isolates each executor (**Claude Code**, **Cursor**) run parallel worktrees natively; runtimes exposing a headless exec with an explicit working directory (**Codex**, **OpenCode**, **Kimi**, **Kimi Code**) get worktrees GSD itself creates and merges — where a dispatch site can only drive the harness model, those hosts degrade to sequential with a warning rather than aborting. Every other runtime declares no isolation primitive, and forcing `use_worktrees: true` there still fails closed before any executor dispatch. `/gsd-health` reports such a value as warning `W025` (#2486). **Default on a non-Claude install:** if a worktree-capable non-Claude host is not isolating as described above, check whether the install stamped this key's default to `false` and set an explicit `use_worktrees: true`. See [Executor isolation per runtime](#executor-isolation-per-runtime). |
| `workflow.agent_hint_routing` | boolean | `true` | Per-plan specialist executor routing (#1689). When `true`, a plan whose `agent_hint:` frontmatter names a subagent that resolves on the active runtime is dispatched to that specialist instead of `gsd-executor`. Default `true` — a no-op for plans without `agent_hint:`, so existing dispatch is unchanged. Set `false` to disable. See [PLAN.md `agent_hint`](reference/plan-md.md#per-plan-executor-routing). | | `workflow.agent_hint_routing` | boolean | `true` | Per-plan specialist executor routing (#1689). When `true`, a plan whose `agent_hint:` frontmatter names a subagent that resolves on the active runtime is dispatched to that specialist instead of `gsd-executor`. Default `true` — a no-op for plans without `agent_hint:`, so existing dispatch is unchanged. Set `false` to disable. See [PLAN.md `agent_hint`](reference/plan-md.md#per-plan-executor-routing). |
| `workflow.compact_content` | boolean | `false` | Compact content mode (#4139, [ADR-4139](adr/4139-compact-content-seam.md)). Per-project boolean selecting the terser form of GSD's own shipped prompt content (workflows, templates, agent-skill payloads). Six workflows branch on it today — `plan-phase` (#4402, the pilot), `execute-phase`, `docs-update`, `new-project`, `verify-work`, and `complete-milestone` (#4405) — each split into a spine plus a deferred `<workflow>/detail/*.md` elaboration: with the key off, the spine reads its own elaboration back in before continuing (byte-identical instruction set to before); with it on, that read is skipped. The remaining eagerly-`@`-included workflows were reviewed and recorded as not worth splitting (see `docs/PARTITION-RULES.md` § "Deciding whether a file is worth splitting") — either their size comes from safety-critical orchestration logic rather than deferrable narrative (`review.md`), or they're small enough that a split's fixed structural overhead would exceed the savings. The eager-window token reduction each split actually achieves is measured, not asserted: `npm run benchmark:compact-content` reports per-split and aggregate on/off token counts (a proxy-tokenizer delta — Anthropic publishes no tokenizer for Claude 3+, so the comparison is exact under a pinned tokenizer even though the absolute counts are not Claude's real ones) against a committed baseline (`tests/fixtures/compact-content-benchmark-baseline.json`, #4404). Reporting-only — it never fails CI. | | `workflow.compact_content` | boolean | `false` | Compact content mode (#4139, [ADR-4139](adr/4139-compact-content-seam.md)). Per-project boolean selecting the terser form of GSD's own shipped prompt content (workflows, templates, agent-skill payloads). Two mechanisms exist, chosen per stream. **Spine + detail** (top-level, eagerly-`@`-included workflows): six workflows branch on it today — `plan-phase` (#4402, the pilot), `execute-phase`, `docs-update`, `new-project`, `verify-work`, and `complete-milestone` (#4405) — each split into a spine plus a deferred `<workflow>/detail/*.md` elaboration: with the key off, the spine reads its own elaboration back in before continuing (byte-identical instruction set to before); with it on, that read is skipped. The remaining eagerly-`@`-included workflows were reviewed and recorded as not worth splitting (see `docs/PARTITION-RULES.md` § "Deciding whether a file is worth splitting") — either their size comes from safety-critical orchestration logic rather than deferrable narrative (`review.md`), or they're small enough that a split's fixed structural overhead would exceed the savings. **Variant swap** (#4406 — lazily-`Read` workflow subdirectory files and `gsd-core/templates/**` planning-artifact templates, which have no eager window to shrink): a `.compact.md` sibling next to the canonical file, resolved at the point of the existing `Read` per `gsd-core/references/compact-content-gate.md` § "Streams 1b and 4". Three call sites are wired today — `help --full`'s reference doc (`gsd-core/workflows/help/modes/full.md`) and the sequential-execution `SUMMARY.md`/`USER-SETUP.md` template reads in `execute-plan.md` — after a per-candidate reachability audit found most other size-based candidates were either genuinely unreferenced (deleted), reached only through an eager `@`-include or orchestrator build-time embed (left unconverted, same reasoning as the eagerly-included workflows above), or consumed only by a test fixture or a parser's documented grammar rather than a runtime `Read`. The token reduction each mechanism actually achieves is measured, not asserted: `npm run benchmark:compact-content` (spine/detail) and `npm run benchmark:compact-content-variants` (variant-swap) each report per-item and aggregate on/off token counts (a proxy-tokenizer delta — Anthropic publishes no tokenizer for Claude 3+, so the comparison is exact under a pinned tokenizer even though the absolute counts are not Claude's real ones) against their own committed baseline (`tests/fixtures/compact-content-benchmark-baseline.json`, #4404; `tests/fixtures/compact-content-variant-benchmark-baseline.json`, #4406). Both are reporting-only — neither ever fails CI. |
| `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.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_point` | string | `execute:post` | Loop point at which the code-review capability's step registers: `execute:post` reviews once, after every wave in a phase has landed (default — unchanged behavior); `execute:wave:post` reviews once per completed wave instead, scoped to what changed since the phase's prior review (the whole phase's diff on the first wave, each subsequent wave's own diff thereafter). Manual `/gsd-code-review <phase>` invocation is unaffected by this key — it is gated by `workflow.code_review` alone and runs regardless of which point is configured. `/gsd-autonomous` and `/gsd-quick` have no wave granularity of their own, so setting this to `execute:wave:post` means code review does not run automatically inside those two flows (consistent with how every other `execute:wave:post`-only capability already behaves for them). Added in #3661 | | `workflow.code_review_point` | string | `execute:post` | Loop point at which the code-review capability's step registers: `execute:post` reviews once, after every wave in a phase has landed (default — unchanged behavior); `execute:wave:post` reviews once per completed wave instead, scoped to what changed since the phase's prior review (the whole phase's diff on the first wave, each subsequent wave's own diff thereafter). Manual `/gsd-code-review <phase>` invocation is unaffected by this key — it is gated by `workflow.code_review` alone and runs regardless of which point is configured. `/gsd-autonomous` and `/gsd-quick` have no wave granularity of their own, so setting this to `execute:wave:post` means code review does not run automatically inside those two flows (consistent with how every other `execute:wave:post`-only capability already behaves for them). Added in #3661 |

View File

@@ -603,6 +603,7 @@
"discuss-phase/modes/text.md", "discuss-phase/modes/text.md",
"help/modes/brief.md", "help/modes/brief.md",
"help/modes/default.md", "help/modes/default.md",
"help/modes/full.compact.md",
"help/modes/full.md", "help/modes/full.md",
"help/modes/topic.md" "help/modes/topic.md"
], ],

View File

@@ -1,6 +1,9 @@
# Compact Content Gate # Compact Content Gate
Shared by every workflow spine split under ADR-4139. States the config check and the resolution rule once — a spine references this file; it never restates the check inline. Shared by every workflow spine split under ADR-4139, and by every lazily-read fragment or
planning-artifact template given a compact variant under Phase 6 (#4406). States the config check
and both resolution rules once — a spine or fragment references this file; it never restates
either check inline.
## The check ## The check
@@ -8,11 +11,40 @@ Shared by every workflow spine split under ADR-4139. States the config check and
COMPACT_CONTENT=$(gsd_run query config-get workflow.compact_content --raw 2>/dev/null || echo "false") COMPACT_CONTENT=$(gsd_run query config-get workflow.compact_content --raw 2>/dev/null || echo "false")
``` ```
## The resolution rule ## Stream 1 — spine + detail (top-level, eagerly `@`-included workflows)
- **`COMPACT_CONTENT` is `"false"` (default):** Read every part under this workflow's own `detail/` directory (a sibling of this spine, e.g. `gsd-core/workflows/<name>/detail/*.md`) now, in full, before continuing past this point. Their content elaborates on the spine you are reading — treat everything they say as part of this document from here on. - **`COMPACT_CONTENT` is `"false"` (default):** Read every part under this workflow's own `detail/` directory (a sibling of this spine, e.g. `gsd-core/workflows/<name>/detail/*.md`) now, in full, before continuing past this point. Their content elaborates on the spine you are reading — treat everything they say as part of this document from here on.
- **`COMPACT_CONTENT` is `"true"`:** Do not read the detail file. Continue directly with the spine's own content — per ADR-4139 Decision 3, it is complete enough to run this workflow correctly on its own. - **`COMPACT_CONTENT` is `"true"`:** Do not read the detail file. Continue directly with the spine's own content — per ADR-4139 Decision 3, it is complete enough to run this workflow correctly on its own.
## The fail-safe this exists to hold (ADR-4139 Decision 4) **The fail-safe this holds (ADR-4139 Decision 4):** A `Read` that does not fire for any reason (tool error, a skipped step, a misread condition) leaves you running on the spine alone. That is the same, correct, terser state an opted-in project runs in on purpose — never a state with no instructions. The spine's own completeness is what makes this safe; this gate is only ever additive.
A `Read` that does not fire for any reason (tool error, a skipped step, a misread condition) leaves you running on the spine alone. That is the same, correct, terser state an opted-in project runs in on purpose — never a state with no instructions. The spine's own completeness is what makes this safe; this gate is only ever additive. ## Streams 1b and 4 — variant resolution (lazily-read fragments and planning-artifact templates)
For a `workflows/<name>/{modes,steps,templates}/*.md` fragment or a `gsd-core/templates/**`
planning-artifact template that has a registered `.compact.md` sibling (same directory, same stem,
`.compact.md` suffix):
- **`COMPACT_CONTENT` is `"false"` (default), or the file has no registered `.compact.md` sibling:** Read the canonical path exactly as named — unchanged from today.
- **`COMPACT_CONTENT` is `"true"` and a `.compact.md` sibling is registered:** Read the `.compact.md` sibling instead of the canonical path.
Both files are complete, independently — Read exactly one, never both, and never read the compact
sibling's content as an addendum to the canonical file.
**The fail-safe this holds:** unlike stream 1, a call site this rule actually applies to is already
reached only by a runtime `Read` — a missed `Read` already means zero overlay content, with or
without `workflow.compact_content`. Selecting between two independently-complete files at that
call site does not introduce a new way to end up with nothing; the worst case is identical to
today's. This is why stream 1b/4 can use variant-swap (two independent files) where stream 1 could
not: the degradation-direction argument that ruled out converting stream 1's `@`-includes (ADR-4139
Decision 4) does not apply at a genuine runtime-`Read` call site, because there is no
host-guaranteed baseline being traded away there.
**This rule is scoped per call site, not per file.** A `gsd-core/templates/**` file can have both
kinds of reference in the corpus at once — some places name it inside an eager `@`-include or an
orchestrator build-time embed (the same mechanism as stream 1, just reaching a template path
instead of a workflow path), others name it in prose instructing a runtime `Read`. Only the latter
gets rewritten to point at this rule; an eager reference to the canonical file is left exactly as
it is, for the same reason stream 1's `@`-includes were left alone — converting it would trade a
host-guaranteed load for a conditional one. Before wiring any call site, confirm by inspection
which kind it is; do not assume every mention of a `gsd-core/templates/**` path is a runtime `Read`
just because the directory's typical case is.

View File

@@ -289,7 +289,7 @@ Set via `workflow.*` namespace in config.json (e.g., `"workflow": { "research":
| `workflow.ui_phase` | boolean | `true` | `true`, `false` | Generate UI-SPEC.md for frontend phases | | `workflow.ui_phase` | boolean | `true` | `true`, `false` | Generate UI-SPEC.md for frontend phases |
| `workflow.ui_safety_gate` | boolean | `true` | `true`, `false` | Require safety gate approval for UI changes | | `workflow.ui_safety_gate` | boolean | `true` | `true`, `false` | Require safety gate approval for UI changes |
| `workflow.text_mode` | boolean | `false` | `true`, `false` | Use plain-text numbered lists instead of AskUserQuestion menus | | `workflow.text_mode` | boolean | `false` | `true`, `false` | Use plain-text numbered lists instead of AskUserQuestion menus |
| `workflow.compact_content` | boolean | `false` | `true`, `false` | Compact content mode (#4139, ADR-4139) — per-project boolean selecting terser payloads. Six workflows branch on it: `plan-phase` (#4402, pilot), `execute-phase`, `docs-update`, `new-project`, `verify-work`, `complete-milestone` (#4405). The rest of the eager-window corpus was reviewed and recorded as not worth splitting (`docs/PARTITION-RULES.md`) | | `workflow.compact_content` | boolean | `false` | `true`, `false` | Compact content mode (#4139, ADR-4139) — per-project boolean selecting terser payloads. Six workflows branch on it via spine+detail: `plan-phase` (#4402, pilot), `execute-phase`, `docs-update`, `new-project`, `verify-work`, `complete-milestone` (#4405). The rest of the eager-window corpus was reviewed and recorded as not worth splitting (`docs/PARTITION-RULES.md`). Lazily-`Read` workflow fragments and `gsd-core/templates/**` templates use a `.compact.md` sibling instead (#4406, `gsd-core/references/compact-content-gate.md` § "Streams 1b and 4") — wired today for `help --full` and the sequential-execution `SUMMARY.md`/`USER-SETUP.md` reads |
| `workflow.research_before_questions` | boolean | `false` | `true`, `false` | Run research before interactive questions in discuss phase (also honored on the `/gsd:quick` path, #3894). _Alias:_ `research_before_questions` is the flat-key form used in `CONFIG_DEFAULTS`; `workflow.research_before_questions` is the canonical namespaced form. | | `workflow.research_before_questions` | boolean | `false` | `true`, `false` | Run research before interactive questions in discuss phase (also honored on the `/gsd:quick` path, #3894). _Alias:_ `research_before_questions` is the flat-key form used in `CONFIG_DEFAULTS`; `workflow.research_before_questions` is the canonical namespaced form. |
| `workflow.discuss_mode` | string | `"discuss"` | `"discuss"`, `"assumptions"` | Default mode for discuss-phase: `"discuss"` runs interactive questioning; `"assumptions"` analyzes codebase and surfaces assumptions instead | | `workflow.discuss_mode` | string | `"discuss"` | `"discuss"`, `"assumptions"` | Default mode for discuss-phase: `"discuss"` runs interactive questioning; `"assumptions"` analyzes codebase and surfaces assumptions instead |
| `workflow.skip_discuss` | boolean | `false` | `true`, `false` | Skip discuss phase entirely | | `workflow.skip_discuss` | boolean | `false` | `true`, `false` | Skip discuss phase entirely |

View File

@@ -21,7 +21,7 @@ These files live directly at `.planning/` — not inside phase subdirectories.
| `LEARNINGS.md` | *(inline)* | `/gsd:extract-learnings`, `/gsd:execute-phase` (gated: `features.global_learnings`) | Phase retrospective learnings for future plans | | `LEARNINGS.md` | *(inline)* | `/gsd:extract-learnings`, `/gsd:execute-phase` (gated: `features.global_learnings`) | Phase retrospective learnings for future plans |
| `THREADS.md` | *(inline)* | `/gsd:thread` | Persistent discussion threads | | `THREADS.md` | *(inline)* | `/gsd:thread` | Persistent discussion threads |
| `config.json` | `config.json` | `/gsd:new-project`, `/gsd:health --repair` | Project-specific GSD configuration | | `config.json` | `config.json` | `/gsd:new-project`, `/gsd:health --repair` | Project-specific GSD configuration |
| `CLAUDE.md` | `claude-md.md` | `/gsd-profile` | Auto-assembled Claude Code context file | | `CLAUDE.md` | *(inline)* | `/gsd-profile` | Auto-assembled Claude Code context file |
| `RETROSPECTIVE.md` | *(inline)* | `/gsd:complete-milestone` | Living milestone retrospective updated at each milestone close | | `RETROSPECTIVE.md` | *(inline)* | `/gsd:complete-milestone` | Living milestone retrospective updated at each milestone close |
### Version-stamped artifacts (pattern: `vX.Y-*.md`) ### Version-stamped artifacts (pattern: `vX.Y-*.md`)

View File

@@ -1,145 +0,0 @@
# CLAUDE.md Template
Template for project-root `CLAUDE.md` — auto-generated by `gsd-tools generate-claude-md`.
Contains 7 marker-bounded sections. Each section is independently updatable.
The `generate-claude-md` subcommand manages 6 sections (project, stack, conventions, architecture, skills, workflow enforcement).
The profile section is managed exclusively by `generate-claude-profile`.
---
## Section Templates
### Project Section
```
<!-- GSD:project-start source:PROJECT.md -->
## Project
{{project_content}}
<!-- GSD:project-end -->
```
**Fallback text:**
```
Project not yet initialized. Run /gsd:new-project to set up.
```
### Stack Section
```
<!-- GSD:stack-start source:STACK.md -->
## Technology Stack
{{stack_content}}
<!-- GSD:stack-end -->
```
**Fallback text:**
```
Technology stack not yet documented. Will populate after codebase mapping or first phase.
```
### Conventions Section
```
<!-- GSD:conventions-start source:CONVENTIONS.md -->
## Conventions
{{conventions_content}}
<!-- GSD:conventions-end -->
```
**Fallback text:**
```
Conventions not yet established. Will populate as patterns emerge during development.
```
### Architecture Section
```
<!-- GSD:architecture-start source:ARCHITECTURE.md -->
## Architecture
{{architecture_content}}
<!-- GSD:architecture-end -->
```
**Fallback text:**
```
Architecture not yet mapped. Follow existing patterns found in the codebase.
```
### Skills Section
```
<!-- GSD:skills-start source:skills/ -->
## Project Skills
| Skill | Description | Path |
| -------------- | --------------------- | ------------------------- |
| {{skill_name}} | {{skill_description}} | `{{skill_path}}/SKILL.md` |
<!-- GSD:skills-end -->
```
**Fallback text:**
```
No project skills found. Add skills to any of: `.claude/skills/`, `.agents/skills/`, `.cursor/skills/`, or `.github/skills/` with a `SKILL.md` index file.
```
**Discovery behavior:**
- Scans `.claude/skills/`, `.agents/skills/`, `.cursor/skills/`, `.github/skills/` for subdirectories containing `SKILL.md`
- Extracts `name` and `description` from YAML frontmatter (supports multi-line descriptions)
- Skips GSD's own installed skills (directories starting with `gsd-`)
- Deduplicates by skill name across directories
### Workflow Enforcement Section
```
<!-- GSD:workflow-start source:GSD defaults -->
## GSD Workflow Enforcement
Before using Edit, Write, or other file-changing tools, start work through a GSD command so planning artifacts and execution context stay in sync.
Use these entry points:
- `/gsd:quick` for small fixes, doc updates, and ad-hoc tasks
- `/gsd:debug` for investigation and bug fixing
- `/gsd:execute-phase` for planned phase work
Do not make direct repo edits outside a GSD workflow unless the user explicitly asks to bypass it.
<!-- GSD:workflow-end -->
```
### Profile Section (Placeholder Only)
```
<!-- GSD:profile-start -->
## Developer Profile
> Profile not yet configured. Run `/gsd:profile-user` to generate your developer profile.
> This section is managed by `generate-claude-profile` — do not edit manually.
<!-- GSD:profile-end -->
```
**Note:** This section is NOT managed by `generate-claude-md`. It is managed exclusively
by `generate-claude-profile`. The placeholder above is only used when creating a new
CLAUDE.md file and no profile section exists yet.
---
## Section Ordering
1. **Project** — Identity and purpose (what this project is)
2. **Stack** — Technology choices (what tools are used)
3. **Conventions** — Code patterns and rules (how code is written)
4. **Architecture** — System structure (how components fit together)
5. **Skills** — Discovered project skills with name and description (what domain knowledge is available)
6. **Workflow Enforcement** — Default GSD entry points for file-changing work
7. **Profile** — Developer behavioral preferences (how to interact)
## Marker Format
- Start: `<!-- GSD:{name}-start source:{file} -->`
- End: `<!-- GSD:{name}-end -->`
- Source attribute enables targeted updates when source files change
- Partial match on start marker (without closing `-->`) for detection
## Fallback Behavior
When a source file is missing, fallback text provides Claude-actionable guidance:
- Guides Claude's behavior in the absence of data
- Not placeholder ads or "missing" notices
- Each fallback tells Claude what to do, not just what's absent

View File

@@ -1,310 +0,0 @@
# Codebase Concerns Template
Template for `.planning/codebase/CONCERNS.md` - captures known issues and areas requiring care.
**Purpose:** Surface actionable warnings about the codebase. Focused on "what to watch out for when making changes."
---
## File Template
```markdown
# Codebase Concerns
**Analysis Date:** [YYYY-MM-DD]
## Tech Debt
**[Area/Component]:**
- Issue: [What's the shortcut/workaround]
- Why: [Why it was done this way]
- Impact: [What breaks or degrades because of it]
- Fix approach: [How to properly address it]
**[Area/Component]:**
- Issue: [What's the shortcut/workaround]
- Why: [Why it was done this way]
- Impact: [What breaks or degrades because of it]
- Fix approach: [How to properly address it]
## Known Bugs
**[Bug description]:**
- Symptoms: [What happens]
- Trigger: [How to reproduce]
- Workaround: [Temporary mitigation if any]
- Root cause: [If known]
- Blocked by: [If waiting on something]
**[Bug description]:**
- Symptoms: [What happens]
- Trigger: [How to reproduce]
- Workaround: [Temporary mitigation if any]
- Root cause: [If known]
## Security Considerations
**[Area requiring security care]:**
- Risk: [What could go wrong]
- Current mitigation: [What's in place now]
- Recommendations: [What should be added]
**[Area requiring security care]:**
- Risk: [What could go wrong]
- Current mitigation: [What's in place now]
- Recommendations: [What should be added]
## Performance Bottlenecks
**[Slow operation/endpoint]:**
- Problem: [What's slow]
- Measurement: [Actual numbers: "500ms p95", "2s load time"]
- Cause: [Why it's slow]
- Improvement path: [How to speed it up]
**[Slow operation/endpoint]:**
- Problem: [What's slow]
- Measurement: [Actual numbers]
- Cause: [Why it's slow]
- Improvement path: [How to speed it up]
## Fragile Areas
**[Component/Module]:**
- Why fragile: [What makes it break easily]
- Common failures: [What typically goes wrong]
- Safe modification: [How to change it without breaking]
- Test coverage: [Is it tested? Gaps?]
**[Component/Module]:**
- Why fragile: [What makes it break easily]
- Common failures: [What typically goes wrong]
- Safe modification: [How to change it without breaking]
- Test coverage: [Is it tested? Gaps?]
## Scaling Limits
**[Resource/System]:**
- Current capacity: [Numbers: "100 req/sec", "10k users"]
- Limit: [Where it breaks]
- Symptoms at limit: [What happens]
- Scaling path: [How to increase capacity]
## Dependencies at Risk
**[Package/Service]:**
- Risk: [e.g., "deprecated", "unmaintained", "breaking changes coming"]
- Impact: [What breaks if it fails]
- Migration plan: [Alternative or upgrade path]
## Missing Critical Features
**[Feature gap]:**
- Problem: [What's missing]
- Current workaround: [How users cope]
- Blocks: [What can't be done without it]
- Implementation complexity: [Rough effort estimate]
## Test Coverage Gaps
**[Untested area]:**
- What's not tested: [Specific functionality]
- Risk: [What could break unnoticed]
- Priority: [High/Medium/Low]
- Difficulty to test: [Why it's not tested yet]
---
*Concerns audit: [date]*
*Update as issues are fixed or new ones discovered*
```
<good_examples>
```markdown
# Codebase Concerns
**Analysis Date:** 2025-01-20
## Tech Debt
**Database queries in React components:**
- Issue: Direct Supabase queries in 15+ page components instead of server actions
- Files: `app/dashboard/page.tsx`, `app/profile/page.tsx`, `app/courses/[id]/page.tsx`, `app/settings/page.tsx` (and 11 more in `app/`)
- Why: Rapid prototyping during MVP phase
- Impact: Can't implement RLS properly, exposes DB structure to client
- Fix approach: Move all queries to server actions in `app/actions/`, add proper RLS policies
**Manual webhook signature validation:**
- Issue: Copy-pasted Stripe webhook verification code in 3 different endpoints
- Files: `app/api/webhooks/stripe/route.ts`, `app/api/webhooks/checkout/route.ts`, `app/api/webhooks/subscription/route.ts`
- Why: Each webhook added ad-hoc without abstraction
- Impact: Easy to miss verification in new webhooks (security risk)
- Fix approach: Create shared `lib/stripe/validate-webhook.ts` middleware
## Known Bugs
**Race condition in subscription updates:**
- Symptoms: User shows as "free" tier for 5-10 seconds after successful payment
- Trigger: Fast navigation after Stripe checkout redirect, before webhook processes
- Files: `app/checkout/success/page.tsx` (redirect handler), `app/api/webhooks/stripe/route.ts` (webhook)
- Workaround: Stripe webhook eventually updates status (self-heals)
- Root cause: Webhook processing slower than user navigation, no optimistic UI update
- Fix: Add polling in `app/checkout/success/page.tsx` after redirect
**Inconsistent session state after logout:**
- Symptoms: User redirected to /dashboard after logout instead of /login
- Trigger: Logout via button in mobile nav (desktop works fine)
- File: `components/MobileNav.tsx` (line ~45, logout handler)
- Workaround: Manual URL navigation to /login works
- Root cause: Mobile nav component not awaiting supabase.auth.signOut()
- Fix: Add await to logout handler in `components/MobileNav.tsx`
## Security Considerations
**Admin role check client-side only:**
- Risk: Admin dashboard pages check isAdmin from Supabase client, no server verification
- Files: `app/admin/page.tsx`, `app/admin/users/page.tsx`, `components/AdminGuard.tsx`
- Current mitigation: None (relying on UI hiding)
- Recommendations: Add middleware to admin routes in `middleware.ts`, verify role server-side
**Unvalidated file uploads:**
- Risk: Users can upload any file type to avatar bucket (no size/type validation)
- File: `components/AvatarUpload.tsx` (upload handler)
- Current mitigation: Supabase bucket limits to 2MB (configured in dashboard)
- Recommendations: Add file type validation (image/* only) in `lib/storage/validate.ts`
## Performance Bottlenecks
**/api/courses endpoint:**
- Problem: Fetching all courses with nested lessons and authors
- File: `app/api/courses/route.ts`
- Measurement: 1.2s p95 response time with 50+ courses
- Cause: N+1 query pattern (separate query per course for lessons)
- Improvement path: Use Prisma include to eager-load lessons in `lib/db/courses.ts`, add Redis caching
**Dashboard initial load:**
- Problem: Waterfall of 5 serial API calls on mount
- File: `app/dashboard/page.tsx`
- Measurement: 3.5s until interactive on slow 3G
- Cause: Each component fetches own data independently
- Improvement path: Convert to Server Component with single parallel fetch
## Fragile Areas
**Authentication middleware chain:**
- File: `middleware.ts`
- Why fragile: 4 different middleware functions run in specific order (auth -> role -> subscription -> logging)
- Common failures: Middleware order change breaks everything, hard to debug
- Safe modification: Add tests before changing order, document dependencies in comments
- Test coverage: No integration tests for middleware chain (only unit tests)
**Stripe webhook event handling:**
- File: `app/api/webhooks/stripe/route.ts`
- Why fragile: Giant switch statement with 12 event types, shared transaction logic
- Common failures: New event type added without handling, partial DB updates on error
- Safe modification: Extract each event handler to `lib/stripe/handlers/*.ts`
- Test coverage: Only 3 of 12 event types have tests
## Scaling Limits
**Supabase Free Tier:**
- Current capacity: 500MB database, 1GB file storage, 2GB bandwidth/month
- Limit: ~5000 users estimated before hitting limits
- Symptoms at limit: 429 rate limit errors, DB writes fail
- Scaling path: Upgrade to Pro ($25/mo) extends to 8GB DB, 100GB storage
**Server-side render blocking:**
- Current capacity: ~50 concurrent users before slowdown
- Limit: Vercel Hobby plan (10s function timeout, 100GB-hrs/mo)
- Symptoms at limit: 504 gateway timeouts on course pages
- Scaling path: Upgrade to Vercel Pro ($20/mo), add edge caching
## Dependencies at Risk
**react-hot-toast:**
- Risk: Unmaintained (last update 18 months ago), React 19 compatibility unknown
- Impact: Toast notifications break, no graceful degradation
- Migration plan: Switch to sonner (actively maintained, similar API)
## Missing Critical Features
**Payment failure handling:**
- Problem: No retry mechanism or user notification when subscription payment fails
- Current workaround: Users manually re-enter payment info (if they notice)
- Blocks: Can't retain users with expired cards, no dunning process
- Implementation complexity: Medium (Stripe webhooks + email flow + UI)
**Course progress tracking:**
- Problem: No persistent state for which lessons completed
- Current workaround: Users manually track progress
- Blocks: Can't show completion percentage, can't recommend next lesson
- Implementation complexity: Low (add completed_lessons junction table)
## Test Coverage Gaps
**Payment flow end-to-end:**
- What's not tested: Full Stripe checkout -> webhook -> subscription activation flow
- Risk: Payment processing could break silently (has happened twice)
- Priority: High
- Difficulty to test: Need Stripe test fixtures and webhook simulation setup
**Error boundary behavior:**
- What's not tested: How app behaves when components throw errors
- Risk: White screen of death for users, no error reporting
- Priority: Medium
- Difficulty to test: Need to intentionally trigger errors in test environment
---
*Concerns audit: 2025-01-20*
*Update as issues are fixed or new ones discovered*
```
</good_examples>
<guidelines>
**What belongs in CONCERNS.md:**
- Tech debt with clear impact and fix approach
- Known bugs with reproduction steps
- Security gaps and mitigation recommendations
- Performance bottlenecks with measurements
- Fragile code that breaks easily
- Scaling limits with numbers
- Dependencies that need attention
- Missing features that block workflows
- Test coverage gaps
**What does NOT belong here:**
- Opinions without evidence ("code is messy")
- Complaints without solutions ("auth sucks")
- Future feature ideas (that's for product planning)
- Normal TODOs (those live in code comments)
- Architectural decisions that are working fine
- Minor code style issues
**When filling this template:**
- **Always include file paths** - Concerns without locations are not actionable. Use backticks: `src/file.ts`
- Be specific with measurements ("500ms p95" not "slow")
- Include reproduction steps for bugs
- Suggest fix approaches, not just problems
- Focus on actionable items
- Prioritize by risk/impact
- Update as issues get resolved
- Add new concerns as discovered
**Tone guidelines:**
- Professional, not emotional ("N+1 query pattern" not "terrible queries")
- Solution-oriented ("Fix: add index" not "needs fixing")
- Risk-focused ("Could expose user data" not "security is bad")
- Factual ("3.5s load time" not "really slow")
**Useful for phase planning when:**
- Deciding what to work on next
- Estimating risk of changes
- Understanding where to be careful
- Prioritizing improvements
- Onboarding new Claude contexts
- Planning refactoring work
**How this gets populated:**
Explore agents detect these during codebase mapping. Manual additions welcome for human-discovered issues. This is living documentation, not a complaint list.
</guidelines>

View File

@@ -1,307 +0,0 @@
# Coding Conventions Template
Template for `.planning/codebase/CONVENTIONS.md` - captures coding style and patterns.
**Purpose:** Document how code is written in this codebase. Prescriptive guide for Claude to match existing style.
---
## File Template
```markdown
# Coding Conventions
**Analysis Date:** [YYYY-MM-DD]
## Naming Patterns
**Files:**
- [Pattern: e.g., "kebab-case for all files"]
- [Test files: e.g., "*.test.ts alongside source"]
- [Components: e.g., "PascalCase.tsx for React components"]
**Functions:**
- [Pattern: e.g., "camelCase for all functions"]
- [Async: e.g., "no special prefix for async functions"]
- [Handlers: e.g., "handleEventName for event handlers"]
**Variables:**
- [Pattern: e.g., "camelCase for variables"]
- [Constants: e.g., "UPPER_SNAKE_CASE for constants"]
- [Private: e.g., "_prefix for private members" or "no prefix"]
**Types:**
- [Interfaces: e.g., "PascalCase, no I prefix"]
- [Types: e.g., "PascalCase for type aliases"]
- [Enums: e.g., "PascalCase for enum name, UPPER_CASE for values"]
## Code Style
**Formatting:**
- [Tool: e.g., "Prettier with config in .prettierrc"]
- [Line length: e.g., "100 characters max"]
- [Quotes: e.g., "single quotes for strings"]
- [Semicolons: e.g., "required" or "omitted"]
**Linting:**
- [Tool: e.g., "ESLint with eslint.config.js"]
- [Rules: e.g., "extends airbnb-base, no console in production"]
- [Run: e.g., "npm run lint"]
## Import Organization
**Order:**
1. [e.g., "External packages (react, express, etc.)"]
2. [e.g., "Internal modules (@/lib, @/components)"]
3. [e.g., "Relative imports (., ..)"]
4. [e.g., "Type imports (import type {})"]
**Grouping:**
- [Blank lines: e.g., "blank line between groups"]
- [Sorting: e.g., "alphabetical within each group"]
**Path Aliases:**
- [Aliases used: e.g., "@/ for src/, @components/ for src/components/"]
## Error Handling
**Patterns:**
- [Strategy: e.g., "throw errors, catch at boundaries"]
- [Custom errors: e.g., "extend Error class, named *Error"]
- [Async: e.g., "use try/catch, no .catch() chains"]
**Error Types:**
- [When to throw: e.g., "invalid input, missing dependencies"]
- [When to return: e.g., "expected failures return Result<T, E>"]
- [Logging: e.g., "log error with context before throwing"]
## Logging
**Framework:**
- [Tool: e.g., "console.log, pino, winston"]
- [Levels: e.g., "debug, info, warn, error"]
**Patterns:**
- [Format: e.g., "structured logging with context object"]
- [When: e.g., "log state transitions, external calls"]
- [Where: e.g., "log at service boundaries, not in utils"]
## Comments
**When to Comment:**
- [e.g., "explain why, not what"]
- [e.g., "document business logic, algorithms, edge cases"]
- [e.g., "avoid obvious comments like // increment counter"]
**JSDoc/TSDoc:**
- [Usage: e.g., "required for public APIs, optional for internal"]
- [Format: e.g., "use @param, @returns, @throws tags"]
**TODO Comments:**
- [Pattern: e.g., "// TODO(username): description"]
- [Tracking: e.g., "link to issue number if available"]
## Function Design
**Size:**
- [e.g., "keep under 50 lines, extract helpers"]
**Parameters:**
- [e.g., "max 3 parameters, use object for more"]
- [e.g., "destructure objects in parameter list"]
**Return Values:**
- [e.g., "explicit returns, no implicit undefined"]
- [e.g., "return early for guard clauses"]
## Module Design
**Exports:**
- [e.g., "named exports preferred, default exports for React components"]
- [e.g., "export from index.ts for public API"]
**Barrel Files:**
- [e.g., "use index.ts to re-export public API"]
- [e.g., "avoid circular dependencies"]
---
*Convention analysis: [date]*
*Update when patterns change*
```
<good_examples>
```markdown
# Coding Conventions
**Analysis Date:** 2025-01-20
## Naming Patterns
**Files:**
- kebab-case for all files (command-handler.ts, user-service.ts)
- *.test.ts alongside source files
- index.ts for barrel exports
**Functions:**
- camelCase for all functions
- No special prefix for async functions
- handleEventName for event handlers (handleClick, handleSubmit)
**Variables:**
- camelCase for variables
- UPPER_SNAKE_CASE for constants (MAX_RETRIES, API_BASE_URL)
- No underscore prefix (no private marker in TS)
**Types:**
- PascalCase for interfaces, no I prefix (User, not IUser)
- PascalCase for type aliases (UserConfig, ResponseData)
- PascalCase for enum names, UPPER_CASE for values (Status.PENDING)
## Code Style
**Formatting:**
- Prettier with .prettierrc
- 100 character line length
- Single quotes for strings
- Semicolons required
- 2 space indentation
**Linting:**
- ESLint with eslint.config.js
- Extends @typescript-eslint/recommended
- No console.log in production code (use logger)
- Run: npm run lint
## Import Organization
**Order:**
1. External packages (react, express, commander)
2. Internal modules (@/lib, @/services)
3. Relative imports (./utils, ../types)
4. Type imports (import type { User })
**Grouping:**
- Blank line between groups
- Alphabetical within each group
- Type imports last within each group
**Path Aliases:**
- @/ maps to src/
- No other aliases defined
## Error Handling
**Patterns:**
- Throw errors, catch at boundaries (route handlers, main functions)
- Extend Error class for custom errors (ValidationError, NotFoundError)
- Async functions use try/catch, no .catch() chains
**Error Types:**
- Throw on invalid input, missing dependencies, invariant violations
- Log error with context before throwing: logger.error({ err, userId }, 'Failed to process')
- Include cause in error message: new Error('Failed to X', { cause: originalError })
## Logging
**Framework:**
- pino logger instance exported from lib/logger.ts
- Levels: debug, info, warn, error (no trace)
**Patterns:**
- Structured logging with context: logger.info({ userId, action }, 'User action')
- Log at service boundaries, not in utility functions
- Log state transitions, external API calls, errors
- No console.log in committed code
## Comments
**When to Comment:**
- Explain why, not what: // Retry 3 times because API has transient failures
- Document business rules: // Users must verify email within 24 hours
- Explain non-obvious algorithms or workarounds
- Avoid obvious comments: // set count to 0
**JSDoc/TSDoc:**
- Required for public API functions
- Optional for internal functions if signature is self-explanatory
- Use @param, @returns, @throws tags
**TODO Comments:**
- Format: // TODO: description (no username, using git blame)
- Link to issue if exists: // TODO: Fix race condition (issue #123)
## Function Design
**Size:**
- Keep under 50 lines
- Extract helpers for complex logic
- One level of abstraction per function
**Parameters:**
- Max 3 parameters
- Use options object for 4+ parameters: function create(options: CreateOptions)
- Destructure in parameter list: function process({ id, name }: ProcessParams)
**Return Values:**
- Explicit return statements
- Return early for guard clauses
- Use Result<T, E> type for expected failures
## Module Design
**Exports:**
- Named exports preferred
- Default exports only for React components
- Export public API from index.ts barrel files
**Barrel Files:**
- index.ts re-exports public API
- Keep internal helpers private (don't export from index)
- Avoid circular dependencies (import from specific files if needed)
---
*Convention analysis: 2025-01-20*
*Update when patterns change*
```
</good_examples>
<guidelines>
**What belongs in CONVENTIONS.md:**
- Naming patterns observed in the codebase
- Formatting rules (Prettier config, linting rules)
- Import organization patterns
- Error handling strategy
- Logging approach
- Comment conventions
- Function and module design patterns
**What does NOT belong here:**
- Architecture decisions (that's ARCHITECTURE.md)
- Technology choices (that's STACK.md)
- Test patterns (that's TESTING.md)
- File organization (that's STRUCTURE.md)
**When filling this template:**
- Check .prettierrc, .eslintrc, or similar config files
- Examine 5-10 representative source files for patterns
- Look for consistency: if 80%+ follows a pattern, document it
- Be prescriptive: "Use X" not "Sometimes Y is used"
- Note deviations: "Legacy code uses Y, new code should use X"
- Keep under ~150 lines total
**Useful for phase planning when:**
- Writing new code (match existing style)
- Adding features (follow naming patterns)
- Refactoring (apply consistent conventions)
- Code review (check against documented patterns)
- Onboarding (understand style expectations)
**Analysis approach:**
- Scan src/ directory for file naming patterns
- Check package.json scripts for lint/format commands
- Read 5-10 files to identify function naming, error handling
- Look for config files (.prettierrc, eslint.config.js)
- Note patterns in imports, comments, function signatures
</guidelines>

View File

@@ -1,280 +0,0 @@
# External Integrations Template
Template for `.planning/codebase/INTEGRATIONS.md` - captures external service dependencies.
**Purpose:** Document what external systems this codebase communicates with. Focused on "what lives outside our code that we depend on."
---
## File Template
```markdown
# External Integrations
**Analysis Date:** [YYYY-MM-DD]
## APIs & External Services
**Payment Processing:**
- [Service] - [What it's used for: e.g., "subscription billing, one-time payments"]
- SDK/Client: [e.g., "stripe npm package v14.x"]
- Auth: [e.g., "API key in STRIPE_SECRET_KEY env var"]
- Endpoints used: [e.g., "checkout sessions, webhooks"]
**Email/SMS:**
- [Service] - [What it's used for: e.g., "transactional emails"]
- SDK/Client: [e.g., "sendgrid/mail v8.x"]
- Auth: [e.g., "API key in SENDGRID_API_KEY env var"]
- Templates: [e.g., "managed in SendGrid dashboard"]
**External APIs:**
- [Service] - [What it's used for]
- Integration method: [e.g., "REST API via fetch", "GraphQL client"]
- Auth: [e.g., "OAuth2 token in AUTH_TOKEN env var"]
- Rate limits: [if applicable]
## Data Storage
**Databases:**
- [Type/Provider] - [e.g., "PostgreSQL on Supabase"]
- Connection: [e.g., "via DATABASE_URL env var"]
- Client: [e.g., "Prisma ORM v5.x"]
- Migrations: [e.g., "prisma migrate in migrations/"]
**File Storage:**
- [Service] - [e.g., "AWS S3 for user uploads"]
- SDK/Client: [e.g., "@aws-sdk/client-s3"]
- Auth: [e.g., "IAM credentials in AWS_* env vars"]
- Buckets: [e.g., "prod-uploads, dev-uploads"]
**Caching:**
- [Service] - [e.g., "Redis for session storage"]
- Connection: [e.g., "REDIS_URL env var"]
- Client: [e.g., "ioredis v5.x"]
## Authentication & Identity
**Auth Provider:**
- [Service] - [e.g., "Supabase Auth", "Auth0", "custom JWT"]
- Implementation: [e.g., "Supabase client SDK"]
- Token storage: [e.g., "httpOnly cookies", "localStorage"]
- Session management: [e.g., "JWT refresh tokens"]
**OAuth Integrations:**
- [Provider] - [e.g., "Google OAuth for sign-in"]
- Credentials: [e.g., "GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET"]
- Scopes: [e.g., "email, profile"]
## Monitoring & Observability
**Error Tracking:**
- [Service] - [e.g., "Sentry"]
- DSN: [e.g., "SENTRY_DSN env var"]
- Release tracking: [e.g., "via SENTRY_RELEASE"]
**Analytics:**
- [Service] - [e.g., "Mixpanel for product analytics"]
- Token: [e.g., "MIXPANEL_TOKEN env var"]
- Events tracked: [e.g., "user actions, page views"]
**Logs:**
- [Service] - [e.g., "CloudWatch", "Datadog", "none (stdout only)"]
- Integration: [e.g., "AWS Lambda built-in"]
## CI/CD & Deployment
**Hosting:**
- [Platform] - [e.g., "Vercel", "AWS Lambda", "Docker on ECS"]
- Deployment: [e.g., "automatic on main branch push"]
- Environment vars: [e.g., "configured in Vercel dashboard"]
**CI Pipeline:**
- [Service] - [e.g., "GitHub Actions"]
- Workflows: [e.g., "test.yml, deploy.yml"]
- Secrets: [e.g., "stored in GitHub repo secrets"]
## Environment Configuration
**Development:**
- Required env vars: [List critical vars]
- Secrets location: [e.g., ".env.local (gitignored)", "1Password vault"]
- Mock/stub services: [e.g., "Stripe test mode", "local PostgreSQL"]
**Staging:**
- Environment-specific differences: [e.g., "uses staging Stripe account"]
- Data: [e.g., "separate staging database"]
**Production:**
- Secrets management: [e.g., "Vercel environment variables"]
- Failover/redundancy: [e.g., "multi-region DB replication"]
## Webhooks & Callbacks
**Incoming:**
- [Service] - [Endpoint: e.g., "/api/webhooks/stripe"]
- Verification: [e.g., "signature validation via stripe.webhooks.constructEvent"]
- Events: [e.g., "payment_intent.succeeded, customer.subscription.updated"]
**Outgoing:**
- [Service] - [What triggers it]
- Endpoint: [e.g., "external CRM webhook on user signup"]
- Retry logic: [if applicable]
---
*Integration audit: [date]*
*Update when adding/removing external services*
```
<good_examples>
```markdown
# External Integrations
**Analysis Date:** 2025-01-20
## APIs & External Services
**Payment Processing:**
- Stripe - Subscription billing and one-time course payments
- SDK/Client: stripe npm package v14.8
- Auth: API key in STRIPE_SECRET_KEY env var
- Endpoints used: checkout sessions, customer portal, webhooks
**Email/SMS:**
- SendGrid - Transactional emails (receipts, password resets)
- SDK/Client: @sendgrid/mail v8.1
- Auth: API key in SENDGRID_API_KEY env var
- Templates: Managed in SendGrid dashboard (template IDs in code)
**External APIs:**
- OpenAI API - Course content generation
- Integration method: REST API via openai npm package v4.x
- Auth: Bearer token in OPENAI_API_KEY env var
- Rate limits: 3500 requests/min (tier 3)
## Data Storage
**Databases:**
- PostgreSQL on Supabase - Primary data store
- Connection: via DATABASE_URL env var
- Client: Prisma ORM v5.8
- Migrations: prisma migrate in prisma/migrations/
**File Storage:**
- Supabase Storage - User uploads (profile images, course materials)
- SDK/Client: @supabase/supabase-js v2.x
- Auth: Service role key in SUPABASE_SERVICE_ROLE_KEY
- Buckets: avatars (public), course-materials (private)
**Caching:**
- None currently (all database queries, no Redis)
## Authentication & Identity
**Auth Provider:**
- Supabase Auth - Email/password + OAuth
- Implementation: Supabase client SDK with server-side session management
- Token storage: httpOnly cookies via @supabase/ssr
- Session management: JWT refresh tokens handled by Supabase
**OAuth Integrations:**
- Google OAuth - Social sign-in
- Credentials: GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET (Supabase dashboard)
- Scopes: email, profile
## Monitoring & Observability
**Error Tracking:**
- Sentry - Server and client errors
- DSN: SENTRY_DSN env var
- Release tracking: Git commit SHA via SENTRY_RELEASE
**Analytics:**
- None (planned: Mixpanel)
**Logs:**
- Vercel logs - stdout/stderr only
- Retention: 7 days on Pro plan
## CI/CD & Deployment
**Hosting:**
- Vercel - Next.js app hosting
- Deployment: Automatic on main branch push
- Environment vars: Configured in Vercel dashboard (synced to .env.example)
**CI Pipeline:**
- GitHub Actions - Tests and type checking
- Workflows: .github/workflows/ci.yml
- Secrets: None needed (public repo tests only)
## Environment Configuration
**Development:**
- Required env vars: DATABASE_URL, NEXT_PUBLIC_SUPABASE_URL, NEXT_PUBLIC_SUPABASE_ANON_KEY
- Secrets location: .env.local (gitignored), team shared via 1Password vault
- Mock/stub services: Stripe test mode, Supabase local dev project
**Staging:**
- Uses separate Supabase staging project
- Stripe test mode
- Same Vercel account, different environment
**Production:**
- Secrets management: Vercel environment variables
- Database: Supabase production project with daily backups
## Webhooks & Callbacks
**Incoming:**
- Stripe - /api/webhooks/stripe
- Verification: Signature validation via stripe.webhooks.constructEvent
- Events: payment_intent.succeeded, customer.subscription.updated, customer.subscription.deleted
**Outgoing:**
- None
---
*Integration audit: 2025-01-20*
*Update when adding/removing external services*
```
</good_examples>
<guidelines>
**What belongs in INTEGRATIONS.md:**
- External services the code communicates with
- Authentication patterns (where secrets live, not the secrets themselves)
- SDKs and client libraries used
- Environment variable names (not values)
- Webhook endpoints and verification methods
- Database connection patterns
- File storage locations
- Monitoring and logging services
**What does NOT belong here:**
- Actual API keys or secrets (NEVER write these)
- Internal architecture (that's ARCHITECTURE.md)
- Code patterns (that's PATTERNS.md)
- Technology choices (that's STACK.md)
- Performance issues (that's CONCERNS.md)
**When filling this template:**
- Check .env.example or .env.template for required env vars
- Look for SDK imports (stripe, @sendgrid/mail, etc.)
- Check for webhook handlers in routes/endpoints
- Note where secrets are managed (not the secrets)
- Document environment-specific differences (dev/staging/prod)
- Include auth patterns for each service
**Useful for phase planning when:**
- Adding new external service integrations
- Debugging authentication issues
- Understanding data flow outside the application
- Setting up new environments
- Auditing third-party dependencies
- Planning for service outages or migrations
**Security note:**
Document WHERE secrets live (env vars, Vercel dashboard, 1Password), never WHAT the secrets are.
</guidelines>

View File

@@ -1,285 +0,0 @@
# Structure Template
Template for `.planning/codebase/STRUCTURE.md` - captures physical file organization.
**Purpose:** Document where things physically live in the codebase. Answers "where do I put X?"
---
## File Template
```markdown
# Codebase Structure
**Analysis Date:** [YYYY-MM-DD]
## Directory Layout
[ASCII box-drawing tree of top-level directories with purpose - use ├── └── │ characters for tree structure only]
```
[project-root]/
├── [dir]/ # [Purpose]
├── [dir]/ # [Purpose]
├── [dir]/ # [Purpose]
└── [file] # [Purpose]
```
## Directory Purposes
**[Directory Name]:**
- Purpose: [What lives here]
- Contains: [Types of files: e.g., "*.ts source files", "component directories"]
- Key files: [Important files in this directory]
- Subdirectories: [If nested, describe structure]
**[Directory Name]:**
- Purpose: [What lives here]
- Contains: [Types of files]
- Key files: [Important files]
- Subdirectories: [Structure]
## Key File Locations
**Entry Points:**
- [Path]: [Purpose: e.g., "CLI entry point"]
- [Path]: [Purpose: e.g., "Server startup"]
**Configuration:**
- [Path]: [Purpose: e.g., "TypeScript config"]
- [Path]: [Purpose: e.g., "Build configuration"]
- [Path]: [Purpose: e.g., "Environment variables"]
**Core Logic:**
- [Path]: [Purpose: e.g., "Business services"]
- [Path]: [Purpose: e.g., "Database models"]
- [Path]: [Purpose: e.g., "API routes"]
**Testing:**
- [Path]: [Purpose: e.g., "Unit tests"]
- [Path]: [Purpose: e.g., "Test fixtures"]
**Documentation:**
- [Path]: [Purpose: e.g., "User-facing docs"]
- [Path]: [Purpose: e.g., "Developer guide"]
## Naming Conventions
**Files:**
- [Pattern]: [Example: e.g., "kebab-case.ts for modules"]
- [Pattern]: [Example: e.g., "PascalCase.tsx for React components"]
- [Pattern]: [Example: e.g., "*.test.ts for test files"]
**Directories:**
- [Pattern]: [Example: e.g., "kebab-case for feature directories"]
- [Pattern]: [Example: e.g., "plural names for collections"]
**Special Patterns:**
- [Pattern]: [Example: e.g., "index.ts for directory exports"]
- [Pattern]: [Example: e.g., "__tests__ for test directories"]
## Where to Add New Code
**New Feature:**
- Primary code: [Directory path]
- Tests: [Directory path]
- Config if needed: [Directory path]
**New Component/Module:**
- Implementation: [Directory path]
- Types: [Directory path]
- Tests: [Directory path]
**New Route/Command:**
- Definition: [Directory path]
- Handler: [Directory path]
- Tests: [Directory path]
**Utilities:**
- Shared helpers: [Directory path]
- Type definitions: [Directory path]
## Special Directories
[Any directories with special meaning or generation]
**[Directory]:**
- Purpose: [e.g., "Generated code", "Build output"]
- Source: [e.g., "Auto-generated by X", "Build artifacts"]
- Committed: [Yes/No - in .gitignore?]
---
*Structure analysis: [date]*
*Update when directory structure changes*
```
<good_examples>
```markdown
# Codebase Structure
**Analysis Date:** 2025-01-20
## Directory Layout
```
gsd-core/
├── bin/ # Executable entry points
├── commands/ # Slash command definitions
│ └── gsd/ # GSD-specific commands
├── gsd-core/ # Skill resources
│ ├── references/ # Principle documents
│ ├── templates/ # File templates
│ └── workflows/ # Multi-step procedures
├── src/ # Source code (if applicable)
├── tests/ # Test files
├── package.json # Project manifest
└── README.md # User documentation
```
## Directory Purposes
**bin/**
- Purpose: CLI entry points
- Contains: install.js (installer script)
- Key files: install.js - handles npx installation
- Subdirectories: None
**commands/gsd/**
- Purpose: Slash command definitions for Claude Code
- Contains: *.md files (one per command)
- Key files: new-project.md, plan-phase.md, execute-plan.md
- Subdirectories: None (flat structure)
**gsd-core/references/**
- Purpose: Core philosophy and guidance documents
- Contains: principles.md, questioning.md, plan-format.md
- Key files: principles.md - system philosophy
- Subdirectories: None
**gsd-core/templates/**
- Purpose: Document templates for .planning/ files
- Contains: Template definitions with frontmatter
- Key files: project.md, roadmap.md, plan.md, summary.md
- Subdirectories: codebase/ (new - for stack/architecture/structure templates)
**gsd-core/workflows/**
- Purpose: Reusable multi-step procedures
- Contains: Workflow definitions called by commands
- Key files: execute-plan.md, research-phase.md
- Subdirectories: None
## Key File Locations
**Entry Points:**
- `bin/install.js` - Installation script (npx entry)
**Configuration:**
- `package.json` - Project metadata, dependencies, bin entry
- `.gitignore` - Excluded files
**Core Logic:**
- `bin/install.js` - All installation logic (file copying, path replacement)
**Testing:**
- `tests/` - Test files (if present)
**Documentation:**
- `README.md` - User-facing installation and usage guide
- `CLAUDE.md` - Instructions for Claude Code when working in this repo
## Naming Conventions
**Files:**
- kebab-case.md: Markdown documents
- kebab-case.js: JavaScript source files
- UPPERCASE.md: Important project files (README, CLAUDE, CHANGELOG)
**Directories:**
- kebab-case: All directories
- Plural for collections: templates/, commands/, workflows/
**Special Patterns:**
- {command-name}.md: Slash command definition
- *-template.md: Could be used but templates/ directory preferred
## Where to Add New Code
**New Slash Command:**
- Primary code: `commands/gsd/{command-name}.md`
- Tests: `tests/commands/{command-name}.test.js` (if testing implemented)
- Documentation: Update `README.md` with new command
**New Template:**
- Implementation: `gsd-core/templates/{name}.md`
- Documentation: Template is self-documenting (includes guidelines)
**New Workflow:**
- Implementation: `gsd-core/workflows/{name}.md`
- Usage: Reference from command with `@~/.claude/gsd-core/workflows/{name}.md`
**New Reference Document:**
- Implementation: `gsd-core/references/{name}.md`
- Usage: Reference from commands/workflows as needed
**Utilities:**
- No utilities yet (`install.js` is monolithic)
- If extracted: `src/utils/`
## Special Directories
**gsd-core/**
- Purpose: Resources installed to ~/.claude/
- Source: Copied by bin/install.js during installation
- Committed: Yes (source of truth)
**commands/**
- Purpose: Slash commands installed to ~/.claude/commands/
- Source: Copied by bin/install.js during installation
- Committed: Yes (source of truth)
---
*Structure analysis: 2025-01-20*
*Update when directory structure changes*
```
</good_examples>
<guidelines>
**What belongs in STRUCTURE.md:**
- Directory layout (ASCII box-drawing tree for structure visualization)
- Purpose of each directory
- Key file locations (entry points, configs, core logic)
- Naming conventions
- Where to add new code (by type)
- Special/generated directories
**What does NOT belong here:**
- Conceptual architecture (that's ARCHITECTURE.md)
- Technology stack (that's STACK.md)
- Code implementation details (defer to code reading)
- Every single file (focus on directories and key files)
**When filling this template:**
- Use `tree -L 2` or similar to visualize structure
- Identify top-level directories and their purposes
- Note naming patterns by observing existing files
- Locate entry points, configs, and main logic areas
- Keep directory tree concise (max 2-3 levels)
**Tree format (ASCII box-drawing characters for structure only):**
```
root/
├── dir1/ # Purpose
│ ├── subdir/ # Purpose
│ └── file.ts # Purpose
├── dir2/ # Purpose
└── file.ts # Purpose
```
**Useful for phase planning when:**
- Adding new features (where should files go?)
- Understanding project organization
- Finding where specific logic lives
- Following existing conventions
</guidelines>

View File

@@ -1,480 +0,0 @@
# Testing Patterns Template
Template for `.planning/codebase/TESTING.md` - captures test framework and patterns.
**Purpose:** Document how tests are written and run. Guide for adding tests that match existing patterns.
---
## File Template
```markdown
# Testing Patterns
**Analysis Date:** [YYYY-MM-DD]
## Test Framework
**Runner:**
- [Framework: e.g., "Jest 29.x", "Vitest 1.x"]
- [Config: e.g., "jest.config.js in project root"]
**Assertion Library:**
- [Library: e.g., "built-in expect", "chai"]
- [Matchers: e.g., "toBe, toEqual, toThrow"]
**Run Commands:**
```bash
[e.g., "npm test" or "npm run test"] # Run all tests
[e.g., "npm test -- --watch"] # Watch mode
[e.g., "npm test -- path/to/file.test.ts"] # Single file
[e.g., "npm run test:coverage"] # Coverage report
```
## Test File Organization
**Location:**
- [Pattern: e.g., "*.test.ts alongside source files"]
- [Alternative: e.g., "__tests__/ directory" or "separate tests/ tree"]
**Naming:**
- [Unit tests: e.g., "module-name.test.ts"]
- [Integration: e.g., "feature-name.integration.test.ts"]
- [E2E: e.g., "user-flow.e2e.test.ts"]
**Structure:**
```
[Show actual directory pattern, e.g.:
src/
lib/
utils.ts
utils.test.ts
services/
user-service.ts
user-service.test.ts
]
```
## Test Structure
**Suite Organization:**
```typescript
[Show actual pattern used, e.g.:
describe('ModuleName', () => {
describe('functionName', () => {
it('should handle success case', () => {
// arrange
// act
// assert
});
it('should handle error case', () => {
// test code
});
});
});
]
```
**Patterns:**
- [Setup: e.g., "beforeEach for shared setup, avoid beforeAll"]
- [Teardown: e.g., "afterEach to clean up, restore mocks"]
- [Structure: e.g., "arrange/act/assert pattern required"]
## Mocking
**Framework:**
- [Tool: e.g., "Jest built-in mocking", "Vitest vi", "Sinon"]
- [Import mocking: e.g., "vi.mock() at top of file"]
**Patterns:**
```typescript
[Show actual mocking pattern, e.g.:
// Mock external dependency
vi.mock('./external-service', () => ({
fetchData: vi.fn()
}));
// Mock in test
const mockFetch = vi.mocked(fetchData);
mockFetch.mockResolvedValue({ data: 'test' });
]
```
**What to Mock:**
- [e.g., "External APIs, file system, database"]
- [e.g., "Time/dates (use vi.useFakeTimers)"]
- [e.g., "Network calls (use mock fetch)"]
**What NOT to Mock:**
- [e.g., "Pure functions, utilities"]
- [e.g., "Internal business logic"]
## Fixtures and Factories
**Test Data:**
```typescript
[Show pattern for creating test data, e.g.:
// Factory pattern
function createTestUser(overrides?: Partial<User>): User {
return {
id: 'test-id',
name: 'Test User',
email: 'test@example.com',
...overrides
};
}
// Fixture file
// tests/fixtures/users.ts
export const mockUsers = [/* ... */];
]
```
**Location:**
- [e.g., "tests/fixtures/ for shared fixtures"]
- [e.g., "factory functions in test file or tests/factories/"]
## Coverage
**Requirements:**
- [Target: e.g., "80% line coverage", "no specific target"]
- [Enforcement: e.g., "CI blocks <80%", "coverage for awareness only"]
**Configuration:**
- [Tool: e.g., "built-in coverage via --coverage flag"]
- [Exclusions: e.g., "exclude *.test.ts, config files"]
**View Coverage:**
```bash
[e.g., "npm run test:coverage"]
[e.g., "open coverage/index.html"]
```
## Test Types
**Unit Tests:**
- [Scope: e.g., "test single function/class in isolation"]
- [Mocking: e.g., "mock all external dependencies"]
- [Speed: e.g., "must run in <1s per test"]
**Integration Tests:**
- [Scope: e.g., "test multiple modules together"]
- [Mocking: e.g., "mock external services, use real internal modules"]
- [Setup: e.g., "use test database, seed data"]
**E2E Tests:**
- [Framework: e.g., "Playwright for E2E"]
- [Scope: e.g., "test full user flows"]
- [Location: e.g., "e2e/ directory separate from unit tests"]
## Common Patterns
**Async Testing:**
```typescript
[Show pattern, e.g.:
it('should handle async operation', async () => {
const result = await asyncFunction();
expect(result).toBe('expected');
});
]
```
**Error Testing:**
```typescript
[Show pattern, e.g.:
it('should throw on invalid input', () => {
expect(() => functionCall()).toThrow('error message');
});
// Async error
it('should reject on failure', async () => {
await expect(asyncCall()).rejects.toThrow('error message');
});
]
```
**Snapshot Testing:**
- [Usage: e.g., "for React components only" or "not used"]
- [Location: e.g., "__snapshots__/ directory"]
---
*Testing analysis: [date]*
*Update when test patterns change*
```
<good_examples>
```markdown
# Testing Patterns
**Analysis Date:** 2025-01-20
## Test Framework
**Runner:**
- Vitest 1.0.4
- Config: vitest.config.ts in project root
**Assertion Library:**
- Vitest built-in expect
- Matchers: toBe, toEqual, toThrow, toMatchObject
**Run Commands:**
```bash
npm test # Run all tests
npm test -- --watch # Watch mode
npm test -- path/to/file.test.ts # Single file
npm run test:coverage # Coverage report
```
## Test File Organization
**Location:**
- *.test.ts alongside source files
- No separate tests/ directory
**Naming:**
- unit-name.test.ts for all tests
- No distinction between unit/integration in filename
**Structure:**
```
src/
lib/
parser.ts
parser.test.ts
services/
install-service.ts
install-service.test.ts
bin/
install.ts
(no test - integration tested via CLI)
```
## Test Structure
**Suite Organization:**
```typescript
import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
describe('ModuleName', () => {
describe('functionName', () => {
beforeEach(() => {
// reset state
});
it('should handle valid input', () => {
// arrange
const input = createTestInput();
// act
const result = functionName(input);
// assert
expect(result).toEqual(expectedOutput);
});
it('should throw on invalid input', () => {
expect(() => functionName(null)).toThrow('Invalid input');
});
});
});
```
**Patterns:**
- Use beforeEach for per-test setup, avoid beforeAll
- Use afterEach to restore mocks: vi.restoreAllMocks()
- Explicit arrange/act/assert comments in complex tests
- One assertion focus per test (but multiple expects OK)
## Mocking
**Framework:**
- Vitest built-in mocking (vi)
- Module mocking via vi.mock() at top of test file
**Patterns:**
```typescript
import { vi } from 'vitest';
import { externalFunction } from './external';
// Mock module
vi.mock('./external', () => ({
externalFunction: vi.fn()
}));
describe('test suite', () => {
it('mocks function', () => {
const mockFn = vi.mocked(externalFunction);
mockFn.mockReturnValue('mocked result');
// test code using mocked function
expect(mockFn).toHaveBeenCalledWith('expected arg');
});
});
```
**What to Mock:**
- File system operations (fs-extra)
- Child process execution (child_process.exec)
- External API calls
- Environment variables (process.env)
**What NOT to Mock:**
- Internal pure functions
- Simple utilities (string manipulation, array helpers)
- TypeScript types
## Fixtures and Factories
**Test Data:**
```typescript
// Factory functions in test file
function createTestConfig(overrides?: Partial<Config>): Config {
return {
targetDir: '/tmp/test',
global: false,
...overrides
};
}
// Shared fixtures in tests/fixtures/
// tests/fixtures/sample-command.md
export const sampleCommand = `---
description: Test command
---
Content here`;
```
**Location:**
- Factory functions: define in test file near usage
- Shared fixtures: tests/fixtures/ (for multi-file test data)
- Mock data: inline in test when simple, factory when complex
## Coverage
**Requirements:**
- No enforced coverage target
- Coverage tracked for awareness
- Focus on critical paths (parsers, service logic)
**Configuration:**
- Vitest coverage via c8 (built-in)
- Excludes: *.test.ts, bin/install.ts, config files
**View Coverage:**
```bash
npm run test:coverage
open coverage/index.html
```
## Test Types
**Unit Tests:**
- Test single function in isolation
- Mock all external dependencies (fs, child_process)
- Fast: each test <100ms
- Examples: parser.test.ts, validator.test.ts
**Integration Tests:**
- Test multiple modules together
- Mock only external boundaries (file system, process)
- Examples: install-service.test.ts (tests service + parser)
**E2E Tests:**
- Not currently used
- CLI integration tested manually
## Common Patterns
**Async Testing:**
```typescript
it('should handle async operation', async () => {
const result = await asyncFunction();
expect(result).toBe('expected');
});
```
**Error Testing:**
```typescript
it('should throw on invalid input', () => {
expect(() => parse(null)).toThrow('Cannot parse null');
});
// Async error
it('should reject on file not found', async () => {
await expect(readConfig('invalid.txt')).rejects.toThrow('ENOENT');
});
```
**File System Mocking:**
```typescript
import { vi } from 'vitest';
import * as fs from 'fs-extra';
vi.mock('fs-extra');
it('mocks file system', () => {
vi.mocked(fs.readFile).mockResolvedValue('file content');
// test code
});
```
**Snapshot Testing:**
- Not used in this codebase
- Prefer explicit assertions for clarity
---
*Testing analysis: 2025-01-20*
*Update when test patterns change*
```
</good_examples>
<guidelines>
**What belongs in TESTING.md:**
- Test framework and runner configuration
- Test file location and naming patterns
- Test structure (describe/it, beforeEach patterns)
- Mocking approach and examples
- Fixture/factory patterns
- Coverage requirements
- How to run tests (commands)
- Common testing patterns in actual code
**What does NOT belong here:**
- Specific test cases (defer to actual test files)
- Technology choices (that's STACK.md)
- CI/CD setup (that's deployment docs)
**When filling this template:**
- Check package.json scripts for test commands
- Find test config file (jest.config.js, vitest.config.ts)
- Read 3-5 existing test files to identify patterns
- Look for test utilities in tests/ or test-utils/
- Check for coverage configuration
- Document actual patterns used, not ideal patterns
**Useful for phase planning when:**
- Adding new features (write matching tests)
- Refactoring (maintain test patterns)
- Fixing bugs (add regression tests)
- Understanding verification approach
- Setting up test infrastructure
**Analysis approach:**
- Check package.json for test framework and scripts
- Read test config file for coverage, setup
- Examine test file organization (collocated vs separate)
- Review 5 test files for patterns (mocking, structure, assertions)
- Look for test utilities, fixtures, factories
- Note any test types (unit, integration, e2e)
- Document commands for running tests
</guidelines>

View File

@@ -1,91 +0,0 @@
# Debug Subagent Prompt Template
Template for spawning gsd-debugger agent. The agent contains all debugging expertise - this template provides problem context only.
---
## Template
```markdown
<objective>
Investigate issue: {issue_id}
**Summary:** {issue_summary}
</objective>
<symptoms>
expected: {expected}
actual: {actual}
errors: {errors}
reproduction: {reproduction}
timeline: {timeline}
</symptoms>
<mode>
symptoms_prefilled: {true_or_false}
goal: {find_root_cause_only | find_and_fix}
</mode>
<debug_file>
Create: .planning/debug/{slug}.md
</debug_file>
```
---
## Placeholders
| Placeholder | Source | Example |
|-------------|--------|---------|
| `{issue_id}` | Orchestrator-assigned | `auth-screen-dark` |
| `{issue_summary}` | User description | `Auth screen is too dark` |
| `{expected}` | From symptoms | `See logo clearly` |
| `{actual}` | From symptoms | `Screen is dark` |
| `{errors}` | From symptoms | `None in console` |
| `{reproduction}` | From symptoms | `Open /auth page` |
| `{timeline}` | From symptoms | `After recent deploy` |
| `{goal}` | Orchestrator sets | `find_and_fix` |
| `{slug}` | Generated | `auth-screen-dark` |
---
## Usage
**From /gsd:debug:**
```python
Task(
prompt=filled_template,
subagent_type="gsd-debugger",
description="Debug {slug}"
)
```
**From diagnose-issues (UAT):**
```python
Task(prompt=template, subagent_type="gsd-debugger", description="Debug UAT-001")
```
---
## Continuation
For checkpoints, spawn fresh agent with:
```markdown
<objective>
Continue debugging {slug}. Evidence is in the debug file.
</objective>
<prior_state>
Debug file: @.planning/debug/{slug}.md
</prior_state>
<checkpoint_response>
**Type:** {checkpoint_type}
**Response:** {user_response}
</checkpoint_response>
<mode>
goal: {goal}
</mode>
```

View File

@@ -1,146 +0,0 @@
# Discovery Template
Template for `.planning/phases/XX-name/DISCOVERY.md` - shallow research for library/option decisions.
**Purpose:** Answer "which library/option should we use" questions during mandatory discovery in plan-phase.
For deep ecosystem research ("how do experts build this"), use `/gsd:plan-phase --research-phase` which produces RESEARCH.md.
---
## File Template
```markdown
---
phase: XX-name
type: discovery
topic: [discovery-topic]
---
<session_initialization>
Before beginning discovery, verify today's date:
!`date +%Y-%m-%d`
Use this date when searching for "current" or "latest" information.
Example: If today is 2025-11-22, search for "2025" not "2024".
</session_initialization>
<discovery_objective>
Discover [topic] to inform [phase name] implementation.
Purpose: [What decision/implementation this enables]
Scope: [Boundaries]
Output: DISCOVERY.md with recommendation
</discovery_objective>
<discovery_scope>
<include>
- [Question to answer]
- [Area to investigate]
- [Specific comparison if needed]
</include>
<exclude>
- [Out of scope for this discovery]
- [Defer to implementation phase]
</exclude>
</discovery_scope>
<discovery_protocol>
**Source Priority:**
1. **Context7 MCP** - For library/framework documentation (current, authoritative)
2. **Official Docs** - For platform-specific or non-indexed libraries
3. **WebSearch** - For comparisons, trends, community patterns (verify all findings)
**Quality Checklist:**
Before completing discovery, verify:
- [ ] All claims have authoritative sources (Context7 or official docs)
- [ ] Negative claims ("X is not possible") verified with official documentation
- [ ] API syntax/configuration from Context7 or official docs (never WebSearch alone)
- [ ] WebSearch findings cross-checked with authoritative sources
- [ ] Recent updates/changelogs checked for breaking changes
- [ ] Alternative approaches considered (not just first solution found)
**Confidence Levels:**
- HIGH: Context7 or official docs confirm
- MEDIUM: WebSearch + Context7/official docs confirm
- LOW: WebSearch only or training knowledge only (mark for validation)
</discovery_protocol>
<output_structure>
Create `.planning/phases/XX-name/DISCOVERY.md`:
```markdown
# [Topic] Discovery
## Summary
[2-3 paragraph executive summary - what was researched, what was found, what's recommended]
## Primary Recommendation
[What to do and why - be specific and actionable]
## Alternatives Considered
[What else was evaluated and why not chosen]
## Key Findings
### [Category 1]
- [Finding with source URL and relevance to our case]
### [Category 2]
- [Finding with source URL and relevance]
## Code Examples
[Relevant implementation patterns, if applicable]
## Metadata
<metadata>
<confidence level="high|medium|low">
[Why this confidence level - based on source quality and verification]
</confidence>
<sources>
- [Primary authoritative sources used]
</sources>
<open_questions>
[What couldn't be determined or needs validation during implementation]
</open_questions>
<validation_checkpoints>
[If confidence is LOW or MEDIUM, list specific things to verify during implementation]
</validation_checkpoints>
</metadata>
```
</output_structure>
<success_criteria>
- All scope questions answered with authoritative sources
- Quality checklist items completed
- Clear primary recommendation
- Low-confidence findings marked with validation checkpoints
- Ready to inform PLAN.md creation
</success_criteria>
<guidelines>
**When to use discovery:**
- Technology choice unclear (library A vs B)
- Best practices needed for unfamiliar integration
- API/library investigation required
- Single decision pending
**When NOT to use:**
- Established patterns (CRUD, auth with known library)
- Implementation details (defer to execution)
- Questions answerable from existing project context
**When to use RESEARCH.md instead:**
- Niche/complex domains (3D, games, audio, shaders)
- Need ecosystem knowledge, not just library choice
- "How do experts build this" questions
- Use `/gsd:plan-phase --research-phase` for these
</guidelines>

View File

@@ -0,0 +1,212 @@
# Summary Template
Template for `.planning/phases/XX-name/{phase}-{plan}-SUMMARY.md` - phase completion documentation.
---
## File Template
```markdown
---
phase: XX-name
plan: YY
subsystem: [primary category: auth, payments, ui, api, database, infra, testing, etc.]
tags: [searchable tech: jwt, stripe, react, postgres, prisma]
# Dependency graph
requires:
- phase: [prior phase this depends on]
provides: [what that phase built that this uses]
provides:
- [bullet list of what this phase built/delivered]
affects: [list of phase names or keywords that will need this context]
# Actuals (#2632) — pairs with the plan's `estimate` to calibrate future estimates.
# Same estimateTokens scale (chars/4 over the realized diff), never a harness token count.
actuals:
tokens: [chars/4 over files actually changed]
tasks: [tasks completed]
commits: [commits made]
# Tech tracking
tech-stack:
added: [libraries/tools added in this phase]
patterns: [architectural/code patterns established]
key-files:
created: [important files created]
modified: [important files modified]
key-decisions:
- "Decision 1"
- "Decision 2"
patterns-established:
- "Pattern 1: description"
- "Pattern 2: description"
requirements-completed: [] # REQUIRED — Copy ALL requirement IDs from this plan's `requirements` frontmatter field.
# Coverage metadata (#1602) — one entry per shipped deliverable. Drives DETERMINISTIC UAT routing in verify-work.
# OMIT this whole block for legacy/prose-only SUMMARYs — verify-work then falls back to the ## Accomplishments bullets
# (byte-identical behavior for un-migrated phases). See <coverage_guidance> below for the contract.
coverage:
- id: D1
description: "[deliverable in human-readable form — what would have been a prose ## Accomplishments bullet]"
requirement: "[REQ-ID from this plan's `requirements`, or omit if none]"
verification:
- kind: unit # unit | integration | e2e | automated_ui | manual_procedural | other
ref: "[tests/path.test.ts#test name | playwright:shot.png | command invocation]"
status: pass # pass | fail | unknown — from the latest run
human_judgment: false # REQUIRED boolean. false => may auto-pass IF every verification status is `pass`.
- id: D2
description: "[a deliverable that needs a human to sign off]"
verification: []
human_judgment: true
rationale: "[REQUIRED when human_judgment: true — why automation is insufficient]"
# Metrics
duration: Xmin
completed: YYYY-MM-DD
status: complete
---
# Phase [X]: [Name] Summary
**[Substantive one-liner describing outcome - NOT "phase complete" or "implementation finished"]**
## Performance
- **Duration:** [time] (e.g., 23 min, 1h 15m)
- **Started:** [ISO timestamp]
- **Completed:** [ISO timestamp]
- **Tasks:** [count completed]
- **Files modified:** [count]
## Accomplishments
- [Most important outcome]
- [Second key accomplishment]
- [Third if applicable]
## Task Commits
Each task was committed atomically:
1. **Task 1: [task name]** - `abc123f` (feat/fix/test/refactor)
2. **Task 2: [task name]** - `def456g` (feat/fix/test/refactor)
3. **Task 3: [task name]** - `hij789k` (feat/fix/test/refactor)
**Plan metadata:** `lmn012o` (docs: complete plan)
_Note: TDD tasks may have multiple commits (test → feat → refactor)_
## Files Created/Modified
- `path/to/file.ts` - What it does
- `path/to/another.ts` - What it does
## Decisions Made
[Key decisions with brief rationale, or "None - followed plan as specified"]
## Deviations from Plan
[If no deviations: "None - plan executed exactly as written"]
[If deviations occurred:]
### Auto-fixed Issues
**1. [Rule X - Category] Brief description**
- **Found during:** Task [N] ([task name])
- **Issue:** [What was wrong]
- **Fix:** [What was done]
- **Files modified:** [file paths]
- **Verification:** [How it was verified]
- **Committed in:** [hash] (part of task commit)
[... repeat for each auto-fix ...]
---
**Total deviations:** [N] auto-fixed ([breakdown by rule])
**Impact on plan:** [Brief assessment - e.g., "All auto-fixes necessary for correctness/security. No scope creep."]
## Issues Encountered
[Problems and how they were resolved, or "None"]
[Note: "Deviations from Plan" documents unplanned work that was handled automatically via deviation rules. "Issues Encountered" documents problems during planned work that required problem-solving.]
## User Setup Required
[If USER-SETUP.md was generated:]
**External services require manual configuration.** See [{phase}-USER-SETUP.md](./{phase}-USER-SETUP.md) for:
- Environment variables to add
- Dashboard configuration steps
- Verification commands
[If no USER-SETUP.md:]
None - no external service configuration required.
## Next Phase Readiness
[What's ready for next phase]
[Any blockers or concerns]
---
*Phase: XX-name*
*Completed: [date]*
```
<frontmatter_guidance>
**Purpose:** Enable automatic context assembly via dependency graph. Frontmatter makes summary metadata machine-readable so plan-phase can scan all summaries quickly and select relevant ones based on dependencies (`requires`/`provides`/`affects` create the explicit links; transitive closure follows from them).
**Subsystem/Tags:** Primary categorization + searchable technical keywords, for detecting related phases and tech-stack awareness. **Key-files:** important files for @context references in PLAN.md. **Patterns:** established conventions future phases should maintain.
**Population:** Frontmatter is populated during summary creation in execute-plan.md. See `<step name="create_summary">` for field-by-field guidance.
**Status (#2830):** `status: complete` is the default — the plan finished. Use `status: halted` instead when the plan reached a designed stop (a gate failure, a spike concluding without expanding into the full build, or any other intentional non-completion) and intentionally left tasks unfinished. `halted` is machine-read: any plan whose `depends_on` (directly or transitively) names a halted plan is reported as blocked, not offered to the executor, until the halt is resolved and re-summarized as `complete`.
</frontmatter_guidance>
<coverage_guidance>
**Purpose (#1602):** The `coverage:` block is a per-deliverable Requirements Traceability Matrix. It lets `verify-work`'s `extract_tests` step route deliverables DETERMINISTICALLY — auto-passing those proven by passing tests and reserving human UAT for genuine judgment — instead of re-deriving coverage from prose. Consumed via `gsd-tools uat classify-coverage --summary <SUMMARY>`.
**Field semantics:**
| Field | Purpose |
|---|---|
| `id` | Stable identifier (`D1`, `D2`…) for cross-referencing from UAT.md and audit reports. Must be unique within the SUMMARY. |
| `description` | The deliverable in human-readable form — what would have been a prose bullet. |
| `requirement` | Links back to a REQUIREMENTS.md REQ-ID (joins `requirements-completed`). Optional. |
| `verification[].kind` | Enum: `unit \| integration \| e2e \| automated_ui \| manual_procedural \| other`. |
| `verification[].ref` | Test path + descriptor (`file#test name`), Playwright screenshot ref, or command invocation. Required per entry. |
| `verification[].status` | `pass \| fail \| unknown` — populated from the latest test run. |
| `human_judgment` | Explicit boolean; REQUIRED. `true` always routes to a human. |
| `rationale` | REQUIRED when `human_judgment: true`. The audit trail for why automation is insufficient. |
**Deterministic contract (what the classifier does):**
- A deliverable auto-passes (no human prompt) **only** when `human_judgment: false` AND `verification` is non-empty AND every `verification[].status` is `pass`. This is the narrow, fully-proven case.
- **Everything else is presented to a human** — `human_judgment: true`, an empty `verification:`, any non-`pass`/`unknown` status, or any schema error. A false-negative is a redundant prompt (the status quo); a false-positive ships a bug UAT existed to catch.
- **Fail-safe default:** if you cannot determine coverage for a deliverable, you MUST set `human_judgment: true` with `rationale: "Coverage not determined at authoring time — verifier must classify"`. Never leave a deliverable's `human_judgment` empty, and never set it `false` just to skip the prompt — auto-pass additionally requires a passing `verification` entry, so the flag alone cannot skip the human.
- `coverage: []` means "no deliverables to classify" (the single-confirmation path). OMITTING the block entirely means "legacy" — `verify-work` falls back to prose `## Accomplishments` extraction unchanged.
</coverage_guidance>
<one_liner_rules>
The one-liner MUST be substantive:
**Good:** "JWT auth with refresh rotation using jose library" · "Prisma schema with User, Session, and Product models" · "Dashboard with real-time metrics via Server-Sent Events"
**Bad:** "Phase complete" · "Authentication implemented" · "Foundation finished" · "All tasks done"
The one-liner should tell someone what actually shipped.
</one_liner_rules>
<guidelines>
**Frontmatter:** MANDATORY - complete all fields. Enables automatic context assembly for future planning.
**One-liner:** Must be substantive. "JWT auth with refresh rotation using jose library" not "Authentication implemented".
**Decisions section:**
- Key decisions made during execution with rationale
- Extracted to STATE.md accumulated context
- Use "None - followed plan as specified" if no deviations
**After creation:** STATE.md updated with position, decisions, issues.
</guidelines>

View File

@@ -0,0 +1,199 @@
# User Setup Template
Template for `.planning/phases/XX-name/{phase}-USER-SETUP.md` - human-required configuration that Claude cannot automate.
**Purpose:** Document setup tasks that literally require human action - account creation, dashboard configuration, secret retrieval. Claude automates everything possible; this file captures only what remains.
---
## File Template
```markdown
# Phase {X}: User Setup Required
**Generated:** [YYYY-MM-DD]
**Phase:** {phase-name}
**Status:** Incomplete
Complete these items for the integration to function. Claude automated everything possible; these items require human access to external dashboards/accounts.
## Environment Variables
| Status | Variable | Source | Add to |
|--------|----------|--------|--------|
| [ ] | `ENV_VAR_NAME` | [Service Dashboard → Path → To → Value] | `.env.local` |
| [ ] | `ANOTHER_VAR` | [Service Dashboard → Path → To → Value] | `.env.local` |
## Account Setup
[Only if new account creation is required]
- [ ] **Create [Service] account**
- URL: [signup URL]
- Skip if: Already have account
## Dashboard Configuration
[Only if dashboard configuration is required]
- [ ] **[Configuration task]**
- Location: [Service Dashboard → Path → To → Setting]
- Set to: [Required value or configuration]
- Notes: [Any important details]
## Verification
After completing setup, verify with:
```bash
# [Verification commands]
```
Expected results:
- [What success looks like]
---
**Once all items complete:** Mark status as "Complete" at top of file.
```
---
## When to Generate
Generate `{phase}-USER-SETUP.md` when plan frontmatter contains `user_setup` field.
**Trigger:** `user_setup` exists in PLAN.md frontmatter and has items.
**Location:** Same directory as PLAN.md and SUMMARY.md.
**Timing:** Generated during execute-plan.md after tasks complete, before SUMMARY.md creation.
---
## Frontmatter Schema
In PLAN.md, `user_setup` declares human-required configuration:
```yaml
user_setup:
- service: stripe
why: "Payment processing requires API keys"
env_vars:
- name: STRIPE_SECRET_KEY
source: "Stripe Dashboard → Developers → API keys → Secret key"
- name: STRIPE_WEBHOOK_SECRET
source: "Stripe Dashboard → Developers → Webhooks → Signing secret"
dashboard_config:
- task: "Create webhook endpoint"
location: "Stripe Dashboard → Developers → Webhooks → Add endpoint"
details: "URL: https://[your-domain]/api/webhooks/stripe, Events: checkout.session.completed, customer.subscription.*"
local_dev:
- "Run: stripe listen --forward-to localhost:3000/api/webhooks/stripe"
- "Use the webhook secret from CLI output for local testing"
```
---
## The Automation-First Rule
**USER-SETUP.md contains ONLY what Claude literally cannot do.**
| Claude CAN Do (not in USER-SETUP) | Claude CANNOT Do (→ USER-SETUP) |
|-----------------------------------|--------------------------------|
| `npm install stripe` | Create Stripe account |
| Write webhook handler code | Get API keys from dashboard |
| Create `.env.local` file structure | Copy actual secret values |
| Run `stripe listen` | Authenticate Stripe CLI (browser OAuth) |
| Configure package.json | Access external service dashboards |
| Write any code | Retrieve secrets from third-party systems |
**The test:** "Does this require a human in a browser, accessing an account Claude doesn't have credentials for?"
- Yes → USER-SETUP.md
- No → Claude does it automatically
---
## Service-Specific Example
<stripe_example>
```markdown
# Phase 10: User Setup Required
**Generated:** 2025-01-14
**Phase:** 10-monetization
**Status:** Incomplete
Complete these items for Stripe integration to function.
## Environment Variables
| Status | Variable | Source | Add to |
|--------|----------|--------|--------|
| [ ] | `STRIPE_SECRET_KEY` | Stripe Dashboard → Developers → API keys → Secret key | `.env.local` |
| [ ] | `NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY` | Stripe Dashboard → Developers → API keys → Publishable key | `.env.local` |
| [ ] | `STRIPE_WEBHOOK_SECRET` | Stripe Dashboard → Developers → Webhooks → [endpoint] → Signing secret | `.env.local` |
## Account Setup
- [ ] **Create Stripe account** (if needed)
- URL: https://dashboard.stripe.com/register
- Skip if: Already have Stripe account
## Dashboard Configuration
- [ ] **Create webhook endpoint**
- Location: Stripe Dashboard → Developers → Webhooks → Add endpoint
- Endpoint URL: `https://[your-domain]/api/webhooks/stripe`
- Events to send:
- `checkout.session.completed`
- `customer.subscription.created`
- `customer.subscription.updated`
- `customer.subscription.deleted`
- [ ] **Create products and prices** (if using subscription tiers)
- Location: Stripe Dashboard → Products → Add product
- Create each subscription tier
- Copy Price IDs to:
- `STRIPE_STARTER_PRICE_ID`
- `STRIPE_PRO_PRICE_ID`
## Local Development
For local webhook testing:
```bash
stripe listen --forward-to localhost:3000/api/webhooks/stripe
```
Use the webhook signing secret from CLI output (starts with `whsec_`).
## Verification
After completing setup:
```bash
# Verify build passes
npm run build
# Test webhook endpoint (should return 400 bad signature, not 500 crash)
curl -X POST http://localhost:3000/api/webhooks/stripe \
-H "Content-Type: application/json" \
-d '{}'
```
Expected: Build passes, webhook returns 400 (signature validation working).
---
**Once all items complete:** Mark status as "Complete" at top of file.
```
</stripe_example>
---
## Guidelines
**Never include:** Actual secret values. Steps Claude can automate (package installs, code changes).
**Naming:** `{phase}-USER-SETUP.md` matches the phase number pattern.
**Status tracking:** User marks checkboxes and updates status line when complete.
**Searchability:** `grep -r "USER-SETUP" .planning/` finds all phases with user requirements.

View File

@@ -288,7 +288,7 @@ Mode resolution:
| architecture | docs/architecture/overview.md | create | new directory | | architecture | docs/architecture/overview.md | create | new directory |
| getting_started | docs/guides/getting-started.md | update | found, hand-written | | getting_started | docs/guides/getting-started.md | update | found, hand-written |
| development | docs/guides/development.md | create | matched docs/guides/ | | development | docs/guides/development.md | create | matched docs/guides/ |
| testing | docs/guides/testing.md | create | matched docs/guides/ | | contributing | docs/guides/contributing.md | create | matched docs/guides/ |
| configuration | docs/guides/configuration.md | create | matched docs/guides/ | | configuration | docs/guides/configuration.md | create | matched docs/guides/ |
| api | docs/api/reference.md | create | new directory | | api | docs/api/reference.md | create | new directory |
| deployment | docs/guides/deployment.md | update | found, hand-written | | deployment | docs/guides/deployment.md | update | found, hand-written |

View File

@@ -400,7 +400,7 @@ fi
grep -A 50 "^user_setup:" .planning/phases/XX-name/{phase}-{plan}-PLAN.md | head -50 grep -A 50 "^user_setup:" .planning/phases/XX-name/{phase}-{plan}-PLAN.md | head -50
``` ```
If user_setup exists: create `{phase}-USER-SETUP.md` using template `~/.claude/gsd-core/templates/user-setup.md`. Per service: env vars table, account setup checklist, dashboard config, local dev notes, verification commands. Status "Incomplete". Set `USER_SETUP_CREATED=true`. If empty/missing: skip. If user_setup exists: create `{phase}-USER-SETUP.md` using the template at `~/.claude/gsd-core/templates/user-setup.md` (or its `~/.claude/gsd-core/templates/user-setup.compact.md` variant — resolve per `~/.claude/gsd-core/references/compact-content-gate.md` §"Streams 1b and 4"). Per service: env vars table, account setup checklist, dashboard config, local dev notes, verification commands. Status "Incomplete". Set `USER_SETUP_CREATED=true`. If empty/missing: skip.
</step> </step>
<step name="create_summary"> <step name="create_summary">
@@ -409,7 +409,7 @@ emit narrative output between the Write tool call and the commit tool call.
Truncation at this boundary is a known failure mode (see #2070 rescue logic in Truncation at this boundary is a known failure mode (see #2070 rescue logic in
execute-phase.md step 5.5). execute-phase.md step 5.5).
Create `{phase}-{plan}-SUMMARY.md` at `.planning/phases/XX-name/`. Use `~/.claude/gsd-core/templates/summary.md`. Create `{phase}-{plan}-SUMMARY.md` at `.planning/phases/XX-name/`. Use the template at `~/.claude/gsd-core/templates/summary.md` (or its `~/.claude/gsd-core/templates/summary.compact.md` variant — resolve per `~/.claude/gsd-core/references/compact-content-gate.md` §"Streams 1b and 4").
**Frontmatter:** phase, plan, subsystem, tags | requires/provides/affects | tech-stack.added/patterns | key-files.created/modified | key-decisions | requirements-completed (**MUST** copy `requirements` array from PLAN.md frontmatter verbatim) | duration ($DURATION), completed ($PLAN_END_TIME date). **Frontmatter:** phase, plan, subsystem, tags | requires/provides/affects | tech-stack.added/patterns | key-files.created/modified | key-decisions | requirements-completed (**MUST** copy `requirements` array from PLAN.md frontmatter verbatim) | duration ($DURATION), completed ($PLAN_END_TIME date).

View File

@@ -10,7 +10,7 @@ Display GSD command help at the tier the user asked for. Output ONLY the referen
| When `$ARGUMENTS` is | Read | | When `$ARGUMENTS` is | Read |
|---|---| |---|---|
| `--brief` (or `-b`) alone | `workflows/help/modes/brief.md` | | `--brief` (or `-b`) alone | `workflows/help/modes/brief.md` |
| `--full` (or `-f`, `--all`) alone | `workflows/help/modes/full.md` | | `--full` (or `-f`, `--all`) alone | `workflows/help/modes/full.md` (or its `workflows/help/modes/full.compact.md` variant per `gsd-core/references/compact-content-gate.md` §"Streams 1b and 4 — variant resolution") |
| empty / unset | `workflows/help/modes/default.md` | | empty / unset | `workflows/help/modes/default.md` |
| `--brief <topic>` (or `-b <topic>`) | `workflows/help/modes/topic.md` in compact scope (signature + one-line summary of the matched section) | | `--brief <topic>` (or `-b <topic>`) | `workflows/help/modes/topic.md` in compact scope (signature + one-line summary of the matched section) |
| anything else — bare topic, `--full <topic>`, or topic with leading `--` | `workflows/help/modes/topic.md` in full scope (entire matched section) | | anything else — bare topic, `--full <topic>`, or topic with leading `--` | `workflows/help/modes/topic.md` in full scope (entire matched section) |

View File

@@ -0,0 +1,398 @@
Apply response_language to all user-facing prose — narration between tool calls, status updates, progress notes, and findings included; preserve code, paths, and identifiers.
<purpose>
Display the complete GSD Core command reference. Output ONLY the reference content. Do NOT add project-specific analysis, git status, next-step suggestions, or any commentary beyond the reference.
</purpose>
<reference>
# GSD Core Command Reference
**GSD Core** (Git. Ship. Done.) creates hierarchical project plans optimized for solo agentic development with Claude Code.
## Quick Start
1. `/gsd:new-project` — Initialize project (research, requirements, roadmap)
2. `/gsd:plan-phase 1` — Create detailed plan for first phase
3. `/gsd:execute-phase 1` — Execute the phase
Not sure where to start? `/gsd:next` reads your project state and routes you to the right next action.
### Smart Entry
**`/gsd:next`** — State-aware front door. Detects your situation via `gsd-tools smart-entry` (no-project, paused, blocked, planning, executing, needs-verify, idle, complete, …) and shows a menu with one recommended action. Launcher only; falls back to `/gsd:progress`.
Usage: `/gsd:next`
## Staying Updated
```bash
npx @opengsd/gsd-core@latest
```
## Core Workflow
```text
/gsd:new-project → /gsd:plan-phase → /gsd:execute-phase → repeat
```
### Project Initialization
**`/gsd:new-project`** — Unified flow from idea to ready-for-planning: deep questioning, optional domain research (4 parallel researchers), requirements with v1/v2/out-of-scope scoping, roadmap with phase breakdown. Creates `.planning/`: `PROJECT.md`, `config.json`, `research/`, `REQUIREMENTS.md`, `ROADMAP.md`, `STATE.md`.
Usage: `/gsd:new-project`
**`/gsd:onboard [--fast] [--text]`** — Guides first-time onboarding for an existing codebase: detects brownfield state, routes through `/gsd:map-codebase` → `/gsd:ingest-docs` → `/gsd:new-project` in safe order, idempotent.
Usage: `/gsd:onboard`
**`/gsd:map-codebase [--fast] [--focus <area>] [--query <term>]`** — Maps an existing codebase with parallel Explore agents into `.planning/codebase/` (stack, architecture, structure, conventions, testing, integrations, concerns). `--fast` for rapid assessment, `--query` to search the intel index.
Usage: `/gsd:map-codebase`
### Phase Planning
**`/gsd:discuss-phase <number> [--chain | --analyze | --power | --assumptions] [--batch[=N]]`** — Articulate your vision for a phase before planning; creates CONTEXT.md. `--chain` chained flow, `--analyze` assumption analysis, `--power` extended questions, `--assumptions` surfaces implementation assumptions non-interactively, `--batch` groups 2-5 questions per turn.
Usage: `/gsd:discuss-phase 2`
Usage: `/gsd:discuss-phase 2 --batch=3`
**`/gsd:plan-phase <number> [--research] [--skip-research] [--research-phase <N>] [--view] [--gaps] [--skip-verify] [--skip-ui] [--prd <file>] [--ingest <path-or-glob>] [--ingest-format <auto|nygard|madr|narrative>] [--reviews] [--text] [--bounce] [--skip-bounce] [--chunked] [--tdd] [--mvp] [--granularity <coarse|standard|fine>] [--no-tracer] [--no-reversibility-gates]`** — Creates `.planning/phases/XX-phase-name/XX-YY-PLAN.md` with concrete tasks, verification criteria, and success measures (multiple plans per phase supported).
Key flags: `--research-phase <N>` runs research only and writes `RESEARCH.md` then exits (replaces the deleted `gsd-research-phase`; `--research` forces refresh, `--view` prints existing without spawning). `--gaps` closes gaps from a prior plan-check. `--ingest`/`--ingest-format` pre-ingest external ADRs/PRDs/SPECs (see PRD Express Path). `--bounce`/`--skip-bounce` toggle the optional external refinement pass (`workflow.plan_bounce`). `--chunked` splits planning into short, individually-committed passes for crash resilience (`workflow.plan_chunked`), resumable. `--tdd` tests-before-code order. `--mvp` adds user story + Walking Skeleton (see `/gsd:mvp-phase`). `--granularity` overrides resolved plan granularity. `--no-tracer` opts out of tracer-first ordering. `--no-reversibility-gates` suppresses the one-way-door checkpoint for unattended runs.
Usage: `/gsd:plan-phase 1`
Result: Creates `.planning/phases/01-foundation/01-01-PLAN.md`
**PRD Express Path:** Pass `--prd path/to/requirements.md` to skip discuss-phase — your PRD becomes locked decisions in CONTEXT.md.
### Execution
**`/gsd:execute-phase <phase-number> [--wave N] [--gaps-only] [--tdd]`** — Groups plans by wave (frontmatter), executes sequentially with parallel plans per wave via Task tool, verifies phase goal, updates REQUIREMENTS/ROADMAP/STATE. `--wave N` runs only wave N; `--gaps-only` re-runs verifier-flagged plans; `--tdd` enforces test-driven order.
Usage: `/gsd:execute-phase 5`
Usage: `/gsd:execute-phase 5 --wave 2`
### Smart Router
**`/gsd:progress --do "<description>"`** — Routes freeform text to the best-matching GSD command; asks you to pick between top matches on ambiguity. Never does the work itself.
Usage: `/gsd:progress --do "fix the login button"`
### Quick Mode
**`/gsd:quick [--full] [--validate] [--discuss] [--research]`** — Small ad-hoc tasks in `.planning/quick/` (updates STATE.md, not ROADMAP.md); spawns planner+executor only by default. `--full` = discuss+research+plan-check+verify; `--validate` = plan-check + post-execution verify; `--discuss`/`--research` add one step each; flags compose.
Usage: `/gsd:quick`
Result: Creates `.planning/quick/NNN-slug/PLAN.md`, `.planning/quick/NNN-slug/NNN-slug-SUMMARY.md`
---
**`/gsd:quick-batch [--file <path>] [--jobs auto|N] [--validate] [--research] [--resume <batch-id>] [task list]`** — Batches several quick-shaped tasks (inline or `--file`); one coordinator plans/dispatches/merges. `--jobs` caps concurrency, `--resume` dispatches only eligible items; `--discuss`/`--full` are rejected.
Usage: `/gsd:quick-batch --jobs 3 --validate`
Result: Per-item artifacts under `.planning/quick/`; batch state in `.planning/quick-batches/<batch-id>/BATCH.json`
---
**`/gsd:fast [description]`** — Trivial task inline, no subagent, no planning files: typo fixes, config changes, ≤3 file edits (redirects to `/gsd:quick` above that). Atomic commit, logs to STATE.md.
Usage: `/gsd:fast "fix the typo in README"`
### Roadmap Management
**`/gsd:phase <description>`** — Appends a new phase (next sequential number) to ROADMAP.md.
Usage: `/gsd:phase "Add admin dashboard"`
**`/gsd:phase --insert <after> <description>`** — Inserts a decimal phase (e.g. 7.1) between existing phases for discovered mid-milestone work.
Usage: `/gsd:phase --insert 7 "Fix critical auth bug"`
Result: Creates Phase 7.1
**`/gsd:phase --remove <number>`** — Deletes a future (unstarted) phase and renumbers subsequent phases; git commit preserves history.
Usage: `/gsd:phase --remove 17`
Result: Phase 17 deleted, phases 18-20 become 17-19
**`/gsd:phase --edit <number> [--force]`** — Edits title/description/requirements/dependencies in place; `--force` allows editing already-started phases.
### Milestone Management
**`/gsd:new-milestone <name>`** — Mirrors `/gsd:new-project`'s flow for brownfield (existing PROJECT.md): questioning, optional research, requirements, roadmap. `--reset-phase-numbers` restarts at Phase 1 (archives old dirs first); `--ws <name>` scopes to a workstream, skipping the shared PROJECT.md write.
Usage: `/gsd:new-milestone "v2.0 Features"`
**`/gsd:complete-milestone <version>`** — Archives to MILESTONES.md + milestones/ dir, tags the release, preps workspace for next version.
Usage: `/gsd:complete-milestone 1.0.0`
### Progress Tracking
**`/gsd:progress [--next | --forensic | --do "<description>"]`** — Progress bar, SUMMARY recap, current position, key decisions, offers to execute/create next plan, detects 100% completion.
Modes: default (report+routing) · `--next` (auto-advance; `--force` bypasses safety gates) · `--next --auto` (chains steps until milestone completion or a blocking decision) · `--next --converge` (routes planning through `/gsd:plan-review-convergence`, requires `workflow.plan_review_convergence`; reviewer flags and `--max-cycles` forward) · `--forensic` (appends a 6-check integrity audit) · `--do "<text>"` (smart router, see above).
Usage: `/gsd:progress`
Usage: `/gsd:progress --next --auto`
### Session Management
**`/gsd:resume-work`** — Reads STATE.md, shows position and recent progress, offers next actions.
Usage: `/gsd:resume-work`
**`/gsd:pause-work [--report]`** — Creates a `.continue-here` handoff, updates STATE.md's session-continuity section. `--report` also writes a post-session summary to `.planning/reports/`.
Usage: `/gsd:pause-work`
### Debugging
**`/gsd:debug [issue description] [--diagnose]`** — Adaptive-question symptom gathering, `.planning/debug/[slug].md` tracking, scientific-method investigation, survives `/clear` (resume with no args), archives resolved issues. `--diagnose` runs a one-shot pass without a persistent session.
Usage: `/gsd:debug "login button doesn't work"`
### Spiking & Sketching
**`/gsd:spike [idea] [--quick]`** — Decomposes into 2-5 risk-ordered Given/When/Then experiments, builds minimum code, captures VALIDATED/INVALIDATED/PARTIAL, saves to `.planning/spikes/` with MANIFEST.md. Works in any repo, no `/gsd:new-project` needed. `--quick` skips decomposition.
Usage: `/gsd:spike "can we stream LLM output over WebSockets?"`
**`/gsd:sketch [idea] [--quick]`** — Conversational mood intake, 2-3 tabbed HTML variants per sketch, shared CSS theme system, saves to `.planning/sketches/` with MANIFEST.md. `--quick` skips mood intake.
Usage: `/gsd:sketch "dashboard layout for the admin panel"`
**`/gsd:spike --wrap-up`** — Curates spikes one-at-a-time (include/exclude/partial/UAT), generates a project skill under `./.claude/skills/spike-findings-[project]/`, writes `.planning/spikes/WRAP-UP-SUMMARY.md`, adds a CLAUDE.md auto-load line.
Usage: `/gsd:spike --wrap-up`
**`/gsd:sketch --wrap-up`** — Same curation flow for sketches, generating `./.claude/skills/sketch-findings-[project]/` with design decisions/CSS/HTML structures.
Usage: `/gsd:sketch --wrap-up`
### Capturing Ideas, Notes, and Todos
**`/gsd:capture [description]`** — Extracts context from conversation (or uses the given text), creates a todo in `.planning/todos/pending/`, infers area, checks duplicates, updates STATE.md count.
Usage: `/gsd:capture Add auth token refresh`
**`/gsd:capture --note <text>`** — Zero-friction timestamped note to `.planning/notes/` (or `~/.claude/notes/` globally). Subcommands: append (default), list, promote (note → todo). Works without a project.
Usage: `/gsd:capture --note refactor the hook system`
Usage: `/gsd:capture --note promote 3`
**`/gsd:capture --list [area]`** — Lists pending todos (optional area filter), loads full context for the one you pick, routes to work-now/add-to-phase/brainstorm, moves it to completed/ on start.
Usage: `/gsd:capture --list api`
**`/gsd:capture --list-seeds [status]`** — Read-only listing of captured seeds (ID, status, scope, trigger, title); optional status filter. Enrich via `/gsd:capture --seed --enrich SEED-NNN`.
Usage: `/gsd:capture --list-seeds dormant`
### User Acceptance Testing
**`/gsd:verify-work [phase]`** — Extracts testable deliverables from SUMMARY.md, presents tests one at a time (yes/no), auto-diagnoses failures into fix plans, ready for re-execution.
Usage: `/gsd:verify-work 3`
### Ship Work
**`/gsd:ship [phase]`** — Pushes branch, opens a PR with a body from SUMMARY/VERIFICATION/REQUIREMENTS, optionally requests review, updates STATE.md. Requires a verified phase and authenticated `gh`.
Usage: `/gsd:ship 4` or `/gsd:ship 4 --draft`
---
**`/gsd:review --phase N [--gemini] [--claude] [--codex] [--coderabbit] [--opencode] [--qwen] [--cursor] [--agy] [--all]`** — Detects available external AI CLIs, each independently reviews the phase's plans with the same structured prompt (CodeRabbit reviews the live diff, up to ~5 min), produces REVIEWS.md with consensus. Feed back via `/gsd:plan-phase N --reviews`.
Usage: `/gsd:review --phase 3 --all`
---
**`/gsd:pr-branch [target]`** — Classifies commits (code-only/planning-only/mixed), cherry-picks code onto a clean branch so reviewers see no `.planning/` artifacts.
Usage: `/gsd:pr-branch` or `/gsd:pr-branch main`
---
**`/gsd:capture --seed [idea]`** — Captures a forward-looking idea with WHY/WHEN-to-surface trigger conditions; auto-surfaces during `/gsd:new-milestone` when triggers match.
Usage: `/gsd:capture --seed "add real-time notifications when we build the events system"`
**`/gsd:capture --backlog [description]`** — Adds an idea to the 999.x backlog without committing to the current milestone; promote later via `/gsd:review-backlog`.
Usage: `/gsd:capture --backlog "real-time notifications when events ship"`
---
**`/gsd:audit-uat`** — Cross-phase audit of all outstanding UAT/verification items (pending, skipped, blocked, human_needed), cross-references the codebase for stale docs, produces a prioritized test plan. Run before a new milestone.
Usage: `/gsd:audit-uat`
### Milestone Auditing
**`/gsd:audit-milestone [version]`** — Reads all phase VERIFICATION.md files, checks requirements coverage, spawns an integration checker for cross-phase wiring, creates MILESTONE-AUDIT.md.
Usage: `/gsd:audit-milestone`
### Configuration
**`/gsd:settings`** — Interactively toggles researcher/plan-checker/verifier agents and the model profile (quality/balanced/budget/inherit); updates `.planning/config.json`.
Usage: `/gsd:settings`
**`/gsd:config [--profile <profile> | --advanced | --integrations]`** — `--profile` quick-switches model profile (`quality` = Opus everywhere but verification, `balanced` = Opus planning/Sonnet execution (default), `budget` = Sonnet writing/Haiku research-verification, `inherit` = current session model). `--advanced` = plan bounce, timeouts, branch templates, cross-AI execution. `--integrations` = third-party API keys, code-review CLI routing, agent-skill injection.
Usage: `/gsd:config --profile budget`
**`/gsd:surface [list|status|profile <name>|disable <cluster>|enable <cluster>|reset]`** — Toggles which skills are surfaced without reinstalling: `list`/`status` show enabled/disabled + token cost, `profile <name>` switches base profile (`core`/`standard`/`full`), `disable`/`enable` a cluster, `reset` returns to install-time profile.
Usage: `/gsd:surface profile standard`
### Utility Commands
**`/gsd:cleanup`** — Dry-run then moves completed-milestone phase dirs from `.planning/phases/` to `.planning/milestones/v{X.Y}-phases/`.
Usage: `/gsd:cleanup`
**`/gsd:help [--brief | --full | <topic> | --brief <topic>]`** — `--brief` = ~10-line refresher; no flag = one-page newcomer tour; `--full` = this complete reference; `<topic>` = matching section only (e.g. `/gsd:help debug`); `--brief <topic>` = compact scoped lookup. Every topic output starts with a `**Topic:** \`<alias>\` → \`<heading>\` *(scope: full | compact)*` preamble. See `gsd-core/workflows/help/modes/topic.md` for the alias table.
Usage: `/gsd:help debug`
Usage: `/gsd:help --brief debug`
**`/gsd:update [--sync] [--reapply] [--next | --rc]`** — Shows installed-vs-latest, changelog since your version, breaking changes, confirms before installing. `--sync` syncs managed skills across runtime roots; `--reapply` reapplies local modifications post-update; `--next`/`--rc` installs from the `@next` RC dist-tag (ADR #660) instead of `@latest`.
Usage: `/gsd:update`
## Additional Commands
Every command below is also a live `/gsd-*` slash command, grouped by purpose.
### Discovery & Specification
- **`/gsd:explore`** — Socratic ideation and idea routing before committing to plans.
- **`/gsd:spec-phase <phase> [--auto] [--text]`** — Clarify WHAT a phase delivers with ambiguity scoring; produces SPEC.md before discuss-phase.
- **`/gsd:ai-integration-phase [phase]`** — Generate an AI-SPEC.md design contract for phases building AI systems.
- **`/gsd:ui-phase [phase]`** — Generate UI design contract (UI-SPEC.md) for frontend phases.
- **`/gsd:import --from <filepath> | --from-gsd2`** — Ingest external plans with conflict detection, or reverse-migrate a GSD-2 project to v1 format.
- **`/gsd:ingest-docs [path] [--mode new|merge] [--manifest <file>] [--resolve auto|interactive]`** — Bootstrap or merge `.planning/` from existing ADRs/PRDs/SPECs/docs.
### Planning & Execution
- **`/gsd:mvp-phase <phase-number>`** — Plans a phase as a vertical MVP slice (user story + SPIDR splitting) before handoff to plan-phase; same end-state as `/gsd:plan-phase --mvp` with a guided intro.
- **`/gsd:ultraplan-phase [phase]`** — [BETA] Offload plan phase to Claude Code's ultraplan cloud; review in browser, import back.
- **`/gsd:plan-review-convergence <phase> [--gemini] [--claude] [--codex] [--coderabbit] [--opencode] [--qwen] [--cursor] [--agy/--antigravity] [--ollama] [--lm-studio] [--llama-cpp] [--kimi-code] [--all] [--text] [--ws <name>] [--max-cycles N]`** — Cross-AI convergence loop: replan with review feedback until no HIGH concerns remain (cloud and local-model reviewers).
- **`/gsd:autonomous [--from N] [--to N] [--only N] [--interactive] [--converge]`** — Runs all remaining phases unattended: discuss → plan → execute per phase; `--converge`/`--cross-ai` routes planning through convergence.
### Quality, Review & Verification
- **`/gsd:code-review <phase> [--depth=quick|standard|deep] [--files file1,file2,...] [--fix [--all] [--auto]]`** — Reviews phase-changed source for bugs, security, quality.
- **`/gsd:secure-phase [phase]`** — Retroactively verifies threat mitigations for a completed phase.
- **`/gsd:validate-phase [phase]`** — Retroactively audits and fills Nyquist validation gaps.
- **`/gsd:ui-review [phase]`** — Retroactive 6-pillar visual audit of implemented frontend code.
- **`/gsd:eval-review [phase]`** — Audits an executed AI phase's evaluation coverage; produces EVAL-REVIEW.md.
- **`/gsd:audit-fix --source <audit-uat> [--severity medium|high|all] [--max N] [--dry-run]`** — Autonomous audit-to-fix: find, classify, fix, test, commit.
- **`/gsd:add-tests <phase> [additional instructions]`** — Generates tests for a completed phase from UAT criteria and implementation.
### Diagnostics & Maintenance
- **`/gsd:health [--repair] [--context]`** — Diagnoses planning-directory health, optionally repairs.
- **`/gsd:forensics [problem description]`** — Post-mortem investigation for failed GSD workflows.
- **`/gsd:undo --last N | --phase NN | --plan NN-MM`** — Safe git revert using the phase manifest with dependency checks.
- **`/gsd:docs-update [--force] [--verify-only]`** — Generates/updates docs verified against the codebase.
- **`/gsd:extract-learnings <phase>`** — Extracts decisions, lessons, patterns, surprises from phase artifacts.
### Knowledge & Context
- **`/gsd:graphify [build|query <term>|status|diff]`** — Builds/queries/inspects the project knowledge graph in `.planning/graphs/`.
- **`/gsd:mempalace-recall`** — Recalls prior decisions/patterns/surprises from MemPalace before planning.
- **`/gsd:mempalace-capture [artifact-type]`** — Files a phase artifact into MemPalace, mirrors decisions into its temporal KG.
- **`/gsd:thread [list [--open|--resolved] | close <slug> | status <slug> | name | description]`** — Manages persistent context threads across sessions.
- **`/gsd:profile-user [--questionnaire] [--refresh]`** — Generates a developer behavioral profile + Claude-discoverable artifacts.
- **`/gsd:stats`** — Project statistics: phases, plans, requirements, git metrics, timeline.
### Workflow & Orchestration
- **`/gsd:manager [--analyze-deps]`** — Interactive command center for multiple phases from one terminal; `--analyze-deps` scans dependency relationships before parallel execution.
- **`/gsd:workspace [--new | --list | --remove] [name]`** — Creates/lists/removes isolated GSD workspace environments.
- **`/gsd:workstreams`** — List, create, switch, status, progress, complete, and resume parallel workstreams.
- **`/gsd:review-backlog`** — Reviews and promotes backlog items to the active milestone.
- **`/gsd:milestone-summary [version]`** — Comprehensive project summary from milestone artifacts, for onboarding/review.
### Repository Integration
- **`/gsd:inbox [--issues] [--prs] [--label] [--close-incomplete] [--repo owner/repo]`** — Triages open GitHub issues/PRs against project templates and contribution guidelines.
### Namespace Routers (model-facing meta-skills)
Six skills for two-stage hierarchical routing across 60+ skills; invoke directly to browse a category interactively:
- **`/gsd-context`** — Codebase intelligence (map, graphify, docs, learnings, mempalace).
- **`/gsd-ideate`** — Exploration/capture (explore, sketch, spike, spec, capture).
- **`/gsd-manage`** — Configuration/workspace (workstreams, thread, update, ship, inbox).
- **`/gsd-project`** — Project-lifecycle (milestones, audits, summary).
- **`/gsd-quality`** — Quality gates (code review, debug, audit, security, eval, ui).
- **`/gsd-workflow`** — Phase pipeline (discuss, plan, execute, verify, phase, progress).
## Files & Structure
```text
.planning/
├── PROJECT.md # Project vision
├── ROADMAP.md # Current phase breakdown
├── STATE.md # Project memory & context
├── RETROSPECTIVE.md # Living retrospective (updated per milestone)
├── config.json # Workflow mode & gates
├── todos/ # Captured ideas and tasks (pending/, completed/)
├── spikes/ # Spike experiments — MANIFEST.md + NNN-name/ dirs
├── sketches/ # Design sketches — MANIFEST.md, themes/, NNN-name/ dirs
├── debug/ # Active debug sessions (resolved/ archive)
├── milestones/ # Archived roadmap/requirements snapshots + v{X.Y}-phases/
├── codebase/ # Codebase map (brownfield): STACK/ARCHITECTURE/STRUCTURE/
│ # CONVENTIONS/TESTING/INTEGRATIONS/CONCERNS.md
└── phases/ # 01-foundation/01-01-PLAN.md + -SUMMARY.md, etc.
```
## Workflow Modes
Set during `/gsd:new-project`, changeable anytime in `.planning/config.json`:
- **Interactive** — confirms each major decision, pauses at checkpoints, more guidance.
- **YOLO** — auto-approves most decisions, executes without confirmation, stops only for critical checkpoints.
## Planning Configuration
`.planning/config.json`:
- **`planning.commit_docs`** (default `true`) — `false` keeps planning artifacts local-only (add `.planning/` to `.gitignore`); useful for OSS/client projects wanting private planning.
- **`planning.search_gitignored`** (default `false`) — `true` adds `--no-ignore` to broad ripgrep searches when `.planning/` is gitignored.
```json
{
"planning": {
"commit_docs": false,
"search_gitignored": true
}
}
```
## Common Workflows
**New project:** `/gsd:new-project` → `/clear` → `/gsd:plan-phase 1` → `/clear` → `/gsd:execute-phase 1`
**Resuming:** `/gsd:progress`
**Urgent mid-milestone work:** `/gsd:phase --insert 5 "Critical security fix"` → `/gsd:plan-phase 5.1` → `/gsd:execute-phase 5.1`
**Completing a milestone:** `/gsd:complete-milestone 1.0.0` → `/clear` → `/gsd:new-milestone`
**Capturing ideas:** `/gsd:capture` (from context) · `/gsd:capture --note ...` (quick note) · `/gsd:capture --seed "..."` (forward-looking) · `/gsd:capture --list` (review)
**Debugging:** `/gsd:debug "symptom"` → (investigate, context fills) → `/clear` → `/gsd:debug` (resumes)
## Getting Help
- Read `.planning/PROJECT.md` for project vision
- Read `.planning/STATE.md` for current context
- Check `.planning/ROADMAP.md` for phase status
- Run `/gsd:progress` to check where you're up to
</reference>

View File

@@ -140,6 +140,7 @@
"lint:hooks-runtime-build-seam": "node scripts/lint-hooks-runtime-build-seam.cjs", "lint:hooks-runtime-build-seam": "node scripts/lint-hooks-runtime-build-seam.cjs",
"ci:test-scope": "node scripts/ci-test-scope.cjs", "ci:test-scope": "node scripts/ci-test-scope.cjs",
"benchmark:compact-content": "node scripts/benchmark-compact-content.cjs --check", "benchmark:compact-content": "node scripts/benchmark-compact-content.cjs --check",
"benchmark:compact-content-variants": "node scripts/benchmark-compact-content-variants.cjs --check",
"changeset": "node scripts/changeset/new.cjs", "changeset": "node scripts/changeset/new.cjs",
"changelog:render": "node scripts/changeset/cli.cjs render", "changelog:render": "node scripts/changeset/cli.cjs render",
"test": "node scripts/run-tests.cjs", "test": "node scripts/run-tests.cjs",

View File

@@ -0,0 +1,291 @@
#!/usr/bin/env node
'use strict';
/**
* Benchmarks the token-count effect of every registered variant-swap pair
* (ADR-4139, Phase 6 #4406 — `gsd-core/workflows/<name>/{modes,steps,templates}/*.compact.md`
* and `gsd-core/templates/**\/*.compact.md`). Sibling to
* `scripts/benchmark-compact-content.cjs` (Phase 3's spine/detail benchmark) rather than an
* extension of it — the two are different data shapes (a variant pair is two independent,
* deliberately-overlapping complete files; a spine/detail split is one document partitioned in
* two disjoint halves), and mixing them into one report would conflate an "off" total that means
* something different in each case.
*
* For every registered pair it reports the "off" token count (the canonical file — what
* `workflow.compact_content=false`, the default, pays at that call site) against the "on" token
* count (the `.compact.md` sibling — what `workflow.compact_content=true` pays once the gate
* resolves to it). See `gsd-core/references/compact-content-gate.md` §"Streams 1b and 4" for the
* resolution rule this measures.
*
* PROXY-TOKENIZER CAVEAT: same as the sibling script — `gpt-tokenizer` is a stand-in tokenizer;
* Anthropic publishes none for Claude 3+. The on/off comparison is exact under this one pinned
* tokenizer applied identically to both sides; the absolute counts are not Claude's real counts.
*
* Discovery is REIMPLEMENTED here rather than imported from
* `tests/helpers/compact-content-variant.cjs`, for the same reason
* `benchmark-compact-content.cjs` reimplements spine/detail discovery instead of importing it: a
* `scripts/` reporting tool depending on a test-only helper module inverts this repo's normal
* layering, and a test-only module changing shape should never be able to break a benchmark.
*
* Usage:
* node scripts/benchmark-compact-content-variants.cjs # print JSON to stdout
* node scripts/benchmark-compact-content-variants.cjs --write # write the committed baseline
* node scripts/benchmark-compact-content-variants.cjs --check # recompute, diff vs committed baseline
* node scripts/benchmark-compact-content-variants.cjs --check --baseline-path=<path>
*
* Same CRITICAL contract as the sibling script: this — and `--check` especially — MUST NEVER
* exit non-zero because a baseline is drifted, stale, or missing. Only a genuine I/O error
* reading a SOURCE file the benchmark measures may throw. This is a reporting instrument, never
* a gate.
*/
const fs = require('node:fs');
const path = require('node:path');
const { countTokens } = require('gpt-tokenizer');
const { runMain } = require('./lib/cli-exit.cjs');
const ROOT = path.resolve(__dirname, '..');
const VARIANT_ROOTS = [path.join(ROOT, 'gsd-core', 'workflows'), path.join(ROOT, 'gsd-core', 'templates')];
const BASELINE_PATH = path.join(ROOT, 'tests', 'fixtures', 'compact-content-variant-benchmark-baseline.json');
const COMPACT_SUFFIX = '.compact.md';
function getTokenizerVersion() {
const pkgPath = require.resolve('gpt-tokenizer/package.json');
const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
return pkg.version;
}
/**
* Discover every registered variant pair under `roots`: a `.compact.md` file
* with a same-directory, same-stem canonical `.md` sibling. Mirrors
* `tests/helpers/compact-content-variant.cjs`'s `discoverRegisteredVariants`
* in shape but is a from-scratch, self-contained implementation (see module
* header for why this is not a shared import). Skips an orphaned compact
* file with no canonical sibling — that is the guard's problem, not this
* benchmark's; a pair with no canonical baseline has no "off" number to
* report against.
*
* @param {string[]} [roots]
* @returns {Array<{name: string, canonicalPath: string, compactPath: string}>}
*/
function discoverRegisteredVariants(roots = VARIANT_ROOTS) {
const pairs = [];
function walk(dir) {
let entries;
try {
entries = fs.readdirSync(dir, { withFileTypes: true });
} catch {
return;
}
for (const entry of entries) {
const full = path.join(dir, entry.name);
if (entry.isDirectory()) {
walk(full);
} else if (entry.isFile() && entry.name.endsWith(COMPACT_SUFFIX)) {
const stem = entry.name.slice(0, -COMPACT_SUFFIX.length);
const canonicalPath = path.join(dir, `${stem}.md`);
if (fs.existsSync(canonicalPath)) {
const name = path.relative(ROOT, canonicalPath).split(path.sep).join('/');
pairs.push({ name, canonicalPath, compactPath: full });
}
}
}
}
for (const root of roots) walk(root);
return pairs.sort((a, b) => a.name.localeCompare(b.name));
}
/**
* Compute the off/on/reduction numbers for ONE registered variant pair.
* Throws on a genuine read failure of a source file (the one thing allowed
* to throw, per the module-header CRITICAL note).
*
* @param {{canonicalPath: string, compactPath: string}} pair
* @returns {{offTokens: number, onTokens: number, reductionPct: number}}
*/
function computePairTokens(pair) {
const offTokens = countTokens(fs.readFileSync(pair.canonicalPath, 'utf8'));
const onTokens = countTokens(fs.readFileSync(pair.compactPath, 'utf8'));
const reductionPct = offTokens === 0 ? 0 : round2(((offTokens - onTokens) / offTokens) * 100);
return { offTokens, onTokens, reductionPct };
}
function round2(n) {
return Math.round(n * 100) / 100;
}
/**
* Aggregate per-pair numbers from SUMMED off/on totals, never averaged
* per-pair percentages. Reports `0` (not `NaN`) for zero registered pairs.
* @param {Record<string, {offTokens: number, onTokens: number}>} pairResults
*/
function computeAggregate(pairResults) {
let offTokens = 0;
let onTokens = 0;
for (const key of Object.keys(pairResults)) {
offTokens += pairResults[key].offTokens;
onTokens += pairResults[key].onTokens;
}
const reductionPct = offTokens === 0 ? 0 : round2(((offTokens - onTokens) / offTokens) * 100);
return { offTokens, onTokens, reductionPct };
}
const LABEL =
"PROXY-TOKENIZER DELTA — gpt-tokenizer is a stand-in; Anthropic publishes no tokenizer for Claude 3+. " +
"The on/off COMPARISON is exact under this pinned tokenizer; absolute counts are not Claude's real token counts.";
/**
* @param {string[]} [roots]
* @returns {object}
*/
function buildReport(roots = VARIANT_ROOTS) {
const pairs = discoverRegisteredVariants(roots);
const pairReports = {};
for (const pair of pairs) {
pairReports[pair.name] = computePairTokens(pair);
}
return {
schema_version: 1,
generated_by: 'scripts/benchmark-compact-content-variants.cjs',
tokenizer: { name: 'gpt-tokenizer', version: getTokenizerVersion() },
label: LABEL,
pairs: pairReports,
aggregate: computeAggregate(pairReports),
};
}
/**
* Format a human-readable drift summary between a (possibly missing/invalid)
* committed baseline and a freshly-computed live report. Never throws.
* @param {string} baselinePath
* @param {object} live
* @returns {string}
*/
function formatDriftReport(baselinePath, live) {
const lines = [];
let baseline = null;
let baselineReadError = null;
try {
const raw = fs.readFileSync(baselinePath, 'utf8');
try {
baseline = JSON.parse(raw);
} catch (parseErr) {
baselineReadError = `baseline at ${baselinePath} could not be parsed as JSON: ${parseErr.message}`;
}
} catch {
baselineReadError = `no baseline found at ${baselinePath}`;
}
if (baselineReadError) {
lines.push(`DRIFT: ${baselineReadError} — treating as fully drifted (this is reported, not an error).`);
lines.push('Live pairs:');
for (const name of Object.keys(live.pairs).sort()) {
const p = live.pairs[name];
lines.push(` + ${name}: off=${p.offTokens} on=${p.onTokens} reduction=${p.reductionPct}%`);
}
lines.push(
`Live aggregate: off=${live.aggregate.offTokens} on=${live.aggregate.onTokens} ` +
`reduction=${live.aggregate.reductionPct}%`,
);
return lines.join('\n');
}
const baselinePairs = (baseline && typeof baseline === 'object' && baseline.pairs) || {};
const livePairs = live.pairs;
const allNames = new Set([...Object.keys(baselinePairs), ...Object.keys(livePairs)]);
let anyDrift = false;
if (!baseline || typeof baseline.label !== 'string' || !baseline.label.includes('PROXY-TOKENIZER')) {
anyDrift = true;
lines.push('DRIFT: committed baseline is missing the required "PROXY-TOKENIZER" label.');
}
for (const name of [...allNames].sort()) {
const b = baselinePairs[name];
const l = livePairs[name];
if (!b) {
anyDrift = true;
lines.push(`DRIFT: pair "${name}" is new (not in committed baseline) — live off=${l.offTokens} on=${l.onTokens} reduction=${l.reductionPct}%`);
} else if (!l) {
anyDrift = true;
lines.push(`DRIFT: pair "${name}" was removed (present in committed baseline, not found live) — baseline off=${b.offTokens} on=${b.onTokens} reduction=${b.reductionPct}%`);
} else if (b.offTokens !== l.offTokens || b.onTokens !== l.onTokens || b.reductionPct !== l.reductionPct) {
anyDrift = true;
lines.push(
`DRIFT: pair "${name}": off ${b.offTokens} -> ${l.offTokens} (${l.offTokens - b.offTokens >= 0 ? '+' : ''}${l.offTokens - b.offTokens}), ` +
`on ${b.onTokens} -> ${l.onTokens} (${l.onTokens - b.onTokens >= 0 ? '+' : ''}${l.onTokens - b.onTokens}), ` +
`reduction ${b.reductionPct}% -> ${l.reductionPct}% (${round2(l.reductionPct - b.reductionPct) >= 0 ? '+' : ''}${round2(l.reductionPct - b.reductionPct)}pp)`,
);
}
}
const ba = (baseline && baseline.aggregate) || {};
const la = live.aggregate;
if (ba.offTokens !== la.offTokens || ba.onTokens !== la.onTokens || ba.reductionPct !== la.reductionPct) {
anyDrift = true;
lines.push(
`DRIFT: aggregate: off ${ba.offTokens} -> ${la.offTokens}, on ${ba.onTokens} -> ${la.onTokens}, ` +
`reduction ${ba.reductionPct}% -> ${la.reductionPct}%`,
);
}
if (!anyDrift) {
lines.push(`Baseline at ${baselinePath} is up to date with the live recompute.`);
} else {
lines.push('');
lines.push('Run `node scripts/benchmark-compact-content-variants.cjs --write` to refresh the committed baseline.');
lines.push('(This is a REPORT, not a gate — exiting 0 regardless of drift, per this script\'s own contract.)');
}
return lines.join('\n');
}
function parseArgs(argv) {
const opts = { write: false, check: false, baselinePath: BASELINE_PATH };
for (const arg of argv) {
if (arg === '--write') opts.write = true;
else if (arg === '--check') opts.check = true;
else if (arg.startsWith('--baseline-path=')) opts.baselinePath = arg.slice('--baseline-path='.length);
}
return opts;
}
function main() {
const opts = parseArgs(process.argv.slice(2));
if (opts.write) {
const report = buildReport();
fs.mkdirSync(path.dirname(BASELINE_PATH), { recursive: true });
fs.writeFileSync(BASELINE_PATH, JSON.stringify(report, null, 2) + '\n');
process.stdout.write(`Wrote ${BASELINE_PATH}\n`);
return;
}
if (opts.check) {
const live = buildReport();
process.stdout.write(formatDriftReport(opts.baselinePath, live) + '\n');
return;
}
process.stdout.write(JSON.stringify(buildReport(), null, 2) + '\n');
}
/* c8 ignore next 3 -- CLI entry guard; this repo measures coverage with c8, which does not honor istanbul pragmas */
if (require.main === module) {
runMain(main);
}
module.exports = {
discoverRegisteredVariants,
computePairTokens,
computeAggregate,
buildReport,
formatDriftReport,
getTokenizerVersion,
parseArgs,
LABEL,
BASELINE_PATH,
VARIANT_ROOTS,
};

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,142 @@
'use strict';
/**
* tests/compact-content-template-variant-parity.test.cjs — ADR-4139, epic #4139, Phase 6 (#4406).
*
* Check 5 of `.gsd/phase/enhance-4406-lazy-remainder/40-design.md`'s variant-pair checklist:
* template consumer parity. Only two `gsd-core/templates/**` files got a `.compact.md` variant
* wired to a genuine runtime `Read` this phase — `summary.md` and `user-setup.md` (see
* `40-design.md`'s "a size-only candidate list was also the wrong test here" for why `spec.md`
* was dropped and why `summary.md`'s wiring is scoped to one call site only).
*
* The actual guarantee that makes compacting these templates safe: downstream consumers parse
* the GENERATED artifact (a real SUMMARY.md / USER-SETUP.md an agent wrote), never the template
* file itself. So the only way a compact variant could silently break a real consumer is if it
* changed the artifact's OUTPUT-FORMAT CONTRACT — the `## File Template` fenced block — relative
* to the canonical file. Both compact variants were authored to leave that block byte-identical
* and compact only the surrounding illustrative material (examples, guidelines prose). This test
* proves that invariant directly, rather than assuming it from the authoring process, and then
* proves the shared contract really is what the one real deterministic consumer
* (`gsd-core/bin/lib/coverage.cjs`'s `classifyContent`, backing `gsd-tools uat classify-coverage`)
* accepts and classifies correctly.
*
* `user-setup.md` has no deterministic content parser anywhere in this repo (confirmed by
* repo-wide search — the only "consumption" beyond an agent `Read` is a human `grep -r
* "USER-SETUP" .planning/` search over filenames, insensitive to internal structure). Its parity
* check is therefore limited to the File Template identity assertion; there is no real parser
* round trip to run against it.
*/
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, '..');
const { classifyContent } = require(path.join(ROOT, 'gsd-core', 'bin', 'lib', 'coverage.cjs'));
/**
* Extract the fenced code block immediately following a `## File Template` heading.
* Returns the block's inner content (without the opening/closing fences), or null if
* the heading or a following fence isn't found.
* @param {string} content
* @returns {string | null}
*/
function extractFileTemplateBlock(content) {
const headingIdx = content.indexOf('## File Template');
if (headingIdx === -1) return null;
const fenceStart = content.indexOf('```', headingIdx);
if (fenceStart === -1) return null;
const afterOpenFence = content.indexOf('\n', fenceStart) + 1;
const fenceEnd = content.indexOf('\n```', afterOpenFence);
if (fenceEnd === -1) return null;
return content.slice(afterOpenFence, fenceEnd);
}
describe('template consumer parity — File Template contract identity', () => {
test('summary.md and summary.compact.md share a byte-identical File Template block', () => {
const canonical = fs.readFileSync(path.join(ROOT, 'gsd-core', 'templates', 'summary.md'), 'utf8');
const compact = fs.readFileSync(path.join(ROOT, 'gsd-core', 'templates', 'summary.compact.md'), 'utf8');
const canonicalBlock = extractFileTemplateBlock(canonical);
const compactBlock = extractFileTemplateBlock(compact);
assert.ok(canonicalBlock, 'canonical summary.md must have an extractable File Template block');
assert.ok(compactBlock, 'summary.compact.md must have an extractable File Template block');
assert.strictEqual(
compactBlock,
canonicalBlock,
'summary.compact.md must not alter the output-format contract any downstream consumer parses',
);
});
test('user-setup.md and user-setup.compact.md share a byte-identical File Template block', () => {
const canonical = fs.readFileSync(path.join(ROOT, 'gsd-core', 'templates', 'user-setup.md'), 'utf8');
const compact = fs.readFileSync(path.join(ROOT, 'gsd-core', 'templates', 'user-setup.compact.md'), 'utf8');
const canonicalBlock = extractFileTemplateBlock(canonical);
const compactBlock = extractFileTemplateBlock(compact);
assert.ok(canonicalBlock, 'canonical user-setup.md must have an extractable File Template block');
assert.ok(compactBlock, 'user-setup.compact.md must have an extractable File Template block');
assert.strictEqual(
compactBlock,
canonicalBlock,
'user-setup.compact.md must not alter the output-format contract',
);
});
});
describe('template consumer parity — real classify-coverage round trip (summary.md)', () => {
const REALISTIC_SUMMARY = `---
phase: 07-example
plan: 01
subsystem: testing
tags: [example]
requires: []
provides: []
affects: []
coverage:
- id: D1
description: "Deterministic deliverable"
verification:
- kind: unit
ref: "tests/example.test.cjs#does the thing"
status: pass
human_judgment: false
- id: D2
description: "Deliverable needing a human"
verification: []
human_judgment: true
rationale: "UI screenshot review"
duration: 5min
completed: 2026-01-01
status: complete
---
# Phase 7: Example Summary
**A deterministic deliverable and a human-judgment deliverable.**
`;
test('a SUMMARY.md built from the shared File Template coverage schema classifies correctly', () => {
const result = classifyContent(REALISTIC_SUMMARY, '07-example-01-SUMMARY.md');
assert.strictEqual(result.mode, 'coverage');
assert.strictEqual(result.errors.length, 0, `expected no validation errors: ${JSON.stringify(result.errors)}`);
assert.strictEqual(result.auto_passed.length, 1, 'D1 (human_judgment:false, all verification pass) must auto-pass');
assert.strictEqual(result.present.length, 1, 'D2 (human_judgment:true) must route to a human');
assert.strictEqual(result.all_auto_covered, false);
});
test('boundary: a legacy SUMMARY.md with no coverage block still classifies (byte-identical fallback)', () => {
const legacy = REALISTIC_SUMMARY.replace(/coverage:[\s\S]*?rationale: "UI screenshot review"\n/, '');
const result = classifyContent(legacy, '07-example-01-SUMMARY.md');
assert.strictEqual(result.mode, 'legacy');
});
test('negative: a coverage block that fails validation is presented to a human, never silently auto-passed', () => {
const malformed = REALISTIC_SUMMARY.replace('human_judgment: false', '');
const result = classifyContent(malformed, '07-example-01-SUMMARY.md');
assert.strictEqual(result.mode, 'coverage');
assert.ok(
result.present.some((p) => p.id === 'D1'),
'D1 missing human_judgment must route to present, never auto-pass',
);
});
});

View File

@@ -0,0 +1,293 @@
'use strict';
/**
* tests/compact-content-variant-guard.test.cjs — ADR-4139, epic #4139, Phase 6 (#4406).
*
* Implements the four mechanical checks `.gsd/phase/enhance-4406-lazy-remainder/40-design.md`
* describes for the variant-swap shape (two independent, complete files; the gate picks which
* one gets `Read`) covering `gsd-core/workflows/<name>/{modes,steps,templates}/*.compact.md`
* and `gsd-core/templates/**\/*.compact.md`. This is a DIFFERENT shape from
* `tests/compact-content-partition-guard.test.cjs` (stream 1's spine+detail partition) — see
* `tests/helpers/compact-content-variant.cjs` for why disjointness/completeness do not apply
* here. Template consumer parity (the fifth check) lives in its own file,
* `tests/compact-content-template-variant-parity.test.cjs`, because it needs a real
* artifact-generation + real-parser round trip per template rather than a generic file-shape
* check.
*
* Each check gets a RED (deliberately broken) and GREEN (fixed) fixture pair, built against
* synthetic temp files — never against this repo's own real variants — per this repo's rule
* that a guard nobody has seen go red is not yet a guard.
*/
const { describe, test } = require('node:test');
const assert = require('node:assert/strict');
const fs = require('node:fs');
const os = require('node:os');
const path = require('node:path');
const { cleanup } = require('./helpers.cjs');
const {
discoverRegisteredVariants,
checkRegistration,
checkReachability,
checkProtectedContentPreserved,
checkSizeSmaller,
} = require('./helpers/compact-content-variant.cjs');
describe('compact-content variant guard — real repo state (ADR-4139, Phase 6 #4406)', () => {
test('check 1 (registration): every .compact.md file has a canonical sibling', () => {
const pairs = discoverRegisteredVariants();
const violations = checkRegistration(pairs);
assert.deepStrictEqual(violations, [], `registration violations: ${JSON.stringify(violations, null, 2)}`);
});
test('check 2 (reachability): every registered compact variant is named by at least one spine', () => {
const pairs = discoverRegisteredVariants();
const violations = checkReachability(pairs);
assert.deepStrictEqual(violations, [], `reachability violations: ${JSON.stringify(violations, null, 2)}`);
});
test('check 3 (protected content preserved): every protected block in a canonical file survives in its compact sibling', () => {
const pairs = discoverRegisteredVariants();
const violations = checkProtectedContentPreserved(pairs);
assert.deepStrictEqual(violations, [], `protected-content violations: ${JSON.stringify(violations, null, 2)}`);
});
test('check 4 (size smaller): every compact file is strictly smaller than its canonical sibling', () => {
const pairs = discoverRegisteredVariants();
const violations = checkSizeSmaller(pairs);
assert.deepStrictEqual(violations, [], `size violations: ${JSON.stringify(violations, null, 2)}`);
});
test('non-vacuity: this repo actually has registered variant pairs to check', () => {
const pairs = discoverRegisteredVariants();
assert.ok(pairs.length > 0, 'expected at least one registered .compact.md pair — an empty result proves nothing');
});
});
describe('failing-first fixture: check 1 (registration)', () => {
test('RED — a .compact.md file exists with no canonical sibling (orphan)', () => {
const tmpRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'gsd-variant-orphan-'));
try {
const workflowsDir = path.join(tmpRoot, 'gsd-core', 'workflows', 'foo', 'steps');
fs.mkdirSync(workflowsDir, { recursive: true });
fs.writeFileSync(path.join(workflowsDir, 'bar.compact.md'), 'Compact content with no canonical pair.\n');
const pairs = discoverRegisteredVariants([path.join(tmpRoot, 'gsd-core', 'workflows')]);
const violations = checkRegistration(pairs);
assert.ok(violations.length > 0, 'expected at least one registration violation');
assert.ok(
violations.some((v) => v.kind === 'orphan_compact_file' && v.compactPath.endsWith('bar.compact.md')),
`expected the orphan file to be named: ${JSON.stringify(violations)}`,
);
} finally {
cleanup(tmpRoot);
}
});
test('GREEN — the canonical sibling is added', () => {
const tmpRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'gsd-variant-orphan-ok-'));
try {
const workflowsDir = path.join(tmpRoot, 'gsd-core', 'workflows', 'foo', 'steps');
fs.mkdirSync(workflowsDir, { recursive: true });
fs.writeFileSync(path.join(workflowsDir, 'bar.compact.md'), 'Terser.\n');
fs.writeFileSync(path.join(workflowsDir, 'bar.md'), 'Canonical, longer content.\n');
const pairs = discoverRegisteredVariants([path.join(tmpRoot, 'gsd-core', 'workflows')]);
const violations = checkRegistration(pairs);
assert.deepStrictEqual(violations, []);
} finally {
cleanup(tmpRoot);
}
});
});
describe('failing-first fixture: check 2 (reachability)', () => {
test('RED — a registered pair whose compact path is never named by any spine', () => {
const tmpRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'gsd-variant-unreached-'));
try {
const workflowsRoot = path.join(tmpRoot, 'gsd-core', 'workflows');
const stepsDir = path.join(workflowsRoot, 'foo', 'steps');
fs.mkdirSync(stepsDir, { recursive: true });
fs.writeFileSync(path.join(stepsDir, 'bar.md'), 'Canonical, longer content.\n');
fs.writeFileSync(path.join(stepsDir, 'bar.compact.md'), 'Terser.\n');
fs.writeFileSync(path.join(workflowsRoot, 'foo.md'), 'Spine with entirely unrelated content and no path reference of any kind.\n');
const pairs = discoverRegisteredVariants([workflowsRoot]);
const violations = checkReachability(pairs, [workflowsRoot]);
assert.ok(violations.length > 0, 'expected at least one reachability violation');
assert.ok(
violations.some((v) => v.kind === 'unreachable_compact_file' && v.compactPath.endsWith('bar.compact.md')),
`expected the unreached file to be named: ${JSON.stringify(violations)}`,
);
} finally {
cleanup(tmpRoot);
}
});
test('GREEN — the spine names the compact path via the variant-resolution rule', () => {
const tmpRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'gsd-variant-unreached-ok-'));
try {
const workflowsRoot = path.join(tmpRoot, 'gsd-core', 'workflows');
const stepsDir = path.join(workflowsRoot, 'foo', 'steps');
fs.mkdirSync(stepsDir, { recursive: true });
fs.writeFileSync(path.join(stepsDir, 'bar.md'), 'Canonical, longer content.\n');
fs.writeFileSync(path.join(stepsDir, 'bar.compact.md'), 'Terser.\n');
fs.writeFileSync(
path.join(workflowsRoot, 'foo.md'),
'Read and execute `gsd-core/workflows/foo/steps/bar.md` (or its `gsd-core/workflows/foo/steps/bar.compact.md` variant per the shared gate).\n',
);
const pairs = discoverRegisteredVariants([workflowsRoot]);
const violations = checkReachability(pairs, [workflowsRoot]);
assert.deepStrictEqual(violations, []);
} finally {
cleanup(tmpRoot);
}
});
test('a vendored path ending in the same filename does not grant false reachability', () => {
const tmpRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'gsd-variant-unreached-prefix-'));
try {
const workflowsRoot = path.join(tmpRoot, 'gsd-core', 'workflows');
const stepsDir = path.join(workflowsRoot, 'foo', 'steps');
fs.mkdirSync(stepsDir, { recursive: true });
fs.writeFileSync(path.join(stepsDir, 'bar.md'), 'Canonical, longer content.\n');
fs.writeFileSync(path.join(stepsDir, 'bar.compact.md'), 'Terser.\n');
fs.writeFileSync(
path.join(workflowsRoot, 'foo.md'),
'This mentions vendor/foo/steps/bar.compact.md, a different tree entirely.\n',
);
const pairs = discoverRegisteredVariants([workflowsRoot]);
const violations = checkReachability(pairs, [workflowsRoot]);
assert.ok(
violations.some((v) => v.kind === 'unreachable_compact_file'),
'a prefixed match must not count as reachability',
);
} finally {
cleanup(tmpRoot);
}
});
});
describe('failing-first fixture: check 3 (protected content preserved)', () => {
test('RED — a protected block in the canonical file is absent from the compact sibling', () => {
const tmpRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'gsd-variant-protected-'));
try {
const workflowsRoot = path.join(tmpRoot, 'gsd-core', 'workflows', 'foo', 'steps');
fs.mkdirSync(workflowsRoot, { recursive: true });
fs.writeFileSync(
path.join(workflowsRoot, 'bar.md'),
'Intro.\n\n<!-- gsd:protected -->\nNever weaken this exact guardrail sentence.\n\nMore filler text that is safe to shorten elsewhere in this file to pad it out longer than the compact sibling.\n',
);
fs.writeFileSync(path.join(workflowsRoot, 'bar.compact.md'), 'Terser intro with the guardrail dropped.\n');
const pairs = discoverRegisteredVariants([path.join(tmpRoot, 'gsd-core', 'workflows')]);
const violations = checkProtectedContentPreserved(pairs);
assert.ok(violations.length > 0, 'expected at least one protected-content violation');
assert.ok(
violations.some((v) => v.missing.includes('Never weaken this exact guardrail sentence.')),
`expected the dropped sentence to be named: ${JSON.stringify(violations)}`,
);
} finally {
cleanup(tmpRoot);
}
});
test('GREEN — the guardrail sentence is preserved verbatim in the compact sibling', () => {
const tmpRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'gsd-variant-protected-ok-'));
try {
const workflowsRoot = path.join(tmpRoot, 'gsd-core', 'workflows', 'foo', 'steps');
fs.mkdirSync(workflowsRoot, { recursive: true });
fs.writeFileSync(
path.join(workflowsRoot, 'bar.md'),
'Intro.\n\n<!-- gsd:protected -->\nNever weaken this exact guardrail sentence.\n\nMore filler text that is safe to shorten elsewhere in this file to pad it out longer than the compact sibling.\n',
);
fs.writeFileSync(
path.join(workflowsRoot, 'bar.compact.md'),
'Terser intro.\n\nNever weaken this exact guardrail sentence.\n',
);
const pairs = discoverRegisteredVariants([path.join(tmpRoot, 'gsd-core', 'workflows')]);
const violations = checkProtectedContentPreserved(pairs);
assert.deepStrictEqual(violations, []);
} finally {
cleanup(tmpRoot);
}
});
test('a canonical file with no protected blocks is a correct no-op (nothing to preserve)', () => {
const tmpRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'gsd-variant-protected-none-'));
try {
const workflowsRoot = path.join(tmpRoot, 'gsd-core', 'workflows', 'foo', 'steps');
fs.mkdirSync(workflowsRoot, { recursive: true });
fs.writeFileSync(path.join(workflowsRoot, 'bar.md'), 'Plain canonical content with no protected sentinel at all.\n');
fs.writeFileSync(path.join(workflowsRoot, 'bar.compact.md'), 'Terser.\n');
const pairs = discoverRegisteredVariants([path.join(tmpRoot, 'gsd-core', 'workflows')]);
const violations = checkProtectedContentPreserved(pairs);
assert.deepStrictEqual(
violations,
[],
'a canonical file with zero <!-- gsd:protected --> blocks has nothing to check — never a violation',
);
} finally {
cleanup(tmpRoot);
}
});
});
describe('failing-first fixture: check 4 (size smaller)', () => {
test('RED — a "compact" file the same size as its canonical sibling', () => {
const tmpRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'gsd-variant-size-'));
try {
const workflowsRoot = path.join(tmpRoot, 'gsd-core', 'workflows', 'foo', 'steps');
fs.mkdirSync(workflowsRoot, { recursive: true });
fs.writeFileSync(path.join(workflowsRoot, 'bar.md'), 'x'.repeat(100));
fs.writeFileSync(path.join(workflowsRoot, 'bar.compact.md'), 'y'.repeat(100));
const pairs = discoverRegisteredVariants([path.join(tmpRoot, 'gsd-core', 'workflows')]);
const violations = checkSizeSmaller(pairs);
assert.ok(violations.length > 0, 'expected at least one size violation');
assert.ok(
violations.some((v) => v.kind === 'compact_not_smaller' && v.canonicalSize === 100 && v.compactSize === 100),
`expected the equal-size pair to be named: ${JSON.stringify(violations)}`,
);
} finally {
cleanup(tmpRoot);
}
});
test('RED — a "compact" file one byte LARGER than its canonical sibling (boundary point)', () => {
const tmpRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'gsd-variant-size-over-'));
try {
const workflowsRoot = path.join(tmpRoot, 'gsd-core', 'workflows', 'foo', 'steps');
fs.mkdirSync(workflowsRoot, { recursive: true });
fs.writeFileSync(path.join(workflowsRoot, 'bar.md'), 'x'.repeat(100));
fs.writeFileSync(path.join(workflowsRoot, 'bar.compact.md'), 'y'.repeat(101));
const pairs = discoverRegisteredVariants([path.join(tmpRoot, 'gsd-core', 'workflows')]);
const violations = checkSizeSmaller(pairs);
assert.ok(violations.length > 0, 'expected at least one size violation');
} finally {
cleanup(tmpRoot);
}
});
test('GREEN — a compact file exactly one byte smaller (boundary point)', () => {
const tmpRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'gsd-variant-size-ok-'));
try {
const workflowsRoot = path.join(tmpRoot, 'gsd-core', 'workflows', 'foo', 'steps');
fs.mkdirSync(workflowsRoot, { recursive: true });
fs.writeFileSync(path.join(workflowsRoot, 'bar.md'), 'x'.repeat(100));
fs.writeFileSync(path.join(workflowsRoot, 'bar.compact.md'), 'y'.repeat(99));
const pairs = discoverRegisteredVariants([path.join(tmpRoot, 'gsd-core', 'workflows')]);
const violations = checkSizeSmaller(pairs);
assert.deepStrictEqual(violations, []);
} finally {
cleanup(tmpRoot);
}
});
});

View File

@@ -13,8 +13,8 @@
"reductionPct": 36.67 "reductionPct": 36.67
}, },
"docs-update": { "docs-update": {
"offTokens": 14231, "offTokens": 14232,
"onTokens": 11881, "onTokens": 11882,
"reductionPct": 16.51 "reductionPct": 16.51
}, },
"execute-phase": { "execute-phase": {
@@ -39,8 +39,8 @@
} }
}, },
"aggregate": { "aggregate": {
"offTokens": 106922, "offTokens": 106923,
"onTokens": 90274, "onTokens": 90275,
"reductionPct": 15.57 "reductionPct": 15.57
} }
} }

View File

@@ -0,0 +1,31 @@
{
"schema_version": 1,
"generated_by": "scripts/benchmark-compact-content-variants.cjs",
"tokenizer": {
"name": "gpt-tokenizer",
"version": "4.0.0"
},
"label": "PROXY-TOKENIZER DELTA — gpt-tokenizer is a stand-in; Anthropic publishes no tokenizer for Claude 3+. The on/off COMPARISON is exact under this pinned tokenizer; absolute counts are not Claude's real token counts.",
"pairs": {
"gsd-core/templates/summary.md": {
"offTokens": 2938,
"onTokens": 2299,
"reductionPct": 21.75
},
"gsd-core/templates/user-setup.md": {
"offTokens": 2061,
"onTokens": 1363,
"reductionPct": 33.87
},
"gsd-core/workflows/help/modes/full.md": {
"offTokens": 9950,
"onTokens": 6579,
"reductionPct": 33.88
}
},
"aggregate": {
"offTokens": 14949,
"onTokens": 10241,
"reductionPct": 31.49
}
}

View File

@@ -296,21 +296,13 @@
"gsd-core/templates/UAT.md", "gsd-core/templates/UAT.md",
"gsd-core/templates/UI-SPEC.md", "gsd-core/templates/UI-SPEC.md",
"gsd-core/templates/VALIDATION.md", "gsd-core/templates/VALIDATION.md",
"gsd-core/templates/claude-md.md",
"gsd-core/templates/codebase/architecture.md", "gsd-core/templates/codebase/architecture.md",
"gsd-core/templates/codebase/concerns.md",
"gsd-core/templates/codebase/conventions.md",
"gsd-core/templates/codebase/integrations.md",
"gsd-core/templates/codebase/stack.md", "gsd-core/templates/codebase/stack.md",
"gsd-core/templates/codebase/structure.md",
"gsd-core/templates/codebase/testing.md",
"gsd-core/templates/config.json", "gsd-core/templates/config.json",
"gsd-core/templates/context.md", "gsd-core/templates/context.md",
"gsd-core/templates/continue-here.md", "gsd-core/templates/continue-here.md",
"gsd-core/templates/copilot-instructions.md", "gsd-core/templates/copilot-instructions.md",
"gsd-core/templates/debug-subagent-prompt.md",
"gsd-core/templates/dev-preferences.md", "gsd-core/templates/dev-preferences.md",
"gsd-core/templates/discovery.md",
"gsd-core/templates/discussion-log.md", "gsd-core/templates/discussion-log.md",
"gsd-core/templates/milestone-archive.md", "gsd-core/templates/milestone-archive.md",
"gsd-core/templates/milestone.md", "gsd-core/templates/milestone.md",
@@ -331,8 +323,10 @@
"gsd-core/templates/summary-complex.md", "gsd-core/templates/summary-complex.md",
"gsd-core/templates/summary-minimal.md", "gsd-core/templates/summary-minimal.md",
"gsd-core/templates/summary-standard.md", "gsd-core/templates/summary-standard.md",
"gsd-core/templates/summary.compact.md",
"gsd-core/templates/summary.md", "gsd-core/templates/summary.md",
"gsd-core/templates/user-profile.md", "gsd-core/templates/user-profile.md",
"gsd-core/templates/user-setup.compact.md",
"gsd-core/templates/user-setup.md", "gsd-core/templates/user-setup.md",
"gsd-core/templates/verification-report.md", "gsd-core/templates/verification-report.md",
"gsd-core/workflows/_runtime-launcher.snippet.sh", "gsd-core/workflows/_runtime-launcher.snippet.sh",
@@ -412,6 +406,7 @@
"gsd-core/workflows/help.md", "gsd-core/workflows/help.md",
"gsd-core/workflows/help/modes/brief.md", "gsd-core/workflows/help/modes/brief.md",
"gsd-core/workflows/help/modes/default.md", "gsd-core/workflows/help/modes/default.md",
"gsd-core/workflows/help/modes/full.compact.md",
"gsd-core/workflows/help/modes/full.md", "gsd-core/workflows/help/modes/full.md",
"gsd-core/workflows/help/modes/topic.md", "gsd-core/workflows/help/modes/topic.md",
"gsd-core/workflows/import.md", "gsd-core/workflows/import.md",

View File

@@ -368,21 +368,13 @@
"gsd-core/templates/UAT.md", "gsd-core/templates/UAT.md",
"gsd-core/templates/UI-SPEC.md", "gsd-core/templates/UI-SPEC.md",
"gsd-core/templates/VALIDATION.md", "gsd-core/templates/VALIDATION.md",
"gsd-core/templates/claude-md.md",
"gsd-core/templates/codebase/architecture.md", "gsd-core/templates/codebase/architecture.md",
"gsd-core/templates/codebase/concerns.md",
"gsd-core/templates/codebase/conventions.md",
"gsd-core/templates/codebase/integrations.md",
"gsd-core/templates/codebase/stack.md", "gsd-core/templates/codebase/stack.md",
"gsd-core/templates/codebase/structure.md",
"gsd-core/templates/codebase/testing.md",
"gsd-core/templates/config.json", "gsd-core/templates/config.json",
"gsd-core/templates/context.md", "gsd-core/templates/context.md",
"gsd-core/templates/continue-here.md", "gsd-core/templates/continue-here.md",
"gsd-core/templates/copilot-instructions.md", "gsd-core/templates/copilot-instructions.md",
"gsd-core/templates/debug-subagent-prompt.md",
"gsd-core/templates/dev-preferences.md", "gsd-core/templates/dev-preferences.md",
"gsd-core/templates/discovery.md",
"gsd-core/templates/discussion-log.md", "gsd-core/templates/discussion-log.md",
"gsd-core/templates/milestone-archive.md", "gsd-core/templates/milestone-archive.md",
"gsd-core/templates/milestone.md", "gsd-core/templates/milestone.md",
@@ -403,8 +395,10 @@
"gsd-core/templates/summary-complex.md", "gsd-core/templates/summary-complex.md",
"gsd-core/templates/summary-minimal.md", "gsd-core/templates/summary-minimal.md",
"gsd-core/templates/summary-standard.md", "gsd-core/templates/summary-standard.md",
"gsd-core/templates/summary.compact.md",
"gsd-core/templates/summary.md", "gsd-core/templates/summary.md",
"gsd-core/templates/user-profile.md", "gsd-core/templates/user-profile.md",
"gsd-core/templates/user-setup.compact.md",
"gsd-core/templates/user-setup.md", "gsd-core/templates/user-setup.md",
"gsd-core/templates/verification-report.md", "gsd-core/templates/verification-report.md",
"gsd-core/workflows/_runtime-launcher.snippet.sh", "gsd-core/workflows/_runtime-launcher.snippet.sh",
@@ -484,6 +478,7 @@
"gsd-core/workflows/help.md", "gsd-core/workflows/help.md",
"gsd-core/workflows/help/modes/brief.md", "gsd-core/workflows/help/modes/brief.md",
"gsd-core/workflows/help/modes/default.md", "gsd-core/workflows/help/modes/default.md",
"gsd-core/workflows/help/modes/full.compact.md",
"gsd-core/workflows/help/modes/full.md", "gsd-core/workflows/help/modes/full.md",
"gsd-core/workflows/help/modes/topic.md", "gsd-core/workflows/help/modes/topic.md",
"gsd-core/workflows/import.md", "gsd-core/workflows/import.md",

View File

@@ -261,21 +261,13 @@
"gsd-core/templates/UAT.md", "gsd-core/templates/UAT.md",
"gsd-core/templates/UI-SPEC.md", "gsd-core/templates/UI-SPEC.md",
"gsd-core/templates/VALIDATION.md", "gsd-core/templates/VALIDATION.md",
"gsd-core/templates/claude-md.md",
"gsd-core/templates/codebase/architecture.md", "gsd-core/templates/codebase/architecture.md",
"gsd-core/templates/codebase/concerns.md",
"gsd-core/templates/codebase/conventions.md",
"gsd-core/templates/codebase/integrations.md",
"gsd-core/templates/codebase/stack.md", "gsd-core/templates/codebase/stack.md",
"gsd-core/templates/codebase/structure.md",
"gsd-core/templates/codebase/testing.md",
"gsd-core/templates/config.json", "gsd-core/templates/config.json",
"gsd-core/templates/context.md", "gsd-core/templates/context.md",
"gsd-core/templates/continue-here.md", "gsd-core/templates/continue-here.md",
"gsd-core/templates/copilot-instructions.md", "gsd-core/templates/copilot-instructions.md",
"gsd-core/templates/debug-subagent-prompt.md",
"gsd-core/templates/dev-preferences.md", "gsd-core/templates/dev-preferences.md",
"gsd-core/templates/discovery.md",
"gsd-core/templates/discussion-log.md", "gsd-core/templates/discussion-log.md",
"gsd-core/templates/milestone-archive.md", "gsd-core/templates/milestone-archive.md",
"gsd-core/templates/milestone.md", "gsd-core/templates/milestone.md",
@@ -296,8 +288,10 @@
"gsd-core/templates/summary-complex.md", "gsd-core/templates/summary-complex.md",
"gsd-core/templates/summary-minimal.md", "gsd-core/templates/summary-minimal.md",
"gsd-core/templates/summary-standard.md", "gsd-core/templates/summary-standard.md",
"gsd-core/templates/summary.compact.md",
"gsd-core/templates/summary.md", "gsd-core/templates/summary.md",
"gsd-core/templates/user-profile.md", "gsd-core/templates/user-profile.md",
"gsd-core/templates/user-setup.compact.md",
"gsd-core/templates/user-setup.md", "gsd-core/templates/user-setup.md",
"gsd-core/templates/verification-report.md", "gsd-core/templates/verification-report.md",
"gsd-core/workflows/_runtime-launcher.snippet.sh", "gsd-core/workflows/_runtime-launcher.snippet.sh",
@@ -377,6 +371,7 @@
"gsd-core/workflows/help.md", "gsd-core/workflows/help.md",
"gsd-core/workflows/help/modes/brief.md", "gsd-core/workflows/help/modes/brief.md",
"gsd-core/workflows/help/modes/default.md", "gsd-core/workflows/help/modes/default.md",
"gsd-core/workflows/help/modes/full.compact.md",
"gsd-core/workflows/help/modes/full.md", "gsd-core/workflows/help/modes/full.md",
"gsd-core/workflows/help/modes/topic.md", "gsd-core/workflows/help/modes/topic.md",
"gsd-core/workflows/import.md", "gsd-core/workflows/import.md",

View File

@@ -296,21 +296,13 @@
"gsd-core/templates/UAT.md", "gsd-core/templates/UAT.md",
"gsd-core/templates/UI-SPEC.md", "gsd-core/templates/UI-SPEC.md",
"gsd-core/templates/VALIDATION.md", "gsd-core/templates/VALIDATION.md",
"gsd-core/templates/claude-md.md",
"gsd-core/templates/codebase/architecture.md", "gsd-core/templates/codebase/architecture.md",
"gsd-core/templates/codebase/concerns.md",
"gsd-core/templates/codebase/conventions.md",
"gsd-core/templates/codebase/integrations.md",
"gsd-core/templates/codebase/stack.md", "gsd-core/templates/codebase/stack.md",
"gsd-core/templates/codebase/structure.md",
"gsd-core/templates/codebase/testing.md",
"gsd-core/templates/config.json", "gsd-core/templates/config.json",
"gsd-core/templates/context.md", "gsd-core/templates/context.md",
"gsd-core/templates/continue-here.md", "gsd-core/templates/continue-here.md",
"gsd-core/templates/copilot-instructions.md", "gsd-core/templates/copilot-instructions.md",
"gsd-core/templates/debug-subagent-prompt.md",
"gsd-core/templates/dev-preferences.md", "gsd-core/templates/dev-preferences.md",
"gsd-core/templates/discovery.md",
"gsd-core/templates/discussion-log.md", "gsd-core/templates/discussion-log.md",
"gsd-core/templates/milestone-archive.md", "gsd-core/templates/milestone-archive.md",
"gsd-core/templates/milestone.md", "gsd-core/templates/milestone.md",
@@ -331,8 +323,10 @@
"gsd-core/templates/summary-complex.md", "gsd-core/templates/summary-complex.md",
"gsd-core/templates/summary-minimal.md", "gsd-core/templates/summary-minimal.md",
"gsd-core/templates/summary-standard.md", "gsd-core/templates/summary-standard.md",
"gsd-core/templates/summary.compact.md",
"gsd-core/templates/summary.md", "gsd-core/templates/summary.md",
"gsd-core/templates/user-profile.md", "gsd-core/templates/user-profile.md",
"gsd-core/templates/user-setup.compact.md",
"gsd-core/templates/user-setup.md", "gsd-core/templates/user-setup.md",
"gsd-core/templates/verification-report.md", "gsd-core/templates/verification-report.md",
"gsd-core/workflows/_runtime-launcher.snippet.sh", "gsd-core/workflows/_runtime-launcher.snippet.sh",
@@ -412,6 +406,7 @@
"gsd-core/workflows/help.md", "gsd-core/workflows/help.md",
"gsd-core/workflows/help/modes/brief.md", "gsd-core/workflows/help/modes/brief.md",
"gsd-core/workflows/help/modes/default.md", "gsd-core/workflows/help/modes/default.md",
"gsd-core/workflows/help/modes/full.compact.md",
"gsd-core/workflows/help/modes/full.md", "gsd-core/workflows/help/modes/full.md",
"gsd-core/workflows/help/modes/topic.md", "gsd-core/workflows/help/modes/topic.md",
"gsd-core/workflows/import.md", "gsd-core/workflows/import.md",

View File

@@ -298,21 +298,13 @@
"gsd-core/templates/UAT.md", "gsd-core/templates/UAT.md",
"gsd-core/templates/UI-SPEC.md", "gsd-core/templates/UI-SPEC.md",
"gsd-core/templates/VALIDATION.md", "gsd-core/templates/VALIDATION.md",
"gsd-core/templates/claude-md.md",
"gsd-core/templates/codebase/architecture.md", "gsd-core/templates/codebase/architecture.md",
"gsd-core/templates/codebase/concerns.md",
"gsd-core/templates/codebase/conventions.md",
"gsd-core/templates/codebase/integrations.md",
"gsd-core/templates/codebase/stack.md", "gsd-core/templates/codebase/stack.md",
"gsd-core/templates/codebase/structure.md",
"gsd-core/templates/codebase/testing.md",
"gsd-core/templates/config.json", "gsd-core/templates/config.json",
"gsd-core/templates/context.md", "gsd-core/templates/context.md",
"gsd-core/templates/continue-here.md", "gsd-core/templates/continue-here.md",
"gsd-core/templates/copilot-instructions.md", "gsd-core/templates/copilot-instructions.md",
"gsd-core/templates/debug-subagent-prompt.md",
"gsd-core/templates/dev-preferences.md", "gsd-core/templates/dev-preferences.md",
"gsd-core/templates/discovery.md",
"gsd-core/templates/discussion-log.md", "gsd-core/templates/discussion-log.md",
"gsd-core/templates/milestone-archive.md", "gsd-core/templates/milestone-archive.md",
"gsd-core/templates/milestone.md", "gsd-core/templates/milestone.md",
@@ -333,8 +325,10 @@
"gsd-core/templates/summary-complex.md", "gsd-core/templates/summary-complex.md",
"gsd-core/templates/summary-minimal.md", "gsd-core/templates/summary-minimal.md",
"gsd-core/templates/summary-standard.md", "gsd-core/templates/summary-standard.md",
"gsd-core/templates/summary.compact.md",
"gsd-core/templates/summary.md", "gsd-core/templates/summary.md",
"gsd-core/templates/user-profile.md", "gsd-core/templates/user-profile.md",
"gsd-core/templates/user-setup.compact.md",
"gsd-core/templates/user-setup.md", "gsd-core/templates/user-setup.md",
"gsd-core/templates/verification-report.md", "gsd-core/templates/verification-report.md",
"gsd-core/workflows/_runtime-launcher.snippet.sh", "gsd-core/workflows/_runtime-launcher.snippet.sh",
@@ -414,6 +408,7 @@
"gsd-core/workflows/help.md", "gsd-core/workflows/help.md",
"gsd-core/workflows/help/modes/brief.md", "gsd-core/workflows/help/modes/brief.md",
"gsd-core/workflows/help/modes/default.md", "gsd-core/workflows/help/modes/default.md",
"gsd-core/workflows/help/modes/full.compact.md",
"gsd-core/workflows/help/modes/full.md", "gsd-core/workflows/help/modes/full.md",
"gsd-core/workflows/help/modes/topic.md", "gsd-core/workflows/help/modes/topic.md",
"gsd-core/workflows/import.md", "gsd-core/workflows/import.md",

View File

@@ -368,21 +368,13 @@
"gsd-core/templates/UAT.md", "gsd-core/templates/UAT.md",
"gsd-core/templates/UI-SPEC.md", "gsd-core/templates/UI-SPEC.md",
"gsd-core/templates/VALIDATION.md", "gsd-core/templates/VALIDATION.md",
"gsd-core/templates/claude-md.md",
"gsd-core/templates/codebase/architecture.md", "gsd-core/templates/codebase/architecture.md",
"gsd-core/templates/codebase/concerns.md",
"gsd-core/templates/codebase/conventions.md",
"gsd-core/templates/codebase/integrations.md",
"gsd-core/templates/codebase/stack.md", "gsd-core/templates/codebase/stack.md",
"gsd-core/templates/codebase/structure.md",
"gsd-core/templates/codebase/testing.md",
"gsd-core/templates/config.json", "gsd-core/templates/config.json",
"gsd-core/templates/context.md", "gsd-core/templates/context.md",
"gsd-core/templates/continue-here.md", "gsd-core/templates/continue-here.md",
"gsd-core/templates/copilot-instructions.md", "gsd-core/templates/copilot-instructions.md",
"gsd-core/templates/debug-subagent-prompt.md",
"gsd-core/templates/dev-preferences.md", "gsd-core/templates/dev-preferences.md",
"gsd-core/templates/discovery.md",
"gsd-core/templates/discussion-log.md", "gsd-core/templates/discussion-log.md",
"gsd-core/templates/milestone-archive.md", "gsd-core/templates/milestone-archive.md",
"gsd-core/templates/milestone.md", "gsd-core/templates/milestone.md",
@@ -403,8 +395,10 @@
"gsd-core/templates/summary-complex.md", "gsd-core/templates/summary-complex.md",
"gsd-core/templates/summary-minimal.md", "gsd-core/templates/summary-minimal.md",
"gsd-core/templates/summary-standard.md", "gsd-core/templates/summary-standard.md",
"gsd-core/templates/summary.compact.md",
"gsd-core/templates/summary.md", "gsd-core/templates/summary.md",
"gsd-core/templates/user-profile.md", "gsd-core/templates/user-profile.md",
"gsd-core/templates/user-setup.compact.md",
"gsd-core/templates/user-setup.md", "gsd-core/templates/user-setup.md",
"gsd-core/templates/verification-report.md", "gsd-core/templates/verification-report.md",
"gsd-core/workflows/_runtime-launcher.snippet.sh", "gsd-core/workflows/_runtime-launcher.snippet.sh",
@@ -484,6 +478,7 @@
"gsd-core/workflows/help.md", "gsd-core/workflows/help.md",
"gsd-core/workflows/help/modes/brief.md", "gsd-core/workflows/help/modes/brief.md",
"gsd-core/workflows/help/modes/default.md", "gsd-core/workflows/help/modes/default.md",
"gsd-core/workflows/help/modes/full.compact.md",
"gsd-core/workflows/help/modes/full.md", "gsd-core/workflows/help/modes/full.md",
"gsd-core/workflows/help/modes/topic.md", "gsd-core/workflows/help/modes/topic.md",
"gsd-core/workflows/import.md", "gsd-core/workflows/import.md",

View File

@@ -332,21 +332,13 @@
"gsd-core/templates/UAT.md", "gsd-core/templates/UAT.md",
"gsd-core/templates/UI-SPEC.md", "gsd-core/templates/UI-SPEC.md",
"gsd-core/templates/VALIDATION.md", "gsd-core/templates/VALIDATION.md",
"gsd-core/templates/claude-md.md",
"gsd-core/templates/codebase/architecture.md", "gsd-core/templates/codebase/architecture.md",
"gsd-core/templates/codebase/concerns.md",
"gsd-core/templates/codebase/conventions.md",
"gsd-core/templates/codebase/integrations.md",
"gsd-core/templates/codebase/stack.md", "gsd-core/templates/codebase/stack.md",
"gsd-core/templates/codebase/structure.md",
"gsd-core/templates/codebase/testing.md",
"gsd-core/templates/config.json", "gsd-core/templates/config.json",
"gsd-core/templates/context.md", "gsd-core/templates/context.md",
"gsd-core/templates/continue-here.md", "gsd-core/templates/continue-here.md",
"gsd-core/templates/copilot-instructions.md", "gsd-core/templates/copilot-instructions.md",
"gsd-core/templates/debug-subagent-prompt.md",
"gsd-core/templates/dev-preferences.md", "gsd-core/templates/dev-preferences.md",
"gsd-core/templates/discovery.md",
"gsd-core/templates/discussion-log.md", "gsd-core/templates/discussion-log.md",
"gsd-core/templates/milestone-archive.md", "gsd-core/templates/milestone-archive.md",
"gsd-core/templates/milestone.md", "gsd-core/templates/milestone.md",
@@ -367,8 +359,10 @@
"gsd-core/templates/summary-complex.md", "gsd-core/templates/summary-complex.md",
"gsd-core/templates/summary-minimal.md", "gsd-core/templates/summary-minimal.md",
"gsd-core/templates/summary-standard.md", "gsd-core/templates/summary-standard.md",
"gsd-core/templates/summary.compact.md",
"gsd-core/templates/summary.md", "gsd-core/templates/summary.md",
"gsd-core/templates/user-profile.md", "gsd-core/templates/user-profile.md",
"gsd-core/templates/user-setup.compact.md",
"gsd-core/templates/user-setup.md", "gsd-core/templates/user-setup.md",
"gsd-core/templates/verification-report.md", "gsd-core/templates/verification-report.md",
"gsd-core/workflows/_runtime-launcher.snippet.sh", "gsd-core/workflows/_runtime-launcher.snippet.sh",
@@ -448,6 +442,7 @@
"gsd-core/workflows/help.md", "gsd-core/workflows/help.md",
"gsd-core/workflows/help/modes/brief.md", "gsd-core/workflows/help/modes/brief.md",
"gsd-core/workflows/help/modes/default.md", "gsd-core/workflows/help/modes/default.md",
"gsd-core/workflows/help/modes/full.compact.md",
"gsd-core/workflows/help/modes/full.md", "gsd-core/workflows/help/modes/full.md",
"gsd-core/workflows/help/modes/topic.md", "gsd-core/workflows/help/modes/topic.md",
"gsd-core/workflows/import.md", "gsd-core/workflows/import.md",

View File

@@ -297,21 +297,13 @@
"gsd-core/templates/UAT.md", "gsd-core/templates/UAT.md",
"gsd-core/templates/UI-SPEC.md", "gsd-core/templates/UI-SPEC.md",
"gsd-core/templates/VALIDATION.md", "gsd-core/templates/VALIDATION.md",
"gsd-core/templates/claude-md.md",
"gsd-core/templates/codebase/architecture.md", "gsd-core/templates/codebase/architecture.md",
"gsd-core/templates/codebase/concerns.md",
"gsd-core/templates/codebase/conventions.md",
"gsd-core/templates/codebase/integrations.md",
"gsd-core/templates/codebase/stack.md", "gsd-core/templates/codebase/stack.md",
"gsd-core/templates/codebase/structure.md",
"gsd-core/templates/codebase/testing.md",
"gsd-core/templates/config.json", "gsd-core/templates/config.json",
"gsd-core/templates/context.md", "gsd-core/templates/context.md",
"gsd-core/templates/continue-here.md", "gsd-core/templates/continue-here.md",
"gsd-core/templates/copilot-instructions.md", "gsd-core/templates/copilot-instructions.md",
"gsd-core/templates/debug-subagent-prompt.md",
"gsd-core/templates/dev-preferences.md", "gsd-core/templates/dev-preferences.md",
"gsd-core/templates/discovery.md",
"gsd-core/templates/discussion-log.md", "gsd-core/templates/discussion-log.md",
"gsd-core/templates/milestone-archive.md", "gsd-core/templates/milestone-archive.md",
"gsd-core/templates/milestone.md", "gsd-core/templates/milestone.md",
@@ -332,8 +324,10 @@
"gsd-core/templates/summary-complex.md", "gsd-core/templates/summary-complex.md",
"gsd-core/templates/summary-minimal.md", "gsd-core/templates/summary-minimal.md",
"gsd-core/templates/summary-standard.md", "gsd-core/templates/summary-standard.md",
"gsd-core/templates/summary.compact.md",
"gsd-core/templates/summary.md", "gsd-core/templates/summary.md",
"gsd-core/templates/user-profile.md", "gsd-core/templates/user-profile.md",
"gsd-core/templates/user-setup.compact.md",
"gsd-core/templates/user-setup.md", "gsd-core/templates/user-setup.md",
"gsd-core/templates/verification-report.md", "gsd-core/templates/verification-report.md",
"gsd-core/workflows/_runtime-launcher.snippet.sh", "gsd-core/workflows/_runtime-launcher.snippet.sh",
@@ -413,6 +407,7 @@
"gsd-core/workflows/help.md", "gsd-core/workflows/help.md",
"gsd-core/workflows/help/modes/brief.md", "gsd-core/workflows/help/modes/brief.md",
"gsd-core/workflows/help/modes/default.md", "gsd-core/workflows/help/modes/default.md",
"gsd-core/workflows/help/modes/full.compact.md",
"gsd-core/workflows/help/modes/full.md", "gsd-core/workflows/help/modes/full.md",
"gsd-core/workflows/help/modes/topic.md", "gsd-core/workflows/help/modes/topic.md",
"gsd-core/workflows/import.md", "gsd-core/workflows/import.md",

View File

@@ -296,21 +296,13 @@
"gsd-core/templates/UAT.md", "gsd-core/templates/UAT.md",
"gsd-core/templates/UI-SPEC.md", "gsd-core/templates/UI-SPEC.md",
"gsd-core/templates/VALIDATION.md", "gsd-core/templates/VALIDATION.md",
"gsd-core/templates/claude-md.md",
"gsd-core/templates/codebase/architecture.md", "gsd-core/templates/codebase/architecture.md",
"gsd-core/templates/codebase/concerns.md",
"gsd-core/templates/codebase/conventions.md",
"gsd-core/templates/codebase/integrations.md",
"gsd-core/templates/codebase/stack.md", "gsd-core/templates/codebase/stack.md",
"gsd-core/templates/codebase/structure.md",
"gsd-core/templates/codebase/testing.md",
"gsd-core/templates/config.json", "gsd-core/templates/config.json",
"gsd-core/templates/context.md", "gsd-core/templates/context.md",
"gsd-core/templates/continue-here.md", "gsd-core/templates/continue-here.md",
"gsd-core/templates/copilot-instructions.md", "gsd-core/templates/copilot-instructions.md",
"gsd-core/templates/debug-subagent-prompt.md",
"gsd-core/templates/dev-preferences.md", "gsd-core/templates/dev-preferences.md",
"gsd-core/templates/discovery.md",
"gsd-core/templates/discussion-log.md", "gsd-core/templates/discussion-log.md",
"gsd-core/templates/milestone-archive.md", "gsd-core/templates/milestone-archive.md",
"gsd-core/templates/milestone.md", "gsd-core/templates/milestone.md",
@@ -331,8 +323,10 @@
"gsd-core/templates/summary-complex.md", "gsd-core/templates/summary-complex.md",
"gsd-core/templates/summary-minimal.md", "gsd-core/templates/summary-minimal.md",
"gsd-core/templates/summary-standard.md", "gsd-core/templates/summary-standard.md",
"gsd-core/templates/summary.compact.md",
"gsd-core/templates/summary.md", "gsd-core/templates/summary.md",
"gsd-core/templates/user-profile.md", "gsd-core/templates/user-profile.md",
"gsd-core/templates/user-setup.compact.md",
"gsd-core/templates/user-setup.md", "gsd-core/templates/user-setup.md",
"gsd-core/templates/verification-report.md", "gsd-core/templates/verification-report.md",
"gsd-core/workflows/_runtime-launcher.snippet.sh", "gsd-core/workflows/_runtime-launcher.snippet.sh",
@@ -412,6 +406,7 @@
"gsd-core/workflows/help.md", "gsd-core/workflows/help.md",
"gsd-core/workflows/help/modes/brief.md", "gsd-core/workflows/help/modes/brief.md",
"gsd-core/workflows/help/modes/default.md", "gsd-core/workflows/help/modes/default.md",
"gsd-core/workflows/help/modes/full.compact.md",
"gsd-core/workflows/help/modes/full.md", "gsd-core/workflows/help/modes/full.md",
"gsd-core/workflows/help/modes/topic.md", "gsd-core/workflows/help/modes/topic.md",
"gsd-core/workflows/import.md", "gsd-core/workflows/import.md",

View File

@@ -296,21 +296,13 @@
"gsd-core/templates/UAT.md", "gsd-core/templates/UAT.md",
"gsd-core/templates/UI-SPEC.md", "gsd-core/templates/UI-SPEC.md",
"gsd-core/templates/VALIDATION.md", "gsd-core/templates/VALIDATION.md",
"gsd-core/templates/claude-md.md",
"gsd-core/templates/codebase/architecture.md", "gsd-core/templates/codebase/architecture.md",
"gsd-core/templates/codebase/concerns.md",
"gsd-core/templates/codebase/conventions.md",
"gsd-core/templates/codebase/integrations.md",
"gsd-core/templates/codebase/stack.md", "gsd-core/templates/codebase/stack.md",
"gsd-core/templates/codebase/structure.md",
"gsd-core/templates/codebase/testing.md",
"gsd-core/templates/config.json", "gsd-core/templates/config.json",
"gsd-core/templates/context.md", "gsd-core/templates/context.md",
"gsd-core/templates/continue-here.md", "gsd-core/templates/continue-here.md",
"gsd-core/templates/copilot-instructions.md", "gsd-core/templates/copilot-instructions.md",
"gsd-core/templates/debug-subagent-prompt.md",
"gsd-core/templates/dev-preferences.md", "gsd-core/templates/dev-preferences.md",
"gsd-core/templates/discovery.md",
"gsd-core/templates/discussion-log.md", "gsd-core/templates/discussion-log.md",
"gsd-core/templates/milestone-archive.md", "gsd-core/templates/milestone-archive.md",
"gsd-core/templates/milestone.md", "gsd-core/templates/milestone.md",
@@ -331,8 +323,10 @@
"gsd-core/templates/summary-complex.md", "gsd-core/templates/summary-complex.md",
"gsd-core/templates/summary-minimal.md", "gsd-core/templates/summary-minimal.md",
"gsd-core/templates/summary-standard.md", "gsd-core/templates/summary-standard.md",
"gsd-core/templates/summary.compact.md",
"gsd-core/templates/summary.md", "gsd-core/templates/summary.md",
"gsd-core/templates/user-profile.md", "gsd-core/templates/user-profile.md",
"gsd-core/templates/user-setup.compact.md",
"gsd-core/templates/user-setup.md", "gsd-core/templates/user-setup.md",
"gsd-core/templates/verification-report.md", "gsd-core/templates/verification-report.md",
"gsd-core/workflows/_runtime-launcher.snippet.sh", "gsd-core/workflows/_runtime-launcher.snippet.sh",
@@ -412,6 +406,7 @@
"gsd-core/workflows/help.md", "gsd-core/workflows/help.md",
"gsd-core/workflows/help/modes/brief.md", "gsd-core/workflows/help/modes/brief.md",
"gsd-core/workflows/help/modes/default.md", "gsd-core/workflows/help/modes/default.md",
"gsd-core/workflows/help/modes/full.compact.md",
"gsd-core/workflows/help/modes/full.md", "gsd-core/workflows/help/modes/full.md",
"gsd-core/workflows/help/modes/topic.md", "gsd-core/workflows/help/modes/topic.md",
"gsd-core/workflows/import.md", "gsd-core/workflows/import.md",

View File

@@ -368,21 +368,13 @@
"gsd-core/templates/UAT.md", "gsd-core/templates/UAT.md",
"gsd-core/templates/UI-SPEC.md", "gsd-core/templates/UI-SPEC.md",
"gsd-core/templates/VALIDATION.md", "gsd-core/templates/VALIDATION.md",
"gsd-core/templates/claude-md.md",
"gsd-core/templates/codebase/architecture.md", "gsd-core/templates/codebase/architecture.md",
"gsd-core/templates/codebase/concerns.md",
"gsd-core/templates/codebase/conventions.md",
"gsd-core/templates/codebase/integrations.md",
"gsd-core/templates/codebase/stack.md", "gsd-core/templates/codebase/stack.md",
"gsd-core/templates/codebase/structure.md",
"gsd-core/templates/codebase/testing.md",
"gsd-core/templates/config.json", "gsd-core/templates/config.json",
"gsd-core/templates/context.md", "gsd-core/templates/context.md",
"gsd-core/templates/continue-here.md", "gsd-core/templates/continue-here.md",
"gsd-core/templates/copilot-instructions.md", "gsd-core/templates/copilot-instructions.md",
"gsd-core/templates/debug-subagent-prompt.md",
"gsd-core/templates/dev-preferences.md", "gsd-core/templates/dev-preferences.md",
"gsd-core/templates/discovery.md",
"gsd-core/templates/discussion-log.md", "gsd-core/templates/discussion-log.md",
"gsd-core/templates/milestone-archive.md", "gsd-core/templates/milestone-archive.md",
"gsd-core/templates/milestone.md", "gsd-core/templates/milestone.md",
@@ -403,8 +395,10 @@
"gsd-core/templates/summary-complex.md", "gsd-core/templates/summary-complex.md",
"gsd-core/templates/summary-minimal.md", "gsd-core/templates/summary-minimal.md",
"gsd-core/templates/summary-standard.md", "gsd-core/templates/summary-standard.md",
"gsd-core/templates/summary.compact.md",
"gsd-core/templates/summary.md", "gsd-core/templates/summary.md",
"gsd-core/templates/user-profile.md", "gsd-core/templates/user-profile.md",
"gsd-core/templates/user-setup.compact.md",
"gsd-core/templates/user-setup.md", "gsd-core/templates/user-setup.md",
"gsd-core/templates/verification-report.md", "gsd-core/templates/verification-report.md",
"gsd-core/workflows/_runtime-launcher.snippet.sh", "gsd-core/workflows/_runtime-launcher.snippet.sh",
@@ -484,6 +478,7 @@
"gsd-core/workflows/help.md", "gsd-core/workflows/help.md",
"gsd-core/workflows/help/modes/brief.md", "gsd-core/workflows/help/modes/brief.md",
"gsd-core/workflows/help/modes/default.md", "gsd-core/workflows/help/modes/default.md",
"gsd-core/workflows/help/modes/full.compact.md",
"gsd-core/workflows/help/modes/full.md", "gsd-core/workflows/help/modes/full.md",
"gsd-core/workflows/help/modes/topic.md", "gsd-core/workflows/help/modes/topic.md",
"gsd-core/workflows/import.md", "gsd-core/workflows/import.md",

View File

@@ -297,21 +297,13 @@
"gsd-core/templates/UAT.md", "gsd-core/templates/UAT.md",
"gsd-core/templates/UI-SPEC.md", "gsd-core/templates/UI-SPEC.md",
"gsd-core/templates/VALIDATION.md", "gsd-core/templates/VALIDATION.md",
"gsd-core/templates/claude-md.md",
"gsd-core/templates/codebase/architecture.md", "gsd-core/templates/codebase/architecture.md",
"gsd-core/templates/codebase/concerns.md",
"gsd-core/templates/codebase/conventions.md",
"gsd-core/templates/codebase/integrations.md",
"gsd-core/templates/codebase/stack.md", "gsd-core/templates/codebase/stack.md",
"gsd-core/templates/codebase/structure.md",
"gsd-core/templates/codebase/testing.md",
"gsd-core/templates/config.json", "gsd-core/templates/config.json",
"gsd-core/templates/context.md", "gsd-core/templates/context.md",
"gsd-core/templates/continue-here.md", "gsd-core/templates/continue-here.md",
"gsd-core/templates/copilot-instructions.md", "gsd-core/templates/copilot-instructions.md",
"gsd-core/templates/debug-subagent-prompt.md",
"gsd-core/templates/dev-preferences.md", "gsd-core/templates/dev-preferences.md",
"gsd-core/templates/discovery.md",
"gsd-core/templates/discussion-log.md", "gsd-core/templates/discussion-log.md",
"gsd-core/templates/milestone-archive.md", "gsd-core/templates/milestone-archive.md",
"gsd-core/templates/milestone.md", "gsd-core/templates/milestone.md",
@@ -332,8 +324,10 @@
"gsd-core/templates/summary-complex.md", "gsd-core/templates/summary-complex.md",
"gsd-core/templates/summary-minimal.md", "gsd-core/templates/summary-minimal.md",
"gsd-core/templates/summary-standard.md", "gsd-core/templates/summary-standard.md",
"gsd-core/templates/summary.compact.md",
"gsd-core/templates/summary.md", "gsd-core/templates/summary.md",
"gsd-core/templates/user-profile.md", "gsd-core/templates/user-profile.md",
"gsd-core/templates/user-setup.compact.md",
"gsd-core/templates/user-setup.md", "gsd-core/templates/user-setup.md",
"gsd-core/templates/verification-report.md", "gsd-core/templates/verification-report.md",
"gsd-core/workflows/_runtime-launcher.snippet.sh", "gsd-core/workflows/_runtime-launcher.snippet.sh",
@@ -413,6 +407,7 @@
"gsd-core/workflows/help.md", "gsd-core/workflows/help.md",
"gsd-core/workflows/help/modes/brief.md", "gsd-core/workflows/help/modes/brief.md",
"gsd-core/workflows/help/modes/default.md", "gsd-core/workflows/help/modes/default.md",
"gsd-core/workflows/help/modes/full.compact.md",
"gsd-core/workflows/help/modes/full.md", "gsd-core/workflows/help/modes/full.md",
"gsd-core/workflows/help/modes/topic.md", "gsd-core/workflows/help/modes/topic.md",
"gsd-core/workflows/import.md", "gsd-core/workflows/import.md",

View File

@@ -333,21 +333,13 @@
"gsd-core/templates/UAT.md", "gsd-core/templates/UAT.md",
"gsd-core/templates/UI-SPEC.md", "gsd-core/templates/UI-SPEC.md",
"gsd-core/templates/VALIDATION.md", "gsd-core/templates/VALIDATION.md",
"gsd-core/templates/claude-md.md",
"gsd-core/templates/codebase/architecture.md", "gsd-core/templates/codebase/architecture.md",
"gsd-core/templates/codebase/concerns.md",
"gsd-core/templates/codebase/conventions.md",
"gsd-core/templates/codebase/integrations.md",
"gsd-core/templates/codebase/stack.md", "gsd-core/templates/codebase/stack.md",
"gsd-core/templates/codebase/structure.md",
"gsd-core/templates/codebase/testing.md",
"gsd-core/templates/config.json", "gsd-core/templates/config.json",
"gsd-core/templates/context.md", "gsd-core/templates/context.md",
"gsd-core/templates/continue-here.md", "gsd-core/templates/continue-here.md",
"gsd-core/templates/copilot-instructions.md", "gsd-core/templates/copilot-instructions.md",
"gsd-core/templates/debug-subagent-prompt.md",
"gsd-core/templates/dev-preferences.md", "gsd-core/templates/dev-preferences.md",
"gsd-core/templates/discovery.md",
"gsd-core/templates/discussion-log.md", "gsd-core/templates/discussion-log.md",
"gsd-core/templates/milestone-archive.md", "gsd-core/templates/milestone-archive.md",
"gsd-core/templates/milestone.md", "gsd-core/templates/milestone.md",
@@ -368,8 +360,10 @@
"gsd-core/templates/summary-complex.md", "gsd-core/templates/summary-complex.md",
"gsd-core/templates/summary-minimal.md", "gsd-core/templates/summary-minimal.md",
"gsd-core/templates/summary-standard.md", "gsd-core/templates/summary-standard.md",
"gsd-core/templates/summary.compact.md",
"gsd-core/templates/summary.md", "gsd-core/templates/summary.md",
"gsd-core/templates/user-profile.md", "gsd-core/templates/user-profile.md",
"gsd-core/templates/user-setup.compact.md",
"gsd-core/templates/user-setup.md", "gsd-core/templates/user-setup.md",
"gsd-core/templates/verification-report.md", "gsd-core/templates/verification-report.md",
"gsd-core/workflows/_runtime-launcher.snippet.sh", "gsd-core/workflows/_runtime-launcher.snippet.sh",
@@ -449,6 +443,7 @@
"gsd-core/workflows/help.md", "gsd-core/workflows/help.md",
"gsd-core/workflows/help/modes/brief.md", "gsd-core/workflows/help/modes/brief.md",
"gsd-core/workflows/help/modes/default.md", "gsd-core/workflows/help/modes/default.md",
"gsd-core/workflows/help/modes/full.compact.md",
"gsd-core/workflows/help/modes/full.md", "gsd-core/workflows/help/modes/full.md",
"gsd-core/workflows/help/modes/topic.md", "gsd-core/workflows/help/modes/topic.md",
"gsd-core/workflows/import.md", "gsd-core/workflows/import.md",

View File

@@ -368,21 +368,13 @@
"gsd-core/templates/UAT.md", "gsd-core/templates/UAT.md",
"gsd-core/templates/UI-SPEC.md", "gsd-core/templates/UI-SPEC.md",
"gsd-core/templates/VALIDATION.md", "gsd-core/templates/VALIDATION.md",
"gsd-core/templates/claude-md.md",
"gsd-core/templates/codebase/architecture.md", "gsd-core/templates/codebase/architecture.md",
"gsd-core/templates/codebase/concerns.md",
"gsd-core/templates/codebase/conventions.md",
"gsd-core/templates/codebase/integrations.md",
"gsd-core/templates/codebase/stack.md", "gsd-core/templates/codebase/stack.md",
"gsd-core/templates/codebase/structure.md",
"gsd-core/templates/codebase/testing.md",
"gsd-core/templates/config.json", "gsd-core/templates/config.json",
"gsd-core/templates/context.md", "gsd-core/templates/context.md",
"gsd-core/templates/continue-here.md", "gsd-core/templates/continue-here.md",
"gsd-core/templates/copilot-instructions.md", "gsd-core/templates/copilot-instructions.md",
"gsd-core/templates/debug-subagent-prompt.md",
"gsd-core/templates/dev-preferences.md", "gsd-core/templates/dev-preferences.md",
"gsd-core/templates/discovery.md",
"gsd-core/templates/discussion-log.md", "gsd-core/templates/discussion-log.md",
"gsd-core/templates/milestone-archive.md", "gsd-core/templates/milestone-archive.md",
"gsd-core/templates/milestone.md", "gsd-core/templates/milestone.md",
@@ -403,8 +395,10 @@
"gsd-core/templates/summary-complex.md", "gsd-core/templates/summary-complex.md",
"gsd-core/templates/summary-minimal.md", "gsd-core/templates/summary-minimal.md",
"gsd-core/templates/summary-standard.md", "gsd-core/templates/summary-standard.md",
"gsd-core/templates/summary.compact.md",
"gsd-core/templates/summary.md", "gsd-core/templates/summary.md",
"gsd-core/templates/user-profile.md", "gsd-core/templates/user-profile.md",
"gsd-core/templates/user-setup.compact.md",
"gsd-core/templates/user-setup.md", "gsd-core/templates/user-setup.md",
"gsd-core/templates/verification-report.md", "gsd-core/templates/verification-report.md",
"gsd-core/workflows/_runtime-launcher.snippet.sh", "gsd-core/workflows/_runtime-launcher.snippet.sh",
@@ -484,6 +478,7 @@
"gsd-core/workflows/help.md", "gsd-core/workflows/help.md",
"gsd-core/workflows/help/modes/brief.md", "gsd-core/workflows/help/modes/brief.md",
"gsd-core/workflows/help/modes/default.md", "gsd-core/workflows/help/modes/default.md",
"gsd-core/workflows/help/modes/full.compact.md",
"gsd-core/workflows/help/modes/full.md", "gsd-core/workflows/help/modes/full.md",
"gsd-core/workflows/help/modes/topic.md", "gsd-core/workflows/help/modes/topic.md",
"gsd-core/workflows/import.md", "gsd-core/workflows/import.md",

View File

@@ -156,21 +156,13 @@
"gsd-core/templates/UAT.md", "gsd-core/templates/UAT.md",
"gsd-core/templates/UI-SPEC.md", "gsd-core/templates/UI-SPEC.md",
"gsd-core/templates/VALIDATION.md", "gsd-core/templates/VALIDATION.md",
"gsd-core/templates/claude-md.md",
"gsd-core/templates/codebase/architecture.md", "gsd-core/templates/codebase/architecture.md",
"gsd-core/templates/codebase/concerns.md",
"gsd-core/templates/codebase/conventions.md",
"gsd-core/templates/codebase/integrations.md",
"gsd-core/templates/codebase/stack.md", "gsd-core/templates/codebase/stack.md",
"gsd-core/templates/codebase/structure.md",
"gsd-core/templates/codebase/testing.md",
"gsd-core/templates/config.json", "gsd-core/templates/config.json",
"gsd-core/templates/context.md", "gsd-core/templates/context.md",
"gsd-core/templates/continue-here.md", "gsd-core/templates/continue-here.md",
"gsd-core/templates/copilot-instructions.md", "gsd-core/templates/copilot-instructions.md",
"gsd-core/templates/debug-subagent-prompt.md",
"gsd-core/templates/dev-preferences.md", "gsd-core/templates/dev-preferences.md",
"gsd-core/templates/discovery.md",
"gsd-core/templates/discussion-log.md", "gsd-core/templates/discussion-log.md",
"gsd-core/templates/milestone-archive.md", "gsd-core/templates/milestone-archive.md",
"gsd-core/templates/milestone.md", "gsd-core/templates/milestone.md",
@@ -191,8 +183,10 @@
"gsd-core/templates/summary-complex.md", "gsd-core/templates/summary-complex.md",
"gsd-core/templates/summary-minimal.md", "gsd-core/templates/summary-minimal.md",
"gsd-core/templates/summary-standard.md", "gsd-core/templates/summary-standard.md",
"gsd-core/templates/summary.compact.md",
"gsd-core/templates/summary.md", "gsd-core/templates/summary.md",
"gsd-core/templates/user-profile.md", "gsd-core/templates/user-profile.md",
"gsd-core/templates/user-setup.compact.md",
"gsd-core/templates/user-setup.md", "gsd-core/templates/user-setup.md",
"gsd-core/templates/verification-report.md", "gsd-core/templates/verification-report.md",
"gsd-core/workflows/_runtime-launcher.snippet.sh", "gsd-core/workflows/_runtime-launcher.snippet.sh",
@@ -272,6 +266,7 @@
"gsd-core/workflows/help.md", "gsd-core/workflows/help.md",
"gsd-core/workflows/help/modes/brief.md", "gsd-core/workflows/help/modes/brief.md",
"gsd-core/workflows/help/modes/default.md", "gsd-core/workflows/help/modes/default.md",
"gsd-core/workflows/help/modes/full.compact.md",
"gsd-core/workflows/help/modes/full.md", "gsd-core/workflows/help/modes/full.md",
"gsd-core/workflows/help/modes/topic.md", "gsd-core/workflows/help/modes/topic.md",
"gsd-core/workflows/import.md", "gsd-core/workflows/import.md",

View File

@@ -296,21 +296,13 @@
"gsd-core/templates/UAT.md", "gsd-core/templates/UAT.md",
"gsd-core/templates/UI-SPEC.md", "gsd-core/templates/UI-SPEC.md",
"gsd-core/templates/VALIDATION.md", "gsd-core/templates/VALIDATION.md",
"gsd-core/templates/claude-md.md",
"gsd-core/templates/codebase/architecture.md", "gsd-core/templates/codebase/architecture.md",
"gsd-core/templates/codebase/concerns.md",
"gsd-core/templates/codebase/conventions.md",
"gsd-core/templates/codebase/integrations.md",
"gsd-core/templates/codebase/stack.md", "gsd-core/templates/codebase/stack.md",
"gsd-core/templates/codebase/structure.md",
"gsd-core/templates/codebase/testing.md",
"gsd-core/templates/config.json", "gsd-core/templates/config.json",
"gsd-core/templates/context.md", "gsd-core/templates/context.md",
"gsd-core/templates/continue-here.md", "gsd-core/templates/continue-here.md",
"gsd-core/templates/copilot-instructions.md", "gsd-core/templates/copilot-instructions.md",
"gsd-core/templates/debug-subagent-prompt.md",
"gsd-core/templates/dev-preferences.md", "gsd-core/templates/dev-preferences.md",
"gsd-core/templates/discovery.md",
"gsd-core/templates/discussion-log.md", "gsd-core/templates/discussion-log.md",
"gsd-core/templates/milestone-archive.md", "gsd-core/templates/milestone-archive.md",
"gsd-core/templates/milestone.md", "gsd-core/templates/milestone.md",
@@ -331,8 +323,10 @@
"gsd-core/templates/summary-complex.md", "gsd-core/templates/summary-complex.md",
"gsd-core/templates/summary-minimal.md", "gsd-core/templates/summary-minimal.md",
"gsd-core/templates/summary-standard.md", "gsd-core/templates/summary-standard.md",
"gsd-core/templates/summary.compact.md",
"gsd-core/templates/summary.md", "gsd-core/templates/summary.md",
"gsd-core/templates/user-profile.md", "gsd-core/templates/user-profile.md",
"gsd-core/templates/user-setup.compact.md",
"gsd-core/templates/user-setup.md", "gsd-core/templates/user-setup.md",
"gsd-core/templates/verification-report.md", "gsd-core/templates/verification-report.md",
"gsd-core/workflows/_runtime-launcher.snippet.sh", "gsd-core/workflows/_runtime-launcher.snippet.sh",
@@ -412,6 +406,7 @@
"gsd-core/workflows/help.md", "gsd-core/workflows/help.md",
"gsd-core/workflows/help/modes/brief.md", "gsd-core/workflows/help/modes/brief.md",
"gsd-core/workflows/help/modes/default.md", "gsd-core/workflows/help/modes/default.md",
"gsd-core/workflows/help/modes/full.compact.md",
"gsd-core/workflows/help/modes/full.md", "gsd-core/workflows/help/modes/full.md",
"gsd-core/workflows/help/modes/topic.md", "gsd-core/workflows/help/modes/topic.md",
"gsd-core/workflows/import.md", "gsd-core/workflows/import.md",

View File

@@ -296,21 +296,13 @@
"gsd-core/templates/UAT.md", "gsd-core/templates/UAT.md",
"gsd-core/templates/UI-SPEC.md", "gsd-core/templates/UI-SPEC.md",
"gsd-core/templates/VALIDATION.md", "gsd-core/templates/VALIDATION.md",
"gsd-core/templates/claude-md.md",
"gsd-core/templates/codebase/architecture.md", "gsd-core/templates/codebase/architecture.md",
"gsd-core/templates/codebase/concerns.md",
"gsd-core/templates/codebase/conventions.md",
"gsd-core/templates/codebase/integrations.md",
"gsd-core/templates/codebase/stack.md", "gsd-core/templates/codebase/stack.md",
"gsd-core/templates/codebase/structure.md",
"gsd-core/templates/codebase/testing.md",
"gsd-core/templates/config.json", "gsd-core/templates/config.json",
"gsd-core/templates/context.md", "gsd-core/templates/context.md",
"gsd-core/templates/continue-here.md", "gsd-core/templates/continue-here.md",
"gsd-core/templates/copilot-instructions.md", "gsd-core/templates/copilot-instructions.md",
"gsd-core/templates/debug-subagent-prompt.md",
"gsd-core/templates/dev-preferences.md", "gsd-core/templates/dev-preferences.md",
"gsd-core/templates/discovery.md",
"gsd-core/templates/discussion-log.md", "gsd-core/templates/discussion-log.md",
"gsd-core/templates/milestone-archive.md", "gsd-core/templates/milestone-archive.md",
"gsd-core/templates/milestone.md", "gsd-core/templates/milestone.md",
@@ -331,8 +323,10 @@
"gsd-core/templates/summary-complex.md", "gsd-core/templates/summary-complex.md",
"gsd-core/templates/summary-minimal.md", "gsd-core/templates/summary-minimal.md",
"gsd-core/templates/summary-standard.md", "gsd-core/templates/summary-standard.md",
"gsd-core/templates/summary.compact.md",
"gsd-core/templates/summary.md", "gsd-core/templates/summary.md",
"gsd-core/templates/user-profile.md", "gsd-core/templates/user-profile.md",
"gsd-core/templates/user-setup.compact.md",
"gsd-core/templates/user-setup.md", "gsd-core/templates/user-setup.md",
"gsd-core/templates/verification-report.md", "gsd-core/templates/verification-report.md",
"gsd-core/workflows/_runtime-launcher.snippet.sh", "gsd-core/workflows/_runtime-launcher.snippet.sh",
@@ -412,6 +406,7 @@
"gsd-core/workflows/help.md", "gsd-core/workflows/help.md",
"gsd-core/workflows/help/modes/brief.md", "gsd-core/workflows/help/modes/brief.md",
"gsd-core/workflows/help/modes/default.md", "gsd-core/workflows/help/modes/default.md",
"gsd-core/workflows/help/modes/full.compact.md",
"gsd-core/workflows/help/modes/full.md", "gsd-core/workflows/help/modes/full.md",
"gsd-core/workflows/help/modes/topic.md", "gsd-core/workflows/help/modes/topic.md",
"gsd-core/workflows/import.md", "gsd-core/workflows/import.md",

View File

@@ -224,21 +224,13 @@
"gsd-core/templates/UAT.md", "gsd-core/templates/UAT.md",
"gsd-core/templates/UI-SPEC.md", "gsd-core/templates/UI-SPEC.md",
"gsd-core/templates/VALIDATION.md", "gsd-core/templates/VALIDATION.md",
"gsd-core/templates/claude-md.md",
"gsd-core/templates/codebase/architecture.md", "gsd-core/templates/codebase/architecture.md",
"gsd-core/templates/codebase/concerns.md",
"gsd-core/templates/codebase/conventions.md",
"gsd-core/templates/codebase/integrations.md",
"gsd-core/templates/codebase/stack.md", "gsd-core/templates/codebase/stack.md",
"gsd-core/templates/codebase/structure.md",
"gsd-core/templates/codebase/testing.md",
"gsd-core/templates/config.json", "gsd-core/templates/config.json",
"gsd-core/templates/context.md", "gsd-core/templates/context.md",
"gsd-core/templates/continue-here.md", "gsd-core/templates/continue-here.md",
"gsd-core/templates/copilot-instructions.md", "gsd-core/templates/copilot-instructions.md",
"gsd-core/templates/debug-subagent-prompt.md",
"gsd-core/templates/dev-preferences.md", "gsd-core/templates/dev-preferences.md",
"gsd-core/templates/discovery.md",
"gsd-core/templates/discussion-log.md", "gsd-core/templates/discussion-log.md",
"gsd-core/templates/milestone-archive.md", "gsd-core/templates/milestone-archive.md",
"gsd-core/templates/milestone.md", "gsd-core/templates/milestone.md",
@@ -259,8 +251,10 @@
"gsd-core/templates/summary-complex.md", "gsd-core/templates/summary-complex.md",
"gsd-core/templates/summary-minimal.md", "gsd-core/templates/summary-minimal.md",
"gsd-core/templates/summary-standard.md", "gsd-core/templates/summary-standard.md",
"gsd-core/templates/summary.compact.md",
"gsd-core/templates/summary.md", "gsd-core/templates/summary.md",
"gsd-core/templates/user-profile.md", "gsd-core/templates/user-profile.md",
"gsd-core/templates/user-setup.compact.md",
"gsd-core/templates/user-setup.md", "gsd-core/templates/user-setup.md",
"gsd-core/templates/verification-report.md", "gsd-core/templates/verification-report.md",
"gsd-core/workflows/_runtime-launcher.snippet.sh", "gsd-core/workflows/_runtime-launcher.snippet.sh",
@@ -340,6 +334,7 @@
"gsd-core/workflows/help.md", "gsd-core/workflows/help.md",
"gsd-core/workflows/help/modes/brief.md", "gsd-core/workflows/help/modes/brief.md",
"gsd-core/workflows/help/modes/default.md", "gsd-core/workflows/help/modes/default.md",
"gsd-core/workflows/help/modes/full.compact.md",
"gsd-core/workflows/help/modes/full.md", "gsd-core/workflows/help/modes/full.md",
"gsd-core/workflows/help/modes/topic.md", "gsd-core/workflows/help/modes/topic.md",
"gsd-core/workflows/import.md", "gsd-core/workflows/import.md",

View File

@@ -368,21 +368,13 @@
"gsd-core/templates/UAT.md", "gsd-core/templates/UAT.md",
"gsd-core/templates/UI-SPEC.md", "gsd-core/templates/UI-SPEC.md",
"gsd-core/templates/VALIDATION.md", "gsd-core/templates/VALIDATION.md",
"gsd-core/templates/claude-md.md",
"gsd-core/templates/codebase/architecture.md", "gsd-core/templates/codebase/architecture.md",
"gsd-core/templates/codebase/concerns.md",
"gsd-core/templates/codebase/conventions.md",
"gsd-core/templates/codebase/integrations.md",
"gsd-core/templates/codebase/stack.md", "gsd-core/templates/codebase/stack.md",
"gsd-core/templates/codebase/structure.md",
"gsd-core/templates/codebase/testing.md",
"gsd-core/templates/config.json", "gsd-core/templates/config.json",
"gsd-core/templates/context.md", "gsd-core/templates/context.md",
"gsd-core/templates/continue-here.md", "gsd-core/templates/continue-here.md",
"gsd-core/templates/copilot-instructions.md", "gsd-core/templates/copilot-instructions.md",
"gsd-core/templates/debug-subagent-prompt.md",
"gsd-core/templates/dev-preferences.md", "gsd-core/templates/dev-preferences.md",
"gsd-core/templates/discovery.md",
"gsd-core/templates/discussion-log.md", "gsd-core/templates/discussion-log.md",
"gsd-core/templates/milestone-archive.md", "gsd-core/templates/milestone-archive.md",
"gsd-core/templates/milestone.md", "gsd-core/templates/milestone.md",
@@ -403,8 +395,10 @@
"gsd-core/templates/summary-complex.md", "gsd-core/templates/summary-complex.md",
"gsd-core/templates/summary-minimal.md", "gsd-core/templates/summary-minimal.md",
"gsd-core/templates/summary-standard.md", "gsd-core/templates/summary-standard.md",
"gsd-core/templates/summary.compact.md",
"gsd-core/templates/summary.md", "gsd-core/templates/summary.md",
"gsd-core/templates/user-profile.md", "gsd-core/templates/user-profile.md",
"gsd-core/templates/user-setup.compact.md",
"gsd-core/templates/user-setup.md", "gsd-core/templates/user-setup.md",
"gsd-core/templates/verification-report.md", "gsd-core/templates/verification-report.md",
"gsd-core/workflows/_runtime-launcher.snippet.sh", "gsd-core/workflows/_runtime-launcher.snippet.sh",
@@ -484,6 +478,7 @@
"gsd-core/workflows/help.md", "gsd-core/workflows/help.md",
"gsd-core/workflows/help/modes/brief.md", "gsd-core/workflows/help/modes/brief.md",
"gsd-core/workflows/help/modes/default.md", "gsd-core/workflows/help/modes/default.md",
"gsd-core/workflows/help/modes/full.compact.md",
"gsd-core/workflows/help/modes/full.md", "gsd-core/workflows/help/modes/full.md",
"gsd-core/workflows/help/modes/topic.md", "gsd-core/workflows/help/modes/topic.md",
"gsd-core/workflows/import.md", "gsd-core/workflows/import.md",

View File

@@ -0,0 +1,293 @@
'use strict';
/**
* Shared library for the compact-content VARIANT guard (ADR-4139, epic #4139,
* Phase 6 #4406). See `gsd-core/references/compact-content-gate.md` §"Streams
* 1b and 4 — variant resolution" for the operational rule this module checks;
* this file is the mechanics, not the source of truth for behavior.
*
* This is a DIFFERENT shape from `compact-content-split.cjs` (Phase 3, stream
* 1's spine+detail partition). A partition is one document split into two
* halves that must never overlap (disjointness) and whose union must equal
* the original (completeness). A variant pair is two INDEPENDENT, complete
* documents that are EXPECTED to overlap heavily — the compact file is a
* hand-terser rewrite of the same content, not an extracted remainder. So
* this module has no disjointness check and no completeness-at-split-time
* check; it has the five checks `40-design.md` (Phase 6) describes instead:
*
* 1. Registration — `discoverRegisteredVariants` (a `.compact.md`
* file with no canonical sibling is not a registered pair; the guard
* test reports it as an orphan).
* 2. Reachability — `checkReachability` (a registered pair whose
* compact path is never named by any spine's "Read ... variant
* resolution" call site is unwired dead weight).
* 3. Protected content preserved — `checkProtectedContentPreserved` (a
* `<!-- gsd:protected -->` block's lines must appear verbatim in BOTH
* files, since nothing is "moved" in a variant pair — it is duplicated).
* 4. Size smaller — `checkSizeSmaller`.
* 5. Template consumer parity — NOT implemented here; it needs a real
* artifact-generation + real-parser round trip per template, which is
* the domain of `tests/compact-content-template-variant-parity.test.cjs`
* directly, not a generic file-shape check.
*
* This module only reads (filesystem + a search of markdown source for
* literal path substrings). No writes, no network, no git.
*/
const fs = require('node:fs');
const path = require('node:path');
const { extractProtectedBlocks, normalizeNonTrivialLines } = require('./compact-content-split.cjs');
/** Default scan roots: everywhere a `.compact.md` sibling can legally live. */
const DEFAULT_VARIANT_ROOTS = [
path.join(__dirname, '..', '..', 'gsd-core', 'workflows'),
path.join(__dirname, '..', '..', 'gsd-core', 'templates'),
];
/** Every markdown-source root a spine/fragment might name a variant path from. */
const DEFAULT_SEARCH_ROOTS = [
path.join(__dirname, '..', '..', 'gsd-core', 'workflows'),
];
const COMPACT_SUFFIX = '.compact.md';
/**
* Recursively list every file under `dir` whose name ends with `suffix`.
* Shared by both file-discovery needs this module has — `.compact.md` files
* (`findCompactFiles`) and general `.md` files to search for reachability
* (`findMarkdownFiles`) — which otherwise duplicated the same walk with only
* the extension predicate differing.
* @param {string} dir
* @param {string} suffix
* @returns {string[]} absolute paths
*/
function findFilesWithSuffix(dir, suffix) {
const results = [];
let entries;
try {
entries = fs.readdirSync(dir, { withFileTypes: true });
} catch {
return results;
}
for (const entry of entries) {
const full = path.join(dir, entry.name);
if (entry.isDirectory()) {
results.push(...findFilesWithSuffix(full, suffix));
} else if (entry.isFile() && entry.name.endsWith(suffix)) {
results.push(full);
}
}
return results;
}
/**
* Recursively list every `*.compact.md` file under `dir`.
* @param {string} dir
* @returns {string[]} absolute paths
*/
function findCompactFiles(dir) {
return findFilesWithSuffix(dir, COMPACT_SUFFIX);
}
/**
* Discover every registered compact/canonical variant pair under `roots`.
*
* A pair is registered by a `<dir>/<stem>.compact.md` file existing on disk —
* there is no separate registry. Its canonical sibling is `<dir>/<stem>.md`
* in the SAME directory. A `.compact.md` file with no canonical sibling is
* still returned (with `canonicalExists: false`) so the registration check
* can report it as an orphan by name, rather than silently skipping it.
*
* @param {string[]} roots
* @returns {{compactPath: string, canonicalPath: string, canonicalExists: boolean}[]}
*/
function discoverRegisteredVariants(roots = DEFAULT_VARIANT_ROOTS) {
const pairs = [];
for (const root of roots) {
for (const compactPath of findCompactFiles(root)) {
const dir = path.dirname(compactPath);
const stem = path.basename(compactPath, COMPACT_SUFFIX);
const canonicalPath = path.join(dir, `${stem}.md`);
pairs.push({
compactPath,
canonicalPath,
canonicalExists: fs.existsSync(canonicalPath),
});
}
}
return pairs.sort((a, b) => a.compactPath.localeCompare(b.compactPath));
}
/**
* Check 1 — registration. A `.compact.md` file must have a canonical sibling.
* @param {ReturnType<typeof discoverRegisteredVariants>} pairs
*/
function checkRegistration(pairs) {
const violations = [];
for (const pair of pairs) {
if (!pair.canonicalExists) {
violations.push({ kind: 'orphan_compact_file', compactPath: pair.compactPath });
}
}
return violations;
}
/**
* Check 2 — reachability. A registered pair's compact path must be named by
* at least one markdown file under `searchRoots` (a spine's "Read ... variant
* resolution" call site). Three needle forms, matched differently, because
* this corpus has two live conventions for naming these paths (found by
* walking up from the compact file itself to its nearest `gsd-core` ancestor,
* so this works the same way against the real repo and against a fixture
* that builds its own `<tmp>/gsd-core/...` tree):
*
* - The `gsd-core/<rest>` form (e.g. `gsd-core/workflows/autonomous/steps/
* converge-fail-fast.md`'s own convention) is unambiguous on its own — a
* different, longer path coincidentally ending in this exact multi-segment
* suffix is not a realistic false positive, so a plain substring match is
* sufficient without the "unprefixed" guard below.
* - The `<rest>` form without the leading `gsd-core/` (e.g. `workflows/help/
* modes/full.compact.md`, `help.md`'s own dispatch-table convention) is
* equally unambiguous for the same reason.
* - The bare `<stem>.compact.md` form has no such guarantee — a same-named
* file under an unrelated nested directory (the exact class of bug already
* hit once this phase: `discuss-phase/templates/context.md` vs. the root
* `templates/context.md`) could grant it a false reachability. This form
* keeps the `isUnprefixedMatch` guard from `namesFragmentAsEntryPoint`
* (`scripts/lint-response-language-coverage.cjs`): a path character
* immediately before the match means this is the tail of some longer,
* different path, not the fragment itself.
*
* @param {ReturnType<typeof discoverRegisteredVariants>} pairs
* @param {string[]} searchRoots
*/
function checkReachability(pairs, searchRoots = DEFAULT_SEARCH_ROOTS) {
const violations = [];
const haystacks = [];
for (const root of searchRoots) {
for (const file of findMarkdownFiles(root)) {
haystacks.push(fs.readFileSync(file, 'utf8'));
}
}
for (const pair of pairs) {
if (!pair.canonicalExists) continue; // already reported by checkRegistration
const gsdCoreRelative = relativeToNearestGsdCore(pair.compactPath);
const stem = path.basename(pair.compactPath, COMPACT_SUFFIX);
const bareNeedle = `${stem}${COMPACT_SUFFIX}`;
const reached = haystacks.some((text) => {
if (gsdCoreRelative && (text.includes(`gsd-core/${gsdCoreRelative}`) || text.includes(gsdCoreRelative))) {
return true;
}
return isUnprefixedMatch(text, bareNeedle);
});
if (!reached) {
violations.push({ kind: 'unreachable_compact_file', compactPath: pair.compactPath });
}
}
return violations;
}
/**
* Walk up from `filePath` to the nearest ancestor directory literally named
* `gsd-core`, and return the path from there to `filePath` (POSIX-separated).
* Returns `null` if no such ancestor exists. Anchoring on the literal
* `gsd-core` segment — rather than a hardcoded repo-root constant — is what
* lets this match both the real repo and a fixture built under its own
* `<tmp>/gsd-core/...` tree the same way.
* @param {string} filePath
* @returns {string | null}
*/
function relativeToNearestGsdCore(filePath) {
const segments = filePath.split(path.sep);
const idx = segments.lastIndexOf('gsd-core');
if (idx === -1) return null;
return segments.slice(idx + 1).join('/');
}
/** Is `needle` present in `text` with no path character immediately before it (any line)? */
function isUnprefixedMatch(text, needle) {
return text.split(/\r?\n/).some((line) => {
const at = line.indexOf(needle);
if (at === -1) return false;
const before = at > 0 ? line[at - 1] : '';
return !/[A-Za-z0-9_\-./]/.test(before);
});
}
function findMarkdownFiles(dir) {
return findFilesWithSuffix(dir, '.md');
}
/**
* Check 3 — protected content preserved. Every protected block's non-trivial
* lines in the canonical file must also appear (verbatim, after the same
* normalization the partition guard uses) somewhere in the compact sibling.
* Unlike the partition guard, this is NOT a sentinel-presence check on the
* compact file itself — the compact file need not carry `<!-- gsd:protected -->`
* markers of its own, since it is not itself audited for content it might
* shed later; it only must not have DROPPED the protected wording.
*
* @param {ReturnType<typeof discoverRegisteredVariants>} pairs
*/
function checkProtectedContentPreserved(pairs) {
const violations = [];
for (const pair of pairs) {
if (!pair.canonicalExists) continue;
const canonical = fs.readFileSync(pair.canonicalPath, 'utf8');
const compact = fs.readFileSync(pair.compactPath, 'utf8');
const { blocks } = extractProtectedBlocks(canonical);
if (blocks.length === 0) continue;
const compactLines = new Set(normalizeNonTrivialLines(compact));
for (const block of blocks) {
const missing = block.lines
.map((l) => l.trim())
.filter((l) => l.length > 0)
.filter((l) => !compactLines.has(l));
if (missing.length > 0) {
violations.push({
kind: 'protected_content_dropped',
canonicalPath: pair.canonicalPath,
compactPath: pair.compactPath,
missing,
});
}
}
}
return violations;
}
/**
* Check 4 — size smaller. The compact file must be strictly smaller than its
* canonical sibling; a same-size-or-larger "compact" file is not one.
* @param {ReturnType<typeof discoverRegisteredVariants>} pairs
*/
function checkSizeSmaller(pairs) {
const violations = [];
for (const pair of pairs) {
if (!pair.canonicalExists) continue;
const canonicalSize = fs.statSync(pair.canonicalPath).size;
const compactSize = fs.statSync(pair.compactPath).size;
if (!(compactSize < canonicalSize)) {
violations.push({
kind: 'compact_not_smaller',
canonicalPath: pair.canonicalPath,
compactPath: pair.compactPath,
canonicalSize,
compactSize,
});
}
}
return violations;
}
module.exports = {
DEFAULT_VARIANT_ROOTS,
DEFAULT_SEARCH_ROOTS,
COMPACT_SUFFIX,
discoverRegisteredVariants,
checkRegistration,
checkReachability,
checkProtectedContentPreserved,
checkSizeSmaller,
};