diff --git a/.github/workflows/_process.yml b/.github/workflows/_process.yml index d590052e..a00aec35 100644 --- a/.github/workflows/_process.yml +++ b/.github/workflows/_process.yml @@ -84,8 +84,15 @@ jobs: BLOCKED=false; EXHAUSTED=false; SMALL=false; TRIVIAL=false has blocked && BLOCKED=true has review-4 && EXHAUSTED=true + # Треки #695 (PROCESS §5): `track:show` и `track:ship` — лимит 2, как у + # прежних `small`/`trivial`; `track:ask` — 4. Пока #696 не влит, `ship` + # проходит конвейер как `show`. has small && SMALL=true has trivial && TRIVIAL=true + has track:show && SMALL=true + has track:ship && SMALL=true + # Явный `track:ask` главнее прежних меток: метка владельца окончательна. + if has track:ask; then SMALL=false; TRIVIAL=false; fi # Этап определяется первым: от него зависит, какие вердикты считать. stage=""; marker="" @@ -102,7 +109,7 @@ jobs: stage="" fi - # Лимит циклов: 4 обычный, 2 на лёгком и коротком треке (PROCESS.md §4). + # Лимит циклов: 4 на `track:ask`, 2 на `track:show`/`track:ship` (PROCESS.md §4, §5). limit=4 if [ "$SMALL" = "true" ] || [ "$TRIVIAL" = "true" ]; then limit=2; fi diff --git a/AGENTS.md b/AGENTS.md index 47795b29..ff8938d0 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -73,13 +73,16 @@ overlap. The committed bundle changes only in a commit with a `Release:` trailer (#657); an ordinary task restores it with `npm run bundle:clean` before committing. -**Tracks** (`PROCESS.md` §5, §5.1): `small` is the default — the spec lives in the -issue body and its review is a comment; taking the full track means naming the -`small` criterion the task fails. `trivial` skips the spec stage for a bug whose -expected behaviour is already on record. An **infrastructure** task — not a single +**Tracks** (`PROCESS.md` §5, §5.1): the label `track:ship`, `track:show` or +`track:ask` sets the route, and the owner's label beats the criteria. `show` is the +default: up to three AC in the issue body, no spec review, `S2` → `S5`. `ship` is a +one-sentence change within fixed limits, `S1` → `S5`. `ask` is the full route with +a spec review. Any agent may raise a track with a reason; only the owner lowers it. +`small` and `trivial` read as `show`. An **infrastructure** task — not a single class A file — skips analysis and spec and enters at `S7-code-review` -(`PROCESS.md` §1). Code review is never skipped on any track: it checks scope, -risks and the evidence from executed tests, but does not replace executing them. +(`PROCESS.md` §1). Every change is code-reviewed; on `ship` the review moves to a +batch review of the beta range before the tag. Review checks scope, risks and the +evidence from executed tests, but does not replace executing them. ## Specs diff --git a/PROCESS.md b/PROCESS.md index 06de29ef..d2d5a493 100644 --- a/PROCESS.md +++ b/PROCESS.md @@ -3,7 +3,7 @@ > **Статус документа: канон** (редакция 2026-08-13, ролевое уточнение > 2026-09-13). Решения владельца, на > которых он стоит: прямые коммиты в `dev` **без PR** · канон статуса — **метки**, -> имена английские · лёгкий трек **включён** · автор и ревьюер — независимые +> имена английские · треки `ship`/`show`/`ask` задаёт метка владельца (#695) · автор и ревьюер — независимые > агенты/сессии · любой агент может взять любую роль · инфраструктурные задачи > входят в общий флоу сразу на `S7-code-review`. > @@ -93,8 +93,9 @@ S1-new → S2-analysis → S3-spec → S4-spec-review ⟲ → S5-ready → → S6-in-progress → S7-code-review ⟲ → S8-merged → закрыт при выпуске беты служебные: blocked (поверх статуса) rejected (закрыт) -⟲ — возврат на правки, не более 4 циклов (§4), на лёгком и коротком треке 2 -короткий трек (`trivial`, §5.1) идёт S2-analysis → S5-ready, минуя S3 и S4 +⟲ — возврат на правки, не более 4 циклов (§4), на треке `show` 2 +трек `show` (§5) идёт S2-analysis → S5-ready, минуя S3 и S4 +трек `ship` (§5) идёт S1-new → S5-ready, минуя S2, S3 и S4 инфраструктурный трек (§1): без S → S7-code-review ⟲ S6-in-progress → S8-merged ``` @@ -125,9 +126,10 @@ S1-new → S2-analysis → S3-spec → S4-spec-review ⟲ → S5-ready → 5. приоритет **P1/P2/P3**; 6. тип: баг / фича / техдолг; 7. затронутые поверхности (модули, диалоги, бэкенд, i18n); - 8. трек — **по умолчанию `small`** (§5). Если задача идёт полным треком, - называется критерий §5, который она не проходит: «обычный трек» без - названного критерия обоснованием не является. + 8. трек — метка `track:ship`, `track:show` или `track:ask` (§5), **по + умолчанию `track:show`**. Для `track:ask` называется критерий §5, которого + задача не проходит; `track:ship` предлагается, когда правка описывается + одним предложением. Метка владельца главнее предложения аналитика. - **Оценки и приоритет ставятся метками сразу, согласие не запрашивается.** Комментарий аналитики — уведомление, а не запрос: **молчание владельца — согласие**, несогласие он выражает правкой меток или комментарием, и это не @@ -139,7 +141,8 @@ S1-new → S2-analysis → S3-spec → S4-spec-review ⟲ → S5-ready → умолчанию и `blocked`. Вопрос, который можно отложить до ТЗ, не задаётся в аналитике; вопрос, не блокирующий написание ТЗ, не задаётся вовсе — вместо него в ТЗ пишется блок принятых предположений. -- **Выход:** `S3-spec` — переход выполняет сам аналитик, не дожидаясь ответа. +- **Выход:** на `track:ask` — `S3-spec`, на `track:show` — `S5-ready` после AC в + теле issue (§5); переход выполняет сам аналитик, не дожидаясь ответа. Либо, при явном конфликте со `SCOPE.md`, — предложение отклонить с причиной: это единственный случай, когда аналитика останавливается и ждёт владельца. @@ -159,7 +162,7 @@ S1-new → S2-analysis → S3-spec → S4-spec-review ⟲ → S5-ready → - **Ревьюер ≠ автор.** Ревьюер получает issue и ТЗ, без устных пояснений автора. Его задача — не согласиться, а найти, где ТЗ не выполнимо или не проверяемо. - **Артефакт:** `docs/reviews/SPEC-REVIEW--r.md`, вердикт - зелёный / жёлтый / красный. Лёгкий трек — комментарий в issue. + зелёный / жёлтый / красный. Ревью ТЗ проходит только трек `ask` (§5). - **High-находки блокируют.** Medium **в скоупе задачи** чинится в текущем issue: без High это жёлтый вердикт, автор правит ТЗ, фикс проходит повторный цикл. Medium **вне скоупа** — отдельный issue: чужой скоуп в этой задаче не @@ -174,7 +177,9 @@ S1-new → S2-analysis → S3-spec → S4-spec-review ⟲ → S5-ready → Не работа, а **очередь**: единственный статус, из которого можно трогать код. Все пункты обязательны: -- ТЗ существует, ревью ТЗ зелёное, ссылки issue ↔ ТЗ на месте; +- ТЗ существует, на `track:ask` ревью ТЗ зелёное, ссылки issue ↔ ТЗ на месте. + На `ship` и `show` ТЗ — в объёме §5, а пункты ниже закрываются одним словом + «нет»: критерии трека их исключают, иначе это `track:ask`; - **AC1…ACn** — пронумерованные проверяемые критерии приёмки; у каждого указано, чем он доказывается: `unit` / `backend` / `smoke` / `golden` / «ревью кода»; - перечислены затронутые файлы и модули; @@ -516,90 +521,91 @@ dev, ни при публикации документа код-ревью: ин - **Граница между «циклом» и «новым багом»:** до закрытия беты находка ревьюера — возврат на правки; после закрытия — новый issue. Иначе лимит 4 обходится заведением issue вместо возврата. -- Для лёгкого трека лимит ревью ТЗ — **2** цикла: задача на три часа, которую - переписывают трижды, лёгкой не была. +- На треке `show` лимит код-ревью — **2** цикла, ревью ТЗ на нём нет (§5): + задача на три часа, которую переписывают трижды, лёгкой не была. --- -## 5. Лёгкий трек (метка `small`) — путь по умолчанию +## 5. Треки `ship`, `show`, `ask` — метка владельца -Умолчание изменено решением владельца 2026-08-27, issue #338. Прежде полный трек -был бесплатен, а выбор лёгкого требовал обоснования. Фактическая цена: **2.9 -ревью-документа на задачу** в среднем и до шести на одну issue (#329, #316, -#290) — при том что Medium-находки всё равно чинятся в той же задаче, без -отдельного цикла. +Решение владельца 2026-09-28, issue #695. Разбор 85 закрытых задач #600–#691 +показал, что прежний лёгкий трек (`small`) стоил почти столько же, сколько +полный: медиана 115 мин и 12 событий против 102 мин и 13. Дешевле был только +короткий (`trivial`) — 41 мин и 5 событий. Трек определялся формальными +критериями, и у владельца не было метки, чтобы задать его самому. -**Порог не изменился.** Критерии ниже те же и по-прежнему обязательны все -одновременно. Изменилась сторона доказательства: теперь обосновывается не выбор -лёгкого трека, а отказ от него — в `S2-analysis` называется критерий, который -задача не проходит. Полный трек остаётся тем, чем был, для геометрии, миграций -конфига и публичных контрактов: там критерии нарушаются сами, и назвать -нарушенный несложно. +**Трек задаёт метка `track:ship`, `track:show` или `track:ask`. Метка владельца +главнее критериев:** критерии ниже — подсказка аналитика, а не приговор. -Инверсия умолчания не отменяет ничего из §5 ниже и ничего из §4: бюджет четырёх -циклов, арбитраж владельца, обязательность ТЗ на полном треке и правило «ревью -до мержа» остаются как были. Меняется только стоимость пути по умолчанию. +- Аналитик предлагает трек в «Оценке» (§7.2) и ставит метку. По умолчанию — + `track:show`. +- Владелец ставит или меняет любую из трёх меток в любой момент; его метка + окончательна. +- Повысить трек (`ship` → `show` → `ask`) вправе любой агент, с причиной в + комментарии. Понизить — только владелец. +- Трек пересматривается, когда владелец снял усложнявший пункт (#688): + аналитик предлагает понижение, решает владелец. -**Критерии — все одновременно; нарушенный называется явно:** +| | `track:ship` | `track:show` | `track:ask` | +|---|---|---|---| +| Для чего | документация, текст, очевидная правка в несколько строк, CSS-мелочь | баг и полировка в рамках описанного поведения; инфраструктура (§1) по умолчанию | геометрия, миграции конфига, публичные контракты, перф и touch, новый UX-контракт | +| Маршрут | `S1-new` → `S5-ready` → `S6` → `S7` → `S8` | `S1-new` → `S2-analysis` → `S5-ready` → `S6` → `S7` → `S8` | полный, §2 | +| ТЗ | строка «что меняется и чем проверить» в теле issue под `## ТЗ` | «Оценка» (§7.2) и до трёх AC в теле issue под `## ТЗ` | полное ТЗ по §7.1 | +| Ревью ТЗ | нет | нет | да, лимит 4 цикла | +| Локальный гейт | `npm run gate:small` | `npm run gate:small` плюс смоуки `smoke-select` и AC | §8 | +| Код-ревью | до слияния нет; пакетное ревью диапазона перед бетой | модель: корректность и AC | документ ревью, как в §2.7 | +| Лимит циклов код-ревью | — | 2 | 4 | + +**Рамки `track:ship`** механические: дифф `src/**` не больше 30 строк, без новых +файлов в `src/**`, без ключей i18n, без полей конфига и без Python. Выход за +рамки переводит задачу в `track:show`. Рамки и слияние `ship` без ревью модели +проверяет и исполняет конвейер (§10.4, #696); **пока #696 не влит**, `ship` и +`show` проходят конвейер как прежний лёгкий трек — с мутантами по диффу и +документом код-ревью. + +**Подсказка аналитику.** `track:show` уместен, когда выполнено всё сразу: - сложность и риск ≤ 3; - одна поверхность (один диалог, один модуль, один эндпоинт); - нет миграции конфига и новых compatibility-полей; - нет нового UX-контракта — меняется поведение в рамках уже описанного; -- нет влияния на производительность и на touch-контракт. - -**Что упрощается:** - -- ТЗ короче: проблема · контракт · AC1…ACn с доказательством · откат - (в теле issue, как и на полном треке с 2026-09-10); -- ревью ТЗ — комментарий второго агента, отдельный документ не нужен; -- лимит ревью ТЗ — 2 цикла. - -**Что не упрощается:** issue, оценка, статусы, трейлеры коммитов, changelog, -**код-ревью и его документ**, закрытие после беты. Код-ревью не пропускается: -оно проверяет скоуп, риски и качество доказательств, но не заменяет исполнение -тестов. Единственное исключение из повторного ревью — починка упавшего -предрелизного гейта, §11.4. - -Если по ходу выясняется, что критерий нарушен (появилась миграция, задело второй -модуль) — метка `small` снимается, issue возвращается в `S3-spec` и получает -полное ТЗ в теле issue по §7.1. Это не провал, это ранняя диагностика. - -### 5.1 Короткий трек (метка `trivial`) - -Решение владельца 2026-08-13, issue #128. Лёгкий трек делает ТЗ дешёвым; короткий -обходится без него совсем. - -**Маршрут:** `S1-new` → `S2-analysis` → `S5-ready` → `S6-in-progress` → -`S7-code-review` → `S8-merged`. Стадии `S3-spec` и `S4-spec-review` пропускаются. - -`S2-analysis` остаётся: это комментарий, а не прогон CI, и именно там владелец -решает приоритет и ценность. AC пишет автор в теле issue при переводе в -`S5-ready` — до перехода, иначе ревьюеру нечего будет сверять. - -**Критерии, все обязательны:** - -- тип `bug`; -- правка ограничена одной поверхностью, нового UX-контракта нет; -- нет миграции конфига, новых ключей i18n, влияния на перф и touch; -- AC выражаются тремя проверяемыми утверждениями или меньше; +- нет влияния на производительность и на touch-контракт; - **ожидаемое поведение уже зафиксировано** — в `docs/USER-GUIDE.ru.md`, в каноническом документе подсистемы либо однозначно в самом отчёте. Решать нечего. - Если есть что решать, это `S3-spec`, и никакая экономия этого не отменяет. -Метка ставится в `S2-analysis` вместе с остальными оценками, одним комментарием, -где владелец утверждает и приоритет. +Невыполненный пункт — повод предложить `track:ask` с названным критерием. +`track:ship` — когда правку можно описать одним предложением и она укладывается +в рамки выше. -**Что не упрощается:** issue, оценка, статусы, трейлеры, changelog и **код-ревью**. -Лимит циклов код-ревью — 2, как на лёгком треке. - -Если по ходу выясняется, что критерий нарушен, метка снимается и issue уходит в -`S3-spec` за нормальным ТЗ. Как и на лёгком треке, это не провал, а ранняя +**Чем опасны `show` и `ship`.** Они убирают место, где решение проверялось до +написания кода. Признак «решать нечего» держит всю конструкцию, и его нельзя +подтверждать ощущением — только ссылкой на уже зафиксированное поведение. Если по +ходу выясняется, что решать есть что, трек повышается до `ask`: issue уходит в +`S3-spec` и получает полное ТЗ в теле issue по §7.1. Это не провал, а ранняя диагностика. -**Чем этот трек опасен.** Он убирает единственное место, где решение проверялось -до написания кода. Признак «решать нечего» держит всю конструкцию, и его нельзя -подтверждать ощущением — только ссылкой на уже зафиксированное поведение. +**Что не меняется ни на одном треке:** issue и правило №1 (§1), трейлеры +коммитов, changelog для видимого изменения, зелёный Validate на точном SHA тега +беты (§8), гейты стабильного релиза. Качество держится на `dev` и на кандидате +беты, а не на каждой ветке. + +### 5.1 Метки тяжёлых проверок и прежние метки + +Тяжёлые проверки заказываются метками на любом треке — ставит владелец или +автор с причиной в комментарии: + +| Метка | Что включает | +|---|---| +| `ci:full` | полный Validate на ветке задачи | +| `ci:golden` | golden на ветке и приёмку сдвинутых кадров в самой задаче | +| `ci:mutants` | мутанты по диффу на кандидате ревью и слияния | + +Как конвейер читает эти метки, описывает §10.4; до #696 и #697 действуют +прежние правила §8. + +**Прежние метки.** `trivial` и `small` читаются как `track:show`; продуктовая +задача без трековой метки — как `track:ask`; инфраструктурная задача (§1) без +трековой метки — как `track:show`. Новые задачи получают только `track:*`. --- @@ -643,7 +649,7 @@ dev, ни при публикации документа код-ревью: ин ``` issue #NN ↔ ТЗ тело issue, раздел `## ТЗ` (хеш тела — в якорях ревью) - ↔ ревью ТЗ docs/reviews/SPEC-REVIEW-NN-rN.md (или комментарий при `small`) + ↔ ревью ТЗ docs/reviews/SPEC-REVIEW-NN-rN.md (только `track:ask`) ↔ ветка issue/NN-slug ↔ коммиты трейлеры Issue: #NN · User-Visible: yes|no ↔ ревью кода docs/reviews/CODE-REVIEW--rN.md @@ -695,7 +701,7 @@ issue #NN Короткие и однообразные, чтобы читались и человеком, и машиной. - **Аналитика:** `Оценка: ценность N/10 · сложность N/10 · P<1-3> · тип · - поверхности: … · дубликаты: … · лёгкий трек: да/нет` + поверхности: … · дубликаты: … · трек: ship/show/ask (причина)` - **Занятие:** `Взял: <роль> · сессия · ветка issue/NN-slug` - **Хендофф:** `Сделано: … · Файлы: … · Гейты: <команда → результат> · НЕ сделано: … · Риски: … · Следующий статус: … · Новые issue: #…` @@ -850,8 +856,10 @@ Performance зелёные на точном SHA, плюс зелёный E2E н | `blocked` | Ждём внешнего или владельца, **поверх** статусной метки | | `rejected` | Отклонено, issue закрыт | -Модификаторы: `small` (лёгкий трек, сложность ≤3), `trivial` (короткий трек, -§5.1), `hotfix`, `process`, `review-4`; приоритет `P1`/`P2`/`P3`; тип `bug`/`feature`/`tech-debt`. +Модификаторы: трек `track:ship`/`track:show`/`track:ask` (§5), тяжёлые проверки +`ci:full`/`ci:golden`/`ci:mutants` (§5.1), `hotfix`, `process`, `review-4`; +приоритет `P1`/`P2`/`P3`; тип `bug`/`feature`/`tech-debt`. Прежние `small` и +`trivial` читаются как `track:show` (§5.1). Тематические метки (`polish`, `infra`, `tests`, `docs`, `security`, `vacuum`) ортогональны процессу. @@ -1230,9 +1238,10 @@ npm ci, Python и Chromium, оставаясь исполненной job: до ## 11. Исключения -### 11.1 Лёгкий трек +### 11.1 Треки -См. §5 — это не исключение из правила №1, а более дешёвый путь по тем же статусам. +См. §5 — треки `ship` и `show` не исключения из правила №1, а более дешёвые пути +по тем же статусам. ### 11.2 Аварийный хотфикс (метка `hotfix`, решение владельца) @@ -1295,8 +1304,10 @@ Golden, браузерные смоки, performance и полный HA-харн запись в issue публична и релиз-менеджер видит, что именно было сделано перед выпуском. -Это исключение из правила «код-ревью не пропускается никогда» (§5, §7.1) — -единственное, и относится только к окну между `S8-merged` и выпуском. +Это исключение из правила «каждое изменение проходит код-ревью» (§5, §7.1). +Второе такое место — трек `ship` (§5): его ревью не отменяется, а переносится +на пакетное ревью диапазона перед бетой. Здесь же исключение относится только к +окну между `S8-merged` и выпуском. ### 11.5 Независимое ревью линии перед стабильным релизом diff --git a/docs/process/AUTHOR.md b/docs/process/AUTHOR.md index f3c915f2..79dff7c6 100644 --- a/docs/process/AUTHOR.md +++ b/docs/process/AUTHOR.md @@ -40,21 +40,28 @@ - Чек-лист комментарием: дубликаты, скоуп по `docs/SCOPE.md` и `docs/TOUCH-SUPPORT.md`, ценность, сложность и риск, приоритет, тип, поверхности, трек. Оценки ставятся метками сразу; молчание владельца — - согласие; в `S3-spec` аналитик переводит сам. Останавливается аналитика + согласие; дальше аналитик переводит сам: `track:ask` — в `S3-spec`, + `track:show` — в `S5-ready`. Останавливается аналитика только на конфликте со `SCOPE.md` ([§2.2](../../PROCESS.md#22-аналитика-и-оценка)). - Шаблон: `Оценка: ценность N/10 · сложность N/10 · P<1-3> · тип · - поверхности: … · дубликаты: … · лёгкий трек: да/нет` + поверхности: … · дубликаты: … · трек: ship/show/ask (причина)` ([§7.2](../../PROCESS.md#72-шаблоны-комментариев)). -- Лёгкий трек `small` — путь по умолчанию: обосновывается не выбор лёгкого - трека, а отказ от него — называется нарушенный критерий. Критерии, все - сразу: сложность и риск ≤ 3; одна поверхность; нет миграции конфига; - нет нового UX-контракта; нет влияния на перф и touch - ([§5](../../PROCESS.md#5-лёгкий-трек-метка-small--путь-по-умолчанию)). -- Короткий трек `trivial`: `S2-analysis` → `S5-ready`, AC автор пишет в теле - issue до перехода. Тип `bug`, одна поверхность, без i18n, миграции, перфа и - touch, не больше трёх AC, и ожидаемое поведение уже зафиксировано — решать - нечего ([§5.1](../../PROCESS.md#51-короткий-трек-метка-trivial)). +- Трек задаёт метка `track:ship`, `track:show` или `track:ask`, по умолчанию + `track:show`. Метка владельца главнее критериев; повысить трек может любой + агент с причиной в комментарии, понизить — только владелец + ([§5](../../PROCESS.md#5-треки-ship-show-ask--метка-владельца)). +- `track:show`: `S2-analysis` → `S5-ready`, до трёх AC автор пишет в теле + issue до перехода; ревью ТЗ нет, лимит код-ревью 2. Уместен, когда всё + сразу: сложность и риск ≤ 3, одна поверхность, нет миграции, нового + UX-контракта, влияния на перф и touch, и ожидаемое поведение уже + зафиксировано — решать нечего ([§5](../../PROCESS.md#5-треки-ship-show-ask--метка-владельца)). +- `track:ship`: `S1-new` → `S5-ready`, в теле issue строка «что меняется и чем + проверить». Рамки: дифф `src/**` до 30 строк, без новых файлов, i18n, полей + конфига и Python ([§5](../../PROCESS.md#5-треки-ship-show-ask--метка-владельца)). +- Тяжёлые проверки на любом треке — метками `ci:full`, `ci:golden`, + `ci:mutants`; прежние `small` и `trivial` читаются как + `track:show` ([§5.1](../../PROCESS.md#51-метки-тяжёлых-проверок-и-прежние-метки)). ## ТЗ (`S3-spec`) @@ -63,9 +70,9 @@ - Обязательные разделы: сценарий · что человек увидит до и после · проблема · скоуп и не-скоуп · контракт поведения · UX · модель данных и миграция · i18n · AC1…ACn с доказательством · план автотестов · риски · откат · - release-артефакты. На лёгком треке короче: проблема · контракт · AC · откат - ([§7.1](../../PROCESS.md#71-цепочка), - [§5](../../PROCESS.md#5-лёгкий-трек-метка-small--путь-по-умолчанию)). + release-артефакты. На `track:show` — до трёх AC, на `track:ship` — одна + строка ([§7.1](../../PROCESS.md#71-цепочка), + [§5](../../PROCESS.md#5-треки-ship-show-ask--метка-владельца)). - Размытое место не додумывается. Владельцу задаются только продуктовые вопросы — что человек видит или делает и какой объём видимых изменений входит в issue. Всё, чего пользователь не наблюдает, автор решает сам и @@ -74,13 +81,13 @@ - Вопросы — одним комментарием, пачкой: что неясно · что изменится от ответа · вариант по умолчанию. Пока ждём ответа, issue остаётся в `S3-spec` и получает `blocked` ([§7.1](../../PROCESS.md#71-цепочка)). -- DoR перед `S5-ready`: зелёное ревью ТЗ; пронумерованные AC со способом +- DoR перед `S5-ready`: на `track:ask` зелёное ревью ТЗ; пронумерованные AC со способом доказательства (`unit` / `backend` / `smoke` / `golden` / «ревью кода»); файлы и модули; ключи i18n en + ru; миграция по `docs/CONFIG-COMPATIBILITY.md`; перф; touch; release-артефакты; откат; нет - открытых продуктовых вопросов - ([§2.5](../../PROCESS.md#25-готово-к-разработке-dor)). -- Лимит — 4 цикла ревью, на лёгком и коротком треке 2; зелёный вердикт цикла + открытых продуктовых вопросов. На `ship` и `show` пункты DoR закрываются + словом «нет» ([§2.5](../../PROCESS.md#25-готово-к-разработке-dor)). +- Лимит — 4 цикла ревью, на `track:show` 2 цикла код-ревью; зелёный вердикт цикла не тратит; исчерпание — решение владельца: разделить, отклонить, арбитраж ([§4](../../PROCESS.md#4-лимит-циклов-ревью-4)). diff --git a/docs/process/REVIEWER.md b/docs/process/REVIEWER.md index 213c386f..a4b73f69 100644 --- a/docs/process/REVIEWER.md +++ b/docs/process/REVIEWER.md @@ -24,8 +24,8 @@ ## Ревью ТЗ -- Артефакт — `docs/reviews/SPEC-REVIEW--r.md`, на лёгком треке — - комментарий ([§2.4](../../PROCESS.md#24-тз-на-ревью)). +- Артефакт — `docs/reviews/SPEC-REVIEW--r.md`. Ревью ТЗ проходит только + трек `ask` ([§2.4](../../PROCESS.md#24-тз-на-ревью)). - ТЗ живёт в теле issue, раздел `## ТЗ`; `docs/specs/` — архив до 2026-09-10 ([§2.3](../../PROCESS.md#23-тз-в-работе--написание-тз)). - Проверить обязательные разделы, однозначность каждого AC и способ его @@ -122,8 +122,8 @@ ([§7.2](../../PROCESS.md#72-шаблоны-комментариев)). - Вперёд двигает только зелёный вердикт; жёлтый и красный возвращают автору ([§7.2](../../PROCESS.md#72-шаблоны-комментариев)). -- Зелёный вердикт цикла не образует; лимит — 4 цикла, на лёгком и коротком - треке 2; бюджет считается по этапу +- Зелёный вердикт цикла не образует; лимит — 4 цикла, на `track:show` 2; + бюджет считается по этапу ([§4](../../PROCESS.md#4-лимит-циклов-ревью-4), [§10.4](../../PROCESS.md#104-событийный-конвейер-метка-как-триггер)). - Запрещено: Medium-находки, оставленные как TODO в документе ревью; diff --git a/scripts/mutation-registry.mjs b/scripts/mutation-registry.mjs index 5f177680..0b2711df 100644 --- a/scripts/mutation-registry.mjs +++ b/scripts/mutation-registry.mjs @@ -10262,8 +10262,8 @@ const MUTANT_DEFINITIONS = [ + 'the digest must fail as soon as an anchor goes stale (#634 AC2)', patches: [{ file: 'docs/process/AUTHOR.md', - find: '[§5.1](../../PROCESS.md#51-короткий-трек-метка-trivial)', - replace: '[§5.1](../../PROCESS.md#51-короткий-трек)', + find: '[§5.1](../../PROCESS.md#51-метки-тяжёлых-проверок-и-прежние-метки)', + replace: '[§5.1](../../PROCESS.md#51-метки-тяжёлых-проверок)', }], }, { @@ -10273,8 +10273,8 @@ const MUTANT_DEFINITIONS = [ + 'digest invented or a paraphrase nobody can check (#634 AC2)', patches: [{ file: 'docs/process/AUTHOR.md', - find: ' нечего ([§5.1](../../PROCESS.md#51-короткий-трек-метка-trivial)).', - replace: ' нечего.', + find: ' `track:show` ([§5.1](../../PROCESS.md#51-метки-тяжёлых-проверок-и-прежние-метки)).', + replace: ' `track:show`.', }], }, { diff --git a/scripts/task-packet.mjs b/scripts/task-packet.mjs index 8b4f2a6e..bd91fbc8 100644 --- a/scripts/task-packet.mjs +++ b/scripts/task-packet.mjs @@ -40,8 +40,8 @@ export function rightsFor(status, labels = [], { infrastructure = false, infrast lines.push('метка infra — только подсказка, не доказательство и не право: до ветки проверь предполагаемые пути; без class A начинай сразу, при любом class A нужен продуктовый S-flow (#562)'); } switch (status) { - case 'S1-new': lines.push('следующий шаг: аналитика (S2) — оценки метками, критерий лёгкого трека, затем ТЗ'); break; - case 'S2-analysis': lines.push('следующий шаг: ТЗ (S3); трек по умолчанию small — отказ от него обосновать названным критерием §5'); break; + case 'S1-new': lines.push('следующий шаг: аналитика (S2) — оценки и трек метками (по умолчанию track:show); на track:ship — строка «что меняется и чем проверить» под «## ТЗ», затем S5'); break; + case 'S2-analysis': lines.push('следующий шаг: track:show — до трёх AC под «## ТЗ», затем S5; track:ask — ТЗ (S3) с названным критерием §5'); break; case 'S3-spec': lines.push('следующий шаг: ТЗ готово → push ветки → метка S4-spec-review (метку после push)'); break; case 'S4-spec-review': lines.push('идёт ревью ТЗ: ждать вердикт (scripts/wait-verdict.mjs), не править материал'); break; case 'S5-ready': lines.push('следующий шаг: ветка issue/NN-slug от dev, код по ТЗ, метка S6-in-progress'); break; @@ -126,6 +126,21 @@ export function branchIsInfrastructure(changedFiles = []) { const PRE_CODE_STATUSES = ['S1-new', 'S2-analysis', 'S3-spec', 'S4-spec-review', 'S5-ready']; +/** + * Трек продуктовой задачи по меткам (PROCESS §5, #695): `track:ship`, + * `track:show` или `track:ask`; прежние `trivial` и `small` читаются как `show` + * (§5.1), задача без трековой метки — как `ask`. Метки трека не доказывают + * продуктовый поток: инфраструктурной задаче владелец тоже может поставить + * `track:*`, чтобы задать ей цену конвейера. + */ +export function trackFromLabels(labels = []) { + if (labels.includes('track:ship')) return 'ship'; + if (labels.includes('track:show')) return 'show'; + if (labels.includes('track:ask')) return 'ask'; + if (labels.includes('trivial') || labels.includes('small')) return 'show'; + return 'ask'; +} + /** * Признаки продуктового S-flow (#632). Инфраструктурная задача входит в поток * сразу на S7 и никогда не несёт S1–S5, ТЗ и ревью ТЗ; поэтому любой из этих @@ -165,7 +180,7 @@ export function buildPacket(inputs) { const track = infrastructure ? 'инфраструктурный' : infrastructureHint ? 'инфраструктурный (предварительно; подтвердить путями/diff)' - : labels.includes('trivial') ? 'trivial' : labels.includes('small') ? 'small' : 'полный'; + : trackFromLabels(labels); const stage = status === 'S4-spec-review' || status === 'S3-spec' || status === 'S5-ready' ? 'spec' : 'code'; const verdict = lastVerdict(comments, reviewDocs, stage); // ТЗ живёт в теле issue (#517); архивный файл — источник только у задач до diff --git a/test/process-digests.test.mjs b/test/process-digests.test.mjs index 0855a8a9..87cba7c2 100644 --- a/test/process-digests.test.mjs +++ b/test/process-digests.test.mjs @@ -46,8 +46,8 @@ const KEY_RULES = { ['1-основное-правило', 'D сильнее A'], ['3-правила', 'Ровно одна метка статуса'], ['3-правила', 'Статус меняется до действия, а не после'], - ['5-лёгкий-трек-метка-small--путь-по-умолчанию', 'обосновывается не выбор лёгкого трека, а отказ от него'], - ['51-короткий-трек-метка-trivial', 'ожидаемое поведение уже зафиксировано'], + ['5-треки-ship-show-ask--метка-владельца', 'Метка владельца главнее критериев'], + ['5-треки-ship-show-ask--метка-владельца', 'ожидаемое поведение уже зафиксировано'], ['71-цепочка', 'Владельцу задаются только продуктовые вопросы'], ['71-цепочка', 'issue остаётся в `S3-spec` и получает `blocked`'], ['26-в-разработке--реализация', 'каждый коммит несёт трейлеры `Issue: #` и `User-Visible: yes|no`'], diff --git a/test/task-packet.test.mjs b/test/task-packet.test.mjs index 15b9c047..0e5af118 100644 --- a/test/task-packet.test.mjs +++ b/test/task-packet.test.mjs @@ -2,6 +2,7 @@ import test from 'node:test'; import assert from 'node:assert/strict'; import { branchIsInfrastructure, buildPacket, evidenceFor, productFlowEvidence, extractAcceptanceCriteria, lastVerdict, ownerDecisions, renderPacket, rightsFor, + trackFromLabels, } from '../scripts/task-packet.mjs'; import { materialAnchorBlock } from '../scripts/review-doc-guard.mjs'; @@ -87,7 +88,7 @@ test('пакет собирается и рендерится: статус, м validate: { status: 'зелёный', url: 'https://run' }, }); assert.equal(packet.status, 'S6-in-progress'); - assert.equal(packet.track, 'small'); + assert.equal(packet.track, 'show'); assert.equal(packet.material.treeMatchesVerdict, true); assert.deepEqual(packet.unverified, ['AC2']); const md = renderPacket(packet); @@ -118,7 +119,7 @@ test('#562: the infra label alone never grants the accelerated track', () => { labels: ['infra', 'S6-in-progress'], branch: { name: 'issue/999-product', tip: 'e'.repeat(40), base: 'f'.repeat(40), ahead: 1, behind: 0, treeWithoutReviews: null, infrastructure: false }, }); - assert.equal(packet.track, 'полный'); + assert.equal(packet.track, 'ask'); assert.ok(packet.rights.some((l) => l.includes('продуктовый код трогать МОЖНО'))); }); @@ -152,7 +153,7 @@ test('#632: product S6 issue keeps class A rights while its diff has no class A branch: { name: 'issue/607-ha-dialog-close', tip: 'e'.repeat(40), base: 'f'.repeat(40), ahead: 1, behind: 0, treeWithoutReviews: null, infrastructure: true }, reviewDocs: [{ name: 'SPEC-REVIEW-607-r1.md', text: 'Вердикт: зелёный' }], }); - assert.equal(packet.track, 'small'); + assert.equal(packet.track, 'show'); assert.ok(packet.rights.some((l) => l.includes('продуктовый код трогать МОЖНО'))); assert.ok(packet.rights.every((l) => !l.includes('файлы класса A трогать НЕЛЬЗЯ'))); assert.match(renderPacket(packet), /Продуктовый поток: .*ТЗ/); @@ -192,7 +193,7 @@ test('#632 r1: trivial issue in S6/S7 keeps class A rights without any spec arte labels, branch: { name: 'issue/612-x', tip: 'e'.repeat(40), base: 'f'.repeat(40), ahead: 1, behind: 0, treeWithoutReviews: null, infrastructure: true }, }); - assert.equal(packet.track, 'trivial', labels.join(',')); + assert.equal(packet.track, 'show', labels.join(',')); assert.ok(packet.rights.some((l) => l.includes('продуктовый код трогать МОЖНО')), labels.join(',')); assert.ok(packet.rights.every((l) => !l.includes('файлы класса A трогать НЕЛЬЗЯ')), labels.join(',')); } @@ -217,3 +218,13 @@ test('#517 AC5: AC берутся из тела issue, файл ТЗ — тол const neither = buildPacket({ ...base, issue: { ...base.issue, body: 'ничего' }, specs: [] }); assert.deepEqual(neither.acceptance, []); }); + +test('#695: трек по меткам — track:* главнее прежних, по умолчанию ask', () => { + assert.equal(trackFromLabels(['track:ship']), 'ship'); + assert.equal(trackFromLabels(['track:show', 'bug']), 'show'); + assert.equal(trackFromLabels(['track:ask', 'small']), 'ask', 'явная метка владельца главнее прежней'); + assert.equal(trackFromLabels(['trivial']), 'show'); + assert.equal(trackFromLabels(['small']), 'show'); + assert.equal(trackFromLabels(['bug', 'P2']), 'ask'); + assert.equal(trackFromLabels([]), 'ask'); +});