Ревью трансформации нашло, что тема 78 спорит сама с собой в четырёх местах. Учёт был отдан агенту, хотя перечень оркестратора объявлен закрытым, а границы задания прямо говорят «задач не заводит»: вызов av-dev:task-track вернулся оркестратору, агенту третьего такта осталось письмо в документы. Ветка отказа не была покрыта — на ответе «ничего» правка первого такта уезжала в коммит невычитанной и с непрогнанным гейтом. Теперь третий такт идёт всякий раз, когда была реплика; не идёт он только тогда, когда реплики не было вовсе. Дом правила вычитки в doc-sync знает про два захода. Барьер карты кластеров из сценария «задачи из ревью и аудита» снимается там, где его уже прошли: список показан человеку и получил ответ. При прямом вызове и вызове из code-deep-review карта по-прежнему вопрос. Счёт стопов сведён в таблицу по сценариям; у обслуживания появился второй заход и одна реплика с поводом «новый запрет или инвариант». Сигнал сверки считается по архиву change и каталогу задач разом — иначе chore и research не считались вовсе — и вошёл в возврат агента и в доклады трёх сценариев. Ось «род правки документа» внесена в перечень осей. Журнал — тема 80; отложенный старший долг назван в С287.
184 lines
17 KiB
Markdown
184 lines
17 KiB
Markdown
---
|
||
name: doc-healthcheck
|
||
description: "Проверка здоровья документации проекта судом, а не машиной: не разошлись ли документы между собой и с кодом. Зовёт двух агентов на весь канон разом — doc-consistency (один факт в двух домах, прямое противоречие, поведение в architecture.md вместо спек, ADR без парного статуса, число без происхождения) и doc-code-drift (протухший факт: имя ветки, команды, пути, зависимости поимённо, настройки с числом, единые точки, capability). Разбирает урожай порциями: строка на замену идёт в документ сразу, работа больше абзаца становится задачей. Прогон оставляет след — ключ [docs] healthcheck_last в .av-dev.toml, — и по нему синк документации считает, сколько задач сделано с прошлой сверки, и выдаёт сигнал строкой. Использовать, когда с прошлой сверки сделан десяток задач, когда вернулись к проекту после перерыва, перед тем как опереться на документ в решении, а также шагом adopt и upgrade. Дорого — не на каждой задаче. Раскладку и версию раскладки проверяет скилл av-dev:canon, язык документов — агент doc-wording."
|
||
---
|
||
|
||
# Здоровье документации
|
||
|
||
Проверяет то, **чего машина не видит**: разошлись ли документы между собой и с
|
||
кодом. Раскладка, версия, битые ссылки, нетронутые плейсхолдеры — это `canon
|
||
check` и его скрипт; здесь начинается там, где кончается `docs.py`.
|
||
|
||
Разрез проверяемый: **машина сверяет форму, этот скилл — утверждения**. «В
|
||
`architecture.md` есть раздел» проверит скрипт. «В `architecture.md` написано,
|
||
что зависимость одна, а в манифесте их три» — суждение, и его выносит агент.
|
||
|
||
## Когда звать
|
||
|
||
**Зовёт человек**, но признак наблюдаемый, а не календарный:
|
||
|
||
- **с прошлой сверки сделан десяток задач.** Документы протухают ровно от
|
||
сделанной работы: переименованная цель сборки, ушедшая зависимость, второй
|
||
способ делать то, что обзор объявил единственным, факт, дописанный в
|
||
`architecture.md` и уже живущий в `CLAUDE.md`. **Этот признак считается, а не
|
||
вспоминается**: счёт ведёт синк документации по следу прошлого прогона и
|
||
выдаёт строкой на каждой сделанной задаче (`av-dev:doc-sync`, раздел «Сигнал
|
||
сверки»);
|
||
- **вернулись к проекту после перерыва** — прежде чем опираться на написанное;
|
||
- **перед тем как опереться на документ в решении**, если оно дорогое;
|
||
- шагом `adopt` и шагом `upgrade` — их зовёт скилл `canon` сам.
|
||
|
||
**Не на каждой задаче и не на каждом синке документации.** Цена реальная:
|
||
`doc-consistency` идёт на `opus`, потому что сличение утверждений — суждение;
|
||
`doc-code-drift` хоть и на `sonnet`, но читает репозиторий целиком. Прогон по
|
||
каждой сделанной задаче был бы самой дорогой церемонией процесса, а находок дал
|
||
бы почти те же: документы расходятся не с одной задачи, а с десятка.
|
||
|
||
Прежде оба звались шагом сессии между спринтами. Спринтов нет, и **момент
|
||
пришлось назвать заново** — иначе их не звал бы никто, кроме разовых `adopt` и
|
||
`upgrade`, то есть на живом проекте никогда.
|
||
|
||
## Чего может не быть
|
||
|
||
**Копия.** Дом правила — `shared/absence.md` в репозитории плагина.
|
||
Правится дом, а не этот файл.
|
||
|
||
<!-- копия: отсутствие из av-dev/shared/absence.md -->
|
||
|
||
**Скилл не вправе считать раскладку проекта полной.** Части заводятся порознь и
|
||
живут порознь; каждая узнаётся своим следом:
|
||
|
||
| Чего нет | Как видно | Чего теперь не делает никто |
|
||
| --- | --- | --- |
|
||
| настройки av-dev | нет `.av-dev.toml` в корне | проект под процесс не заводился; версии нет, настроек нет |
|
||
| документы канона | нет `docs/` | проектную конкретику брать неоткуда — темы, инварианты, прецеденты |
|
||
| учёт работ | нет каталога задач | запись остаётся владельцу: назови её текстом в докладе |
|
||
| источник требований | нет `openspec/config.yaml` | цикл SDD не запускается: спеки не с чем сверять |
|
||
|
||
**Свой скилл зовётся полным именем** — `av-dev:canon`, `av-dev:task-track`,
|
||
`av-dev:code-review`. Короткое имя может разрешиться в устаревшую проектную
|
||
копию из `.claude/skills/`, и подмены не будет видно ни в докладе, ни в
|
||
поведении.
|
||
|
||
**Внешний плагин может не стоять.** Их два: `opsx:*` — цикл SDD, и
|
||
`av-dev-git:commit` — сообщения коммитов. Путь в дерево чужого плагина не
|
||
пишется никогда: `$CLAUDE_PLUGIN_ROOT` ведёт только в своё дерево, а
|
||
вычисленный от него путь к соседу либо не откроется, либо откроет чужую
|
||
установку. Нужен чужой справочник — зови владеющий им скилл, он прочитает его
|
||
сам.
|
||
|
||
**Отсутствие — исход, а не поломка.** Назови строкой доклада, чего теперь не
|
||
делает никто, и продолжай работу. Молчать нельзя: пропуск неотличим от
|
||
сделанного. Выдумывать обходной путь нельзя тоже.
|
||
|
||
**Присутствие узнаётся следом в проекте, а не объявлением.** Перечня того, что
|
||
здесь заведено, проект не ведёт — он разошёлся бы с действительностью молча.
|
||
|
||
<!-- /копия: отсутствие -->
|
||
|
||
Здесь сосед один: `av-dev:task-track`, когда находка тянет на задачу. Его нет —
|
||
находки остаются списком в докладе, и это говорится строкой.
|
||
|
||
## Пачка — весь канон, и это не расточительство
|
||
|
||
Оба агента зовутся **на весь канон разом**, а не на пачку, отобранную работой.
|
||
|
||
Когда пачку отбирала работа, без присмотра оставалось ровно то, чего работа не
|
||
касалась: правка, отменившая решение, живёт в одном документе, а парный статус
|
||
нужен в другом; факт, продублированный год назад, не попадёт ни в один диапазон
|
||
диффа. Канон мал — он читается целиком, и цена этого известна заранее.
|
||
|
||
## Кого зовёшь и что передаёшь
|
||
|
||
| Агент | Что смотрит | Читает | Модель |
|
||
| --- | --- | --- | --- |
|
||
| `doc-consistency` | смысловой дубль, прямое противоречие между документами, поведение в `architecture.md` вместо спек, ADR без ссылки и парного статуса, число без происхождения, заглушка вместо честной строки | `docs/`, `openspec/` | `opus` |
|
||
| `doc-code-drift` | протухший факт: имя ветки, команды, пути, зависимости поимённо, настройки с числом, единые точки проекта, capability | весь репозиторий | `sonnet` |
|
||
|
||
**`doc-code-drift` обязан получить раздел запретов `CLAUDE.md`.** Он гоняет
|
||
команды — только читающие, — и без перечня запретов не знает, чего в этом
|
||
проекте запускать нельзя. Не передал — он либо остановится, либо тронет то, чего
|
||
трогать не следовало.
|
||
|
||
**Судит не тот, кто писал.** Ни один из двоих ничего не правит: оба возвращают
|
||
готовые формулировки, подставляешь ты. Самопроверка документа слабее всего ровно
|
||
там, где формулировка казалась удачной при написании.
|
||
|
||
Одного из двух можно позвать отдельно — но **скажи в докладе, кого именно
|
||
позвал**. Доклад, умолчавший об этом, читается как «сверено целиком».
|
||
|
||
## Разбор урожая
|
||
|
||
Находки — обычный материал правки, и разбирать их надо **порциями**, а не одним
|
||
заходом: тридцать находок подряд получают «принято» не потому, что верны, а
|
||
потому, что разбор затянулся.
|
||
|
||
По каждой находке ровно три исхода:
|
||
|
||
1. **Строка на замену** — правь документ сразу. Формулировка уже готова, спорить
|
||
не с чем, и откладывание превращает её в задачу дороже самой правки.
|
||
2. **Работа больше чем на абзац** — задача типа `chore`. Заводит её **не этот
|
||
скилл**: вызови Skill `av-dev:task-track`, у него свой формат, дедупликация
|
||
против беклога и кладбища. Каталога задач в проекте нет — отдай списком в
|
||
докладе и скажи это строкой.
|
||
3. **Не находка** — агент ошибся, документ прав. Скажи это прямо: неразобранная
|
||
находка и отклонённая различаются, и вторая экономит время на следующем
|
||
прогоне. Класс ошибок, который повторяется, идёт в `docs/review.*`, раздел
|
||
настройки, — там дом типовых ложноположительных.
|
||
|
||
## След прогона
|
||
|
||
**Последним шагом прогон правит `.av-dev.toml`** — ключ `healthcheck_last` в
|
||
секции `[docs]`: хеш коммита `HEAD` и дата комментарием рядом. Состав ключей —
|
||
[канон](../canon/references/canon.md), раздел `.av-dev.toml`; правится **строка**,
|
||
а не файл целиком.
|
||
|
||
**Секцию и имя ключа не выбирай сам.** Неизвестный ключ `.av-dev.toml` — отказ
|
||
кодом 3, а не пропуск: ключ, заведённый мимо константы скрипта-владельца, роняет
|
||
`docs.py`, `tasks.py` и гейт проекта разом. Этот ключ там уже назван
|
||
(`DOCS_KEYS` в `av-dev/skills/canon/scripts/docs.py`), а любой другой пришлось бы
|
||
заводить правкой скрипта.
|
||
|
||
**Без следа признак «десяток задач» не считается никем.** Так и было: сверку
|
||
звали по памяти, то есть не звали — тот же прозаический триггер, что дал 6
|
||
записей ADR на 43 изменения. След превращает признак в число, которое
|
||
`av-dev:doc-sync` считает командой
|
||
`git rev-list --count <last>..HEAD -- openspec/changes/archive` и говорит вслух
|
||
на каждой задаче.
|
||
|
||
Ключ **необязательный и заводится сам** — первым же прогоном сверки; проекту для
|
||
этого делать нечего. Его отсутствие значит «сверки не было ни разу», и синк
|
||
говорит это отдельной строкой.
|
||
|
||
**Позвал одного агента из двух — след всё равно ставится, но в докладе назван
|
||
неполным.** Иначе следующая сверка отсчитывалась бы от прогона, который смотрел
|
||
половину.
|
||
|
||
## Доклад
|
||
|
||
- **Кого позвал** — обоих или одного, и почему одного.
|
||
- Находки по каждому агенту: сколько, что поправлено сразу, что стало задачей
|
||
(со слагами), что отклонено и почему.
|
||
- **Границы покрытия**: что смотрели и чего не смотрели. У `doc-code-drift` она
|
||
идёт из его собственного отчёта — перечень фактов у него закрытый, и он
|
||
называет, какие из них проверить было нечем.
|
||
- Канона в проекте нет вовсе — это исход, а не пустой прогон: скажи строкой и
|
||
предложи `av-dev:canon`.
|
||
|
||
## Чего этот скилл не делает
|
||
|
||
- **Не проверяет раскладку, версию и ссылки** — это `canon check`, там машина.
|
||
- **Не судит язык** документов: залог, англицизмы, жаргон, термин без дома — это
|
||
агент `doc-wording`, и зовут его отдельно, по пачке правленных документов.
|
||
Звонящие у него названные — последний заход синка в `av-dev:doc-sync`, шаг
|
||
вычитки сценария разведки (`av-dev:code-resolve`), шаг 9 `av-dev:doc-init` и
|
||
шаг вычитки в обоих режимах `canon`, — просто ни один из них не здесь. У него
|
||
другой ритм: он нужен там, где текст только что писали, а
|
||
не там, где он год лежал. Оркестровать его нечем — он один и работает по
|
||
названному списку.
|
||
- **Не правит документы за агентов** — они возвращают формулировки, решение
|
||
подставить принимает человек или ты по его правилу.
|
||
- **Не заводит задачи** — этим владеет `av-dev:task-track`.
|
||
- **Не решает, когда себя звать.** Признак считает синк и говорит строкой; часы
|
||
на прогон тратит человек своим словом.
|