Files
msd-core/get-shit-done/workflows/execute-phase/steps/codebase-drift-gate.md
Tom Boucher e3bc53f835 enhancement(#558): add liveness hints to all GSD spawn announcements (#566)
* enhancement(#558): add liveness hints to all GSD spawn announcements

Append '(runs in a subagent — no output until it returns, ~1–5 min; expected,
not a freeze)' inline to every ◆ Spawning… banner and subagent dispatch
instruction across 26 workflows. Silent subagents look identical to frozen
sessions — this note sets the expectation so users wait instead of killing
healthy in-progress work.

Changes:
- references/ui-brand.md: document liveness convention under Spawning Indicators
- 10 banner workflows: append liveness note to ◆ Spawning… lines in-place
- 18 subagent-only workflows: add print instruction with liveness phrase
- tests/spawn-liveness-banner.test.cjs: new test; fails if any workflow with
  subagent_type omits 'runs in a subagent'
- docs/USER-GUIDE.md: troubleshooting entry for frozen-looking spawns
- .changeset/558-spawn-liveness-banner.md: changeset fragment

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

* fix(#558): add missing pr field to changeset fragment

The changeset lint requires pr: <NNN> in frontmatter; the fragment was
written without it, causing parse.cjs to reject it.

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

* fix(#558): address codex review — missed spawns and tighten test

- plan-phase.md: add liveness note to chunked outline planner and
  per-plan chunked planner banners (two missed ◆ Spawning… lines)
- quick.md: add liveness note to research banner and add missing
  display line before planner spawn in Step 5
- plan-review-convergence.md: add liveness note to initial planning
  and review-agent spawn Display lines
- docs-update.md: add Print instructions with liveness note before
  gsd-doc-verifier spawns in Phase 1 and Phase 2
- autonomous.md: add Print instruction with liveness note before
  background plan-phase agent dispatch in step 3b
- tests/spawn-liveness-banner.test.cjs: replace single file-level
  check with two assertions:
  (1) every ◆ Spawning… banner line carries the phrase on that line
  (2) every file with subagent_type contains the phrase somewhere
  The tighter test would have caught all five missed spawns.

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

* fix(#558): tighten spawn-liveness test regex to catch spawn-word-anywhere variants

Previous SPAWN_BANNER_RE only matched ◆ immediately followed by Spawning|spawning.
Replace with /◆[^\n]*\bspawning?\b/i which matches the spawn word anywhere on the
◆ line — catching "◆ Chunked mode: spawning outline planner..." and similar.

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

* fix(#558): rename changeset to PR number 566 and correct pr field

Changeset was filed as 558-spawn-liveness-banner.md (issue#) but the
convention is the PR number. Renamed to 566-spawn-liveness-banner.md
and updated pr: 558 → pr: 566 so release notes link to the right PR.

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

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-31 23:33:49 -04:00

4.0 KiB
Raw Blame History

Step: codebase_drift_gate

Post-execution structural drift detection (#2003). Runs after the last wave commits, before verification. Non-blocking by contract: any internal error here MUST fall through and continue to verify_phase_goal. The phase is never failed by this gate.

DRIFT=$(gsd-tools verify codebase-drift 2>/dev/null || echo '{"skipped":true,"reason":"sdk-failed"}')

Parse JSON for: skipped, reason, action_required, directive, spawn_mapper, affected_paths, elements, threshold, action, last_mapped_commit, message.

If skipped is true (no STRUCTURE.md, missing git, or any internal error): Log one line — Codebase drift check skipped: {reason} — and continue to verify_phase_goal. Do NOT prompt the user. Do NOT block.

If action_required is false: Continue silently to verify_phase_goal.

If action_required is true AND directive is warn: Print the message field verbatim. The format is:

Codebase drift detected: {N} structural element(s) since last mapping.

New directories:
  - {path}
New barrel exports:
  - {path}
New migrations:
  - {path}
New route modules:
  - {path}

Run /gsd:map-codebase --paths {affected_paths} to refresh planning context.

Then continue to verify_phase_goal. Do NOT block. Do NOT spawn anything.

If action_required is true AND directive is auto-remap:

First load the mapper agent's skill bundle (the executor's AGENT_SKILLS from step init_context is for gsd-executor, not the mapper):

_GSD_SHIM_NAME="gsd-tools.cjs"; _GSD_RUNTIME_ROOT="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}"; GSD_TOOLS="${_GSD_RUNTIME_ROOT}/get-shit-done/bin/${_GSD_SHIM_NAME}"; if [ -f "$GSD_TOOLS" ]; then gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${_GSD_RUNTIME_ROOT}/.claude/get-shit-done/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${_GSD_RUNTIME_ROOT}/.claude/get-shit-done/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif command -v gsd-tools >/dev/null 2>&1; then GSD_TOOLS="$(command -v gsd-tools)"; gsd_run() { "$GSD_TOOLS" "$@"; }; elif [ -f "$HOME/.claude/get-shit-done/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="$HOME/.claude/get-shit-done/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; else echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd-tools is not on PATH. Run: npx -y @opengsd/gsd-core@latest --claude --local" >&2; exit 1; fi
AGENT_SKILLS_MAPPER=$(gsd_run query agent-skills gsd-codebase-mapper)

Then spawn gsd-codebase-mapper agents with the --paths hint (runs in a subagent — no output until it returns, ~1–5 min; expected, not a freeze):

Agent(
  subagent_type="gsd-codebase-mapper",
  description="Incremental codebase remap (drift)",
  prompt="Focus: arch
Today's date: {date}
--paths {affected_paths joined by comma}

Refresh STRUCTURE.md and ARCHITECTURE.md scoped to the listed paths only.
Stamp last_mapped_commit in each document's frontmatter.
${AGENT_SKILLS_MAPPER}"
)

ORCHESTRATOR RULE — CODEX RUNTIME: After calling Agent() above, stop working on this task immediately. Do not read more files, edit code, or run tests related to this task while the subagent is active. Wait for the subagent to return its result. This prevents duplicate work, conflicting edits, and wasted context. Only resume when the subagent result is available.

If the spawn fails or the agent reports an error: log Codebase drift auto-remap failed: {reason} and continue to verify_phase_goal. The phase is NOT failed by a remap failure.

If the remap succeeds: log Codebase drift auto-remap completed for paths: {affected_paths} and continue to verify_phase_goal.

The two relevant config keys (continue on error / failure if either is invalid):

  • workflow.drift_threshold (integer, default 3) — minimum drift elements before action
  • workflow.drift_action — warn (default) or auto-remap

This step is fully non-blocking — it never fails the phase, and any exception path returns control to verify_phase_goal.