guard-main: цепочка «git worktree add … && cd … && openspec archive …» блокируется по ветке основного checkout (O-4) #63

Closed
opened 2026-10-24 20:02:30 +03:00 by aep · 1 comment
Owner

Маркер: O-4 (наблюдение контроллера вне ревью). Источник: сессия #42, шаг 1 чеклиста закрытия (архив change отдельным PR от main).

Что случилось

Команда создания worktree и архива в одной цепочке, запущенная из основного checkout на main:

cd /Users/andrey.epifancev/projects/cc-skills/claude-harness \
  && git worktree add .claude/worktrees/archive-dsh-openspec -b chore/archive-dsh-openspec origin/main 2>&1 | tail -2 \
  && cd .claude/worktrees/archive-dsh-openspec \
  && openspec archive dsh-openspec -y

Ответ хука:

BLOCKED [guard-main]: запись в .claude/worktrees/archive-dsh-openspec — репозиторий
/Users/andrey.epifancev/projects/cc-skills/claude-harness на main. В main только через PR.

Блокировка ложная по смыслу: git worktree add создаёт отдельный worktree на ветке
chore/archive-dsh-openspec, и openspec archive выполнился бы уже в нём. Обход, который
сработал: разнести на отдельные вызовы (worktree add, затем archive). Из /tmp с абсолютным
путём та же цепочка проходила — это и сбило диагностику.

Минимальное воспроизведение (парсер, без исполнения)

python3 hooks/harness_target.py targets 'openspec archive foo -y' <repo>
# file <repo> openspec archive

python3 hooks/harness_target.py targets 'git worktree add .claude/worktrees/x -b feat/x origin/main && openspec archive y -y' <repo>
# file <repo> openspec archive

python3 hooks/harness_target.py targets 'cd <repo> && git worktree add .claude/worktrees/x -b feat/x origin/main && cd .claude/worktrees/x && openspec archive y -y' <repo>
# file <repo>/.claude/worktrees/x openspec archive

git worktree add … сам по себе целей не даёт (спец-случай в _git), но следующий за ним
openspec archive в той же цепочке даёт цель в каталоге, которого на момент разбора ещё нет;
resolve() поднимается до объемлющего репозитория и берёт его ветку — main.

Ожидаемое поведение

Цель под <path> из git worktree add <path> -b <branch> в пределах той же команды MUST
оцениваться по <branch>, а не по ветке объемлющего репозитория.

Предложение

В parse() запоминать пары «путь → ветка» для git worktree add <path> -b|-B <branch> и
применять их в decide_guard к последующим целям в этом же вызове. Регрессия: случай в
tests/test-hook-parse.sh (пути, как в воспроизведении выше) и кейс в корпус хуков.

Цена

Один провальный вызов и лишняя диагностика при каждом закрытии фичи; сообщение указывает на
путь worktree, а не на настоящую причину. Обходной рецепт (разнести вызовы) стоит записать в
docs/HARNESS.md, если код хука не будет меняться.

Маркер: **O-4** (наблюдение контроллера вне ревью). Источник: сессия #42, шаг 1 чеклиста закрытия (архив change отдельным PR от main). ## Что случилось Команда создания worktree и архива в одной цепочке, запущенная из основного checkout на main: ```bash cd /Users/andrey.epifancev/projects/cc-skills/claude-harness \ && git worktree add .claude/worktrees/archive-dsh-openspec -b chore/archive-dsh-openspec origin/main 2>&1 | tail -2 \ && cd .claude/worktrees/archive-dsh-openspec \ && openspec archive dsh-openspec -y ``` Ответ хука: ``` BLOCKED [guard-main]: запись в .claude/worktrees/archive-dsh-openspec — репозиторий /Users/andrey.epifancev/projects/cc-skills/claude-harness на main. В main только через PR. ``` Блокировка ложная по смыслу: `git worktree add` создаёт отдельный worktree на ветке `chore/archive-dsh-openspec`, и `openspec archive` выполнился бы уже в нём. Обход, который сработал: разнести на отдельные вызовы (worktree add, затем archive). Из `/tmp` с абсолютным путём та же цепочка проходила — это и сбило диагностику. ## Минимальное воспроизведение (парсер, без исполнения) ```bash python3 hooks/harness_target.py targets 'openspec archive foo -y' <repo> # file <repo> openspec archive python3 hooks/harness_target.py targets 'git worktree add .claude/worktrees/x -b feat/x origin/main && openspec archive y -y' <repo> # file <repo> openspec archive python3 hooks/harness_target.py targets 'cd <repo> && git worktree add .claude/worktrees/x -b feat/x origin/main && cd .claude/worktrees/x && openspec archive y -y' <repo> # file <repo>/.claude/worktrees/x openspec archive ``` `git worktree add …` сам по себе целей не даёт (спец-случай в `_git`), но следующий за ним `openspec archive` в той же цепочке даёт цель в каталоге, которого на момент разбора ещё нет; `resolve()` поднимается до объемлющего репозитория и берёт его ветку — main. ## Ожидаемое поведение Цель под `<path>` из `git worktree add <path> -b <branch>` в пределах той же команды MUST оцениваться по `<branch>`, а не по ветке объемлющего репозитория. ## Предложение В `parse()` запоминать пары «путь → ветка» для `git worktree add <path> -b|-B <branch>` и применять их в `decide_guard` к последующим целям в этом же вызове. Регрессия: случай в `tests/test-hook-parse.sh` (пути, как в воспроизведении выше) и кейс в корпус хуков. ## Цена Один провальный вызов и лишняя диагностика при каждом закрытии фичи; сообщение указывает на путь worktree, а не на настоящую причину. Обходной рецепт (разнести вызовы) стоит записать в `docs/HARNESS.md`, если код хука не будет меняться.
aep added this to the DSH port milestone 2026-10-24 20:44:25 +03:00
Author
Owner

Закрыто: PR #71 (коммиты 8d8dd89, e064de7). O-4 fixed; T1.1-T1.4, T1.6, T1.7 fixed e064de7; T1.5, T1.8, T2.1 — deferred, занесены в #70 (отдельный follow-up issue не нужен). Merge — по команде владельца 24.10.2026.

Закрыто: PR #71 (коммиты 8d8dd89, e064de7). O-4 fixed; T1.1-T1.4, T1.6, T1.7 fixed e064de7; T1.5, T1.8, T2.1 — deferred, занесены в #70 (отдельный follow-up issue не нужен). Merge — по команде владельца 24.10.2026.
aep closed this issue 2026-10-24 22:17:19 +03:00
Sign in to join this conversation.
No Label
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: aep/claude-harness#63
No description provided.