- параллельно гоняем только по явной просьбе И с явно названным набором проходов или стадии; просьба без набора основанием не считается - обосновывается отступление, а не умолчание - пару adversary + ops не параллелим даже по просьбе без переспроса: оба меряют одно железо, испорченный оракул хуже отсутствующего - параллельный прогон объявляется в отчёте с составом, а замеры из него идут в границы покрытия как ослабленные
238 lines
19 KiB
Markdown
238 lines
19 KiB
Markdown
---
|
||
name: healthlog-task-pipeline
|
||
description: Автономно проводит задачу healthlog через полный цикл SDD — от выбора в беклоге до коммита (opsx explore→propose→ревью спек→apply→ревью кода→archive→чистка беклога). Использовать, когда пользователь просит взять/сделать задачу из беклога или довести идею до реализации.
|
||
---
|
||
|
||
# Пайплайн задачи (healthlog)
|
||
|
||
Оркестратор одной задачи по Spec Driven Development: проводит её от беклога до
|
||
коммита максимально автономно, привлекая пользователя **только на реальных
|
||
развилках** (компромиссы, изменение scope, угроза инвариантам). Механику не
|
||
согласовываем — делаем.
|
||
|
||
Перед стартом прочитай `CLAUDE.md`, а также `README.md`, `docs/architecture.md`,
|
||
`docs/conventions.md`, если ещё не в контексте. Это тонкая обёртка над
|
||
каноническими скиллами `opsx:explore` / `opsx:propose` / `opsx:apply` /
|
||
`opsx:archive` — вызывай их через Skill, не переизобретай их шаги.
|
||
|
||
## Что нельзя сломать
|
||
|
||
healthlog — хранилище данных о здоровье, у которого источник (телефон) шлёт
|
||
непрерывно и молча. Отсюда особенности, которых нет в обычном сервисе:
|
||
|
||
- **Поток не останавливается на время задачи.** Сервис поднят в контейнере
|
||
(`task up` / `task restart`), данные в `./data`. Перезапуск на пару секунд
|
||
безопасен — дыру закроют средний и глубокий проходы синхронизации; а вот
|
||
сломанный приём, оставленный работать, теряет данные необратимо.
|
||
- **Потерянная доставка не восстанавливается.** Тело, не попавшее в архив, в
|
||
журнал не попадает вовсе: телефон его не перешлёт. Разобранное же всегда
|
||
пересобираемо свёрткой, поэтому цена ошибки разбора и цена ошибки приёма
|
||
различаются на порядок. Любая правка разбора, слияния или вывода слоя — это
|
||
`deep`-профиль ревью, без исключений.
|
||
- **Данные чувствительны.** Ничего из `./data` не попадает ни в git, ни в
|
||
логи выше `DEBUG`, ни в вывод агента. Гейт проверяет первое механически
|
||
(`no-health-data`), остальное — на тебе.
|
||
- **Разведка уже проведена.** `docs/local-research.md` — 46 находок на живом
|
||
потоке, половина расходится с документацией HAE. Проверь там, прежде чем
|
||
строить догадку о формате: скорее всего вопрос уже закрыт измерением.
|
||
|
||
## Принцип автономности
|
||
|
||
**Умолчание — делать, а не спрашивать.** Задача доводится до коммита без
|
||
участия человека; предполагается, что так пройдёт большинство задач.
|
||
|
||
Наткнулся на вопрос, который решать не тебе, — **не останавливайся и не
|
||
спрашивай**. Вынь его блокером и продолжай:
|
||
|
||
1. Заведи пункт в секции `блокеры` беклога:
|
||
`backlog.py add --slug <slug> --priority блокеры --hook <что заблокировано>`.
|
||
Тело отвечает на три вопроса: **что именно решить**, **какие есть варианты
|
||
и цена каждого**, **что стоит, пока решения нет**. Плюс твоя рекомендация —
|
||
человек чаще соглашается, чем выбирает заново, и готовое суждение экономит
|
||
ему весь контекст.
|
||
2. **Переформулируй задачу на остаток** — то, что делается без этого решения.
|
||
Впиши в её тело ссылку на блокер и границу: докуда доводим сейчас.
|
||
3. Доведи остаток до конца и закоммить. Задача не «висит на вопросе», она
|
||
сделана в объявленных границах.
|
||
|
||
Если полезного остатка нет вовсе — блокер заводится, задача остаётся на месте
|
||
со ссылкой на него, и берётся следующая. Это редкий случай; чаще остаток есть.
|
||
|
||
Блокеры разбираются пачками, а не по одному: прерывать поток ради каждого
|
||
дороже, чем накопить.
|
||
|
||
### Когда всё-таки спрашивать
|
||
|
||
Узко и по другому основанию — не «сложное решение», а **необратимое действие**:
|
||
|
||
- деплой, выкладка наружу, смена публичного адреса или токенов;
|
||
- удаление или перезапись данных в `./data`, включая подрезку архива;
|
||
- всё, что уходит за пределы машины.
|
||
|
||
Здесь ошибка не откатывается коммитом, поэтому спрашиваем даже когда решение
|
||
кажется очевидным. Развилка в дизайне — блокер; необратимое действие — вопрос.
|
||
|
||
Стиль правок — заточка под проект и конвенции, right-size, без золочения.
|
||
|
||
## Шаги
|
||
|
||
### 1. Выбрать / прочитать задачу
|
||
|
||
- Если задача задана (slug, файл в `docs/backlog/` или описание) — прочитай её
|
||
файл и связанные спеки/черновики.
|
||
- Если не задана — выбирай сам: верхняя секция приоритета, не `[idea]`, не
|
||
заблокированная целиком. Из равных бери ту, что разблокирует больше других.
|
||
Выбор объявляешь в докладе, а не согласовываешь заранее.
|
||
- Задача с префиксом `[idea]` (ещё без решения «делаем») — сперва обязательно
|
||
через explore (шаг 2), там она либо становится задачей, либо остаётся идеей.
|
||
|
||
Формат файла задачи и индекса держит скилл `backlog` — здесь мы беклог только
|
||
читаем. Если по ходу выбора вскрылось, что задача устарела, дублируется или
|
||
разрослась в эпик, это работа для скилла `backlog`, а не для пайплайна.
|
||
|
||
Оцени тривиальность (влияет на шаг 4):
|
||
- **Тривиальная** — локальная правка без изменения поведения/спек/схемы БД,
|
||
очевидное решение. Explore и ревью спек пропускаем.
|
||
- **Нетривиальная** — новое/изменённое поведение, дизайн-развилки, затрагивает
|
||
инварианты, схему БД или несколько capability. Полный цикл.
|
||
|
||
### 2. (Опц.) Груммить идею — `opsx:explore`
|
||
|
||
Только для `[idea]`-задач или когда постановка мутная. Вызови Skill
|
||
`opsx:explore`. Развилку грумминга не выноси на человека — заведи блокером и
|
||
груми остаток. Выход: ясная постановка, готовая к propose. **В explore не
|
||
пишем код.**
|
||
|
||
### 3. Завести change — `opsx:propose`
|
||
|
||
Вызови Skill `opsx:propose`. Получаем `proposal.md`, дизайн (для нетривиальных),
|
||
дельта-спеки (`ADDED`/`MODIFIED`/`REMOVED Requirements`), `tasks.md`. Каждое
|
||
`### Requirement` содержит `SHALL`/`MUST`; структурные заголовки английские,
|
||
сценарии `GIVEN/WHEN/THEN`. Прогони `openspec validate --strict <id>`.
|
||
|
||
### 4. (Нетривиальная) Ревью предложения — профиль `design`, ДО кода
|
||
|
||
Первый чекпоинт ревью-процесса. Вызови Skill **`healthlog-review-pipeline`** с профилем
|
||
`design` и ссылкой на change `<id>`. Он запустит `healthlog-review-specs` (режим
|
||
«дизайн/спеки ДО кода»), `healthlog-review-rubric` (фаза 1: приёмочные критерии
|
||
для задуманного узла) и `healthlog-review-architecture` по предложению.
|
||
|
||
Смысл профиля: архитектурная находка на готовом коде стоит переписывания и
|
||
потому игнорируется — та же находка здесь стоит абзаца обсуждения. Рубрику из
|
||
`healthlog-review-rubric` перенеси в `tasks.md` как приёмочные критерии.
|
||
|
||
### 5. Отработать замечания ревью предложения
|
||
|
||
- Мелочь и явные улучшения — правь сам в спеках/дизайне.
|
||
- Развилки (компромисс, scope, инвариант) — блокером, спеки урезаются на
|
||
остаток.
|
||
- После правок перепрогони `openspec validate --strict <id>`.
|
||
|
||
### 6. Написать код — `opsx:apply`
|
||
|
||
Вызови Skill `opsx:apply` для реализации `tasks.md`. Код по конвенциям
|
||
`docs/conventions.md`: ошибки stdlib с `%w`/`errors.Is`, логи только `slog` без
|
||
секретов и тел запросов, время в UTC через `store.Now()`, ULID через
|
||
`internal/ident`, миграции goose. Меняешь схему — обнови ER-схему
|
||
`docs/database.md` в том же change (гейт это проверяет).
|
||
|
||
Прогони `task gate` и добейся зелёного — он же гейт следующего шага.
|
||
|
||
**Поведенческая верификация.** Если задача меняет реальное поведение (новый
|
||
эндпоинт, разбор входа, схема БД, форма ответа) — зелёных юнит-тестов мало.
|
||
Подними изменение вживую: `task restart`, затем прогони сценарий по настоящим
|
||
данным из `./data` (89+ доставок реального потока) или скриптом из
|
||
`tmp/research/`. Пропусти только для чисто внутренних правок без наблюдаемого
|
||
рантайма.
|
||
|
||
**Сервис не оставляем лежать.** Если `task restart` упал — почини или откати
|
||
до конца шага: телефон продолжает слать всё это время.
|
||
|
||
### 7. Ревью кода — Skill `healthlog-review-pipeline`
|
||
|
||
Второй чекпоинт. Вызови Skill **`healthlog-review-pipeline`**, дав ссылку на change
|
||
`<id>`, базу диффа, профиль **и режим запуска**. Профиль выбирается по факту
|
||
изменения, а не по ощущению важности (правило — в самом скилле):
|
||
|
||
- миграция, новый пакет, контракт Read API или MCP, правило слияния точек или
|
||
вывод слоя → `deep`;
|
||
- иначе меняется поведение, видимое снаружи → `standard`;
|
||
- иначе (багфикс, локальная правка, доки) → `quick`.
|
||
|
||
**Режим по умолчанию последовательный, и обосновывать его не надо.** Параллельно
|
||
гоняем только тогда, когда об этом попросили явно **и назвали набор** — какие
|
||
именно проходы или какую стадию. Просьба без набора основанием не считается:
|
||
гони последовательно и скажи строкой, что набор не был назван. Причина умолчания
|
||
— замеры: `adversary` и `ops` доказывают находки числами (удержание блокировки,
|
||
пик кучи, рост `-wal`), а два меряющих прохода на одной машине портят числа друг
|
||
другу; находка с испорченным оракулом хуже отсутствующей, потому что выглядит
|
||
доказанной. Правило целиком и его оговорки — в самом скилле.
|
||
|
||
Скилл сам гоняет гейт, нужные проходы и обязательный триаж. Возвращает отчёт с
|
||
потолком 7 пунктов, разметкой `Действие: инлайн | развилка` и секцией границ
|
||
покрытия.
|
||
|
||
**Сверь состав прогона с таблицей профилей в скилле, прежде чем коммитить.**
|
||
Пропуск прохода не отличим от прохода без находок: гейт зелёный, спеки сошлись,
|
||
отчёт выглядит полным. Единственный, кто мог бы заметить пропуск, — триаж, а он
|
||
заполняется тем, что ему подали. Отчёт обязан называть запущенные проходы
|
||
**поимённо и с исходом**; непущенный идёт строкой «не запускался» в границы
|
||
покрытия. Реестр короткий (4–8 проходов) — сверка стоит одного взгляда, а
|
||
молчащий пропуск уже стоил семи находок и отдельной задачи на их дозакрытие.
|
||
|
||
Отработай так же, как шаг 5: помеченное `инлайн` чини сам и не логируй,
|
||
`развилка` — блокером в беклог (вопрос уже сформулирован триажем, его остаётся
|
||
перенести). После правок — снова `task gate`.
|
||
|
||
**Границы покрытия из отчёта не выбрасывай** — они уезжают в финальный доклад
|
||
(шаг 10) сжатой строкой. Отчёт, из которого исчезло «что проверить было
|
||
невозможно», превращается в ложное ощущение проверенности.
|
||
|
||
### 8. Архивировать — `opsx:archive`
|
||
|
||
Вызови Skill `opsx:archive`: change уезжает в `openspec/changes/archive/`,
|
||
дельты вливаются в `openspec/specs/`.
|
||
|
||
### 9. Закрыть беклог и синк доков
|
||
|
||
Ревью выполненного — **до** чистки. Затем:
|
||
|
||
- Удали файл задачи `docs/backlog/<slug>.md` и строку в `docs/backlog/README.md`.
|
||
Реализованное не держим в беклоге — у него есть коммит и спека.
|
||
- Суть переехавшего решения — в `docs/architecture.md`, если ещё не там.
|
||
- Менялась структура БД — убедись, что `docs/database.md` обновлён в этом же
|
||
change.
|
||
- Новое, узнанное о формате HAE или о данных, — в `docs/local-research.md`
|
||
очередной находкой. Это источник истины по формату, и он ценнее кода.
|
||
- Проверь согласованность индекса командой `check` скилла `backlog`.
|
||
|
||
### 10. Коммит
|
||
|
||
Коммить **в текущую ветку** (`git rev-parse --abbrev-ref HEAD`), сам ветку не
|
||
создавай и не переключай, ничего не пушь. При ручном запуске HEAD обычно на
|
||
`master` — коммит идёт прямо в него, без feature-веток.
|
||
|
||
Сообщение — по-русски, по скиллу `commit` (первая строка отвечает «что
|
||
сделано», тело списком 1–3 пункта, без трейлеров). Одна задача — один
|
||
осмысленный коммит.
|
||
|
||
Готово — доложи пользователю кратко: что сделано, какие блокеры заведены и
|
||
чем ограничен остаток, ссылка на архивный change. **Плюс одна строка границ покрытия** из отчёта
|
||
ревью: какой профиль гонялся и что проверить было невозможно. Доклад без неё
|
||
сообщает «проверено», не сообщая, что именно.
|
||
|
||
## Тонкости
|
||
|
||
- **Не завязывайся на master и корень репо.** Скилл работает в текущем worktree
|
||
и на текущей ветке: не делай `git checkout`/`switch`, не создавай веток, не
|
||
пушь.
|
||
- Не пропускай `openspec validate --strict` перед архивацией.
|
||
- Тривиальная задача: шаги 2 и 4 пропускаются; ревью кода (шаг 7) остаётся
|
||
всегда, но в профиле `quick`.
|
||
- Гейт блокирует: пока `task gate` красный, опиниативные проходы не
|
||
запускаются. Чинить и перезапускать, а не «посмотреть заодно».
|
||
- Если ревью предлагает крупную переработку — это развилка: не правь молча и
|
||
не спрашивай, заведи блокером и доведи остаток.
|
||
- Держи пользователя в цикле короткими репликами на переходах фаз, но не проси
|
||
подтверждать механику.
|