Files
msd-core/docs/adr/1787-gsd-next-smart-entry.md
Jeremy McSpadden e5ef323b15 feat(#1787): add /gsd:next smart entry workflow (#1798)
* docs: design spec for /gsd smart-entry command

Hybrid approach porting gsd-pi's smart-entry wizard to gsd-core:
deterministic classifier (gsd-tools smart-entry --json) + markdown
command/workflow with AskUserQuestion + --text fallback. Routing-first
('what now?' menu), 10 situations redesigned for gsd-core's phase loop.

* feat: add /gsd-start smart-entry command

State-aware front door adapted from gsd-pi's smart-entry wizard,
redesigned for gsd-core's markdown-first, multi-runtime architecture.

- src/smart-entry.cts: deterministic situation classifier (no-project,
  paused, blocked, verify-failed, needs-first-phase, planning, executing,
  verify-pending, idle-stranded, complete, unknown). Reads STATE.md,
  ROADMAP.md, git, and verify signals; emits JSON the workflow consumes.
- gsd-tools.cjs: wire  case + help listing.
- commands/gsd/start.md + gsd-core/workflows/gsd.md: thin markdown
  dispatcher presenting an AskUserQuestion menu (with --text fallback for
  non-Claude runtimes) and dispatching to existing commands. Falls back
  to /gsd:progress if detection is unavailable.
- help.md: document /gsd:start (parity with bug-2954).
- tests: smart-entry.unit.test.cjs (classifier behavior across all
  situations + priority + JSON shape) and gsd-workflow.structure.test.cjs
  (markdown-layer invariants + every emitted command resolves to a real
  slash command).

Spec: docs/superpowers/specs/2026-06-27-gsd-smart-entry-design.md
Note: command-contract (ADR-0002) requires a gsd:* prefix, so the bare
/gsd from the spec surfaces as /gsd-start.

* refactor: rename smart-entry command to /gsd:next

Rename the command from /gsd:start to /gsd:next per feedback. The
command file is now commands/gsd/next.md (name: gsd:next) and the
backing workflow is gsd-core/workflows/smart-entry.md (named for the
smart-entry classifier and gsd-tools smart-entry subcommand; does not
collide with the existing workflows/next.md, which is the progress
--next sub-workflow). help.md and the spec updated to match.

All affected tests (188) pass; lint:ci clean.

* fix: smart-entry reads real STATE.md schema (nested progress YAML + body Phase field)

Codex review found the classifier misread this repo's own STATE.md: it
looked only for scalar current_phase/total_phases frontmatter and body
fields named 'Current Phase'/'Total Phases', but real STATE.md stores
the phase as body 'Phase: N' and total_phases/percent under a nested
'progress:' YAML object. Both came back null, so active projects
(e.g. this repo at Phase 3 / verifying) wrongly classified as
needs-first-phase.

- detectSignals now reads total_phases + percent from nested progress{}
  first, then scalar fm, then body; current_phase falls back to the
  body 'Phase:' field (parseProsePhaseField lineage).
- Add regression tests against the real schema (nested progress YAML +
  body Phase field) covering verify-pending + executing situations.

Verified against this repo: now classifies verify-pending (was
needs-first-phase). Coverage 93.25% lines / 86.99% branches.

* fix(workflow): tiered fallback when gsd-tools is broken (not just smart-entry)

Live test exposed a self-defeating fallback: when smart-entry --json
failed because gsd-tools itself was broken (missing
markdown-sectionizer.cjs), the workflow fell back to /gsd:progress —
which also depends on gsd-tools and would dead-end too.

Replace the single /gsd:progress fallback with a tiered recovery:
1. Probe gsd_run state-snapshot. If it ALSO errors, the whole tool
   layer is down — read .planning/STATE.md directly with the Read tool
   and synthesize a minimal situation + actions menu so /gsd:next stays
   useful. Surface a rebuild hint.
2. Only if smart-entry alone is missing (older gsd-core), fall back to
   /gsd:progress as before.

Matches the direct-read resilience the live agent already did by hand.

* docs: add gsd-next skill surface

* chore: trigger no-mistakes validation

* no-mistakes(review): Fix smart-entry phase ordering

* no-mistakes(review): Fix decimal smart-entry phase ordering

* no-mistakes(test): Fix smart-entry next test contracts

* no-mistakes(document): Docs synced for smart entry

* chore: add changeset fragment for #1798 (/gsd:next smart-entry workflow)

Co-authored-by: Codesmith <codesmith-bot@users.noreply.github.com>

* fix: shorten next.md description and update golden install parity fixtures

Co-authored-by: Codesmith <codesmith-bot@users.noreply.github.com>

* fix: update /gsd-next refs to /gsd:next in docs and add Smart Entry topic alias

Co-authored-by: Codesmith <codesmith-bot@users.noreply.github.com>

* chore: trigger no-mistakes validation

* fix: regenerate INVENTORY-MANIFEST.json for new /gsd-next files

Full CI caught that adding commands/gsd/next.md + gsd-core/workflows/smart-entry.md
left docs/INVENTORY-MANIFEST.json stale (not in the affected-test scope that
no-mistakes' test gate runs, so it surfaced in CI). Regenerated via
node scripts/gen-inventory-manifest.cjs --write; inventory-manifest-sync
test now passes.

* fix: add 'next' to core_loop cluster, update INVENTORY-MANIFEST, fix gates.md ref

Co-authored-by: Codesmith <codesmith-bot@users.noreply.github.com>

* fix: regenerate golden install parity fixtures for /gsd:next

Full CI (shard 3/3) caught that adding commands/gsd/next.md + the
smart-entry workflow/lib made the per-runtime golden install parity
fixtures stale across all 16 runtimes. Regenerated via
UPDATE_GOLDEN=1 node --test tests/golden-install-parity.test.cjs.
All 16 fixtures + inventory-manifest-sync now pass.

* Fix smart-entry verify-failed phase scoping and empty resolve shim step

Scope detectVerifyFailed to STATE.md's current phase so leftover higher
phase directories cannot force verify-failed routing. Move the gsd_run
shim resolver into the workflow resolve step so agents define gsd_run
before the detect step runs smart-entry.

* fix: recapture golden fixtures with updated gates.md hash (/gsd:next)

Co-authored-by: Codesmith <codesmith-bot@users.noreply.github.com>

* fix: recapture all 16 golden fixtures with updated smart-entry.md hash

Co-authored-by: Codesmith <codesmith-bot@users.noreply.github.com>

* chore: regenerate fixtures + inventory manifest after rebase onto next

Rebased onto next which adopted #1837 (package-version normalization to
<VERSION> in golden-install-parity hashes). Recaptured the golden fixture
that needed it (hermes), re-sorted INVENTORY-MANIFEST.json, and regenerated
the gsd-next / ns-workflow skill descriptions to match the command surface.

Co-authored-by: Codesmith <codesmith-bot@users.noreply.github.com>

* refactor(#1787): delegate /gsd:next in-project advancement to gated /gsd:progress --next

Reconciles the /gsd:next smart-entry front door with the existing
/gsd:progress --next engine (davesienkowski review on PR #1798). The
classifier previously recommended /gsd:execute-phase directly for the
`executing` situation, bypassing workflows/next.md Route 0
(resume-incomplete-phase invariant, #160) and Gates 1-3 — reproducing the
duplication that got the old flat /gsd-next removed (#3054), plus a
correctness hazard (executing the recorded current phase while an earlier
phase is silently incomplete).

Now planning/executing/verify-pending recommend `/gsd:progress --next`
(single gated engine); the specific command stays an explicit secondary.
Off-path states (no-project, paused, blocked, verify-failed,
idle-stranded, complete) keep direct recommendations — smart-entry's
distinct value over --next. Adds docs/adr/1787-gsd-next-smart-entry.md and
a regression test locking the delegation contract.

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

* docs(#1787): avoid literal /gsd-next token in ADR (bug-3054 guard)

The repo-invariants #3054 guard bans the removed /gsd-next slash form in
docs surfaces. Refer to the removed command as `gsd-next` (prose) — the
historical reference is unchanged, just the banned token is dropped.

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

* chore: gitignore compiled host-integration-sdk + handshake-serialized .cjs

Pre-existing gap from #1683: these two src/*.cts modules compile to
gsd-core/bin/lib/*.cjs but were omitted from the per-file ignore list, so
`npm run build`/`npm test` left them as untracked build artifacts (dirty
tree + accidental-commit footgun). Adds them alongside their siblings
(host-integration.cjs, mcp-server.cjs, …). Found while finishing #1798.

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

* test(#1787): lock per-situation action invariants for all 11 situations + ADR typo

Adversarial-review follow-ups:
- Add a test asserting every situation's action set has exactly one
  recommended action, 1-4 unique-id /gsd:* actions (previously the
  one-recommended/1-4 invariant was only sampled for 6 of 11 situations).
- Fix ADR typo: /gsd-progress → /gsd:progress.

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

* fix(#1798): split oversized test chunks so a slow shard can't trip the per-chunk timeout

Root-cause of the intermittent `full test (windows-latest, 22, shard 1/3)`
failure. It was NOT a leaked handle (the runner's kill message guesses that,
but --test-force-exit already exits leaks cleanly). Diagnosis:

- Ran every shard-1/3 file WITHOUT --test-force-exit + a 45s kill-timer:
  zero hangs, zero leaks — every file self-exits. So no leaked handle / hang.
- CI activity profile: output kept flowing (slowly) right up to the 600.0s
  kill — a dead hang would go silent. => pure slowness.
- Per-file timing: install-minimal-hooks.test.cjs is a 4987-line / 250-case
  consolidation file doing dozens of real installs — 41s even on a fast Mac
  (much worse on the slow Windows I/O path), plus an install-heavy cluster.

Mechanism: MAX_FILES_PER_CHUNK=180 packed the whole ~171-file shard into ONE
`node --test` chunk, so the entire shard's wall-clock ran against a single
600s per-chunk backstop. On slow Windows runners that single chunk crossed
600s and was killed mid-run — an intermittent false-negative gate that also
hits `next` directly.

Fix: lower MAX_FILES_PER_CHUNK 180 -> 90 so each shard splits into ~2 chunks,
each with its own fresh 600s budget and a fresh node process (also relieves
per-process memory pressure). Verified locally: shard 1/3 now runs as
chunk 1/2 (90 files) + chunk 2/2 (81 files), 5323 tests, 0 fail. Also made the
timeout kill-message name slowness as a cause instead of asserting a leak, so
the next debugger isn't sent hunting a nonexistent handle leak.

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

---------

Co-authored-by: Codesmith <codesmith-bot@users.noreply.github.com>
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Tom Boucher <trekkie@nomorestars.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-03 12:18:25 -04:00

124 lines
6.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# ADR 1787: `/gsd:next` smart-entry front door delegates advancement to `/gsd:progress --next`
- **Status:** Accepted
- **Date:** 2026-07-03
- **Issue:** #1787
- **Implementation:** PR #1798 (`feat(#1787): add /gsd:next smart entry workflow`)
- **Supersedes context:** the removal of the flat `gsd-next` command (#3054)
## Context
gsd-core has no state-aware front door. A user must already know whether to
reach for `/gsd:progress`, `/gsd:plan-phase`, `/gsd:execute-phase`, `/gsd:quick`,
or `/gsd:new-project`. gsd-pi ships a `/gsd` smart-entry wizard (a state-aware
menu with one recommended action) that users run first; gsd-core wants the same
"run one command, get told what to do next" feel without gsd-pi's TUI, since
gsd-core is a markdown prompt framework installed into AI agents, not a Node app.
Two facts constrain the design:
1. **A `gsd-next` command already existed and was deliberately removed (#3054),**
with `/gsd:progress --next` established as the canonical "advance to the next
logical step" engine. `tests/bug-3054-stale-gsd-next-references.test.cjs`
guards against user-facing surfaces re-referencing the removed flat command.
Re-introducing a `next` entry point re-opens a settled question: it must not
recreate the duplication that justified the removal.
2. **`/gsd:progress` is the "unified GSD situational command."** Its `--next`
mode (`gsd-core/workflows/next.md`) is a *gated* advancement engine:
- **Route 0** — the resume-incomplete-phase invariant (#160): if a session
died mid-execution and `STATE.md`'s `current_phase` advanced past a phase
that still has `PLAN.md` files without matching `SUMMARY.md`, `--next`
resumes the *incomplete earlier* phase rather than the recorded current one.
- **Gates 1–3** — unresolved checkpoint, error/failed state, and unchecked
verification failures each hard-stop advancement.
The initial implementation of the new `smart-entry` classifier
(`src/smart-entry.cts`) re-derived in-project forward routing itself. For the
`executing` situation it recommended dispatching `/gsd:execute-phase` **directly**,
bypassing Route 0 and Gates 1–3. That reproduced exactly the duplication that got
`gsd-next` removed — two front doors that can route the *same* in-project state
to *different* phases — and introduced a correctness hazard (executing the
recorded current phase while an earlier phase is silently incomplete). A
maintainer (davesienkowski) flagged the overlap on PR #1798.
## Decision
Ship `/gsd:next` as a **menu front door only**, with a hard boundary against
re-implementing advancement:
1. **Detection + classification** live in Node as `gsd-tools smart-entry [--json]`
(`src/smart-entry.cts`): a pure, unit-tested classifier over `.planning/STATE.md`,
`ROADMAP.md`, and read-only git signals, producing one of 11 situations with a
recommended action and an action menu. **Presentation + dispatch** live in the
markdown layer (`commands/gsd/next.md` → `gsd-core/workflows/smart-entry.md`),
using `AskUserQuestion` with a `--text` numbered-list fallback for non-Claude
runtimes. The command carries no `requires` field so it works pre-project.
2. **In-project forward motion delegates to the single gated engine.** For the
`planning`, `executing`, and `verify-pending` situations, the *recommended*
action is `/gsd:progress --next`. smart-entry never re-derives forward routing;
it hands linear advancement to `workflows/next.md` so Route 0 and Gates 1–3 are
always honored. The specific command (`/gsd:plan-phase`, `/gsd:execute-phase`,
`/gsd:verify-work`) remains available as an explicit secondary menu option for a
user who deliberately wants to bypass advancement gating.
3. **smart-entry's distinct value is the states `--next` cannot reach.** For
situations *off* the linear advance path it keeps direct recommendations, since
these are precisely what `/gsd:progress --next` does not (or cannot, given its
`requires: [phase]`) handle: `no-project` → `/gsd:new-project`, `paused` →
`/gsd:resume-work`, `blocked` → `/gsd:debug`, `verify-failed` →
`/gsd:verify-work`, `needs-first-phase` → `/gsd:discuss-phase`, `idle-stranded`
→ `/gsd:ship`, `complete` → `/gsd:new-milestone`, `unknown` → `/gsd:progress`.
This makes the spec's stated decision #4 ("complementary, not redundant") true in
the implementation, not just the prose: there is exactly one advancement engine,
and `/gsd:next` is a menu over it plus the off-path states.
## Consequences
### Positive
- **One advancement engine.** `/gsd:next` and `/gsd:progress --next` can never
disagree about the next in-project step, and Route 0 / Gates 1–3 cannot be
bypassed through the new front door. The #3054 duplication does not return.
- **Genuine new value, no overlap.** The front door adds pre-project, remediation,
and lifecycle-exit routing that `--next` structurally cannot serve.
- **Testable boundary.** `tests/smart-entry.unit.test.cjs` asserts that every
forward-motion situation recommends `/gsd:progress --next` and every off-path
situation keeps its direct recommendation — the delegation is a regression-locked
contract, not a convention.
### Negative / trade-offs
- One extra indirection hop for the common "just continue" case (`/gsd:next` →
`/gsd:progress --next` → dispatched command) versus dispatching the phase command
directly. Accepted: the hop is what buys gate-safety and single-engine behavior.
- The classifier reads STATE.md via shared primitives (`frontmatter.cjs`,
`state-document.cjs`, `phase-id.cjs`) rather than through `workflows/next.md`'s
own detection, so detection logic exists in two places. Accepted: they share
parsing primitives and only the *routing decision* is centralized (in `--next`),
which is where divergence would actually harm the user.
## Alternatives considered
1. **Keep smart-entry as an independent in-project router (as first implemented).**
Rejected: reproduces the #3054 duplication and the Route 0 / Gates 1–3 bypass
hazard.
2. **Fold everything into `/gsd:progress` (add a menu mode) and ship no new
command.** Rejected: `/gsd:progress` carries `requires: [phase]` and cannot
serve the pre-project `no-project` front-door case, which is a primary goal.
3. **Replace `workflows/next.md`'s inline detection with the new classifier so
there is one detection *and* routing engine.** Rejected for this PR: `--next`
couples detection to safety gates and convergence flags the classifier does not
model; swapping its detection wholesale would risk regressing those invariants.
Left as possible future consolidation.
## References
- Spec: `docs/superpowers/specs/2026-06-27-gsd-smart-entry-design.md`
- Removed flat command guard: `tests/bug-3054-stale-gsd-next-references.test.cjs`
- Gated engine: `gsd-core/workflows/next.md` (Route 0 = resume-incomplete-phase, #160)
- Classifier: `src/smart-entry.cts` → `gsd-core/bin/lib/smart-entry.cjs`
- Command contract naming (`gsd:*`): ADR-0002