fix(#4264): wire both TDD dispatch backends to phase.tdd-applicable (#4284)

This commit is contained in:
Tom Boucher
2026-09-04 16:08:42 -04:00
committed by GitHub
parent 580059251a
commit 2f4f7538e9
27 changed files with 297 additions and 2 deletions

View File

@@ -161,6 +161,18 @@ Assign the composed prompt to a shell variable so it can be passed as one argume
# no host subagent machinery, so the role definition must ride the prompt
# (#3637 acceptance: resolved agent instructions as launch-level
# instructions + provenance of which role definition was used).
# Resolve TDD-applicability for THIS plan (#4266/#4272) — fail closed on
# command failure, mirroring the ISOLATION resolution above: an absent
# verdict must never silently resolve to "not TDD" (ADR-3473 §8.4), since
# that would silently drop a real TDD plan's RED/GREEN/REFACTOR procedure.
_TDD_APPLICABLE_RAW=$(gsd_run query phase.tdd-applicable "{phase_dir}/{plan_file}" --pick applicable 2>/dev/null)
_TDD_APPLICABLE_RC=$?
if [ $_TDD_APPLICABLE_RC -ne 0 ]; then
echo "FATAL: could not resolve TDD-applicability for plan {plan_number} — 'gsd_run query phase.tdd-applicable' failed. Refusing to guess whether this dispatch needs the TDD procedure. Halting." >&2
exit 1
fi
TDD_APPLICABLE="$_TDD_APPLICABLE_RAW"
EXECUTOR_PROMPT='<objective>
Execute plan {plan_number} of phase {phase_number}-{phase_name}.
Commit each task atomically. Create SUMMARY.md.
@@ -181,7 +193,7 @@ the executor workflow from repository search.
SUMMARY commit semantics and the gitignored-planning skip contract)
- summary.md template
- checkpoints.md
${TDD_APPLICABLE ? "- tdd.md" : ""} # #3990: only when this dispatch is TDD (plan type: tdd, or TDD_MODE=true)
${TDD_APPLICABLE ? "- tdd.md" : ""} # #3990/#4265: only when this dispatch is TDD (plan type: tdd, a tdd="true" task, or workflow.tdd_mode config)
- worktree-path-safety.md
- agents/gsd-executor.md (the ROLE DEFINITION you are executing — its steps
0/0a/0b per-commit HEAD/cwd-drift/path-guard discipline applies to every
@@ -257,6 +269,10 @@ printf '%s' "$EXECUTOR_PROMPT" | grep -q '\${AGENT_SKILLS}' && {
echo "FATAL: executor prompt for plan {plan_number} still contains the un-substituted \${AGENT_SKILLS} marker — the role definition was not spliced in (#3637). Halting." >&2
exit 1
}
printf '%s' "$EXECUTOR_PROMPT" | grep -q '\${TDD_APPLICABLE' && {
echo "FATAL: executor prompt for plan {plan_number} still contains the un-substituted \${TDD_APPLICABLE marker — the TDD-applicability decision was not resolved into the prompt (#4266). Halting." >&2
exit 1
}
```
The prompt body must contain no single-quote character, since the assignment above is single-quoted; keep apostrophes out of it when editing.

View File

@@ -0,0 +1,25 @@
# TDD-applicability resolution (#4266/#4272)
Run for each plan, immediately after executor routing and before composing
that plan's `Agent()` prompt in step 3. Resolves whether this dispatch is TDD
— fail closed, do not guess.
## Resolution
```bash
_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}/gsd-core/bin/${_GSD_SHIM_NAME}"; _gsd_at() { for _p; do if [ -f "$_p" ]; then GSD_TOOLS="$_p"; return 0; fi; done; return 1; }; if _gsd_at "${_GSD_RUNTIME_ROOT}/gsd-core/bin/${_GSD_SHIM_NAME}" "${_GSD_RUNTIME_ROOT}/.claude/gsd-core/bin/${_GSD_SHIM_NAME}" "${_GSD_RUNTIME_ROOT}/.codex/gsd-core/bin/${_GSD_SHIM_NAME}"; then gsd_run() { node "$GSD_TOOLS" "$@"; }; elif unset -f gsd_run; _G="$(command -v gsd_run)"; then GSD_TOOLS="$_G"; gsd_run() { "$GSD_TOOLS" "$@"; }; elif _gsd_at "${CLAUDE_CONFIG_DIR:-$HOME/.claude}/gsd-core/bin/${_GSD_SHIM_NAME}" "${HERMES_HOME:-$HOME/.hermes}/gsd-core/bin/${_GSD_SHIM_NAME}" "${CURSOR_CONFIG_DIR:-$HOME/.cursor}/gsd-core/bin/${_GSD_SHIM_NAME}" "${CODEX_HOME:-$HOME/.codex}/gsd-core/bin/${_GSD_SHIM_NAME}" "${GEMINI_CONFIG_DIR:-$HOME/.gemini}/gsd-core/bin/${_GSD_SHIM_NAME}" "${COPILOT_CONFIG_DIR:-$HOME/.copilot}/gsd-core/bin/${_GSD_SHIM_NAME}" "${WINDSURF_CONFIG_DIR:-$HOME/.codeium/windsurf}/gsd-core/bin/${_GSD_SHIM_NAME}" "${AUGMENT_CONFIG_DIR:-$HOME/.augment}/gsd-core/bin/${_GSD_SHIM_NAME}" "${TRAE_CONFIG_DIR:-$HOME/.trae}/gsd-core/bin/${_GSD_SHIM_NAME}" "${QWEN_CONFIG_DIR:-$HOME/.qwen}/gsd-core/bin/${_GSD_SHIM_NAME}" "${CODEBUDDY_CONFIG_DIR:-$HOME/.codebuddy}/gsd-core/bin/${_GSD_SHIM_NAME}" "${CLINE_CONFIG_DIR:-$HOME/.cline}/gsd-core/bin/${_GSD_SHIM_NAME}" "${GROK_AGENTS_HOME:-$HOME/.agents}/gsd-core/bin/${_GSD_SHIM_NAME}" "${ANTIGRAVITY_CONFIG_DIR:-$HOME/.gemini/antigravity}/gsd-core/bin/${_GSD_SHIM_NAME}" "${OPENCODE_CONFIG_DIR:-${XDG_CONFIG_HOME:-$HOME/.config}/opencode}/gsd-core/bin/${_GSD_SHIM_NAME}" "${KILO_CONFIG_DIR:-${XDG_CONFIG_HOME:-$HOME/.config}/kilo}/gsd-core/bin/${_GSD_SHIM_NAME}"; then gsd_run() { node "$GSD_TOOLS" "$@"; }; else echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd_run is not on PATH. Run: npx -y @opengsd/gsd-core@latest --claude --local" >&2; exit 1; fi; GSD_IDENTITY_STATUS=unverified; case "$(gsd_run runtime-identity --raw 2>/dev/null || true)" in '{"packageName":"@opengsd/gsd-core"'*'}') GSD_IDENTITY_STATUS=ok;; esac; export GSD_IDENTITY_STATUS; [ "$GSD_IDENTITY_STATUS" = ok ] || echo "WARNING: \"$GSD_TOOLS\" did not prove it is @opengsd/gsd-core - it is either a different package or an @opengsd/gsd-core older than the runtime-identity verb. See docs/how-to/diagnose-a-foreign-gsd-tools.md" >&2; if [ -n "${CLAUDE_ENV_FILE:-}" ] && [ -n "${GSD_TOOLS:-}" ]; then printf "export PATH='%s':\"\$PATH\"\n" "${GSD_TOOLS%/*}" >> "$CLAUDE_ENV_FILE" 2>/dev/null || true; fi
TDD_APPLICABLE_RAW=$(gsd_run query phase.tdd-applicable "{phase_dir}/{plan_file}" --pick applicable 2>/dev/null)
TDD_APPLICABLE_RC=$?
if [ $TDD_APPLICABLE_RC -ne 0 ]; then
echo "FATAL: could not resolve TDD-applicability for plan {plan_number} — 'gsd_run query phase.tdd-applicable' failed. Refusing to guess whether this dispatch needs the TDD procedure. Halting." >&2
exit 1
fi
TDD_APPLICABLE="$TDD_APPLICABLE_RAW"
```
## Pre-dispatch check (MANDATORY)
Before calling Agent(), confirm every `${...}` conditional in the prompt below
(`TDD_APPLICABLE`, `CONTEXT_WINDOW`, `AGENT_SKILLS`) was resolved to concrete
text for THIS plan. If any marker's value was not computed, HALT — do not
dispatch a prompt containing literal `${...}` template syntax (#4266).