Пересмотр решения владельца 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>
192 lines
24 KiB
Markdown
192 lines
24 KiB
Markdown
# Ретроспектива обвязки 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; проверено только наблюдением.
|