Преглед на файлове

fix: avoid SDD task brief path collisions (PRI-2240)

Drew Ritter преди 2 месеца
родител
ревизия
3567c68388
променени са 2 файла, в които са добавени 120 реда и са изтрити 3 реда
  1. 3 3
      skills/subagent-driven-development/scripts/task-brief
  2. 117 0
      tests/claude-code/test-task-brief.sh

+ 3 - 3
skills/subagent-driven-development/scripts/task-brief

@@ -4,8 +4,7 @@
 # through the controller's context.
 #
 # Usage: task-brief PLAN_FILE TASK_NUMBER [OUTFILE]
-# Default OUTFILE: <git-dir>/sdd/task-<N>-brief.md — unique per repo
-# instance, so concurrent sessions cannot collide.
+# Default OUTFILE: <git-dir>/sdd/task-<N>.<unique>/task-<N>-brief.md.
 set -euo pipefail
 
 if [ $# -lt 2 ] || [ $# -gt 3 ]; then
@@ -23,7 +22,8 @@ else
   dir=$(git rev-parse --git-path sdd)
   mkdir -p "$dir"
   dir=$(cd "$dir" && pwd)
-  out="$dir/task-${n}-brief.md"
+  brief_dir=$(mktemp -d "$dir/task-${n}.XXXXXX")
+  out="$brief_dir/task-${n}-brief.md"
 fi
 
 awk -v n="$n" '

+ 117 - 0
tests/claude-code/test-task-brief.sh

@@ -0,0 +1,117 @@
+#!/usr/bin/env bash
+set -euo pipefail
+
+SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
+REPO_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
+TASK_BRIEF="$REPO_ROOT/skills/subagent-driven-development/scripts/task-brief"
+
+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
+}
+
+extract_written_path() {
+    local output="$1"
+    printf '%s\n' "$output" | sed -n 's/^wrote \(.*\): [0-9][0-9]* lines$/\1/p'
+}
+
+assert_not_equals() {
+    local actual="$1"
+    local expected="$2"
+    local description="$3"
+
+    if [[ "$actual" != "$expected" ]]; then
+        pass "$description"
+    else
+        fail "$description"
+        echo "    both were: $actual"
+    fi
+}
+
+assert_file_contains() {
+    local path="$1"
+    local needle="$2"
+    local description="$3"
+
+    if grep -Fq -- "$needle" "$path"; then
+        pass "$description"
+    else
+        fail "$description"
+        echo "    expected $path to contain: $needle"
+    fi
+}
+
+main() {
+    echo "=== Test: task-brief output paths ==="
+
+    TEST_ROOT="$(mktemp -d)"
+    trap cleanup EXIT
+
+    local repo="$TEST_ROOT/repo"
+    local plan="$repo/plan.md"
+    local output_one
+    local output_two
+    local path_one
+    local path_two
+
+    git init -q -b main "$repo"
+
+    cat > "$plan" <<'EOF'
+# Implementation Plan
+
+## Task 1: First thing
+
+Do the first thing.
+
+## Task 2: Second thing
+
+Do the second thing.
+EOF
+
+    output_one="$(cd "$repo" && "$TASK_BRIEF" "$plan" 1)"
+    output_two="$(cd "$repo" && "$TASK_BRIEF" "$plan" 1)"
+    path_one="$(extract_written_path "$output_one")"
+    path_two="$(extract_written_path "$output_two")"
+
+    assert_not_equals "$path_one" "$path_two" "Default task brief paths are unique per invocation"
+    assert_file_contains "$path_one" "## Task 1: First thing" "First default brief contains the requested task"
+    assert_file_contains "$path_two" "## Task 1: First thing" "Second default brief contains the requested task"
+
+    if [[ "$path_one" == "$repo/.git/sdd/"* ]]; then
+        pass "First default brief stays under the repo git metadata directory"
+    else
+        fail "First default brief stays under the repo git metadata directory"
+        echo "    actual: $path_one"
+    fi
+
+    if [[ "$path_two" == "$repo/.git/sdd/"* ]]; then
+        pass "Second default brief stays under the repo git metadata directory"
+    else
+        fail "Second default brief stays under the repo git metadata directory"
+        echo "    actual: $path_two"
+    fi
+
+    if [[ $FAILURES -ne 0 ]]; then
+        echo ""
+        echo "FAILED: $FAILURES assertion(s) failed."
+        exit 1
+    fi
+
+    echo ""
+    echo "PASS"
+}
+
+main "$@"