andrey.epifantsev 6b7a073f6f chore(openspec): архив hooks-write-target, спека hook-guards в openspec/specs (#6)
openspec archive hooks-write-target: change перенесён в
openspec/changes/archive/2026-10-16-hooks-write-target/, дельта применена —
openspec/specs/hook-guards/spec.md (20 требований), validate --strict проходит.

Ссылки на путь спеки в harness_target.py, hook_cases_build.py и CHANGELOG
переведены на openspec/specs/hook-guards/spec.md; в CLAUDE.md «Текущая работа»
B1+B2 переведены в «Сделано» (PR #12, follow-ups — #13).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 10:16:06 +04:00

4.9 KiB
Raw Blame History

Proposal: хуки решают по цели записи

Issue: #6. Источники: ретро docs/retro/2026-10-11.md — B1, B2, решение владельца 1; находки RT-1, RT-2, RT-6, RT-7.

Why

guard-main решает по тексту команды и по cwd оболочки, а не по тому, куда идёт запись. По подсчёту ретро около трёх четвертей блокировок за период пилота ложные: 2>/dev/null считается записью, grep "npm i" — установкой пакета, Edit файла памяти вне репозитория — записью в main, потому что cwd стоит на main-checkout (RT-1). Чужой cd останавливает фоновый SDD-контроллер (RT-2), отказ хука запускает каскад отказов классификатора auto mode (RT-7). Реальных нарушений main за тот же период — ноль, перехват по делу — единицы. Регрессионных тестов на реальных командах у хуков нет (RT-6), поэтому любая правка регулярного выражения проверяется только в бою. require-plan болен тем же: корень, ветку, план и code-paths он берёт от cwd, а не от репозитория правимого файла.

What Changes

  • guard-main определяет цели записи — файлы и git-мутации — и решает по ветке репозитория каждой цели. cwd служит только базой для относительных путей.
  • Неразрешимая файловая цель пропускается; git-мутация с неопределённым репозиторием блокируется.
  • git push считается записью в main, только если он пушит в main; push origin <feature> и push origin --delete <feature> из main-checkout проходят.
  • BREAKING: исключение для openspec-only коммитов и для openspec archive на main удаляется (решение владельца 1: архив всегда отдельным PR). Правила процесса уже приведены к этому в 0.3.0 (roles/dev.md); меняется поведение хука.
  • pip install больше не блокируется (пишет в окружение, не в репозиторий); npm/yarn/pnpm install в репозитории на main — блокируется, как и раньше.
  • require-plan берёт корень, ветку, .claude/code-paths, .bounded и планы из репозитория правимого файла.
  • Сообщения блокировки получают стабильный префикс BLOCKED [guard-main]: / BLOCKED [require-plan]:, называют цель и выход.
  • Регрессионный корпус: 126 записей из транскриптов плюс живые случаи, каждая с ожидаемым вердиктом; прогон из tests/run.sh (источники) и из doctor.sh (установленные копии).
  • Экстрактор hook_blocks_export.py выгружает только настоящие ошибки хуков.

Capabilities

New Capabilities

  • hook-guards: блокирующие хуки обвязки — защита main/master/detached HEAD от записи (guard-main), требование плана для правок в коде (require-plan), их регрессионный корпус.

Modified Capabilities

Нет: openspec/specs/ пуст, это первая capability обвязки.

Impact

  • Код: hooks/guard-main.sh, hooks/require-plan.sh (становятся обёртками), новый hooks/harness_target.py (stdlib python3, новых зависимостей нет), install.sh (копирование и --check), skills/harness-doctor/ (корпус, песочница, раннер, строка в отчёте), docs/retro/scripts/hook_blocks_export.py.
  • Тесты: tests/test-hook-parse.sh, tests/test-hook-corpus.sh, случаи require-plan.
  • Документация: README.md, docs/HARNESS.md, CLAUDE.md и ARCHITECTURE.md репозитория, roles/dev.md (уточнение про cd), CHANGELOG.md 0.4.0.
  • Установленные копии обновляются повторным bash install.sh; регистрация хуков в settings.json не меняется.
  • Вне задачи: B3 (allow-правило удаления веток), B4 кроме решения 1, B10 (workspace-хук awp-ca), запись в код через Bash для require-plan.