mirror of
https://github.com/obra/superpowers.git
synced 2026-07-23 10:44:01 +08:00
Responds to maintainer review of this branch: the dispatch-hint lines were hardcoded Codex strings inside shared skill tooling that every harness runs. The per-role hint lines now live in a platform-owned data file, skills/using-superpowers/references/codex-dispatch.hints, and the task-brief/review-package scripts only relay the current role's line. The relay is suppressed when CLAUDECODE is set (Claude Code's dispatch templates already carry model selection) and on any harness with no hints file; unknown harnesses fail toward printing, because a silent no-op in the environment that needs the hint is the failure mode this mechanism exists to prevent. Printing at the moment of dispatch is load-bearing: skill text loaded at session start does not survive context compaction, but script output reprints every round. codex-tools.md's SDD dispatch section shrinks to the behavioral rules (fork_turns: "none" always; copy the printed hint verbatim; reviewer tier never exceeds implementer tier; no effort bumps; the <=0.144 inheritance fallback) and points at the hints file for values. Tests cover the relay path, the per-role efforts, and the new CLAUDECODE suppression case. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
258 lines
9.3 KiB
Bash
Executable File
258 lines
9.3 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# Tests for the SDD workspace: scripts/sdd-workspace resolves a self-ignoring,
|
|
# PER-PLAN working-tree directory for SDD artifacts, and the SDD scripts write
|
|
# into their plan's directory.
|
|
set -euo pipefail
|
|
|
|
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
REPO_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
|
|
SDD_SCRIPTS="$REPO_ROOT/skills/subagent-driven-development/scripts"
|
|
|
|
FAILURES=0
|
|
TEST_ROOT=""
|
|
|
|
pass() { echo " [PASS] $1"; }
|
|
fail() {
|
|
echo " [FAIL] $1"
|
|
FAILURES=$((FAILURES + 1))
|
|
}
|
|
|
|
cleanup() {
|
|
if [[ -n "$TEST_ROOT" && -d "$TEST_ROOT" ]]; then
|
|
rm -rf "$TEST_ROOT"
|
|
fi
|
|
}
|
|
|
|
main() {
|
|
echo "=== Test: sdd-workspace ==="
|
|
|
|
TEST_ROOT="$(mktemp -d)"
|
|
trap cleanup EXIT
|
|
|
|
# Resolve repo to its physical path so string comparisons match the
|
|
# helper's output (git rev-parse --show-toplevel resolves symlinks; on
|
|
# macOS mktemp lives under /var -> /private/var).
|
|
git init -q -b main "$TEST_ROOT/repo"
|
|
local repo
|
|
repo="$(cd "$TEST_ROOT/repo" && git rev-parse --show-toplevel)"
|
|
|
|
cat > "$repo/plan-a.md" <<'PLAN'
|
|
# Plan A
|
|
|
|
## Task 1: First thing
|
|
|
|
Do the first thing.
|
|
PLAN
|
|
cat > "$repo/plan-b.md" <<'PLAN'
|
|
# Plan B
|
|
|
|
## Task 1: Other thing
|
|
|
|
Do the other thing.
|
|
PLAN
|
|
|
|
# --- argument validation ---
|
|
local rc=0
|
|
(cd "$repo" && "$SDD_SCRIPTS/sdd-workspace" >/dev/null 2>&1) || rc=$?
|
|
if [[ "$rc" -eq 2 ]]; then
|
|
pass "sdd-workspace without a plan errors with exit 2"
|
|
else
|
|
fail "sdd-workspace without a plan errors with exit 2"
|
|
echo " exit: $rc"
|
|
fi
|
|
|
|
rc=0
|
|
(cd "$repo" && "$SDD_SCRIPTS/sdd-workspace" no-such-plan.md >/dev/null 2>&1) || rc=$?
|
|
if [[ "$rc" -eq 2 ]]; then
|
|
pass "sdd-workspace with a missing plan file errors with exit 2"
|
|
else
|
|
fail "sdd-workspace with a missing plan file errors with exit 2"
|
|
echo " exit: $rc"
|
|
fi
|
|
|
|
# --- per-plan resolution ---
|
|
local dir_a dir_b
|
|
dir_a="$(cd "$repo" && "$SDD_SCRIPTS/sdd-workspace" plan-a.md)"
|
|
dir_b="$(cd "$repo" && "$SDD_SCRIPTS/sdd-workspace" plan-b.md)"
|
|
|
|
if [[ "$dir_a" == "$repo/.superpowers/sdd/plan-a" ]]; then
|
|
pass "prints <repo-root>/.superpowers/sdd/<plan-basename>"
|
|
else
|
|
fail "prints <repo-root>/.superpowers/sdd/<plan-basename>"
|
|
echo " got: $dir_a"
|
|
fi
|
|
|
|
if [[ "$dir_a" != "$dir_b" && -d "$dir_a" && -d "$dir_b" ]]; then
|
|
pass "two plans resolve to two distinct directories"
|
|
else
|
|
fail "two plans resolve to two distinct directories"
|
|
echo " a: $dir_a"
|
|
echo " b: $dir_b"
|
|
fi
|
|
|
|
if [[ -f "$repo/.superpowers/sdd/.gitignore" && "$(cat "$repo/.superpowers/sdd/.gitignore")" == "*" ]]; then
|
|
pass "self-ignoring .gitignore created at .superpowers/sdd/ with '*'"
|
|
else
|
|
fail "self-ignoring .gitignore created at .superpowers/sdd/ with '*'"
|
|
fi
|
|
|
|
printf 'x\n' > "$dir_a/artifact.md"
|
|
local status
|
|
status="$(cd "$repo" && git status --porcelain)"
|
|
# plan-a.md/plan-b.md are intentionally untracked fixture files; only the
|
|
# workspace must be invisible.
|
|
if [[ "$status" != *".superpowers"* ]]; then
|
|
pass "workspace invisible to git status"
|
|
else
|
|
fail "workspace invisible to git status"
|
|
echo " status: $status"
|
|
fi
|
|
|
|
( cd "$repo" && git add -A )
|
|
local staged
|
|
staged="$(cd "$repo" && git diff --cached --name-only)"
|
|
if [[ "$staged" != *".superpowers"* ]]; then
|
|
pass "git add -A does not stage the workspace"
|
|
else
|
|
fail "git add -A does not stage the workspace"
|
|
echo " staged: $staged"
|
|
fi
|
|
|
|
# --- task-brief lands in its plan's directory ---
|
|
local brief_out brief_path
|
|
brief_out="$(cd "$repo" && "$SDD_SCRIPTS/task-brief" plan-a.md 1)"
|
|
brief_path="$(printf '%s\n' "$brief_out" | sed -n 's/^wrote \(.*\): [0-9][0-9]* lines$/\1/p')"
|
|
if [[ "$brief_path" == "$repo/.superpowers/sdd/plan-a/task-1-brief.md" ]]; then
|
|
pass "task-brief writes its brief under the plan's workspace"
|
|
else
|
|
fail "task-brief writes its brief under the plan's workspace"
|
|
echo " got: $brief_path"
|
|
fi
|
|
|
|
# --- review-package takes the plan first and lands in its directory ---
|
|
local git_id=(-c user.email=t@example.com -c user.name=t -c commit.gpgsign=false)
|
|
( cd "$repo" \
|
|
&& git "${git_id[@]}" commit -qm c1 \
|
|
&& printf 'y\n' > f && git add f \
|
|
&& git "${git_id[@]}" commit -qm c2 )
|
|
local rp_out rp_path
|
|
rp_out="$(cd "$repo" && "$SDD_SCRIPTS/review-package" plan-a.md HEAD~1 HEAD)"
|
|
rp_path="$(printf '%s\n' "$rp_out" | sed -n 's/^wrote \(.*\): [0-9].*$/\1/p')"
|
|
case "$rp_path" in
|
|
"$repo/.superpowers/sdd/plan-a/review-"*.diff)
|
|
pass "review-package writes its diff under the plan's workspace" ;;
|
|
*)
|
|
fail "review-package writes its diff under the plan's workspace"
|
|
echo " got: $rp_path"
|
|
;;
|
|
esac
|
|
|
|
rc=0
|
|
(cd "$repo" && "$SDD_SCRIPTS/review-package" HEAD~1 HEAD >/dev/null 2>&1) || rc=$?
|
|
if [[ "$rc" -eq 2 ]]; then
|
|
pass "review-package without a plan errors with exit 2"
|
|
else
|
|
fail "review-package without a plan errors with exit 2"
|
|
echo " exit: $rc"
|
|
fi
|
|
|
|
local rp_explicit
|
|
rp_explicit="$(cd "$repo" && "$SDD_SCRIPTS/review-package" plan-a.md HEAD~1 HEAD "$TEST_ROOT/explicit.diff")"
|
|
if [[ -s "$TEST_ROOT/explicit.diff" && "$rp_explicit" == *"$TEST_ROOT/explicit.diff"* ]]; then
|
|
pass "review-package honors an explicit OUTFILE"
|
|
else
|
|
fail "review-package honors an explicit OUTFILE"
|
|
echo " got: $rp_explicit"
|
|
fi
|
|
|
|
# --- platform dispatch hints ride the script output (suppressed on CC) ---
|
|
local brief_hint
|
|
brief_hint="$(cd "$repo" && env -u CLAUDECODE "$SDD_SCRIPTS/task-brief" plan-a.md 1)"
|
|
if [[ "$brief_hint" == *"dispatch (spawn_agent): fork_turns=none model=gpt-5.6-terra reasoning_effort=high"* ]]; then
|
|
pass "task-brief relays the implementer dispatch hint off Claude Code"
|
|
else
|
|
fail "task-brief relays the implementer dispatch hint off Claude Code"
|
|
echo " got: $brief_hint"
|
|
fi
|
|
|
|
local rp_hint
|
|
rp_hint="$(cd "$repo" && env -u CLAUDECODE "$SDD_SCRIPTS/review-package" plan-a.md HEAD~1 HEAD)"
|
|
if [[ "$rp_hint" == *"dispatch (spawn_agent): fork_turns=none model=gpt-5.6-terra reasoning_effort=high"* ]]; then
|
|
pass "review-package relays the default-role hint off Claude Code"
|
|
else
|
|
fail "review-package relays the default-role hint off Claude Code"
|
|
echo " got: $rp_hint"
|
|
fi
|
|
|
|
local rp_rereview
|
|
rp_rereview="$(cd "$repo" && env -u CLAUDECODE "$SDD_SCRIPTS/review-package" --role re-review plan-a.md HEAD~1 HEAD)"
|
|
if [[ "$rp_rereview" == *"dispatch (spawn_agent): fork_turns=none model=gpt-5.6-terra reasoning_effort=medium"* ]]; then
|
|
pass "review-package --role re-review relays the medium-effort hint"
|
|
else
|
|
fail "review-package --role re-review relays the medium-effort hint"
|
|
echo " got: $rp_rereview"
|
|
fi
|
|
|
|
local rp_final
|
|
rp_final="$(cd "$repo" && env -u CLAUDECODE "$SDD_SCRIPTS/review-package" --role final-review plan-a.md HEAD~1 HEAD)"
|
|
if [[ "$rp_final" == *"dispatch (spawn_agent): fork_turns=none model=gpt-5.6-terra reasoning_effort=high"* ]]; then
|
|
pass "review-package --role final-review relays the high-effort hint"
|
|
else
|
|
fail "review-package --role final-review relays the high-effort hint"
|
|
echo " got: $rp_final"
|
|
fi
|
|
|
|
local brief_cc rp_cc
|
|
brief_cc="$(cd "$repo" && CLAUDECODE=1 "$SDD_SCRIPTS/task-brief" plan-a.md 1)"
|
|
rp_cc="$(cd "$repo" && CLAUDECODE=1 "$SDD_SCRIPTS/review-package" plan-a.md HEAD~1 HEAD)"
|
|
if [[ "$brief_cc" != *"dispatch (spawn_agent)"* && "$rp_cc" != *"dispatch (spawn_agent)"* ]]; then
|
|
pass "dispatch hints are suppressed under Claude Code (CLAUDECODE set)"
|
|
else
|
|
fail "dispatch hints are suppressed under Claude Code (CLAUDECODE set)"
|
|
echo " brief: $brief_cc"
|
|
echo " rp: $rp_cc"
|
|
fi
|
|
|
|
rc=0
|
|
(cd "$repo" && "$SDD_SCRIPTS/review-package" --role bogus plan-a.md HEAD~1 HEAD >/dev/null 2>&1) || rc=$?
|
|
if [[ "$rc" -eq 2 ]]; then
|
|
pass "review-package rejects an unknown --role with exit 2"
|
|
else
|
|
fail "review-package rejects an unknown --role with exit 2"
|
|
echo " exit: $rc"
|
|
fi
|
|
|
|
# --- Worktree isolation: a linked worktree resolves its own workspace ---
|
|
local wt="$TEST_ROOT/wt"
|
|
( cd "$repo" && git worktree add -q "$wt" -b wt-feature )
|
|
local wt_root wt_dir
|
|
wt_root="$(cd "$wt" && git rev-parse --show-toplevel)"
|
|
wt_dir="$(cd "$wt" && "$SDD_SCRIPTS/sdd-workspace" plan-a.md)"
|
|
if [[ "$wt_dir" == "$wt_root/.superpowers/sdd/plan-a" && "$wt_dir" != "$dir_a" ]]; then
|
|
pass "linked worktree resolves its own distinct workspace"
|
|
else
|
|
fail "linked worktree resolves its own distinct workspace"
|
|
echo " main: $dir_a"
|
|
echo " wt: $wt_dir"
|
|
fi
|
|
|
|
printf 'y\n' > "$wt_dir/artifact.md"
|
|
local wt_status
|
|
wt_status="$(cd "$wt" && git status --porcelain)"
|
|
if [[ "$wt_status" != *".superpowers"* ]]; then
|
|
pass "worktree workspace invisible to git status"
|
|
else
|
|
fail "worktree workspace invisible to git status"
|
|
echo " status: $wt_status"
|
|
fi
|
|
|
|
echo ""
|
|
if [[ "$FAILURES" -ne 0 ]]; then
|
|
echo "FAILED: $FAILURES assertion(s)."
|
|
exit 1
|
|
fi
|
|
echo "PASS"
|
|
}
|
|
|
|
main "$@"
|