mirror of
https://github.com/Matysh/houseplan-card
synced 2026-09-29 03:09:36 +00:00
docs: bring the process canon back in line with what actually runs
The canon moved into the repository in #112 and then stood still while the process kept moving. A document that lags is worse than no document: an agent reading it as truth acts on rules that no longer exist. It promised a pre-push hook that was never written, named labels in Russian that the repository has never used, listed a status set the gate no longer applies, and said nothing at all about the event-driven pipeline — the largest mechanism the process has. Label names are now English throughout and S8-merged is documented. Section 1 covers the configuration files the gate kept reporting as unclassified, and records that D beats A where paths overlap, since the built bundle lives inside custom_components/houseplan/frontend/. Section 10.1 admits that pre-push does not exist. Section 10.2 matches ALLOWED_STATUS in scripts/process-gate.mjs, including the two caveats that only surfaced once the pipeline ran. Section 10.4 is new and documents the four silent-failure traps that cost a working day each. The source-of-truth order now says that actual automation outranks its own description — this document included. Issue: #119 User-Visible: no
This commit is contained in:
+262
-91
@@ -1,16 +1,23 @@
|
|||||||
# Процесс работы над House Plan
|
# Процесс работы над House Plan
|
||||||
|
|
||||||
> **Статус документа:** черновик 3 (2026-08-12), на согласование владельцу.
|
> **Статус документа: канон** (редакция 2026-08-13). Решения владельца, на
|
||||||
> Решения владельца, зафиксированные в этой редакции: прямые коммиты в `dev` без
|
> которых он стоит: прямые коммиты в `dev` **без PR** · канон статуса — **метки**,
|
||||||
> PR · канон статуса — **метки** · лёгкий трек для мелких задач **включён**.
|
> имена английские · лёгкий трек **включён** · автор и ревьюер — разные модели ·
|
||||||
|
> инфраструктурные задачи идут **вне** флоу.
|
||||||
>
|
>
|
||||||
> **Область действия:** обязателен для владельца и для любого агента (Cowork,
|
> **Область действия:** обязателен для владельца и для любого агента. Читается
|
||||||
> Cursor Cloud, Codex, локальные сессии). Читается сразу после `AGENTS.md`, до
|
> сразу после `docs/SCOPE.md` и `AGENTS.md`, до `docs/STATUS.md`. Живёт в
|
||||||
> `docs/STATUS.md`.
|
> репозитории: до августа 2026 канон лежал только в папке владельца, и свежий клон
|
||||||
|
> его не содержал вовсе.
|
||||||
>
|
>
|
||||||
> **Приоритет источников:** GitHub Issues + Project v2 — канонический бэклог.
|
> **Приоритет источников.** Канонический бэклог — GitHub Issues; статус живёт в
|
||||||
> Статус живёт в метках issue. При расхождении документации с GitHub побеждает
|
> метках, Project v2 остаётся человеческим представлением. При расхождении
|
||||||
> GitHub; при расхождении процесса и привычки побеждает процесс.
|
> документации с GitHub побеждает GitHub. При расхождении этого документа с
|
||||||
|
> `.github/workflows/*.yml` и `scripts/*` побеждает **фактическая автоматизация**:
|
||||||
|
> она исполняется, а описание — нет. Расхождение при этом не игнорируется, а
|
||||||
|
> заводится issue с меткой `process`.
|
||||||
|
>
|
||||||
|
> При расхождении процесса и привычки побеждает процесс.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -26,29 +33,49 @@
|
|||||||
| Класс | Что входит | Нужен ли issue |
|
| Класс | Что входит | Нужен ли issue |
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
| **A. Продукт** | `src/**`, `custom_components/houseplan/**/*.py`, `manifest.json`, `hacs.json`, `src/i18n/*.json`, `custom_components/**/translations/*` | **Да, обязательно.** Только из «Готово к разработке» или дальше |
|
| **A. Продукт** | `src/**`, `custom_components/houseplan/**/*.py`, `manifest.json`, `hacs.json`, `src/i18n/*.json`, `custom_components/**/translations/*` | **Да, обязательно.** Только из «Готово к разработке» или дальше |
|
||||||
| **B. Гейты и инструменты** | `test/**`, `tests_backend/**`, `demo/**`, `scripts/**`, `.github/workflows/**`, `rollup.config.mjs`, `tsconfig*.json` | **Да.** Может использовать issue того изменения, которое покрывает; самостоятельная работа над гейтом получает свой issue (тип «техдолг») |
|
| **B. Гейты и инструменты** | `test/**`, `tests_backend/**`, `demo/**`, `scripts/**`, весь `.github/**`, `.githooks/**`, `rollup.config.mjs`, `tsconfig*.json`, `package.json`, `package-lock.json`, `pytest.ini`, `.gitignore`, `.gitattributes` | **Да.** Может использовать issue того изменения, которое покрывает; самостоятельная работа над гейтом получает свой issue (тип `tech-debt`) |
|
||||||
| **C. Документация** | `docs/**`, `README*`, `CHANGELOG*`, `AGENTS.md` | Документирование A/B в том же коммите — часть DoD своего issue. Самостоятельная работа над документацией — свой issue |
|
| **C. Документация** | `docs/**`, `README*`, `CHANGELOG*`, `AGENTS.md`, `CONTRIBUTING.md`, `PROCESS*.md`, `LICENSE`, `(CODE\|SPEC)-REVIEW-*.md` | Документирование A/B в том же коммите — часть DoD своего issue. Самостоятельная работа над документацией — свой issue |
|
||||||
| **D. Сгенерированное** | `dist/**`, `custom_components/houseplan/frontend/**`, `demo/srv/assets/houseplan-card.js`, `demo/golden/baselines/**` | Никогда не меняется само по себе. Коммит **только** класса D допустим лишь как релизный промоушен или как принятие эталонов с доказательством ревью |
|
| **D. Сгенерированное** | `dist/**`, `custom_components/houseplan/frontend/**`, `demo/srv/assets/houseplan-card.js`, `demo/golden/baselines/**` | Никогда не меняется само по себе. Коммит **только** класса D допустим лишь как релизный промоушен или как принятие эталонов с доказательством ревью |
|
||||||
|
|
||||||
Практический смысл таблицы: «я только поправил тест» и «я только пересобрал
|
Практический смысл таблицы: «я только поправил тест» и «я только пересобрал
|
||||||
бандл» перестают быть лазейками.
|
бандл» перестают быть лазейками.
|
||||||
|
|
||||||
|
Классы неупорядочены, но при пересечении путей **D сильнее A**: собранный бандл
|
||||||
|
лежит внутри `custom_components/houseplan/frontend/`, и без этого правила он
|
||||||
|
считался бы продуктовым исходником.
|
||||||
|
|
||||||
|
**Инфраструктурная задача идёт вне флоу** (решение владельца 2026-08-13,
|
||||||
|
issue #118). Признак механический: **ни одного файла класса A**. Такая задача
|
||||||
|
делается без ТЗ, ревью ТЗ, код-ревью и без прохода по статусам — флоу построен
|
||||||
|
для изменений, у которых есть персона и видимое поведение, а в инфраструктуре ТЗ
|
||||||
|
пересказывало бы очевидное, и автор с ревьюером оказались бы одной ролью.
|
||||||
|
Проверкой служат гейты и CI. Обязательным остаётся issue, трейлеры и зелёные
|
||||||
|
`typecheck`, `test`, `build`.
|
||||||
|
|
||||||
|
Задача, задевающая класс A хотя бы одним файлом, инфраструктурной **не
|
||||||
|
является** и идёт полным флоу. «В основном инфраструктурная» не бывает: иначе
|
||||||
|
это дорога, по которой продуктовые правки минуют ревью. Признак задан через
|
||||||
|
класс файлов, а не через самоощущение исполнителя, именно поэтому.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 2. Жизненный цикл
|
## 2. Жизненный цикл
|
||||||
|
|
||||||
Семь рабочих статусов и два служебных. Фазы тестирования в цикле сознательно
|
Восемь рабочих статусов и два служебных. Фазы тестирования в цикле сознательно
|
||||||
**нет**: найденные позже дефекты заводятся отдельными issue и проходят цикл
|
**нет**: найденные позже дефекты заводятся отдельными issue и проходят цикл
|
||||||
заново. Issue закрывается после выпуска беты.
|
заново. Issue закрывается после выпуска беты.
|
||||||
|
|
||||||
```
|
```
|
||||||
Новое → Аналитика и оценка → ТЗ в работе → ТЗ на ревью ⟲ → Готово к разработке →
|
S1-new → S2-analysis → S3-spec → S4-spec-review ⟲ → S5-ready →
|
||||||
→ В разработке → Код-ревью ⟲ → Закрыт (после выпуска беты)
|
→ S6-in-progress → S7-code-review ⟲ → S8-merged → закрыт при выпуске беты
|
||||||
|
|
||||||
служебные: Заблокировано (parking) Отклонено (закрыт)
|
служебные: blocked (поверх статуса) rejected (закрыт)
|
||||||
⟲ — возврат на правки, не более 4 циклов (§4)
|
⟲ — возврат на правки, не более 4 циклов (§4), на лёгком треке 2
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Переходы `S4-spec-review` и `S7-code-review` выполняются **автоматически**: метка
|
||||||
|
порождает событие, событие запускает ревью (§10.4). Остальные ставит исполнитель.
|
||||||
|
|
||||||
### 2.1 Новое — заведение задачи
|
### 2.1 Новое — заведение задачи
|
||||||
|
|
||||||
- **Кто:** любой — владелец, агент, пользователь (Telegram, GitHub).
|
- **Кто:** любой — владелец, агент, пользователь (Telegram, GitHub).
|
||||||
@@ -208,7 +235,7 @@
|
|||||||
16. **Стабильный релиз — promotion-only:** версии, сгенерированные бандлы,
|
16. **Стабильный релиз — promotion-only:** версии, сгенерированные бандлы,
|
||||||
changelog и release-метаданные. Продуктового кода там нет.
|
changelog и release-метаданные. Продуктового кода там нет.
|
||||||
17. **История `dev` не перезаписывается.** На неё ссылаются теги. Нарушение
|
17. **История `dev` не перезаписывается.** На неё ссылаются теги. Нарушение
|
||||||
исправляется следующим коммитом плюс issue с меткой `процесс` — не
|
исправляется следующим коммитом плюс issue с меткой `process` — не
|
||||||
force-push'ем.
|
force-push'ем.
|
||||||
18. **AC доказывает автотест или запись ревьюера.** Фразы «проверил локально, всё
|
18. **AC доказывает автотест или запись ревьюера.** Фразы «проверил локально, всё
|
||||||
работает» в процессе не существует: либо тест, который умеет падать, либо
|
работает» в процессе не существует: либо тест, который умеет падать, либо
|
||||||
@@ -222,7 +249,7 @@
|
|||||||
## 4. Лимит циклов ревью: 4
|
## 4. Лимит циклов ревью: 4
|
||||||
|
|
||||||
Оба ревью-гейта возвращают задачу на правки не более **4 раз**. Счётчик виден в
|
Оба ревью-гейта возвращают задачу на правки не более **4 раз**. Счётчик виден в
|
||||||
имени документа: `-r1` … `-r4`; на четвёртом заходе ставится метка `ревью-4`.
|
имени документа: `-r1` … `-r4`; на четвёртом заходе ставится метка `review-4`.
|
||||||
|
|
||||||
- **Что считается циклом:** отправка на ревью → вердикт с блокирующими находками
|
- **Что считается циклом:** отправка на ревью → вердикт с блокирующими находками
|
||||||
→ возврат. Уточняющий вопрос без вердикта циклом не считается.
|
→ возврат. Уточняющий вопрос без вердикта циклом не считается.
|
||||||
@@ -241,7 +268,7 @@
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 5. Лёгкий трек (метка `малое`)
|
## 5. Лёгкий трек (метка `small`)
|
||||||
|
|
||||||
**Критерии — все одновременно:**
|
**Критерии — все одновременно:**
|
||||||
|
|
||||||
@@ -263,7 +290,7 @@
|
|||||||
никогда — именно оно в этом процессе заменяет тестирование.
|
никогда — именно оно в этом процессе заменяет тестирование.
|
||||||
|
|
||||||
Если по ходу выясняется, что критерий нарушен (появилась миграция, задело второй
|
Если по ходу выясняется, что критерий нарушен (появилась миграция, задело второй
|
||||||
модуль) — метка `малое` снимается, issue возвращается в «ТЗ в работе» и получает
|
модуль) — метка `small` снимается, issue возвращается в `S3-spec` и получает
|
||||||
нормальный файл ТЗ. Это не провал, это ранняя диагностика.
|
нормальный файл ТЗ. Это не провал, это ранняя диагностика.
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -286,9 +313,19 @@
|
|||||||
**Правило разделения:** ревьюер работает состязательно. Ему передаётся тег или
|
**Правило разделения:** ревьюер работает состязательно. Ему передаётся тег или
|
||||||
диапазон коммитов и ТЗ — не рассказ автора о том, как всё хорошо.
|
диапазон коммитов и ТЗ — не рассказ автора о том, как всё хорошо.
|
||||||
|
|
||||||
**Принято по умолчанию, поправь если не так:** ревьюер — отдельная сессия
|
**Роли закреплены за исполнителями** (решение владельца 2026-08-12):
|
||||||
(Cowork / Codex / Cursor Cloud), выбор чередуется, лишь бы это была не та сессия,
|
|
||||||
что делала артефакт; релиз-менеджер — владелец.
|
| Исполнитель | Роли |
|
||||||
|
|---|---|
|
||||||
|
| **Codex** | аналитик, автор ТЗ, разработчик, релиз-инженер по команде владельца |
|
||||||
|
| **Claude** | ревьюер ТЗ, ревьюер кода, вся инфраструктура и дистрибуция |
|
||||||
|
| **Владелец** | приоритет, скоуп, арбитраж, закрытие issue, команда на выпуск |
|
||||||
|
|
||||||
|
Автор и ревьюер — **разные модели**, и это сильнее требования «другая сессия»:
|
||||||
|
одна модель, читая свой же артефакт заново, повторяет свои же слепые пятна.
|
||||||
|
|
||||||
|
Ревью ТЗ и код-ревью держатся в **разных сессиях** Claude: ревьюер кода не должен
|
||||||
|
приходить с контекстом того, как обсуждали ТЗ.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -298,8 +335,8 @@
|
|||||||
|
|
||||||
```
|
```
|
||||||
issue #NN
|
issue #NN
|
||||||
↔ ТЗ docs/specs/NN-slug.md (или тело issue при `малое`)
|
↔ ТЗ docs/specs/NN-slug.md (или тело issue при `small`)
|
||||||
↔ ревью ТЗ docs/reviews/SPEC-REVIEW-NN-rN.md (или комментарий при `малое`)
|
↔ ревью ТЗ docs/reviews/SPEC-REVIEW-NN-rN.md (или комментарий при `small`)
|
||||||
↔ ветка issue/NN-slug
|
↔ ветка issue/NN-slug
|
||||||
↔ коммиты трейлеры Issue: #NN · User-Visible: yes|no
|
↔ коммиты трейлеры Issue: #NN · User-Visible: yes|no
|
||||||
↔ ревью кода docs/reviews/CODE-REVIEW-<tag|NN>-rN.md
|
↔ ревью кода docs/reviews/CODE-REVIEW-<tag|NN>-rN.md
|
||||||
@@ -307,9 +344,44 @@ issue #NN
|
|||||||
↔ бета тег, зелёный CI на точном SHA → закрытие
|
↔ бета тег, зелёный CI на точном SHA → закрытие
|
||||||
```
|
```
|
||||||
|
|
||||||
Обязательные разделы ТЗ: проблема · скоуп и **не-скоуп** · контракт поведения ·
|
Обязательные разделы ТЗ: **сценарий** · **что человек увидит до и после** ·
|
||||||
UX · модель данных и миграция · i18n · критерии приёмки AC1…ACn с указанием
|
проблема · скоуп и **не-скоуп** · контракт поведения · UX · модель данных и
|
||||||
доказательства · план автотестов · риски · откат · release-артефакты.
|
миграция · i18n · критерии приёмки AC1…ACn с указанием доказательства · план
|
||||||
|
автотестов · риски · откат · release-артефакты.
|
||||||
|
|
||||||
|
Два первых раздела — продуктовые, и они идут первыми не случайно. **Сценарий:**
|
||||||
|
какая персона (`docs/SCOPE.md`), на какой поверхности, в какой момент это
|
||||||
|
встретит. **Что человек увидит:** одной фразой, без терминов реализации. ТЗ,
|
||||||
|
которое не может ответить на эти два вопроса, описывает работу, а не изменение
|
||||||
|
продукта.
|
||||||
|
|
||||||
|
**Размытое место не додумывается, а выносится владельцу.** Догадка, записанная
|
||||||
|
как факт, — худший вид дефекта: она проходит ревью, потому что выглядит решением.
|
||||||
|
|
||||||
|
Но спрашивать обо всём нельзя: владелец один, и анкета из двадцати пунктов хуже
|
||||||
|
угадывания. Порог такой (решение владельца 2026-08-13).
|
||||||
|
|
||||||
|
**Владельцу задаются только продуктовые вопросы** — что человек видит или делает
|
||||||
|
и какой объём видимых изменений входит в этот issue. Поведение в пограничном
|
||||||
|
случае; какая из персон важнее в конфликте; что считать приемлемой деградацией;
|
||||||
|
относится ли смежное поведение сюда или становится отдельной задачей.
|
||||||
|
|
||||||
|
**Всё, чего пользователь не наблюдает, агенты решают сами** либо согласовывают
|
||||||
|
между собой: где хранится состояние, в каком модуле стоит гвард, именование,
|
||||||
|
раскладка файлов, стратегия тестов, механика миграции. Решение записывается явным
|
||||||
|
блоком в конце ТЗ — «принято предположительно, поменять свободно», и ревьюер
|
||||||
|
вправе его оспорить. Технический спор автора и ревьюера решается вердиктом, а не
|
||||||
|
владельцем; до него он доходит только при исчерпании лимита циклов (§4).
|
||||||
|
|
||||||
|
**Смешанный вопрос делится, а не эскалируется целиком.** «Где живёт это
|
||||||
|
состояние» — техническое. «Переживает ли оно перезагрузку страницы и общее ли оно
|
||||||
|
для всех экранов» — продуктовое.
|
||||||
|
|
||||||
|
Вопросы задаются **одним комментарием, пачкой**, каждый в форме: что неясно ·
|
||||||
|
что изменится от ответа · **предлагаемый вариант по умолчанию**. Вопрос с готовым
|
||||||
|
вариантом стоит владельцу пяти секунд, вопрос без него — пяти минут. Пока ждём
|
||||||
|
ответа, issue остаётся в `S3-spec` и получает `blocked`: статус не подменяется,
|
||||||
|
`blocked` его дополняет, иначе конвейер считает задачу в работе, а она стоит.
|
||||||
|
|
||||||
### 7.2 Шаблоны комментариев
|
### 7.2 Шаблоны комментариев
|
||||||
|
|
||||||
@@ -320,20 +392,26 @@ UX · модель данных и миграция · i18n · критерии
|
|||||||
- **Занятие:** `Взял: <роль> · сессия <id> · ветка issue/NN-slug`
|
- **Занятие:** `Взял: <роль> · сессия <id> · ветка issue/NN-slug`
|
||||||
- **Хендофф:** `Сделано: … · Файлы: … · Гейты: <команда → результат> ·
|
- **Хендофф:** `Сделано: … · Файлы: … · Гейты: <команда → результат> ·
|
||||||
НЕ сделано: … · Риски: … · Следующий статус: … · Новые issue: #…`
|
НЕ сделано: … · Риски: … · Следующий статус: … · Новые issue: #…`
|
||||||
- **Вердикт ревью:** `Вердикт: зелёный/жёлтый/красный · цикл r<N>/4 · High: N ·
|
- **Вердикт ревью:** `Вердикт: зелёный/жёлтый/красный · цикл r<N>/<лимит> ·
|
||||||
Medium: N → #… · Документ: docs/reviews/…`
|
High: N · Medium: N → #… · Документ: docs/reviews/…`
|
||||||
- **Закрытие:** `Выпущено в <тег беты> · CI: <ссылка> · Changelog: <ссылка>`
|
- **Закрытие:** `Выпущено в <тег беты> · CI: <ссылка> · Changelog: <ссылка>`
|
||||||
|
|
||||||
|
**Вперёд двигает только зелёный вердикт.** Жёлтый и красный возвращают автору;
|
||||||
|
разница между ними содержательна для человека, но не для маршрута. Первая
|
||||||
|
редакция конвейера (§10.4) пропускала жёлтый при `High: 0`, и первый же живой
|
||||||
|
прогон показал, почему это неверно: жёлтый там означал, что AC описывает неверное
|
||||||
|
изменение контракта — реализовать такое ТЗ значило бы сделать ошибку по инструкции.
|
||||||
|
|
||||||
### 7.3 Расхождения с текущим состоянием, которые надо закрыть
|
### 7.3 Расхождения с текущим состоянием, которые надо закрыть
|
||||||
|
|
||||||
1. **Ревью живут вне репозитория.** 20+ файлов `CODE-REVIEW-*.md` и
|
1. **Статус ТЗ дублирует статус issue.** `docs/specs/README.md` держит колонку
|
||||||
`SPEC-REVIEW-*.md` лежат только в личной папке владельца. Агент, пришедший
|
|
||||||
через месяц, не видит, почему решение принято именно так, и повторяет
|
|
||||||
разобранную ошибку. → `docs/reviews/`.
|
|
||||||
2. **Статус ТЗ дублирует статус issue.** `docs/specs/README.md` держит колонку
|
|
||||||
«Статус ТЗ» со своим словарём («черновик решения», «в реализации»,
|
«Статус ТЗ» со своим словарём («черновик решения», «в реализации»,
|
||||||
«реализовано»). Два источника статуса уже расходятся. Колонку убрать, оставить
|
«реализовано»). Два источника статуса уже расходятся. Колонку убрать, оставить
|
||||||
таблицу «issue ↔ ТЗ».
|
таблицу «issue ↔ ТЗ».
|
||||||
|
2. **Ревью до релиза 1.62 живут вне репозитория.** Документы `CODE-REVIEW-*.md` и
|
||||||
|
`SPEC-REVIEW-*.md` за прежний период лежат в папке владельца, и переносить их
|
||||||
|
задним числом смысла нет: они описывают код, которого уже нет. Новые документы
|
||||||
|
ревью кладёт в `docs/reviews/` сам конвейер, в ветку задачи.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -365,23 +443,41 @@ Performance зелёные на точном SHA; статусов issue не к
|
|||||||
доступом к Issues, в отличие от Project v2, который требует отдельного скоупа.
|
доступом к Issues, в отличие от Project v2, который требует отдельного скоупа.
|
||||||
Project v2 остаётся человеческим представлением и синхронизируется по меткам.
|
Project v2 остаётся человеческим представлением и синхронизируется по меткам.
|
||||||
|
|
||||||
|
**Имена меток английские** (решение владельца 2026-08-12). Русские имена в этом
|
||||||
|
документе были только на бумаге; репозиторий с самого начала жил на английских.
|
||||||
|
|
||||||
| Метка | Статус |
|
| Метка | Статус |
|
||||||
|---|---|
|
|---|---|
|
||||||
| `S1-новое` | Новое |
|
| `S1-new` | Новое, не разобрано |
|
||||||
| `S2-аналитика` | Аналитика и оценка |
|
| `S2-analysis` | Аналитика и оценка |
|
||||||
| `S3-тз` | ТЗ в работе |
|
| `S3-spec` | ТЗ в работе |
|
||||||
| `S4-тз-ревью` | ТЗ на ревью |
|
| `S4-spec-review` | ТЗ на ревью |
|
||||||
| `S5-к-разработке` | Готово к разработке |
|
| `S5-ready` | Готово к разработке — единственный статус, из которого можно начать трогать код |
|
||||||
| `S6-в-разработке` | В разработке |
|
| `S6-in-progress` | В разработке, занято исполнителем |
|
||||||
| `S7-код-ревью` | Код-ревью |
|
| `S7-code-review` | Код-ревью |
|
||||||
| `заблокировано` | Заблокировано (поверх статусной метки) |
|
| `S8-merged` | Ревью пройдено, код в `dev`, ждёт беты. Issue закрывается пачкой при выпуске |
|
||||||
| `отклонено` | Отклонено, issue закрыт |
|
| `blocked` | Ждём внешнего или владельца, **поверх** статусной метки |
|
||||||
|
| `rejected` | Отклонено, issue закрыт |
|
||||||
|
|
||||||
Модификаторы: `малое` (лёгкий трек), `hotfix`, `процесс`, `ревью-4`,
|
Модификаторы: `small` (лёгкий трек, сложность ≤3), `hotfix`, `process`,
|
||||||
приоритет `P1`/`P2`/`P3`, тип `баг`/`фича`/`техдолг`.
|
`review-4`; приоритет `P1`/`P2`/`P3`; тип `bug`/`feature`/`tech-debt`.
|
||||||
|
Тематические метки (`polish`, `infra`, `tests`, `docs`, `security`, `vacuum`)
|
||||||
|
ортогональны процессу.
|
||||||
|
|
||||||
Правила: ровно одна `S*`-метка; закрытый issue статусных меток не несёт;
|
Инварианты: **ровно одна `S*`-метка** на открытом issue; закрытый issue статусных
|
||||||
`заблокировано` не заменяет статус, а дополняет его.
|
меток не несёт; `blocked` не заменяет статус, а дополняет его.
|
||||||
|
|
||||||
|
**В процесс берутся только issue, созданные владельцем** (решение владельца
|
||||||
|
2026-08-13). Репозиторий публичный, задачи заводят и посторонние; такие issue
|
||||||
|
бывают плохо оформлены или невалидны, и статусных меток им не ставят — инварианты
|
||||||
|
на них не распространяются. Проверять `user.login`. Что делать с чужим issue:
|
||||||
|
прочитать, при необходимости переформулировать и завести **свой** со ссылкой на
|
||||||
|
исходный, либо оставить до решения владельца. Не размечать и не брать в работу.
|
||||||
|
|
||||||
|
`S8-merged` появился позже остальных и закрывает разрыв, который раньше
|
||||||
|
закрывался памятью человека: код принят, но бета ещё не вышла, и issue закрывать
|
||||||
|
рано. Без него принятая задача либо висела в `S7-code-review`, либо закрывалась
|
||||||
|
досрочно.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -402,46 +498,109 @@ Project v2 остаётся человеческим представление
|
|||||||
`npm ci` вызывает `prepare` сам — значит, хуки появляются в каждом окружении,
|
`npm ci` вызывает `prepare` сам — значит, хуки появляются в каждом окружении,
|
||||||
включая свежий контейнер облачного агента, без отдельного шага в инструкции.
|
включая свежий контейнер облачного агента, без отдельного шага в инструкции.
|
||||||
|
|
||||||
- **`commit-msg`** — отклоняет коммит без `Issue: #NN`, если тронут класс A или B;
|
- **`commit-msg`** — есть, работает. Отклоняет коммит без терминального
|
||||||
проверяет `User-Visible`.
|
`Issue: #NN`, требует ровно один `User-Visible: yes|no`, а для коммитов,
|
||||||
- **`pre-push`** — прогоняет `scripts/process-gate.mjs` по всему пушимому
|
трогающих `demo/golden/baselines/**`, — `Release:` плюс `Baseline-Reviewed:`.
|
||||||
диапазону. Это и есть блокирующий гейт вместо PR.
|
Реализация — `scripts/validate-commit-provenance.mjs`, тот же скрипт вызывается
|
||||||
|
job `provenance` в `validate.yml`.
|
||||||
|
- **`pre-push`** — **не реализован.** Задумывался как блокирующий гейт вместо PR;
|
||||||
|
фактически блокирующей проверки на клиенте нет, и `process-gate.mjs` работает
|
||||||
|
только догоняющим job в CI (§10.3). Долг известен, отдельная задача.
|
||||||
|
|
||||||
|
Файл хука обязан быть исполняемым: `assertHookMode` проверяет бит в индексе.
|
||||||
|
Через GitHub API режим не выставляется — хук, отправленный так, приезжает
|
||||||
|
`100644`, и проверка его отвергает. Ставить `git update-index --chmod=+x`.
|
||||||
|
|
||||||
### 10.2 Что проверяет `process-gate.mjs`
|
### 10.2 Что проверяет `process-gate.mjs`
|
||||||
|
|
||||||
Офлайн, без GitHub API:
|
Реализовано, `scripts/process-gate.mjs`, issue #105. Офлайн, без GitHub API:
|
||||||
|
|
||||||
1. трейлер `Issue: #NN` у каждого коммита класса A/B;
|
1. трейлер `Issue: #NN` у каждого коммита класса A/B, допускается несколько;
|
||||||
2. имя ветки `issue/NN-slug` соответствует трейлерам;
|
2. имя ветки `issue/NN-slug` соответствует трейлерам;
|
||||||
3. для класса A существует `docs/specs/NN*-*.md` со ссылкой на issue — **или**
|
3. для класса A существует `docs/specs/NN-*.md` — **или** issue помечен `small`.
|
||||||
issue помечен `малое` (для этого нужен этап 2, до него — исключение по списку);
|
Офлайн это предупреждение: лёгкий трек держит ТЗ в теле issue, и без чтения
|
||||||
|
меток «ТЗ в issue» неотличимо от «ТЗ не написано». С `--issues` — отказ;
|
||||||
4. `User-Visible: yes` → правки в обоих changelog в том же коммите;
|
4. `User-Visible: yes` → правки в обоих changelog в том же коммите;
|
||||||
5. коммит только класса D невалиден без `Release: vX.Y.Z` либо
|
5. коммит только класса D невалиден без `Release: vX.Y.Z` либо
|
||||||
`Baseline-Reviewed: <ссылка на прогон CI>`;
|
`Baseline-Reviewed: <ссылка на прогон CI>`;
|
||||||
6. релизный коммит не содержит изменений в `src/` и `custom_components/**/*.py`;
|
6. релизный коммит не содержит изменений в `src/` и `custom_components/**/*.py`;
|
||||||
7. документов ревью на один issue не больше четырёх (`-r1`…`-r4`).
|
7. документов ревью на один issue не больше четырёх (`-r1`…`-r4`).
|
||||||
|
|
||||||
С токеном GitHub (PAT уже есть у релизных скриптов):
|
С токеном GitHub:
|
||||||
|
|
||||||
8. `--issues` тянет каждый упомянутый issue и требует метку из
|
8. `--issues` тянет каждый упомянутый issue и требует метку из
|
||||||
{`S5-к-разработке`, `S6-в-разработке`, `S7-код-ревью`}; закрытый или
|
{`S5-ready`, `S6-in-progress`, `S7-code-review`, `S8-merged`}; закрытый,
|
||||||
отсутствующий issue — отказ (fail closed);
|
недоступный или помеченный `blocked` — отказ (**fail closed**).
|
||||||
9. `npm run release:prerelease -- --issues=…` отказывается, если у issue нет
|
|
||||||
зелёного вердикта код-ревью;
|
Две оговорки к проверке 8, обе выяснились при реализации.
|
||||||
10. закрытие issue и снятие статусных меток автоматизируются по факту публикации
|
|
||||||
беты — в `publish-prerelease.yml`, а не по памяти человека.
|
**`S8-merged` входит в множество**, хотя по смыслу задача уже принята. Причина
|
||||||
|
механическая: конвейер (§10.4) сливает ветку в `dev` **раньше**, чем ставит метку,
|
||||||
|
Validate стартует от этого push и успевает прочитать issue уже в `S8-merged`.
|
||||||
|
Строгое множество красило бы каждую принятую задачу. Локальная строгость
|
||||||
|
возвращается флагом `--no-merged`.
|
||||||
|
|
||||||
|
**Статус спрашивается только у коммитов класса A/B.** Правило №1 говорит о
|
||||||
|
продуктовом коде и инструментах, а не о документации. Иначе краснел бы каждый
|
||||||
|
документ ревью: он ложится в ветку задачи, пока та в `S4-spec-review` или
|
||||||
|
`S7-code-review`, то есть заведомо вне рабочего множества.
|
||||||
|
|
||||||
|
Не реализовано и остаётся долгом:
|
||||||
|
|
||||||
|
9. `npm run release:prerelease -- --issues=…` не проверяет, есть ли у issue
|
||||||
|
зелёный вердикт код-ревью;
|
||||||
|
10. закрытие issue и снятие статусных меток при публикации беты делаются руками —
|
||||||
|
`node process-labels/apply.mjs cleanup --apply`, а не `publish-prerelease.yml`.
|
||||||
|
Пропуск этого шага уже ломал инвариант «закрытый issue без статусной метки».
|
||||||
|
|
||||||
### 10.3 Страховка и разбор
|
### 10.3 Страховка и разбор
|
||||||
|
|
||||||
- **Тот же `process-gate.mjs` — job в `validate.yml`.** При прямом push проверка
|
- **`process-gate.mjs` — job `process-gate` в `validate.yml`**, без `needs`:
|
||||||
догоняющая: код уже в `dev`, CI краснеет после. Это принятая цена отказа от PR.
|
краснеет сам и не роняет остальные. При прямом push проверка догоняющая: код уже
|
||||||
|
в `dev`, CI краснеет после. Это принятая цена отказа от PR — и, пока `pre-push`
|
||||||
|
не написан, единственная машинная проверка процесса.
|
||||||
- **Нарушение не откатывается force-push'ем** (правило 17): исправляющий коммит
|
- **Нарушение не откатывается force-push'ем** (правило 17): исправляющий коммит
|
||||||
плюс issue с меткой `процесс`. Починить надо проверку, а не только симптом.
|
плюс issue с меткой `process`. Починить надо проверку, а не только симптом.
|
||||||
- **Еженедельная гигиена** (workflow): issue в «Новое» дольше 14 дней и в
|
- **Еженедельная гигиена** (workflow): issue в `S1-new` дольше 14 дней и в
|
||||||
«В разработке» дольше 7; issue класса A в `S5` без ТЗ; issue с нулём или двумя
|
`S6-in-progress` дольше 7; issue класса A в `S5-ready` без ТЗ; issue с нулём или
|
||||||
`S*`-метками; коммиты без трейлера за неделю — **цель 0**; rework rate и число
|
двумя `S*`-метками; коммиты без трейлера за неделю — **цель 0**; rework rate и
|
||||||
issue, дошедших до `ревью-4`; **баги, заведённые после закрытия беты** — прямая
|
число issue, дошедших до `review-4`; **баги, заведённые после закрытия беты** —
|
||||||
цена отказа от фазы тестирования.
|
прямая цена отказа от фазы тестирования.
|
||||||
|
|
||||||
|
### 10.4 Событийный конвейер: метка как триггер
|
||||||
|
|
||||||
|
`.github/workflows/process.yml`, issue #114. Смена статусной метки — не запись в
|
||||||
|
журнал, а **сообщение**: она порождает событие, событие запускает следующий шаг.
|
||||||
|
|
||||||
|
```
|
||||||
|
S4-spec-review → ревью ТЗ → S5-ready либо возврат в S3-spec
|
||||||
|
S7-code-review → код-ревью → слияние в dev → S8-merged либо возврат в S6-in-progress
|
||||||
|
```
|
||||||
|
|
||||||
|
Ревьюер — `anthropics/claude-code-action`. Он читает `docs/SCOPE.md`, `AGENTS.md`,
|
||||||
|
этот документ и тело issue, публикует разбор комментарием, заводит issue на каждую
|
||||||
|
Medium-находку, кладёт документ в `docs/reviews/` ветки задачи и возвращает вердикт
|
||||||
|
структурированным JSON. **Метку переставляет отдельный детерминированный шаг по
|
||||||
|
вердикту, а не модель.**
|
||||||
|
|
||||||
|
Четыре вещи, без которых конвейер молча не работает:
|
||||||
|
|
||||||
|
1. метки переставляет **PAT**, а не `GITHUB_TOKEN`: GitHub намеренно не порождает
|
||||||
|
события от `GITHUB_TOKEN`, чтобы не было циклов, и цепочка обрывалась бы после
|
||||||
|
первого шага без ошибок в логах;
|
||||||
|
2. `process.yml` обязан лежать в **ветке по умолчанию**: для события `issues`
|
||||||
|
GitHub берёт workflow только оттуда, независимо от содержимого `dev`;
|
||||||
|
3. слияние в `dev` происходит **до** простановки `S8-merged`, иначе метка врёт в
|
||||||
|
промежутке — она утверждает, что код в `dev`;
|
||||||
|
4. многострочный текст внутри `run:` — только через heredoc: строка с нулевым
|
||||||
|
отступом обрывает блок YAML, и скрипт обрезается без ошибки парсера.
|
||||||
|
|
||||||
|
**Автор обязан дождаться вердикта, а не заканчивать сессию.** Ревью идёт от десяти
|
||||||
|
минут до сорока пяти. Отчёт «передал на ревью» останавливает конвейер там, где он
|
||||||
|
мог идти сам: вердикт придёт, а подхватить его будет некому. У агента нет часов —
|
||||||
|
он существует только в момент своего хода, поэтому ожидание это опрос: раз в 90
|
||||||
|
секунд, не более 30 попыток. Смотреть на метку, а не на комментарий: метка и есть
|
||||||
|
состояние. При `blocked` не ждать — задача ждёт владельца.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -486,27 +645,35 @@ Project v2 остаётся человеческим представление
|
|||||||
- force-push в `dev`;
|
- force-push в `dev`;
|
||||||
- ручное копирование на домашний инстанс.
|
- ручное копирование на домашний инстанс.
|
||||||
|
|
||||||
**Нарушение процесса — тоже issue** (метка `процесс`): если правило удалось
|
**Нарушение процесса — тоже issue** (метка `process`): если правило удалось
|
||||||
нарушить незаметно, виновата проверка.
|
нарушить незаметно, виновата проверка.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 13. Внедрение
|
## 13. Внедрение
|
||||||
|
|
||||||
1. Создать метки §9; разметить 38 открытых issue. Всё, что по
|
Состояние на 2026-08-13.
|
||||||
`docs/specs/README.md` «в реализации», но не прошло ревью, — в честный статус.
|
|
||||||
2. Перенести существующие `CODE-REVIEW-*.md` и `SPEC-REVIEW-*.md` в
|
1. ✅ **Метки созданы, бэклог размечен.** У всех открытых issue владельца ровно
|
||||||
`docs/reviews/`; убрать колонку «Статус ТЗ» из `docs/specs/README.md`.
|
одна `S*`-метка, инварианты чистые.
|
||||||
3. Завести issue на сам гейт (класс B, техдолг): `scripts/process-gate.mjs`,
|
2. ⏳ **Колонку «Статус ТЗ» из `docs/specs/README.md` убрать** — не сделано, §7.3
|
||||||
`.githooks/`, `prepare`-скрипт, job в `validate.yml`. По новому процессу он
|
п.1. Перенос старых документов ревью в `docs/reviews/` отменён: они описывают
|
||||||
сам обязан пройти ТЗ → ревью → реализацию.
|
код, которого уже нет.
|
||||||
4. Закрыть текущий долг ревью: `beta.2…beta.4` без код-ревью, среди них две новые
|
3. ✅ **Гейт написан** — `scripts/process-gate.mjs` плюс job в `validate.yml`,
|
||||||
фичи (#90, #94).
|
issue #105. Прошёл **вне** флоу как инфраструктурная задача (§1, issue #118), а
|
||||||
5. Завести issue на находку «смок `visual_continuity` не умеет падать» из разбора
|
не через ТЗ и ревью, как предполагала прежняя редакция этого пункта.
|
||||||
11.08 — это ровно тот класс дефектов, который в процессе без ручного
|
4. ✅ **Долг ревью списан решением владельца.** Беты `beta.2`…`beta.10` сделаны по
|
||||||
тестирования стоит дороже всего.
|
прежнему процессу и не пересматриваются. Точка отсчёта — релиз 1.62.0; отсчёт
|
||||||
6. `BACKLOG-2026-08-11.md` объявить разовым отчётом: решения — в issue.
|
начинается с первой беты следующей линии.
|
||||||
7. Добавить в `AGENTS.md` блок §14.
|
5. ⏳ Завести issue на находку «смок `visual_continuity` не умеет падать» — это
|
||||||
|
ровно тот класс дефектов, который в процессе без ручного тестирования стоит
|
||||||
|
дороже всего.
|
||||||
|
6. ✅ `BACKLOG-2026-08-11.md` — разовый отчёт, решения живут в issue.
|
||||||
|
7. ✅ `AGENTS.md` переписан целиком, шире блока §14.
|
||||||
|
8. ✅ **Канон перенесён в репозиторий** (issue #112). До этого полный процесс жил
|
||||||
|
только в папке владельца, а в репозитории лежал файл на 51 строку про трейлеры
|
||||||
|
коммитов — из свежего клона канон не был виден вообще.
|
||||||
|
9. ⏳ **`pre-push` не написан** (§10.1). Блокирующей проверки на клиенте нет.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -519,10 +686,14 @@ Project v2 остаётся человеческим представление
|
|||||||
«Готово к разработке» или дальше. Полные правила, критерии статусов и гейты —
|
«Готово к разработке» или дальше. Полные правила, критерии статусов и гейты —
|
||||||
`docs/PROCESS.md`, читать до начала работы.
|
`docs/PROCESS.md`, читать до начала работы.
|
||||||
|
|
||||||
Жизненный цикл (статус = метка issue): `S1-новое` → `S2-аналитика` → `S3-тз` →
|
Жизненный цикл (статус = метка issue): `S1-new` → `S2-analysis` → `S3-spec` →
|
||||||
`S4-тз-ревью` → `S5-к-разработке` → `S6-в-разработке` → `S7-код-ревью` →
|
`S4-spec-review` → `S5-ready` → `S6-in-progress` → `S7-code-review` → `S8-merged`
|
||||||
закрытие после выпуска беты. Оба ревью возвращают на правки не более 4 циклов;
|
→ закрытие пачкой при выпуске беты. Оба ревью возвращают на правки не более 4
|
||||||
пятый заход — разбор у владельца (разделить / отклонить / арбитраж).
|
циклов; пятый заход — разбор у владельца (разделить / отклонить / арбитраж).
|
||||||
|
|
||||||
|
Ревью запускается **само** от меток `S4-spec-review` и `S7-code-review` и идёт до
|
||||||
|
45 минут. Поставив такую метку, автор не заканчивает работу, а ждёт смены метки
|
||||||
|
опросом и продолжает по тому, чем она стала.
|
||||||
|
|
||||||
- ветка `issue/<NN>-<slug>`, коммиты с трейлерами `Issue: #NN` и `User-Visible: yes|no`;
|
- ветка `issue/<NN>-<slug>`, коммиты с трейлерами `Issue: #NN` и `User-Visible: yes|no`;
|
||||||
- работаем прямыми коммитами в `dev`, без PR: блокирующий гейт — локальный
|
- работаем прямыми коммитами в `dev`, без PR: блокирующий гейт — локальный
|
||||||
@@ -531,7 +702,7 @@ Project v2 остаётся человеческим представление
|
|||||||
- автор ≠ ревьюер, ни для ТЗ, ни для кода;
|
- автор ≠ ревьюер, ни для ТЗ, ни для кода;
|
||||||
- фазы ручного тестирования нет: автотесты пишутся в реализации, AC проверяет
|
- фазы ручного тестирования нет: автотесты пишутся в реализации, AC проверяет
|
||||||
код-ревью, найденные позже дефекты — новые issue типа «баг»;
|
код-ревью, найденные позже дефекты — новые issue типа «баг»;
|
||||||
- мелкие задачи (метка `малое`, сложность ≤3): ТЗ в теле issue, ревью ТЗ
|
- мелкие задачи (метка `small`, сложность ≤3): ТЗ в теле issue, ревью ТЗ
|
||||||
комментарием, код-ревью — как обычно;
|
комментарием, код-ревью — как обычно;
|
||||||
- найденное вне скоупа — новый issue, а не попутная правка;
|
- найденное вне скоупа — новый issue, а не попутная правка;
|
||||||
- issue закрывает релиз-менеджер после выпуска беты, не исполнитель.
|
- issue закрывает релиз-менеджер после выпуска беты, не исполнитель.
|
||||||
|
|||||||
Reference in New Issue
Block a user