From 53da8a1773e43626044a4f2ec321762e1fd7cd8e Mon Sep 17 00:00:00 2001 From: Matysh Date: Thu, 13 Aug 2026 10:30:00 +0300 Subject: [PATCH] docs: align AGENTS.md and PROCESS.md with the actual process Publishes the 538-line process canon into the repository, replacing the 51-line provenance stub that pointed at a non-existent .agents/PROTOCOL.md. Rewrites AGENTS.md: product context first, labels as the canonical status, rule #1 with the status check, change classes, trailers, push cadence, Codex/Claude roles and review cycle limits. Issue: #112 User-Visible: no --- AGENTS.md | 262 ++++++++++++++++++++----- PROCESS.md | 557 +++++++++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 737 insertions(+), 82 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 780fb41f..ddc2b899 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -6,62 +6,229 @@ House Plan is one HACS package with two parts plus a demo harness: - **Storage integration** (`custom_components/houseplan/`, Python) — the Home Assistant backend. - **Demo harness** (`demo/`) — a self-contained Playwright page (`demo/srv/demo.html`) that renders the card against a fake `hass`, used for screenshots and the `smoke_*.mjs` end-to-end suite. -Standard commands live in `package.json` scripts, `CONTRIBUTING.md`, and `docs/DEVELOPMENT.md`. Read `docs/ARCHITECTURE.md` and `docs/STATUS.md` before non-trivial changes. -Issue and commit provenance is defined in repository-visible `PROCESS.md`; -install its commit-message hook in every writable clone. +## Read this first + +**`docs/SCOPE.md` before anything else.** It was fixed with the owner and states +its own authority: features are built, improved and accepted **only** if they +serve a job listed there. It carries the mission, the three personas, the core +user jobs and the out-of-scope list. + +Its central consequence: **View mode is the product for two of the three +personas.** Editors are admin-only tools and must never leak interactions into +View. + +For work that changes visible behaviour, also read `docs/USER-GUIDE.ru.md` — +interface wording comes from there and is not invented, or the UI starts speaking +developer. + +Then `PROCESS.md` (the full process), `docs/STATUS.md` (where the release line +is), and for non-trivial changes `docs/ARCHITECTURE.md` plus the canonical +document of the subsystem you touch: `SUN.md`, `LIGHT.md`, `CANVAS.md`, +`WALL-THICKNESS.md`, `UX-MODES.md`, `CONFIG-COMPATIBILITY.md`, +`TOUCH-SUPPORT.md`. + +Standard commands live in `package.json` scripts, `CONTRIBUTING.md` and +`docs/DEVELOPMENT.md`. + +## Canonical backlog and status + +[GitHub Issues](https://github.com/Matysh/houseplan-card/issues) are the canonical +task records: problem, scope, acceptance criteria and discussion. + +**Status lives in labels:** `S1-new`, `S2-analysis`, `S3-spec`, `S4-spec-review`, +`S5-ready`, `S6-in-progress`, `S7-code-review`, `S8-merged`, plus `blocked` on top +of a status and `rejected` on a closed issue. Exactly one `S*` label per open +issue. [GitHub Projects (v2)](https://github.com/users/Matysh/projects/1) is a +human-facing view synchronised from the labels, not the source of truth. + +Only issues **created by the owner** enter the process. The repository is public; +outside reports may be malformed or invalid, carry no status labels, and are not +picked up until the owner converts them into his own issue. + +Specs, audits and ADRs may live under `docs/`, but must link to their issue and +must not become a parallel task list. When repository documentation disagrees with +Issues, the issue wins. + +## Rule #1 + +> Changing product code without an issue is forbidden. Code changes only when the +> issue exists and sits in "Ready for development" or later. + +Check before touching product code: + +``` +gh issue view --repo Matysh/houseplan-card --json number,state,labels +``` + +The label must be one of `S5-ready`, `S6-in-progress`, `S7-code-review`. Anything +else — refuse and say why. "Issue #83 is in `S2-analysis`, code is off limits. +Start with the spec?" is the correct answer, not a smaller patch. + +## Change classes + +| Class | Paths | Issue required | +|---|---|---| +| **A — product** | `src/**`, `custom_components/houseplan/**/*.py`, `manifest.json`, `hacs.json`, i18n, `custom_components/**/translations/**` | yes | +| **B — gates and tooling** | `test/**`, `tests_backend/**`, `demo/**`, `scripts/**`, `.github/workflows/**`, `rollup.config.mjs`, `tsconfig*.json` | yes; may reuse the issue it covers | +| **C — documentation** | `docs/**`, `README*`, `CHANGELOG*`, `AGENTS.md` | not if it is part of its issue's DoD | +| **D — generated** | `dist/**`, `custom_components/houseplan/frontend/**`, `demo/srv/assets/houseplan-card.js`, `demo/golden/baselines/**` | never changes on its own | + +`PROCESS.md` §1 is the authority; it does not yet list `package.json`, +`package-lock.json`, `.githooks/**`, the rest of `.github/**`, `.gitignore` or +`pytest.ini`. Treat them as class B and tell the owner §1 needs the addition. + +## Commits + +Hooks install themselves: `package.json` runs `"prepare": "node +scripts/install-hooks.mjs"`, so `npm ci` sets `core.hooksPath` in every fresh +clone. Verify with `git config core.hooksPath` — expect `.githooks`. + +Every non-merge commit carries **terminal** trailers: + +```text +Issue: #123 +User-Visible: yes +``` + +One `Issue:` line per issue if a commit closes several. `User-Visible: no` for +tests, refactors, tooling and documentation that does not change the product. +`User-Visible: yes` requires edits to **both** changelogs — `docs/CHANGELOG.md` +and `docs/CHANGELOG.ru.md` — in the same commit. + +A commit touching `demo/golden/baselines/**` additionally requires: + +```text +Release: v1.62.0-beta.9 +Baseline-Reviewed: https://github.com/Matysh/houseplan-card/actions/runs/ +``` + +Never invent a review link and never rewrite published history to satisfy +trailers. `.githooks/commit-msg` and the `provenance` CI job both run +`scripts/validate-commit-provenance.mjs`. + +Branch: `issue/-slug`. Direct commits to `dev`, no PR — the owner's decision; +CI checks after the fact, and a violation is fixed with a follow-up commit, never +a force-push. + +**Push after every task, not before a beta.** While work sits unpushed there is +nothing to review, and reviewing twenty tasks at once is not review. `dev` may hold +unreviewed code while a task is in flight; what matters is its state when the +reviewer says it is accepted. ## Two-agent workflow -House Plan is developed by two agents: **Codex is the author** (analysis, -estimate, spec, implementation) and **Claude is the reviewer** (estimate, spec, -code). They exchange remarks through a local, git-ignored message bus — -**read `.agents/PROTOCOL.md` before acting on any task**. It defines the -message format, the estimate scales every agent must use, the three stages -(`estimate` → `spec` → `code`), the three-round convergence limit and what gets -published to GitHub. +**Codex** writes analysis, specs and all product code. **Claude** reviews specs and +code and owns infrastructure and distribution. The owner rules on disputes, closes +issues and commands releases. -Two rules that matter even if you read nothing else: +Author and reviewer are different models, which is what "a fresh session without +implementation context" means in practice. The reviewer never edits product code; +the author never grades their own work. -- write only into the *other* agent's inbox, never edit a file you did not - create, and move a processed message to `.agents/archive/`; -- "verified" without a command and its output is not evidence — from either side. +The exchange happens in **issue comments** — there is no local message bus. Verdict +format: -## Canonical backlog +```text +Verdict: green/yellow/red · cycle r/4 · High: N · Medium: N → #… · Document: … +``` -GitHub is the only active backlog for House Plan: +High blocks. Medium must become its own issue. Low is fixed or waived with a note +in the review document. A yellow verdict is legitimate even when every acceptance +criterion passes, if the change does not solve the stated scenario or degrades a +neighbouring one. -- [GitHub Issues](https://github.com/Matysh/houseplan-card/issues) are the - canonical task records: problem, scope, acceptance criteria and discussion. -- [GitHub Projects (v2)](https://github.com/users/Matysh/projects/1) is - the canonical prioritization and workflow-status view. Every open in-scope - issue must be present there. +**Four review cycles** (two on the light track). The counter lives in the document +name, `-r1`…`-r4`; the fourth adds the `review-4` label. There is no fifth attempt: +the owner splits the task, rejects it, or arbitrates. -Before starting planned work, find or create its issue and keep its description, -labels and Project status current as decisions and implementation state change. -Close an issue only after the result is verified. Specs, audits and ADRs may -remain under `docs/`, but must link to their issue and must not become a parallel -task list. When repository documentation disagrees with Issues or Project v2, -the GitHub backlog wins. +On the light track (`small`: complexity ≤3, one surface, no config migration, no +new UX contract, no perf or touch impact — all at once) the spec lives in the issue +body and the spec review is a comment. Code review is never skipped. -## Cursor Cloud specific instructions +## Specs -The startup update script already runs `npm ci`, provisions a Python 3.13 backend venv at `.venv-backend`, and installs Playwright Chromium. You do not need to reinstall dependencies. +`docs/specs/-.md`, linked to its issue in both directions. Required +sections are in `PROCESS.md` §7.1, plus two product ones: which persona meets this, +on which surface, at what moment; and what the person sees before and after, in one +sentence without implementation terms. -- **Frontend** (from repo root): `npm run typecheck`, `npm test` (node:test, 424 tests at v1.60.0), `npm run build`. After building, keep both committed snapshots in sync — `cp dist/houseplan-card.js custom_components/houseplan/frontend/` and `cp dist/houseplan-card.js demo/srv/assets/`. CI enforces both comparisons byte-for-byte. -- **Backend HA-harness tests need Python 3.13, not the system 3.12.** Run them with the venv: `.venv-backend/bin/python -m pytest tests_backend/ -q` (150 tests at v1.60.0: 100 pure + 50 HA harness). Running `python3 -m pytest tests_backend` without Home Assistant silently **skips** the `test_ha_*.py` harness tests (`conftest.py` ignores them when `homeassistant` is not importable) and runs only the pure set. -- **Running the app / smoke suite**: build a fresh bundle and copy it into the demo assets first — `npm run build && cp dist/houseplan-card.js demo/srv/assets/houseplan-card.js` — then run `node demo/smoke_*.mjs`. The committed demo snapshot must remain byte-identical to `dist` (CI checks it); rebuilding first also guarantees the browser suite tests the current source in an uncommitted worktree. No real Home Assistant server is required: `demo/srv/demo.html` stubs `hass`, registries and `callService`. -- **Golden images**: `npm run golden:capture` and `npm run golden:verify` refuse a stale demo bundle. Build and copy the current bundle first, then review `artifacts/golden/actual/` and `diff/`. Update baselines only with `npm run golden:accept -- --reviewed`, using the complete Linux CI artifact; never accept a partial scenario or images merely to make CI green. See `demo/golden/README.md`. -- **Freshness contract**: the embedded fingerprint covers `src/` plus Rollup, TypeScript and package-lock build inputs. Benchmark and golden tooling must call `assertFreshDemoBundle` before recording any result; a missing or mismatched fingerprint is a hard failure, not a warning. -- **Demo harness render quirk**: the fake `hass` in `demo.html` is set once, so opening the page directly in a browser renders the floor plan but **device icons only appear after a re-render** (an F5 refresh, or nudging `card.hass = {...card.hass}`). The smoke launcher `demo/serve.mjs` already does this nudge; a plain browser session does not. This is a harness limitation, not a card bug. -- **Known environment-sensitive smoke**: `demo/smoke_opening_measure.mjs` fails two sub-checks (`place_dialog_x_magnetised`, `place_committed_x_center`) under the pinned Chromium — a `1e-6`-tolerance magnet-snap on the opening-*placement* path. It reproduces against the pristine committed bundle, so treat it as pre-existing/pixel-precision, not a regression you introduced. -- **Owner's local Windows checkout is invisible here.** Path - `C:\Users\Sergey\Downloads\dev\houseplan-dev` (workflow notes + often - unpushed edits) is **not mounted** into managed Cloud Agent VMs. Do not - expect to `ls` or diff that folder. To bring local work into the cloud - agent: push a branch to GitHub and say its name, or run a **local** Cursor - Agent / My Machines worker inside that checkout. Day-to-day source of truth - for cloud sessions remains **`origin/dev`** (minors) and **`origin/main`** - (releases) — see `docs/STATUS.md`. +**Ambiguity is asked, not guessed.** A guess written as fact is the worst kind of +defect: it passes review because it looks like a decision. Ask the owner in one +batched issue comment, each question carrying a proposed default, and put `blocked` +on top of `S3-spec` while waiting. Small or cheap calls are decided and recorded in +an explicit "assumed, change freely" block at the end of the spec. + +## Gates + +``` +npm run typecheck +npm test +npm run build +npm run inventory # the only correct way to get test counts +``` + +Never copy test counts into documents by hand; they go stale in days. + +After building, keep all three bundle snapshots in sync — CI compares them +byte-for-byte: + +``` +cp dist/houseplan-card.js custom_components/houseplan/frontend/houseplan-card.js +cp dist/houseplan-card.js demo/srv/assets/houseplan-card.js +``` + +During the implementation cycle only the fast gates run. `smoke`, `golden` and +`performance_smoke` spin up Chromium and belong to the pre-beta run — which is then +mandatory and complete. + +**Backend.** A full Home Assistant harness cannot run on native Windows at all: +Home Assistant imports the Unix-only `fcntl` module. Its canon is Linux CI or WSL. +Locally only the pure subset runs; `python -m pytest tests_backend/ -q` without +Home Assistant **silently skips** `test_ha_*.py` (`conftest.py` ignores them when +`homeassistant` is not importable), so a green result proves nothing. Say so in the +report instead of claiming the backend was verified. Cloud agents have the harness +at `.venv-backend/bin/python`. + +**Running the app / smoke suite**: build a fresh bundle and copy it into the demo +assets first, then run `node demo/smoke_*.mjs`. No real Home Assistant server is +required: `demo/srv/demo.html` stubs `hass`, registries and `callService`. + +**Golden images**: `npm run golden:capture` and `npm run golden:verify` refuse a +stale demo bundle. Build and copy first, then review `artifacts/golden/actual/` and +`diff/`. Update baselines only with `npm run golden:accept -- --reviewed`, using the +complete Linux CI artifact; never accept a partial scenario or images merely to make +CI green. See `demo/golden/README.md`. + +**Freshness contract**: the embedded fingerprint covers `src/` plus Rollup, +TypeScript and package-lock build inputs. Benchmark and golden tooling must call +`assertFreshDemoBundle` before recording any result; a missing or mismatched +fingerprint is a hard failure, not a warning. + +**CI is pinned to an exact SHA.** The release gate accepts only a `completed +success` run for the candidate's SHA, not "the last green one"; a new push cancels +an unfinished Validate for the same branch. Jobs: `provenance`, `hacs`, `hassfest`, +`frontend`, `smoke`, `golden`, `performance_smoke`, `backend`. + +**"Verified" without a named command and its result is not evidence.** + +## Environments + +**Local Windows checkout** is the day-to-day environment: Node 22 as in CI, Python +3.13 in a venv, `gh` authenticated. `.venv-backend` does **not** exist there — it is +provisioned only by cloud agent startup scripts, which also run `npm ci` and install +Playwright Chromium. + +Known environment-sensitive smoke: `demo/smoke_opening_measure.mjs` fails two +sub-checks (`place_dialog_x_magnetised`, `place_committed_x_center`) under the pinned +Chromium — a `1e-6`-tolerance magnet-snap on the opening-*placement* path. It +reproduces against the pristine committed bundle, so treat it as +pre-existing/pixel-precision, not a regression you introduced. + +Demo harness render quirk: the fake `hass` in `demo.html` is set once, so opening the +page directly in a browser renders the floor plan but **device icons only appear +after a re-render** (an F5 refresh, or nudging `card.hass = {...card.hass}`). The +smoke launcher `demo/serve.mjs` already does this nudge; a plain browser session does +not. This is a harness limitation, not a card bug. ## Promotion rule @@ -71,3 +238,10 @@ stable release commit is promotion-only: version fields, generated bundle snapshots and changelog/release metadata. Do not add feature source code in that commit. An explicit owner-requested emergency hotfix is the only exception and must be called out in the release handoff. + +A `Release vX.Y.Z-beta.N candidate` commit is **not** promotion-only: it carries +the work itself and follows the ordinary rules, trailers included. + +Issues are closed in a batch when a beta ships, not when implementation ends: that +way a bug found in the beta returns to the same task, and the beta announcement can +list what went in. Status labels are stripped as the issues close. diff --git a/PROCESS.md b/PROCESS.md index 0349a03e..314168a4 100644 --- a/PROCESS.md +++ b/PROCESS.md @@ -1,57 +1,538 @@ -# House Plan change provenance +# Процесс работы над House Plan -This file is the repository-visible minimum process contract. The detailed -two-agent workflow lives in `.agents/PROTOCOL.md` in the owner's checkout; -contributors and fresh agents must still be able to discover the rules below -from a plain clone. +> **Статус документа:** черновик 3 (2026-08-12), на согласование владельцу. +> Решения владельца, зафиксированные в этой редакции: прямые коммиты в `dev` без +> PR · канон статуса — **метки** · лёгкий трек для мелких задач **включён**. +> +> **Область действия:** обязателен для владельца и для любого агента (Cowork, +> Cursor Cloud, Codex, локальные сессии). Читается сразу после `AGENTS.md`, до +> `docs/STATUS.md`. +> +> **Приоритет источников:** GitHub Issues + Project v2 — канонический бэклог. +> Статус живёт в метках issue. При расхождении документации с GitHub побеждает +> GitHub; при расхождении процесса и привычки побеждает процесс. -## Before changing code +--- -Every product, test, documentation or release change must belong to a GitHub -issue in the canonical House Plan Project. Keep scope and acceptance criteria -there; a local spec supports an issue but does not replace it. +## 1. Основное правило -## Commit trailers +**Изменение продуктового кода без issue запрещено.** Код меняется только тогда, +когда issue существует и находится в статусе «Готово к разработке» или дальше. +Исключения — только §11, и каждое оставляет след. -Every non-merge commit carries: +Правило работает лишь при точной границе «продуктового кода», иначе спор +переносится на границу: -```text -Issue: #123 -User-Visible: yes +| Класс | Что входит | Нужен ли issue | +|---|---|---| +| **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 (тип «техдолг») | +| **C. Документация** | `docs/**`, `README*`, `CHANGELOG*`, `AGENTS.md` | Документирование A/B в том же коммите — часть DoD своего issue. Самостоятельная работа над документацией — свой issue | +| **D. Сгенерированное** | `dist/**`, `custom_components/houseplan/frontend/**`, `demo/srv/assets/houseplan-card.js`, `demo/golden/baselines/**` | Никогда не меняется само по себе. Коммит **только** класса D допустим лишь как релизный промоушен или как принятие эталонов с доказательством ревью | + +Практический смысл таблицы: «я только поправил тест» и «я только пересобрал +бандл» перестают быть лазейками. + +--- + +## 2. Жизненный цикл + +Семь рабочих статусов и два служебных. Фазы тестирования в цикле сознательно +**нет**: найденные позже дефекты заводятся отдельными issue и проходят цикл +заново. Issue закрывается после выпуска беты. + +``` +Новое → Аналитика и оценка → ТЗ в работе → ТЗ на ревью ⟲ → Готово к разработке → + → В разработке → Код-ревью ⟲ → Закрыт (после выпуска беты) + +служебные: Заблокировано (parking) Отклонено (закрыт) +⟲ — возврат на правки, не более 4 циклов (§4) ``` -Use `User-Visible: no` for refactoring, tests, build tooling and documentation -that do not change product behaviour. A commit that changes reviewed golden -baselines additionally carries both: +### 2.1 Новое — заведение задачи -```text -Release: v1.2.3-beta.1 -Baseline-Reviewed: +- **Кто:** любой — владелец, агент, пользователь (Telegram, GitHub). +- **Вход:** проблема в пользовательских терминах; как проявляется или зачем нужно. + Решение **не требуется** и не приветствуется. +- **Запрещено:** ставить приоритет, оценивать, писать ТЗ, начинать код. + +### 2.2 Аналитика и оценка + +Задача разбирается, продуктовое «да» ещё не дано. + +- **Кто:** агент-аналитик готовит, владелец решает. +- **Чек-лист**, результат — комментарием в issue: + 1. дубликаты проверены (ссылки на похожие issue); + 2. в скоупе по `docs/SCOPE.md` и `docs/TOUCH-SUPPORT.md`; + 3. **пользовательская ценность 1–10** и **ценность для разработки** — что + упрощает или разблокирует; + 4. **сложность и риск 1–10** — трудоёмкость плюс вероятность задеть смежное; + 5. приоритет **P1/P2/P3**; + 6. тип: баг / фича / техдолг; + 7. затронутые поверхности (модули, диалоги, бэкенд, i18n); + 8. лёгкий трек — да/нет по критериям §5. +- **Приоритет и ценность — поля владельца.** Агент предлагает, владелец + утверждает; иначе агенты приоритизируют сами и P1 разрастается. +- **Выход:** «ТЗ в работе» либо «Отклонено» с записанной причиной. + +### 2.3 ТЗ в работе — написание ТЗ + +- **Кто:** автор ТЗ, назначает себя. Статус означает «занято». +- **Артефакт:** `docs/specs/-.md`, где `NN` — **номер issue**. + Многоэтапная задача: `--stage.md`. +- **Лёгкий трек:** ТЗ пишется в теле issue, файл не создаётся (§5). +- **Выход:** полная первая редакция по §7. + +### 2.4 ТЗ на ревью + +- **Ревьюер ≠ автор.** Ревьюер получает issue и ТЗ, без устных пояснений автора. + Его задача — не согласиться, а найти, где ТЗ не выполнимо или не проверяемо. +- **Артефакт:** `docs/reviews/SPEC-REVIEW--r.md`, вердикт + зелёный / жёлтый / красный. Лёгкий трек — комментарий в issue. +- **High-находки блокируют.** Medium/Low — либо правятся, либо становятся + отдельными issue со ссылкой; «оставили в тексте ревью» не считается закрытием. +- **Выход:** «Готово к разработке» либо возврат в «ТЗ в работе» — не более + 4 циклов (§4). + +### 2.5 Готово к разработке (DoR) + +Не работа, а **очередь**: единственный статус, из которого можно трогать код. +Все пункты обязательны: + +- ТЗ существует, ревью ТЗ зелёное, ссылки issue ↔ ТЗ на месте; +- **AC1…ACn** — пронумерованные проверяемые критерии приёмки; у каждого указано, + чем он доказывается: `unit` / `backend` / `smoke` / `golden` / «ревью кода»; +- перечислены затронутые файлы и модули; +- i18n: ключи en + ru перечислены; +- миграция и compatibility-поля решены по `docs/CONFIG-COMPATIBILITY.md`; +- влияние на производительность и бюджеты названо (или явно «нет»); +- влияние на touch по `docs/TOUCH-SUPPORT.md` (View и киоск — блокирующие); +- release-артефакты по правилу `docs/specs/README.md` (changelog RU+EN, + документация, golden/скриншоты, performance/security); +- **откат**: как выключить или вернуть назад (флаг Labs, обратная миграция); +- открытых продуктовых вопросов нет; риски перечислены. + +Если хоть один пункт не выполнен — статус не «Готово к разработке», как бы ни +хотелось начать. + +### 2.6 В разработке — реализация + +- **Занятие (claim):** назначить себя, поставить метку, комментарий + «Взял: <роль> · сессия · ветка `issue/-`». +- **WIP-лимиты:** не более **1** issue в «В разработке» на исполнителя, не более + **3** одновременно на цикл релиза, не более **2** в «Код-ревью». +- **Трассируемость:** ветка `issue/-`; каждый коммит несёт трейлеры + `Issue: #` и `User-Visible: yes|no`. +- **Автотесты — часть реализации, а не отдельная фаза.** Каждый AC, помеченный + `unit`/`backend`/`smoke`/`golden`, получает свою проверку здесь же. + «Тестирование вне жизненного цикла» означает отсутствие фазы ручного + тестирования, а не отсутствие тестов. +- **Скоуп не расширяется.** Найденное по пути становится новым issue в «Новое». + Если находка блокирует — текущий issue уходит в «Заблокировано» со ссылкой. + Попутных правок «раз уж я здесь» не бывает. +- **Документация — в том же коммите,** что и поведение (действующая политика + `docs/STATUS.md`): changelog RU+EN для пользовательского, `STATUS.md` для + состояния, `DEVELOPMENT.md` для новых грабель, `ARCHITECTURE.md` для дизайна. +- **Выход:** локальный гейт зелёный (§8), хендофф-комментарий (§7.2). + +### 2.7 Код-ревью + +- **Ревьюер ≠ исполнитель**, свежая сессия без контекста реализации. +- **Артефакт:** `docs/reviews/CODE-REVIEW--r.md` в действующем + формате: скоуп, как проверялось (таблица гейтов с результатами), находки + High/Medium/Low с воспроизведением, что проверено и корректно, чего не проверял. +- **Ревьюер отвечает за AC.** Раз ручного тестирования в цикле нет, именно ревью + кода отвечает на вопрос «оно вообще работает»: каждый AC либо доказан + автотестом — и ревьюер убедился, что **тест умеет падать**, — либо разобран по + коду с явной записью «проверено чтением, не исполнением». +- **High блокируют.** Medium **обязаны** превратиться в issue. +- **Выход:** очередь на пре-релиз либо возврат в «В разработке», не более + 4 циклов (§4). + +### 2.8 Закрытие после выпуска беты + +- **Вход:** изменение вошло в опубликованную бету/RC, CI Validate зелёный на + **точном SHA** тега (промоушен-правило: ни одна фича не попадает в стабильный + релиз, не побывав в бете). +- **Закрывает** релиз-менеджер, не исполнитель. Комментарий закрытия: тег беты, + ссылка на прогон CI, ссылка на бюллетень changelog. +- **Стабильный релиз статусов не двигает** — issue уже закрыты; релизный коммит + promotion-only, changelog ссылается на закрытые issue. +- **Что приходит потом:** дефект, найденный на стенде, дома или пользователем, — + **новый issue** типа «баг» со ссылкой на исходный. Исходный не переоткрывается. + +### 2.9 Заблокировано / Отклонено + +- **Заблокировано:** обязательна ссылка на блокирующий issue или внешнюю причину + и дата пересмотра. Без причины статус не ставится. +- **Отклонено:** закрытие с записанной причиной (вне скоупа, дубликат, цена не + оправдана). Тихое закрытие без причины запрещено. + +--- + +## 3. Правила + +Продолжение черновика владельца. Каждое правило проверяемо — глазами или машиной. + +1. **Никаких изменений в код, если нет issue** и он не помечен «Готово к + разработке» или дальше. +2. **Issue не может быть взят в разработку**, пока у него нет ТЗ с зелёным ревью, + пронумерованных AC с указанием доказательства и назначенного исполнителя. +3. **Issue не может быть взят дважды.** Занятие фиксируется назначением, меткой и + комментарием с именем ветки. У одного исполнителя одновременно не более одного + issue в разработке. +4. **Статус меняется до действия, а не после.** Взял — поставил метку; отдал на + ревью — поставил метку. Метка, поставленная задним числом, — дефект процесса. +5. **Ровно одна метка статуса** на issue в любой момент. Ноль или две — дефект, + еженедельная гигиена его показывает. +6. **Автор не ревьюит своё** — ни ТЗ, ни код. Никто не переводит свою работу через + ревью-гейт. +7. **Ревью возвращает не более 4 раз.** Пятый заход — решение владельца: разделить, + отклонить или арбитраж (§4). +8. **High блокирует. Medium становится issue.** Low либо правится, либо снимается + решением ревьюера с записью в документе. +9. **Скоуп не расширяется.** Всё найденное вне ТЗ — новый issue, а не попутная + правка. Блокирующая находка отправляет текущий issue в «Заблокировано». +10. **Каждый коммит класса A и B несёт трейлер `Issue: #NN`**, ветка называется + `issue/NN-slug`, а `User-Visible: yes` требует правок в **обоих** changelog в + том же коммите. +11. **Документация — в том же коммите, что поведение.** Отдельным «допишу потом» + коммитом документация не бывает. +12. **Сгенерированное не коммитится само по себе.** Только релизный промоушен или + принятие эталонов со ссылкой на прогон CI. +13. **Golden-эталоны принимаются только** `npm run golden:accept -- --reviewed` по + полному Linux-артефакту. Принятие ради зелёного CI — нарушение процесса. +14. **Issue закрывается после выпуска беты** с зелёным CI на точном SHA. Не + раньше, не «по факту наличия кода», не исполнителем. +15. **Закрытый issue не переоткрывается.** Новый дефект — новый issue со ссылкой. +16. **Стабильный релиз — promotion-only:** версии, сгенерированные бандлы, + changelog и release-метаданные. Продуктового кода там нет. +17. **История `dev` не перезаписывается.** На неё ссылаются теги. Нарушение + исправляется следующим коммитом плюс issue с меткой `процесс` — не + force-push'ем. +18. **AC доказывает автотест или запись ревьюера.** Фразы «проверил локально, всё + работает» в процессе не существует: либо тест, который умеет падать, либо + честное «проверено чтением, не исполнением». +19. **Параллельных бэклогов нет.** Планы, разборы и приоритеты живут в issue; + файловые отчёты — разовые и датированные. +20. **Аварийный хотфикс — только решением владельца** и только по §11.2. + +--- + +## 4. Лимит циклов ревью: 4 + +Оба ревью-гейта возвращают задачу на правки не более **4 раз**. Счётчик виден в +имени документа: `-r1` … `-r4`; на четвёртом заходе ставится метка `ревью-4`. + +- **Что считается циклом:** отправка на ревью → вердикт с блокирующими находками + → возврат. Уточняющий вопрос без вердикта циклом не считается. +- **Исчерпание лимита — не «пятая попытка», а разбор.** Задача уходит владельцу, + решение одно из трёх: + 1. **разделить** — issue закрывается как «заменён», вместо него 2–3 меньших с + ясным скоупом (частый настоящий диагноз: ТЗ было слишком большим); + 2. **отклонить** — цена решения оказалась выше ценности; + 3. **арбитраж владельца** — владелец фиксирует решение в issue, оно принимается + как есть; несогласие ревьюера записывается, но не блокирует. +- **Граница между «циклом» и «новым багом»:** до закрытия беты находка ревьюера — + возврат на правки; после закрытия — новый issue. Иначе лимит 4 обходится + заведением issue вместо возврата. +- Для лёгкого трека лимит ревью ТЗ — **2** цикла: задача на три часа, которую + переписывают трижды, лёгкой не была. + +--- + +## 5. Лёгкий трек (метка `малое`) + +**Критерии — все одновременно:** + +- сложность и риск ≤ 3; +- одна поверхность (один диалог, один модуль, один эндпоинт); +- нет миграции конфига и новых compatibility-полей; +- нет нового UX-контракта — меняется поведение в рамках уже описанного; +- нет влияния на производительность и на touch-контракт. + +**Что упрощается:** + +- ТЗ пишется **в теле issue** по шаблону: проблема · контракт · AC1…ACn с + доказательством · откат. Файл в `docs/specs/` не создаётся; +- ревью ТЗ — комментарий второго агента, отдельный документ не нужен; +- лимит ревью ТЗ — 2 цикла. + +**Что не упрощается:** issue, оценка, статусы, трейлеры коммитов, changelog, +**код-ревью и его документ**, закрытие после беты. Код-ревью не пропускается +никогда — именно оно в этом процессе заменяет тестирование. + +Если по ходу выясняется, что критерий нарушен (появилась миграция, задело второй +модуль) — метка `малое` снимается, issue возвращается в «ТЗ в работе» и получает +нормальный файл ТЗ. Это не провал, это ранняя диагностика. + +--- + +## 6. Роли + +Один агент может исполнять несколько ролей в разных issue, но **не две роли в +одном артефакте**. + +| Роль | Делает | Не имеет права | +|---|---|---| +| Аналитик | разбор, оценки, поверхности | окончательно ставить приоритет | +| Автор ТЗ | `docs/specs/NN-*.md` или ТЗ в issue | ревьюить своё ТЗ | +| Ревьюер ТЗ | `docs/reviews/SPEC-REVIEW-NN-rN.md` | править ТЗ вместо автора | +| Разработчик | код, автотесты, документация, changelog | ревьюить свой код, принимать golden | +| Ревьюер кода | `docs/reviews/CODE-REVIEW-*-rN.md`, проверка AC | править продуктовый код | +| Релиз-менеджер | пре-релиз, стабильный релиз, закрытие issue | добавлять код в релизный коммит | +| Владелец | приоритет, ценность, скоуп, отклонение, арбитраж, хотфикс | — | + +**Правило разделения:** ревьюер работает состязательно. Ему передаётся тег или +диапазон коммитов и ТЗ — не рассказ автора о том, как всё хорошо. + +**Принято по умолчанию, поправь если не так:** ревьюер — отдельная сессия +(Cowork / Codex / Cursor Cloud), выбор чередуется, лишь бы это была не та сессия, +что делала артефакт; релиз-менеджер — владелец. + +--- + +## 7. Артефакты и трассируемость + +### 7.1 Цепочка + +``` +issue #NN + ↔ ТЗ docs/specs/NN-slug.md (или тело issue при `малое`) + ↔ ревью ТЗ docs/reviews/SPEC-REVIEW-NN-rN.md (или комментарий при `малое`) + ↔ ветка issue/NN-slug + ↔ коммиты трейлеры Issue: #NN · User-Visible: yes|no + ↔ ревью кода docs/reviews/CODE-REVIEW--rN.md + ↔ changelog бюллетень RU+EN со ссылкой на #NN + ↔ бета тег, зелёный CI на точном SHA → закрытие ``` -Never invent a review reference merely to pass a gate. Baselines are accepted -only from the complete Linux CI artifact via `golden:accept -- --reviewed`. +Обязательные разделы ТЗ: проблема · скоуп и **не-скоуп** · контракт поведения · +UX · модель данных и миграция · i18n · критерии приёмки AC1…ACn с указанием +доказательства · план автотестов · риски · откат · release-артефакты. -## Prerelease naming +### 7.2 Шаблоны комментариев -Use `beta.1` through `beta.9`, then continue the same version line with -`rc.1`. GitHub/HACS prerelease discovery orders `beta.10` behind `beta.9`, so -the publisher rejects beta numbers greater than nine before creating a tag. +Короткие и однообразные, чтобы читались и человеком, и машиной. -Install dependencies once per clone; the `prepare` script activates the -repository hook automatically: +- **Аналитика:** `Оценка: ценность N/10 · сложность N/10 · P<1-3> · тип · + поверхности: … · дубликаты: … · лёгкий трек: да/нет` +- **Занятие:** `Взял: <роль> · сессия · ветка issue/NN-slug` +- **Хендофф:** `Сделано: … · Файлы: … · Гейты: <команда → результат> · + НЕ сделано: … · Риски: … · Следующий статус: … · Новые issue: #…` +- **Вердикт ревью:** `Вердикт: зелёный/жёлтый/красный · цикл r/4 · High: N · + Medium: N → #… · Документ: docs/reviews/…` +- **Закрытие:** `Выпущено в <тег беты> · CI: <ссылка> · Changelog: <ссылка>` -```bash -npm install +### 7.3 Расхождения с текущим состоянием, которые надо закрыть + +1. **Ревью живут вне репозитория.** 20+ файлов `CODE-REVIEW-*.md` и + `SPEC-REVIEW-*.md` лежат только в личной папке владельца. Агент, пришедший + через месяц, не видит, почему решение принято именно так, и повторяет + разобранную ошибку. → `docs/reviews/`. +2. **Статус ТЗ дублирует статус issue.** `docs/specs/README.md` держит колонку + «Статус ТЗ» со своим словарём («черновик решения», «в реализации», + «реализовано»). Два источника статуса уже расходятся. Колонку убрать, оставить + таблицу «issue ↔ ТЗ». + +--- + +## 8. Гейты + +**Локальный гейт перед выходом из «В разработке»** — минимальный набор, +покрывающий изменённые поверхности (действующее правило владельца): + +``` +npx tsc --noEmit +npm test +npm run build && cmp dist/houseplan-card.js custom_components/houseplan/frontend/houseplan-card.js \ + && cmp dist/houseplan-card.js demo/srv/assets/houseplan-card.js +node demo/smoke_<целевые>.mjs +npm run golden:verify # если менялся визуал +python -m pytest tests_backend -q # py3.13, если менялся бэкенд ``` -The hook checks message provenance locally; `validate.yml` enforces the same -terminal-trailer contract for every non-merge commit in a push or PR, so -`--no-verify`, rebases and fresh clones cannot bypass it. Test, build and release gates remain -the commands documented in `CONTRIBUTING.md` and `docs/TESTING.md`. +**Гейт беты** (условие закрытия issue): CI Validate зелёный на точном SHA тега. -## Release history +**Гейт стабильного релиза:** полный локальный прогон плюс Validate и Full +Performance зелёные на точном SHA; статусов issue не касается. -Do not rewrite published commits to add missing trailers. Record the gap in an -audit and enforce this contract on future work. Promotion-only stable commits -remain subject to the same Issue/User-Visible trailers. +--- + +## 9. Метки — канонический статус + +Статус читается из меток: их видно в списке issue и их читает любой токен с +доступом к Issues, в отличие от Project v2, который требует отдельного скоупа. +Project v2 остаётся человеческим представлением и синхронизируется по меткам. + +| Метка | Статус | +|---|---| +| `S1-новое` | Новое | +| `S2-аналитика` | Аналитика и оценка | +| `S3-тз` | ТЗ в работе | +| `S4-тз-ревью` | ТЗ на ревью | +| `S5-к-разработке` | Готово к разработке | +| `S6-в-разработке` | В разработке | +| `S7-код-ревью` | Код-ревью | +| `заблокировано` | Заблокировано (поверх статусной метки) | +| `отклонено` | Отклонено, issue закрыт | + +Модификаторы: `малое` (лёгкий трек), `hotfix`, `процесс`, `ревью-4`, +приоритет `P1`/`P2`/`P3`, тип `баг`/`фича`/`техдолг`. + +Правила: ровно одна `S*`-метка; закрытый issue статусных меток не несёт; +`заблокировано` не заменяет статус, а дополняет его. + +--- + +## 10. Механизация при прямых коммитах в `dev` + +Решение владельца — работать без PR. Значит, GitHub не может ничего заблокировать +на своей стороне: **основной гейт переезжает на клиента, CI остаётся страховкой.** + +### 10.1 Хуки, которые невозможно забыть поставить + +`.githooks/` в репозитории, `core.hooksPath` выставляется автоматически при +установке зависимостей: + +```json +"scripts": { "prepare": "node scripts/install-hooks.mjs" } +``` + +`npm ci` вызывает `prepare` сам — значит, хуки появляются в каждом окружении, +включая свежий контейнер облачного агента, без отдельного шага в инструкции. + +- **`commit-msg`** — отклоняет коммит без `Issue: #NN`, если тронут класс A или B; + проверяет `User-Visible`. +- **`pre-push`** — прогоняет `scripts/process-gate.mjs` по всему пушимому + диапазону. Это и есть блокирующий гейт вместо PR. + +### 10.2 Что проверяет `process-gate.mjs` + +Офлайн, без GitHub API: + +1. трейлер `Issue: #NN` у каждого коммита класса A/B; +2. имя ветки `issue/NN-slug` соответствует трейлерам; +3. для класса A существует `docs/specs/NN*-*.md` со ссылкой на issue — **или** + issue помечен `малое` (для этого нужен этап 2, до него — исключение по списку); +4. `User-Visible: yes` → правки в обоих changelog в том же коммите; +5. коммит только класса D невалиден без `Release: vX.Y.Z` либо + `Baseline-Reviewed: <ссылка на прогон CI>`; +6. релизный коммит не содержит изменений в `src/` и `custom_components/**/*.py`; +7. документов ревью на один issue не больше четырёх (`-r1`…`-r4`). + +С токеном GitHub (PAT уже есть у релизных скриптов): + +8. `--issues` тянет каждый упомянутый issue и требует метку из + {`S5-к-разработке`, `S6-в-разработке`, `S7-код-ревью`}; закрытый или + отсутствующий issue — отказ (fail closed); +9. `npm run release:prerelease -- --issues=…` отказывается, если у issue нет + зелёного вердикта код-ревью; +10. закрытие issue и снятие статусных меток автоматизируются по факту публикации + беты — в `publish-prerelease.yml`, а не по памяти человека. + +### 10.3 Страховка и разбор + +- **Тот же `process-gate.mjs` — job в `validate.yml`.** При прямом push проверка + догоняющая: код уже в `dev`, CI краснеет после. Это принятая цена отказа от PR. +- **Нарушение не откатывается force-push'ем** (правило 17): исправляющий коммит + плюс issue с меткой `процесс`. Починить надо проверку, а не только симптом. +- **Еженедельная гигиена** (workflow): issue в «Новое» дольше 14 дней и в + «В разработке» дольше 7; issue класса A в `S5` без ТЗ; issue с нулём или двумя + `S*`-метками; коммиты без трейлера за неделю — **цель 0**; rework rate и число + issue, дошедших до `ревью-4`; **баги, заведённые после закрытия беты** — прямая + цена отказа от фазы тестирования. + +--- + +## 11. Исключения + +### 11.1 Лёгкий трек + +См. §5 — это не исключение из правила №1, а более дешёвый путь по тем же статусам. + +### 11.2 Аварийный хотфикс (метка `hotfix`, решение владельца) + +Разрешено писать код до появления issue. Обязательно: + +- issue создан в **той же сессии до коммита**, метка `hotfix`; +- ТЗ «как сделано» + раздел «почему нельзя было ждать»; +- в течение 24 часов задача ретроспективно проходит код-ревью; +- аварийность названа явно в релизном хендоффе (действующее правило `AGENTS.md`). + +### 11.3 Гигиена репозитория + +Механические изменения без изменения поведения (форматирование, мёртвые файлы) +идут под квартальный umbrella-issue «Гигиена репозитория»; каждый коммит +ссылается на него. Трассируемость 1:1 сохраняется. + +--- + +## 12. Запрещено + +- код без issue или из статуса раньше «Готово к разработке»; +- ТЗ, написанное после кода (кроме §11.2, и тогда с пометкой «как сделано»); +- ревью своей работы; перевод своей работы через ревью-гейт; +- пятый цикл ревью вместо разбора по §4; +- заведение issue вместо возврата на правки, чтобы обойти лимит циклов; +- принятие golden-эталонов ради зелёного CI или по частичному артефакту; +- закрытие issue до выпуска беты с зелёным CI; +- переоткрытие закрытого issue вместо нового бага; +- Medium-находки, оставленные как TODO в документе ревью; +- **параллельные бэклоги** в файлах (`BACKLOG-*.md`, «планы» в docs); +- ревью-документы вне репозитория; +- попутные правки «раз уж я здесь»; +- фича или материальное изменение поведения в стабильном релиз-коммите; +- force-push в `dev`; +- ручное копирование на домашний инстанс. + +**Нарушение процесса — тоже issue** (метка `процесс`): если правило удалось +нарушить незаметно, виновата проверка. + +--- + +## 13. Внедрение + +1. Создать метки §9; разметить 38 открытых issue. Всё, что по + `docs/specs/README.md` «в реализации», но не прошло ревью, — в честный статус. +2. Перенести существующие `CODE-REVIEW-*.md` и `SPEC-REVIEW-*.md` в + `docs/reviews/`; убрать колонку «Статус ТЗ» из `docs/specs/README.md`. +3. Завести issue на сам гейт (класс B, техдолг): `scripts/process-gate.mjs`, + `.githooks/`, `prepare`-скрипт, job в `validate.yml`. По новому процессу он + сам обязан пройти ТЗ → ревью → реализацию. +4. Закрыть текущий долг ревью: `beta.2…beta.4` без код-ревью, среди них две новые + фичи (#90, #94). +5. Завести issue на находку «смок `visual_continuity` не умеет падать» из разбора + 11.08 — это ровно тот класс дефектов, который в процессе без ручного + тестирования стоит дороже всего. +6. `BACKLOG-2026-08-11.md` объявить разовым отчётом: решения — в issue. +7. Добавить в `AGENTS.md` блок §14. + +--- + +## 14. Блок для AGENTS.md + +```markdown +## Процесс: код только через issue + +Изменение продуктового кода без issue запрещено. Код меняется только из статуса +«Готово к разработке» или дальше. Полные правила, критерии статусов и гейты — +`docs/PROCESS.md`, читать до начала работы. + +Жизненный цикл (статус = метка issue): `S1-новое` → `S2-аналитика` → `S3-тз` → +`S4-тз-ревью` → `S5-к-разработке` → `S6-в-разработке` → `S7-код-ревью` → +закрытие после выпуска беты. Оба ревью возвращают на правки не более 4 циклов; +пятый заход — разбор у владельца (разделить / отклонить / арбитраж). + +- ветка `issue/-`, коммиты с трейлерами `Issue: #NN` и `User-Visible: yes|no`; +- работаем прямыми коммитами в `dev`, без PR: блокирующий гейт — локальный + `pre-push` (ставится автоматически через `npm ci`), CI — страховка. Force-push + в `dev` запрещён; +- автор ≠ ревьюер, ни для ТЗ, ни для кода; +- фазы ручного тестирования нет: автотесты пишутся в реализации, AC проверяет + код-ревью, найденные позже дефекты — новые issue типа «баг»; +- мелкие задачи (метка `малое`, сложность ≤3): ТЗ в теле issue, ревью ТЗ + комментарием, код-ревью — как обычно; +- найденное вне скоупа — новый issue, а не попутная правка; +- issue закрывает релиз-менеджер после выпуска беты, не исполнитель. +```