docs: review document for #738

Issue: #738
User-Visible: no
This commit is contained in:
claude[bot]
2026-10-01 05:52:18 +00:00
parent 82fbad67d5
commit df8482c702
+148
View File
@@ -0,0 +1,148 @@
# CODE-REVIEW-738-r1
**Issue:** #738 — «process-gate, правило 10: код из S3 после reclassify не судится»
**Трек:** show · заход r1 · блокирующих циклов использовано 0 из 2
**Материал раунда:** ветка `issue/738-rule10-epochs`, один коммит
`021a94959856c81c7fafac90f8f84fb87cc2a1c2` поверх `origin/dev`
`bc59917ea473635fe3a2f22893afd28513d37131` (merge-base
`76558bf2a0bf72dcfed369743639c989b4099450`). Диапазон ревью —
`git diff origin/dev...HEAD`.
## Скоуп
Чистая правка процессного гейта: `scripts/process-gate.mjs` (правило 10,
`checkCommitEraStatuses`), `test/process-gate.test.mjs`, PROCESS.md §10.2.
Файлов класса A нет, продуктовый код (`src/**`, `custom_components/**`) не
тронут. `User-Visible: no` — верно: правка видна только конвейеру.
Критерии маршрута §5 (route): `complexity` — одна чистая функция, низкий риск;
`surfaces` — одна поверхность (правило 10 гейта); `migration` — нет;
`ux-contract` — нет; `perf-touch` — нет; `undocumented` — ожидаемое поведение
зафиксировано правилом №1, §2.5 и #726, подтверждено владельцем в комментарии
трека. Все критерии пройдены → **route: fix**, `reclassify` не требуется.
## Что сделано (по диффу)
`checkCommitEraStatuses` раньше сравнивал `authorDate` коммита только с
**первым** событием `labeled` из `allowed` (`readyAt`). Теперь строится шкала
статусных событий (`statusEvents`): метки `allowed` открывают эпоху «можно
писать код», `PRE_READY_STATUS` (`S1-new`…`S4-spec-review`) её закрывают,
остальные метки (`blocked`, `track:*`, `review-4`, `S8-merged` при
`--no-merged`) в шкалу не попадают вовсе. Статус на момент `w` —
`statusIndexAt`: последнее событие с `at ≤ w`. Для коммита: если на его
`authorDate` эпоха открыта — чисто; если нет и готовности вообще не было —
старый текст «до первого достижения…»; если готовность была, но закрылась —
новый текст называет статус на `authorDate`, время возврата (первое закрывающее
событие после последней готовности) и следующую готовность или «ещё не
достигнут».
PROCESS.md §10.2 получил пункт 10, точно описывающий эту модель (эпохи,
закрывающие метки, `warn` без таймлайна).
## Как проверялось
| Гейт | Статус | Как |
|---|---|---|
| `npx tsc --noEmit`, полный `npm test`, `npm run build` + сверка бандла | не перегонялся | Validate на `021a9495` зелёный (run 36821163281) — §8 позволяет не дублировать на этом SHA |
| `test/process-gate.test.mjs` (точечно) | прогнан лично | `node --test test/process-gate.test.mjs` → 38/38 `ok`, включая старый тест rule 10 (#311) и три новых (#738) |
| Тест умеет падать (AC1, AC2) | проверено лично | Временно подменил `scripts/process-gate.mjs` на версию `origin/dev`, прогнал тот же тестовый файл: старый тест (#311) остаётся зелёным, три новых теста (#738) красные (`not ok 36/37/38`). Рабочую копию восстановил из git сразу после, `git status` — чисто |
| `node scripts/mutation-gate.mjs --check` | прогнан лично | `предупреждений mutation registry: 3`, browser guards 200/200 — совпадает с заявленным «как на dev» |
| `node scripts/smoke-select.mjs --base origin/dev --head HEAD` | прогнан лично | «Исполняемого frontend-диффа нет (src/**/*.ts не тронут)» — смоки не выбираются, выбирать нечего (`src/**` не менялся) |
| `python -m pytest tests_backend` | не требуется | `custom_components/**/*.py` не тронут |
| `npm run invariants` | не требуется | геометрия и ссылки на неё не тронуты |
| `npm run golden:verify` | не требуется | метки `ci:golden` на issue нет, рендер не тронут |
| performance-профили | не требуется | не названы в AC |
| Побочное наблюдение из ТЗ (не AC): риск для открытых веток S5…S7 | частично | `gh issue list` по меткам `S5-ready/S6-in-progress/S7-code-review` — живые кандидаты: #729, #731, #735, #736, #737, #739, #740, #741, #742 (и сам #738). По их **текущим** меткам ни один не стоит в `S3-spec`/`S4-spec-review`, то есть тривиального кейса «сейчас в пред-готовом статусе» нет. Полную проверку (`process-gate --range origin/dev..<ветка> --issues --report` по каждой из этих веток, с разбором таймлайна на предмет скрытого возврата `S5+→S3/S4` в прошлом) не гонял — это явно не-AC наблюдение из самого ТЗ, и объём трека show его не требует |
## Проверка AC по тексту ТЗ
- **AC1** (эпоха после возврата) — доказан `test/process-gate.test.mjs:905-988`.
Лично проверил сценарий таблицы ТЗ (S5 t1→S6 t2→S7 t3→S3 t4→S4 t5→S5 t6):
коммит `t2+1ч` чист, `t4+1ч` красит с текстом про `S3-spec`/`t4`/`t6`,
`t5+1ч` — про `S4-spec-review`/`t4`/`t6`, `t6+1ч` чист, `t1-1ч` — старый
текст без «после возврата». Два возврата подряд и «возврат без новой
готовности → ещё не достигнут» — второй тест файла, тоже зелёный на HEAD и
красный на dev. **Доказан автотестом, тест умеет падать — проверено лично.**
- **AC2** (совместимость и границы) — третий новый тест: старый тест #311 не
тронут и зелёный; таймлайн только из `allowed` даёт прежние вердикты; класс
B/C не красит; `blocked`/`track:ask` не меняют статус; `S8-merged` со
`STRICT_STATUS` не открывает и не закрывает эпоху; неотсортированные события
дают тот же результат; `authorDate == S3-spec` уже в `S3`. **Доказан
автотестом, тест умеет падать — проверено лично** (тот же red/green прогон).
- **AC3** (канон и гейт) — PROCESS.md §10.2 действительно называет эпохи,
`S1`…`S4` как закрывающие и `warn` без таймлайна — прочитано лично
(`PROCESS.md:1186-1202`). `gate:small` и `mutation-gate --check`: второе
прогнано лично (см. таблицу), `gate:small` не перегонялся отдельно — его
состав (typecheck/test/lint) покрыт зелёным Validate на этом SHA.
**Проверено чтением канона + частичным исполнением.**
Защитный AC (AC1/AC2 — гард против невидимого нарушения DoR): таблица «AC ·
чем доказан · чем краснеет» в теле issue не пустая и подтверждена мной лично
(red-run на `origin/dev`-версии функции), а не только заявлением автора.
## Находки
Нет High. Нет Medium.
- **Low (не блокирует, снято)**: автор сознательно не завёл мутанта в реестр
(`demo/guard`) для новой ветки `checkCommitEraStatuses`, аргументируя тем,
что функция чистая и тест уже содержит богатый набор отрицательных случаев.
Для трека show это ровно «бухгалтерия» — отсутствие записи в реестре, а не
неподтверждённая защита (защита подтверждена исполнением red/green выше).
Снимаю без действия.
## Что проверено и корректно
- Логика эпох (`statusEvents`/`statusIndexAt`/`checkCommitEraStatuses`)
разобрана построчно и прогнана на сценарии из ТЗ лично — поведение совпадает
с описанием «Что меняется» и с обоими текстами находок.
- Обратная совместимость с правилом 10 до #738 (#311) подтверждена
неизменным зелёным тестом и логически: при таймлайне без возвратов
`lastReady` всегда `-1`, так что ветка кода схлопывается к прежнему
поведению (`readyAt` = `firstReady.at`).
- Трейлеры коммита: `Issue: #738`, `User-Visible: no` — верно, changelog не
требуется. Один коммит, ветка `issue/738-rule10-epochs` соответствует
номеру issue. Класса A файлов нет — отдельного ТЗ-AC на трейлер не теряет
силу.
- Одно число — один источник (§8): список `PRE_READY_STATUS` объявлен один
раз как константа и используется и в коде, и неявно описывается в
PROCESS.md (текстом, не импортом) — это документация поведения, а не
второй независимый источник истины; расхождения нет, проверено построчной
сверкой текста канона с кодом.
- `PRE_READY_STATUS` экспортирован, но нигде не импортируется (ни тестом, ни
другим скриптом) — стилистически не отличается от уже существующих
`ALLOWED_STATUS`/`STRICT_STATUS`, не находка.
## Чего не проверял
- Полный `npm test`, `npx tsc --noEmit`, `npm run build` целиком — не
перегонял, положился на зелёный Validate этого SHA (run 36821163281);
точечно сам прогнал только изменённый тестовый файл.
- Browser-смоки — не прогонял: `smoke-select.mjs` не выбрал ни одного (нет
фронтенд-диффа).
- Исчерпывающий обход таймлайнов всех открытых веток `S5…S7` на предмет
скрытого прошлого возврата `S5+→S3/S4` — не AC, трек show не требует этого
объёма; сделана только лёгкая проверка по текущим меткам (см. таблицу
гейтов).
- Свежесть скриншотов документации — не гейт задачи, не проверялась.
## Вердикт
Зелёный. Код делает ровно то, что заявлено в ТЗ, оба новых и прежний тест
проверены лично на предмет «умеет падать», граница трека show (route: fix)
соблюдена, трейлеры в порядке, гейты по диффу и AC либо прогнаны лично, либо
законно не требуются.
---
<!-- material-anchors: сгенерировано конвейером (#414) -->
## Материал раунда
- Ветка: `issue/738-rule10-epochs`, коммит `021a94959856` — ребейз его осиротит, и это нормально: ниже якоря, которые ребейз не меняет.
- Дерево материала: `22e667a9118166033cd5f1a1fd2f2a2287c7b924`
```
git log --all --format='%H %T' | grep 22e667a91181
```
- Тело issue: `cd8ce90eb1d3e249c9aca6c38257d69e533d0e4b030cd6f4681f385c407ab264`
- Вердикт конвейера: `green` · High 0 · маршрут `fix`