fix(#3097, #3099): add cwd-drift sentinel + absolute-path guard to executor worktree protocol (#3144)
* fix(#3097, #3099): add cwd-drift + absolute-path guards to executor worktree protocol #3097 — cwd-drift sentinel (gsd-executor.md task_commit_protocol step 0a): A Bash cd out of the worktree makes [ -f .git ] false, silently skipping all HEAD/branch safety guards. Commits land on main's branch. Fix: on first commit, capture spawn-time toplevel into sentinel file at .git/worktrees/<name>/gsd-spawn-toplevel. Before every subsequent commit, verify ACTUAL_TL matches EXPECTED_TL. Exits 1 with recovery instructions if drift detected. #3099 — absolute-path guard (gsd-executor.md task_commit_protocol step 0b): Absolute paths constructed from the orchestrator's pwd (main repo root) resolve to the main repo inside worktrees. Edit/Write lands in wrong dir; git commit sees a clean worktree tree; work silently lost or leaks to main. Fix: before any absolute-path Edit/Write, verify path starts with WT_ROOT=/Users/thbouc/projects/get-shit-done. Prefer relative paths. Both guards are documented in references/worktree-path-safety.md, which is now loaded into every executor spawn prompt via <execution_context>. The <worktree_branch_check> footnote references all three steps (0/0a/0b). execute-phase.md: extracted worktree bash commands to reference file (safe embed — @ files are inlined before the executor processes the prompt). The blank line in <required_reading> was removed to stay at the XL=1700 line budget after adding the @ reference. Suite: 6986/6986. Closes #3097. Closes #3099. * fix(lint+executor+docs): allow-test-rule, fix [ -f .git ] guard, fail-closed abs-path check, fix INVENTORY count
This commit is contained in:
@@ -358,6 +358,47 @@ If RED or GREEN gate commits are missing, add a warning to SUMMARY.md under a `#
|
||||
<task_commit_protocol>
|
||||
After each task completes (verification passed, done criteria met), commit immediately.
|
||||
|
||||
**0a. cwd-drift assertion (worktree mode only, MANDATORY before staging — #3097):**
|
||||
A prior Bash call may have `cd`'d out of the worktree into the main repo. When that happens
|
||||
`[ -f .git ]` is false (main repo's `.git` is a directory), silently skipping all worktree guards.
|
||||
Capture the spawn-time toplevel via a sentinel on first commit, then verify on every subsequent commit:
|
||||
```bash
|
||||
WT_GIT_DIR=$(git rev-parse --git-dir 2>/dev/null)
|
||||
case "$WT_GIT_DIR" in
|
||||
*.git/worktrees/*)
|
||||
SENTINEL="$WT_GIT_DIR/gsd-spawn-toplevel"
|
||||
[ ! -f "$SENTINEL" ] && git rev-parse --show-toplevel > "$SENTINEL" 2>/dev/null
|
||||
EXPECTED_TL=$(cat "$SENTINEL" 2>/dev/null)
|
||||
ACTUAL_TL=$(git rev-parse --show-toplevel 2>/dev/null)
|
||||
if [ -n "$EXPECTED_TL" ] && [ "$ACTUAL_TL" != "$EXPECTED_TL" ]; then
|
||||
echo "FATAL: cwd drifted from spawn-time worktree root (#3097)" >&2
|
||||
echo " Spawn-time: $EXPECTED_TL" >&2
|
||||
echo " Current: $ACTUAL_TL" >&2
|
||||
echo "RECOVERY: cd \"$EXPECTED_TL\" before staging, then re-run this commit." >&2
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
```
|
||||
|
||||
**0b. absolute-path safety (worktree mode only, MANDATORY before Edit/Write — #3099):**
|
||||
Before any Edit or Write call that uses an absolute path, verify the path resolves inside the
|
||||
current worktree. Absolute paths constructed from prior `pwd` output (orchestrator's cwd) will
|
||||
resolve to the **main repo**, not the worktree — silently writing files to the wrong location.
|
||||
```bash
|
||||
# Obtain the canonical worktree root
|
||||
WT_ROOT=$(git rev-parse --show-toplevel 2>/dev/null)
|
||||
[ -z "$WT_ROOT" ] && { echo "FATAL: could not determine worktree root" >&2; exit 1; }
|
||||
# Verify absolute path containment with boundary safety (not glob prefix which allows siblings)
|
||||
if [[ "$ABS_PATH" != "$WT_ROOT" && "$ABS_PATH" != "$WT_ROOT/"* ]]; then
|
||||
echo "FATAL: $ABS_PATH is outside the worktree ($WT_ROOT) — use a relative path or recompute from WT_ROOT" >&2
|
||||
exit 1
|
||||
fi
|
||||
```
|
||||
Prefer **relative paths** for all Edit/Write operations inside a worktree. When an absolute path
|
||||
is unavoidable, always derive it from `git rev-parse --show-toplevel` run inside the worktree,
|
||||
not from a `pwd` captured in the orchestrator context.
|
||||
|
||||
**0. Pre-commit HEAD safety assertion (worktree mode only, MANDATORY before every commit — #2924):**
|
||||
When running inside a Claude Code worktree (`.git` is a file, not a directory), assert HEAD is on a per-agent branch BEFORE staging or committing. If HEAD has drifted onto a protected ref, HALT — never self-recover via `git update-ref refs/heads/<protected>`:
|
||||
```bash
|
||||
|
||||
Reference in New Issue
Block a user