claude-harness/docs/retro/2026-10-11.md
andrey.epifantsev 897fa0f3a7 feat: install.sh ставит allow-правила цикла фичи, --no-permissions для отказа (#24, 0.5.0)
Пересмотр решения владельца 2: allow-правила (git worktree, git branch
-m/-D, push фичевых и chore-веток, push --delete, tea issues/pulls
create/list/edit/comments) ставит install.sh в ~/.claude/settings.json,
а не владелец руками. Список — global/permissions.json; merge и push в
main в нём нет. Правила только дописываются, чужие не трогаются; копия
списка — ~/.claude/harness/permissions.json для doctor.sh.

- install.sh: шаг 5 — слияние permissions.allow; --no-permissions;
  неизвестный аргумент — ошибка; --check показывает permissions N/M.
- doctor.sh, «Машина»: ok / WARN со списком недостающих / MISS.
- adopt/new-project: строка push --delete — для --no-permissions.
- harness-doctor: агент чинит install.sh --no-permissions, права ставит
  владелец (иначе обход отказа классификатора auto mode).
- EnterWorktree не входит: вход в worktree вне .claude/worktrees/
  спрашивает подтверждение при любых правилах (#25).
- README, HARNESS.md, roles/dev.md, CLAUDE.md, ретро (пометка о
  пересмотре решения 2), CHANGELOG 0.5.0.

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

192 lines
24 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Ретроспектива обвязки claude-harness — 11.10.2026
Период: 02.10–11.10.2026, полигон — workspace `awp-ca` (АРМ КА: пять git-репозиториев рядом, workspace сам не git).
Предыдущая точка сравнения — `PILOT-2026-09-27.md` (один репозиторий, одна фича).
Источники: 47 транскриптов сессий Claude Code (`~/.claude/projects/-Users-andrey-epifancev-projects-awp-ca/*.jsonl`, 841 МБ),
47 файлов auto-memory того же проекта (179 КБ), код хуков, `HARNESS.md`, `PILOT-2026-09-27.md`, `CHANGELOG.md`.
Количественная часть считалась скриптами `scripts/retro_stats.py` и `scripts/retro_blocks.py` (только чтение транскриптов).
Качественная часть — прочтение всей памяти целиком.
Маркировка находок ретро: `RT-n`. Приоритет: P1 — теряет время каждую неделю или ломает процесс; P2 — трение; P3 — наблюдение.
Статус находки проставляется при закрытии бэклога (fixed / deferred / rejected), как и для любых других маркеров обвязки.
## 1. Цифры
| Показатель | Значение |
|---|---|
| Сессий (непустых) | 44 за 10 дней; 3 сессии больше 20 МБ транскрипта |
| Промптов владельца | 613 |
| Ходов модели / вызовов инструментов | 12 121 / 6 583 (Bash 4 302, Playwright ≈1 100, Read 346, Write 271, Edit 233) |
| Запусков сабагентов | 61 (sonnet 47, opus 9, модель не указана 5) |
| Вызовов skills | brainstorming 19, writing-plans 14, systematic-debugging 8, SDD 4, executing-plans 3, using-git-worktrees 3, TDD 1, finishing-a-development-branch 1, verification-before-completion 0, requesting/receiving-code-review 0 |
| Токены | вывод 18,3 М; чтение из кэша 3,82 Г; запись в кэш 145 М |
| Компакций контекста | 4 (в двух сессиях) |
| Стартовый контекст до первого промпта | медиана 56 К токенов (мин 52 К, макс 61 К); наши инструкции ≈39 КБ текста ≈ 13–16 К токенов, остальное — системный промпт и схемы инструментов |
| Блокировок хуков | 103 (guard-main Bash 91, guard-main Edit/Write 8, require-plan 3, прочие 1) |
| Отказов классификатора auto mode | 6 (Git Destructive 2, Auto-Mode Bypass 2, Interfere With Workloads 1, safety-check 1); отказов владельца — 6 |
| `codegraph init` в командах / вызовов `codegraph_explore` | 43 / 15 |
| `cd` в основной checkout на main (не `.wt/`) | 84 |
| Промптов «перечитай память/контекст» | 9 из 613 |
Сессии по ролям (эвристика по инструментам и первым промптам): разработка — 32 сессии, 377 промптов; администрирование
(Jira, Гант, спринт) — 7 сессий, 122 промпта, все за 10–11.10; QA/фронт (Playwright > 30 вызовов) — 5 сессий, 81 промпт.
Администрирование и QA — треть промптов, при этом вся обвязка и 44 из 47 файлов памяти написаны под разработчика.
## 2. Находки
### Хуки
**RT-1 (P1). Три четверти блокировок guard-main — ложные.** Из 91 блокировки Bash:
36 — команда только чтения с `2>/dev/null` (регулярное выражение хука считает `N>` записью);
27 — команда без единого паттерна записи в репозиторий (чтение памяти, `grep`, `cat`), заблокирована потому, что cwd оболочки
стоял на main-checkout; 8 блокировок Edit/Write пришлись на файлы вне любого репозитория (scratchpad сессии, файлы памяти) —
хук смотрит на cwd, а не на путь файла. Ещё около 20 — шаги самого процесса, которые хук не узнал: `git -C <repo> worktree add`
(исключение есть только для литерала `git worktree`), `mkdir -p .wt/<задача>` в не-git workspace, архивный
`git add openspec && git commit` (проверка staged идёт до `add`). Реальных перехватов записи в main за 10 дней — единицы
(`sed -i` по docs на main в сессии d60ad490). Нарушений main при этом не было ни одного: хук защищает, но ценой шума.
Корень: решение принимается по cwd оболочки, а не по цели записи. То же даёт RT-2.
Источники: `retro_blocks.py`, память `workspace-hooks-and-worktrees`, `q1-2025-run`, `osv-inn-mapping-rework`, `console-files-state`.
**RT-2 (P1). Общий cwd оболочки с фоновым SDD-контроллером.** Один `cd` в основной checkout из главной сессии переводит
контроллер и всех его implementer-ов в состояние `BLOCKED: shell write on main`, и они останавливаются. Правило «не cd, пока
контроллер работает» записано в шести файлах памяти, то есть повторяется, а не устранено. Устраняется вместе с RT-1: хук,
не зависящий от cwd, не ломается от чужого `cd`. Источники: память `slice-2a/2c/3a/3b-state`, `auto-confirm-64`, `arm-web-demo-prototype`.
**RT-3 (P1). Пункт 4 чеклиста закрытия (удалить ветку на сервере) стабильно не выполняется.** `git push origin --delete`
блокируется guard-main при cwd на main и отклоняется классификатором auto mode как Git Destructive / Auto-Mode Bypass
(4 из 6 отказов классификатора за период). Висящие серверные ветки упомянуты в 10 файлах памяти; владелец удаляет их руками.
Найденный опытным путём обход (push из worktree на не-main ветке) нигде в обвязке не описан. Один раз агент обошёл хук
через Gitea API, за что получил замечание (`feedback-no-harness-bypass`).
**RT-4 (P1). Правило «архив OpenSpec прямо в main» не работает в многорепозиторном workspace.** Глобальный guard-main
пропускает openspec-only коммиты, workspace-хук awp-ca запрещает любой commit/push в main без исключений. Итог: около 15
отдельных архивных PR, а поведение «то проходит, то нет» описано в памяти как урок. CLAUDE.md и фактическая практика расходятся.
**RT-5 (P2). Workspace-хук срабатывает на слово `commit`/`push` в любом месте команды**, включая `echo`, и на `reference-old-arm`
в командах удаления симлинков при сносе worktree (владелец удаляет симлинки сам: `slice-3a-state`, `hotfolder-direct-write-state`,
`core-33-golden-tests`).
**RT-6 (P2). У хуков нет регрессионных тестов.** `doctor.sh` делает самотест на нескольких случаях, но ни один из 103 реальных
инцидентов не стал тестом. Транскрипты содержат готовый набор: команда + вердикт хука + факт, была ли это запись в main.
### SDD, сабагенты, классификатор
**RT-7 (P2). После одного отказа хука классификатор auto mode отклоняет у сабагента последующие коммиты как «Auto-Mode Bypass».**
Владелец добавил allow-правила `git -C .wt/*`, `git add`, `git commit` вручную. Следствие RT-1: меньше ложных отказов — меньше каскадов.
**RT-8 (P2). Поднятый стенд ломает integration/e2e-тесты сабагентов** (общая queue group NATS на `recognition.result`).
Повторилось минимум 5 раз, каждый раз оформлено как deferred-находка, системно не починено. Агенту гасить стенд нельзя
(Interfere With Workloads), владелец делает через `!`. Это проектная находка, но обвязка должна давать место для «предусловий
окружения перед SDD» (один раз проверить, а не пять раз откладывать).
**RT-9 (P3). haiku-implementer подписывает коммиты своим trailer вместо указанного в плане** (пилот, R-5/R-7 в `console-files-state`,
O-5 в `slice-3a-state`); переписать нельзя из-за запрета force-push. Третий повтор одной находки.
**RT-10 (P3). Остановленный владельцем контроллер не возобновляется**, нужен новый контроллер «на добивку» (`slice-3b-state`).
Ledger при этом работает: возобновление без потерь подтверждено и на пилоте, и в срезах.
**RT-11 (P3). Агент один раз спросил режим исполнения вопреки CLAUDE.md** (`feedback-execution-mode-from-claude-md`), и один раз
начал задачу «не по харнесу» (сессия e08f3f0b, владелец перезапустил задачу). Процессные правила в 9 КБ глобального CLAUDE.md
плюс 16 КБ проектного читаются не всегда; это аргумент за короткие ролевые файлы (RT-14).
### codegraph
**RT-12 (P2). 43 `codegraph init` против 15 вызовов `codegraph_explore` за 10 дней**; Bash — 4 302. В памяти нет ни одного
свидетельства, что codegraph ускорил задачу; есть только «init сделан» как ритуал на каждый worktree и пустой ответ на пилоте.
При этом правило «implementer вызывает codegraph_explore вместо grep/Read» стоит в глобальном CLAUDE.md. Сервер отстаёт по версии
(1.6.0 при доступной 1.6.2).
### Память и контекст
**RT-13 (P1). Auto-memory стала журналом состояния срезов и дублирует Gitea.** 30 из 47 файлов имеют статус «ЗАКРЫТ» и
фиксируют «issue #N закрыта, PR #M слит, ветка удалена» — то, что по замыслу обвязки помнит Gitea. Факты внутри файлов
расходятся с индексом (`slice-4-state`: в индексе «ЗАКРЫТ», в файле «ждут мержа»; `logger-diagnose-state`: ветки «не удалены»
в тексте, «удалены» в индексе). Один файл (`jira-backlog-actualization`, 15 КБ) — журнал версий артефакта v27…v37.
Уникальные знания, ради которых память нужна, занимают малую долю: уроки по хукам, три файла фидбека владельца, рецепты QA
(стенд, Playwright, скриншоты), структура Jira и ловушки REST, решения владельца по OQ.
**RT-14 (P1). Одна обвязка на четыре роли.** Разработчик, администратор проекта, аналитик требований и QA работают в одном
проекте с одним CLAUDE.md, одним индексом памяти и одним процессом. В админ-сессии грузятся инварианты DBML и поток
superpowers→Gitea→OpenSpec; в дев-сессии — Jira-память. Специализированных агентов в обвязке нет вовсе (ни `~/.claude/agents`,
ни `.claude/agents`), SDD-контроллер описан текстом. Дизайн решения согласован отдельно (skill `/role`, файлы ролей, агенты
с собственной памятью, реорганизация индекса); здесь фиксируется как находка.
**RT-15 (P3). Стартовый контекст 56 К токенов, из них наши инструкции 13–16 К.** Роли срежут 8–10 К в не-дев сессиях, но
главный выигрыш от ролей — не токены, а отсутствие чужих правил. Платформенная часть (≈40 К) не наша.
### Процесс и чеклисты
**RT-16 (P2). Bounded-путь не требует обновления спек.** Bounded-PR arm-core #52/#53 изменили поведение API без правки
`openspec/specs`; понадобился отдельный аудит (#60, четыре PR). Для bounded нужен один пункт: «меняется поведение API/схемы —
спека обновляется в том же PR».
**RT-17 (P2). Сборка многорепозиторного worktree делается руками каждый раз**: симлинки fixtures/CLAUDE.md/.claude/reference-old-arm,
`.bounded`, venv, симлинк `node_modules`, `codegraph init`. Ловушки: `worktree remove` отказывает из-за симлинка `node_modules`;
относительный путь в `git worktree add` считается от репозитория, не от cwd. Около 25 bounded-задач и 7 срезов — столько же ручных сборок.
**RT-18 (P3). Skills завершения не используются**: finishing-a-development-branch 1 раз, verification-before-completion и
requesting-code-review 0 раз. Закрытие и ревью идут по чеклисту CLAUDE.md и через SDD. Это не обязательно плохо, но значит,
что превентивные проверки (verification) для bounded-задач не выполняются формально.
**RT-19 (P3). harness-check и adopt-project не оставили следов в awp-ca**: workspace не git, хук молчит. Для режима
«workspace из нескольких репозиториев» у обвязки нет ни проверки, ни бутстрапа; `doctor.sh` его тоже не знает.
**RT-20 (P3). Follow-up issues растут быстрее, чем закрываются**: за период создано около 40 follow-up issue по чеклисту п. 6
(core, tp, sg, docs, web). Механизм работает, но нет ритуала их разбора. Это кандидат на роль администратора.
## 3. Что сработало (сохранить)
- **guard-main защитил main**: за 10 дней ни одного коммита в main мимо PR. Все потери — ложные срабатывания, не пропуски.
- **Ledger SDD** переживает обрыв контроллера; возобновление без потерь подтверждено повторно.
- **Маркировка находок и follow-up issue**: находки не теряются между сессиями, каждая имеет статус.
- **`design.md` «Decisions made without discussion»**: десятки решений на срез, прослеживаемы после удаления ledger и чата.
- **Финальное ревью ветки на opus** реально находит дефекты (I-1…I-4 в #42, волна C-1/I-1/M-1…M-8 в 3b).
- **Golden-тесты** как гарант парсеров: 138/138, 113 снимков, порог `MIN_SNAPSHOTS`.
- **Чеклист закрытия** выполняется целиком в большинстве случаев; слабое место — только п. 4 (RT-3).
- **Фидбек владельца, записанный в память** (три файла), изменил поведение: сверка с макетом, запрет обхода хуков, режим исполнения.
- **Спека как источник истины** при рулингах (F-1 на пилоте, решения №15/№16 в 3a).
## 4. Бэклог улучшений (по приоритету)
| # | Что | Находки | Оценка |
|---|---|---|---|
| B1 | guard-main: решать по цели записи, не по cwd. Игнорировать `N>`/`N>&`; для Edit/Write брать ветку репозитория файла; для Bash — `git -C <dir>` или пути в команде; записи вне git-репозиториев не блокировать; исключения для `git -C … worktree add`, `mkdir -p .wt/`; архивная проверка по путям в команде | RT-1, RT-2, RT-7 | 1 день + тесты |
| B2 | Регрессионные тесты хуков на реальных командах из транскриптов (103 случая → фикстуры с ожидаемым вердиктом); запуск из `doctor.sh` | RT-6 | 0,5 дня |
| B3 | Закрытие п. 4: явный рецепт в CLAUDE.md и HARNESS.md (push --delete из worktree на ветке фичи) либо allow-правило в проектных настройках по решению владельца; перестать перекладывать на владельца | RT-3 | 0,5 дня |
| B4 | Политика архива OpenSpec: либо «всегда отдельным PR» (как фактически), либо workspace-хук учится исключению openspec-only. Привести CLAUDE.md к выбранному | RT-4 | 0,5 дня |
| B5 | Роли: skill `/role`, файлы ролей (общие в обвязке, проектные в `.claude/roles/`), агенты с собственной памятью (`jira-admin`, `qa-runner`, `briefing`), подсказка роли по `session_title` | RT-14, RT-11, RT-15 | 2–3 дня |
| B6 | Политика памяти: состояние задачи живёт в Gitea (комментарий к issue при закрытии), в память — только уроки, фидбек, знания роли; при «закрывай» файл задачи сворачивается в строку реестра; индекс по ролям; одноразовая чистка 47 файлов | RT-13 | 1 день + чистка |
| B7 | Скрипт сборки/сноса многорепозиторного worktree (`wt-new`, `wt-rm`): симлинки, `.bounded`, venv, `node_modules`, (codegraph по флагу); режим «workspace из репозиториев» в `doctor.sh` и `harness-check` | RT-17, RT-19 | 1 день |
| B8 | codegraph: вывести из обязательного потока (без `init` на worktree и без правила «вместо grep»), оставить опциональным; решение владельца, нужны ли замеры | RT-12 | 0,5 дня |
| B9 | Bounded-чеклист: пункт про спеки при изменении API/схемы; verification-before-completion перед PR | RT-16, RT-18 | 0,5 дня |
| B10 | Workspace-хук: искать `git … commit/push` как команду, а не как слово; `reference-old-arm` только для `rm`-целей, не для симлинков | RT-5 | 0,5 дня |
| B11 | SDD: раздел «предусловия окружения» в плане (стенд погашен, порты свободны); trailer коммита проверяется ревьюером задачи | RT-8, RT-9 | 0,5 дня |
| B12 | Регулярное ретро: skill `/harness-retro` на этих скриптах, метрики: доля ложных блокировок, отказы классификатора, стартовый контекст, невыполненные пункты закрытия, размер памяти; триггер — по команде после среза | все | 1 день |
Порядок, который предлагается: B1+B2 (убирают главный источник трения и каскад RT-7), затем B5+B6 (роли и память — одно
изменение, так как индекс памяти перестраивается под роли), затем B3/B4/B10 (мелкие правила), B12, остальное по мере надобности.
## 5. Решения владельца (11.10.2026)
1. **Архив OpenSpec — всегда отдельным PR.** Исключение openspec-only из guard-main и из CLAUDE.md убирается; правило
«в main только через PR» становится без исключений. (B4 → переформулирован.)
2. **Удаление серверных веток — allow-правило в настройках проекта.** Строку правила владелец добавляет сам; обвязка даёт
готовую строку в `adopt-project.sh` и в отчёте `doctor.sh`. Чеклист закрытия п. 4 остаётся за агентом. (B3.)
*Пересмотрено 23.10.2026 (#24): правило вместе с остальными allow-правилами цикла фичи ставит `install.sh`
в `~/.claude/settings.json`; отказ — `--no-permissions`, тогда строку по-прежнему печатают adopt/new-project и doctor.*
3. **codegraph — оставить и замерить.** Один срез с обязательным codegraph и подсчётом вызовов `codegraph_explore` против
Bash/Read в тех же задачах; решение после замера. Метрика входит в `/harness-retro`. (B8 → замер, не вывод из потока.)
4. **Память — политика «состояние задачи в Gitea, в память только уроки, фидбек и знания роли» и одноразовая чистка
47 файлов по ролям.** Закрытые срезы сворачиваются в реестр (строка на задачу: PR, follow-up); чистка на копии, с бэкапом,
дифф показывается до замены. (B6.)
5. Роли: состав агентов на первом шаге решается в спеке ролей (предложено: `jira-admin`, `qa-runner`, `briefing`;
аналитику — файл роли без агента).
## 6. Что не удалось измерить
- Время, потерянное на каждую ложную блокировку: транскрипт не содержит длительности исправления, только факт.
- Польза codegraph: нет ни одного замера «с ним / без него».
- Доля решений в `design.md`, которые владелец потом пересмотрел: нужен разбор архивов OpenSpec, не делался.
- Поведение памяти вне git (slug по cwd) не описано в документации Claude Code; проверено только наблюдением.