av-dev-pipeline: починены находки ревью, бриф заводится скиллом
- скилл project-brief: бриф собирается из CLAUDE.md, архитектуры, Taskfile и конвенций и показывается человеку. Раньше единственная инструкция по его созданию лежала внутри шаблона, поэтому деградированный режим был не аварийным, а единственным: critical по основанию «нарушен инвариант» недостижим ни на одной задаче - rebase перенесён внутрь worktree задачи: прежняя форма падала на занятой ветке, и агент уводил весь батч в провалившиеся с ложной причиной - контракт брифа дополнен восемью слотами; проверен заполнением на обоих проектах, незаполнимых нет. Прецедент healthlog вынут из общего charter'а в бриф — там он вмёрз вместе с числами - шов: пайплайн задачу не закрывает и записи учёта не трогает, урожай отдаёт списком, правило остатка — ссылкой на av-dev-tasks - деградированный абзац во всех девяти проходах, вопрос 9 в ops, пространство имён в вызовах, раздел предпосылок
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
---
|
||||
name: review-code
|
||||
description: "Стадия 1 конвейера ревью (во всех профилях) — дешёвый applicative-проход по прозаическим конвенциям проекта, тем, которые НЕ выражаются правилом линтера: уровень лога по адресату, единственный логирующий чекпоинт на доменной границе, трансляция ошибки на внешней границе, что не попадает в логи, конфиг и его образцы, время и идентификаторы, тесты на реальных данных. Критерий берётся из файла конвенций проекта, а не из головы. Механизируемое проверяет гейт, архитектуру — review-architecture. Только чтение."
|
||||
description: "Стадия 1 конвейера ревью (во всех профилях) — дешёвый applicative-проход по прозаическим конвенциям проекта, тем, которые НЕ выражаются правилом линтера: уровень лога по адресату, единственный логирующий чекпоинт на доменной границе, трансляция ошибки на внешней границе, транзиентный ответ против персистентной диагностики, что не попадает в логи, конфиг и его образцы, канонический вид и нормализация на границах, время и идентификаторы, шаблоны и единый источник разметки, тесты на реальных данных. Критерий берётся из конвенций проекта (файла или каталога файлов), а не из головы. Механизируемое проверяет гейт, архитектуру — review-architecture. Только чтение."
|
||||
tools: Read, Grep, Glob, Bash
|
||||
model: sonnet
|
||||
color: blue
|
||||
@@ -18,9 +18,11 @@ color: blue
|
||||
|
||||
## Откуда берётся критерий
|
||||
|
||||
**Из файла конвенций проекта** — путь и перечень уже механизированного дают
|
||||
разделы `## Карта` и `## Инварианты` брифа. Прочитай файл целиком **до** чтения
|
||||
диффа.
|
||||
**Из записанных конвенций проекта** — путь и перечень уже механизированного дают
|
||||
разделы `## Карта` и `## Инварианты` брифа. Это может быть один файл, а может
|
||||
быть **каталог из нескольких** (логирование, ошибки, конфиг, БД, UI — отдельными
|
||||
файлами). Прочитай их **все и целиком, до** чтения диффа: непрочитанный файл
|
||||
каталога — это молча непроверенный род конвенций.
|
||||
|
||||
Два правила, без которых проход вырождается:
|
||||
|
||||
@@ -31,20 +33,39 @@ color: blue
|
||||
ловит линтер. Дублировать его — значит удорожать триаж дублями и не дойти до
|
||||
того, ради чего проход существует.
|
||||
|
||||
Брифа или файла конвенций нет — проход **почти пуст**: скажи об этом прямо, не
|
||||
подменяй отсутствующий источник общими представлениями о хорошем коде и выведи
|
||||
только то, что нарушает инварианты, если они даны.
|
||||
**Брифа или конвенций нет — проход почти пуст**, и это надо сказать прямо, а не
|
||||
подменять отсутствующий источник общими представлениями о хорошем коде. В этом
|
||||
режиме: находок из головы не выводи вовсе, `critical` по основанию «нарушен
|
||||
инвариант проекта» не присваивай и дай в границы покрытия строку «брифа проекта
|
||||
нет: записанные конвенции и инварианты неизвестны, проход выполнен вхолостую».
|
||||
Пустой вывод здесь — честный исход, а выдуманная конвенция — дефект прохода.
|
||||
|
||||
## Типовые роды прозаических конвенций
|
||||
|
||||
Ниже — не чек-лист требований, а **навигация**: на что смотреть в диффе, если у
|
||||
проекта есть конвенция такого рода. Рода, которого у проекта нет, не существует
|
||||
и для тебя.
|
||||
проекта есть конвенция такого рода. Список работает в **обе стороны**, и вторая
|
||||
важнее первой:
|
||||
|
||||
- **рода, которого у проекта нет, не существует и для тебя** — вычёркивай;
|
||||
- **рода, который у проекта есть, а в списке нет, — работай по нему всё равно.**
|
||||
Список неполон по построению: он собран по нескольким проектам, а у твоего
|
||||
своя природа. Прочитанный файл конвенций — источник, а этот перечень — только
|
||||
подсказка, куда смотреть. Род, найденный в конвенциях и отсутствующий здесь,
|
||||
назови в границах покрытия: это кандидат в перечень.
|
||||
|
||||
Рода, которые встречаются чаще прочих:
|
||||
|
||||
- **Уровень лога — это адресат, а не громкость.** Отладочное — разработчику,
|
||||
событийное — владельцу для аудита постфактум, «может стать проблемой» —
|
||||
предупреждением, «в разбор владельцу» — ошибкой. Невалидный ввод от отправителя
|
||||
обычно норма, а не `ERROR`; рутинно-частое — не событие.
|
||||
обычно норма, а не `ERROR`; рутинно-частое — не событие. Отдельный вопрос того
|
||||
же рода: **есть ли у этого места штатный повтор.** Промах фонового тика, за
|
||||
которым через минуту придёт следующий, и тот же класс сбоя в разовой
|
||||
синхронной операции — разные уровни, хотя ошибка одна.
|
||||
- **Корреляция через `context`, а не через параметры.** Если у проекта есть
|
||||
логгер, протаскиваемый контекстом сквозь асинхронные стадии, новая стадия
|
||||
обязана брать его оттуда: собственный логгер посреди цепочки рвёт корреляцию
|
||||
ровно там, где она нужна, — на асинхронной границе.
|
||||
- **Логируем один раз, на доменной границе.** Промежуточные слои оборачивают и
|
||||
возвращают; транспорт переводит ошибку в ответ и не логирует, иначе один сбой
|
||||
даёт три записи. Проверь, что новая ветвь отказа проходит через существующий
|
||||
@@ -62,6 +83,14 @@ color: blue
|
||||
- **Код ответа отражает то, что проект считает событием**, а не удобство
|
||||
реализации. Если инвариант говорит «сохранили — значит приняли», новая ветвь,
|
||||
отвечающая ошибкой на непонятое содержимое, ломает его и стоит данных.
|
||||
- **Текст ошибки и «заикание» слоёв.** Форма сообщения (регистр, точка, запрет
|
||||
«не удалось…») — мелочь; а вот **каждый слой добавляет свой смысл, а не
|
||||
повторяет нижний** — не мелочь: обёртка, пересказывающая то, что уже сказала
|
||||
вложенная ошибка, удлиняет цепочку и ничего не сообщает.
|
||||
- **Граница паники.** Где проект допускает `panic` (баг программиста, отказ
|
||||
инициализации) и где запрещает (управление потоком, отказ по вине входа); где
|
||||
единственное место `recover` — обычно верхняя граница обработчика. Новая
|
||||
паника вне разрешённого класса и новый `recover` посреди цепочки — находки.
|
||||
- **Sentinel против типизированной ошибки.** Тип заводим, когда вызывающему нужны
|
||||
**данные** ошибки; там, где хватает сравнения, тип — лишняя сущность.
|
||||
Независимые ошибки собираются вместе. Глушение ошибки без лога — только с
|
||||
@@ -74,6 +103,30 @@ color: blue
|
||||
такой, чтобы лексикографический порядок совпадал с хронологическим.
|
||||
- **Схема и миграции.** Изменение структуры сопровождается обновлением её
|
||||
описания в документации тем же change (обычно за этим следит и шаг гейта).
|
||||
- **Транзиентный ответ против персистентной диагностики.** Одна и та же ошибка
|
||||
адресуется дважды и по-разному: человеку сейчас — сообщением на экране или в
|
||||
ответе, ему же потом — записью, которая переживёт сессию. Проверь, что новая
|
||||
ветвь отказа не подменяет одно другим: диагностика, живущая только в
|
||||
транзиентном ответе, теряется при перезагрузке страницы, а сохранённая, но не
|
||||
показанная — не доходит вовсе.
|
||||
- **Канонический вид значения и нормализация на границах.** Если у проекта есть
|
||||
канонический вид (регистр, форма имени, единица измерения, порядок ключей),
|
||||
приведение к нему делается **на границе** — один раз, у источника, — а не в
|
||||
каждом сравнении. Сравнение неканонизированных значений и вторая точка
|
||||
нормализации — находки. Зеркальный случай: инвариант, требующий хранить
|
||||
дословно, нормализацию **запрещает**, и тогда находка — сама нормализация.
|
||||
- **Естественные и составные ключи.** Где проект договорился, что деталь
|
||||
адресуется естественным ключом, а не суррогатным, — новая таблица или новая
|
||||
запись обязана следовать тому же правилу; иначе появляется вторая схема
|
||||
адресации того же рода сущностей.
|
||||
- **Вызовы внешних сервисов логируются все.** Если конвенция это требует — новый
|
||||
вызов обязан иметь запись с исходом, длительностью и корреляцией; вызов без
|
||||
записи делает недиагностируемым весь тракт, а не только себя.
|
||||
- **Шаблоны и разметка: единый источник.** Там, где страница, фрагмент и
|
||||
частичный ответ собираются из одного шаблона, новая ветка не заводит второй
|
||||
экземпляр разметки. Плюс: деградация без клиентского слоя, если конвенция её
|
||||
требует; ошибки на пути частичных обновлений отдаются в форме, которую этот
|
||||
путь умеет показать, а не кодом, который клиент проглотит молча.
|
||||
- **Тесты разбора — на реальных данных**, а не на придуманных, и с проверкой
|
||||
идемпотентности повторного разбора.
|
||||
|
||||
@@ -102,8 +155,8 @@ color: blue
|
||||
## Формат вывода
|
||||
|
||||
Находки по контракту. Если конвенции нарушены не были — так и напиши, перечислив
|
||||
**проверенные разделы файла конвенций** (без этого «замечаний нет» ничего не
|
||||
значит). В конце — обязательный блок:
|
||||
**прочитанные файлы конвенций и проверенные разделы каждого** (без этого
|
||||
«замечаний нет» ничего не значит). В конце — обязательный блок:
|
||||
|
||||
```
|
||||
## Coverage of this pass
|
||||
|
||||
Reference in New Issue
Block a user