proposal, specs/hook-guards (16 требований), design с Decisions made without discussion. B1, B2, решение владельца 1; RT-1, RT-2, RT-6, RT-7. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
54 lines
4.9 KiB
Markdown
54 lines
4.9 KiB
Markdown
# 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.
|