diff --git a/docs/reviews/CODE-REVIEW-690-r1.md b/docs/reviews/CODE-REVIEW-690-r1.md new file mode 100644 index 00000000..149e63a2 --- /dev/null +++ b/docs/reviews/CODE-REVIEW-690-r1.md @@ -0,0 +1,134 @@ +# CODE-REVIEW-690-r1 + +**Issue:** #690 · **Этап:** code (`S7-code-review`) · **Трек:** show (инфраструктурный) · +**Заход:** r1 · **Блокирующих циклов:** 0 из 2 · **Материал:** ветка +`issue/690-visual-minimum`, ровно `52a56430abbf98f66233b9637a5f7c78cc8d0600` +(рабочая копия на нём; `git rev-parse HEAD` сверен). + +## Скоуп + +Три AC из ТЗ (тело issue, п. 1′/4/попутно, решения владельца 2026-09-28): + +- **AC1.** `smoke-select` при исполняемом диффе без доказанной связи печатает и + отдаёт в JSON фиксированный «визуальный минимум» (5–8 смоков режимов, слоёв, + отрисовки, среди них `smoke_modes`); `gate:small -- --smokes` гоняет его + вместе с выборкой; при доказанной связи или без исполняемого диффа минимума + нет. +- **AC2.** Правило для дефектов растра/резкости/композитинга — свидетель, + красный на старом коде по симптому владельца, подтверждение в реальном + GPU-браузере — в PROCESS §7.1 и `docs/process/AUTHOR.md`. +- **AC3.** `task-packet.mjs` описывает прежнюю метку `trivial` как продуктовый + поток, читаемый как `track:show` (§5.1), а не как «короткий трек без ТЗ». + +Диффа класса A нет (только `PROCESS.md`, `docs/TESTING.md`, +`docs/process/AUTHOR.md`, `scripts/gate-small.mjs`, +`scripts/mutation-registry.mjs`, `scripts/smoke-select.mjs`, +`scripts/task-packet.mjs`, `test/smoke-select.test.mjs`, +`test/task-packet.test.mjs`) — класс B+C, `User-Visible: no` в единственном +коммите корректен (видимого пользователю поведения карточки нет). Трейлер +`Issue: #690` на месте. + +## Как проверялось + +Дешёвые гейты подтверждены зелёным Validate на этом SHA (run 36528250333, +`typecheck`+`npm test`+`npm run build`+`bundle-policy --verify`) — не +перегонялись повторно. + +Дифф по `smoke-select` на самом материале: + +``` +$ node scripts/smoke-select.mjs --base origin/dev --head HEAD +Исполняемого frontend-диффа нет (src/**/*.ts не тронут). +Browser-smoke этим диффом не выбираются... +``` + +`noExecutableDiff: true` — ни один из названных в АС1 смоков, ни визуальный +минимум задачей не требуется: сама задача не трогает `src/**`. Браузерные +смоки не гонялись — по выводу инструмента они не выбраны, а тело issue не +называет смок отдельно для этого прогона. + +По каждому AC — что проверено и как: + +| AC | Чем доказан | Чем краснеет | Прогон | +|---|---|---|---| +| AC1 | `test/smoke-select.test.mjs` (`#690 п.1′: …`, 2 новых теста) + 3 именованных мутанта | `visual-minimum-silent-again` (обнуляет `visualMinimum`), `visual-minimum-on-proven-link` (минимум течёт по одному факту исполняемости, не по недоказанности), `gate-small-skips-visual-minimum` (убирает минимум из `smokesToRun`) | Прогнал сам: baseline зелёный (`node --test --test-name-pattern="#690" test/smoke-select.test.mjs` — 2/2 pass); применил патч каждого из трёх мутантов вручную — все три ломают ровно ожидаемый тест (проверено построчно, дифф отменён после каждой пробы). `node scripts/mutation-registry-check.mjs` — 0 (реестр непротиворечив, `find`-строки совпадают с текущим кодом) | +| AC2 | Текст в PROCESS §7.1 (строки 693–696) и `docs/process/AUTHOR.md` (раздел ТЗ) | защитный AC текстового/процессного рода — «чем краснеет» не применимо к формулировке правила самой по себе; доказательство — точное соответствие формулировке владельца из комментария 2026-09-28 | Проверено чтением, не исполнением: сверил текст правила в обоих файлах с формулировкой владельца дословно — совпадает; место в §7.1 логически стоит рядом с «Размытое место не додумывается» (тот же смысловой блок про доказательства до кода), не конфликтует с соседним текстом | +| AC3 | `test/task-packet.test.mjs` (обновлённое `productFlowEvidence` ожидание), `scripts/mutation-registry.mjs` (`find`/`replace` синхронизированы с новой строкой) | тот же мутант `task-packet-trivial-is-product-flow`, `because` тоже обновлён, чтобы не противоречить #695 | `node --test test/task-packet.test.mjs` — 16/16 pass; сверил формулировку с уже принятым #695 (`scripts/process-track.mjs:39`, `PROCESS.md:935`) — согласовано, не изобретает нового понятия | + +Дополнительно проверено: +- `node --test test/smoke-select.test.mjs` — 9/9 pass (полный файл, не только `#690`-подмножество). +- `node --test test/gate-small.test.mjs` — 5/5 pass. +- `git diff --stat` — бандл (`dist/**`) не тронут, `Release:`-трейлер не нужен. +- Единственное число, дублирующееся в диффе, — «восемь» смоков визуального + минимума: один источник (`VISUAL_MINIMUM.length` в `scripts/smoke-select.mjs`), + PROCESS.md и `docs/TESTING.md` его лишь цитируют текстом, не хардкодят + отдельно; `test/smoke-select.test.mjs` проверяет диапазон 5–8, а не точное + число, так что смещение массива само по себе не расходится с документами + сильнее допустимого. Все 8 файлов `demo/smoke_*.mjs` из `VISUAL_MINIMUM` + существуют (проверено `existsSync`, тест это же утверждает). + +## Находки + +Нет. Изменение узкое, три AC разобраны по коду и тестам, мутанты +воспроизведены вручную и действительно красные на инвертированном +поведении, документный AC2 текстуально совпадает с решением владельца, AC3 +согласован с уже принятым #695 и не вводит расхождений. + +## Что проверено и корректно + +- `VISUAL_MINIMUM` — 8 существующих смоков, включает `smoke_modes.mjs` + (именно его не хватило #687 по тексту issue); список заморожен + (`Object.freeze`). +- `selectSmokes()`: `visualMinimum` заполняется только при `unproven`, при + доказанной связи (прямой или зарегистрированной) и при `noExecutableDiff` + остаётся пустым — подтверждено фикстурами `unproven.diff`, + `234-chain-thickness.diff`, `docs-only.diff`. +- `smokesToRun()` в `gate-small.mjs` включает `visualMinimum` в список для + прогона наравне с `direct`/`registered`, с дедупликацией через `Set`. +- CLI (`report()`) печатает визуальный минимум отдельной громкой строкой + внутри ветки `НЕОПРЕДЕЛЁННОСТЬ», не подменяя её. +- `gate-small.mjs` итоговый лог называет причину («связь не доказана — … + визуальный минимум (#690)») отдельно от обычного случая. +- Мутант `task-packet-trivial-is-product-flow` обновлён синхронно с + изменением текста в `scripts/task-packet.mjs` — `find`-строка совпадает, + `mutation-registry-check.mjs` подтверждает. +- Единственный коммит, трейлеры `Issue:`/`User-Visible:` корректны, + ветка от актуального `dev` (`6e073134`), файлов класса A нет. + +## Чего не проверял + +- Полный `npm run gate:small`, `npm test`, `npm run build`, + `golden:verify`, `pytest tests_backend`, `npm run invariants` — не + прогонял: Validate зелёный на этом SHA закрывает дешёвые гейты + (typecheck/test/build/bundle-verify), диф не трогает Python и геометрию, + `ci:golden` не выставлена. +- Браузерные смоки (включая сам `VISUAL_MINIMUM`) — не гонял: диф не + трогает `src/**`, `smoke-select.mjs --base origin/dev --head HEAD` на + материале прямо отвечает `noExecutableDiff`, обязательного смока в АС нет. +- Мутанты по диффу как отдельный обязательный гейт ревью — не запрашивались + (трек `show`, #690/REVIEWER.md «Трек show»); три названных в АС1 мутанта + всё же проверены вручную вручную, потому что AC1 защитный и без третьей + колонки таблицы «чем краснеет» находка была бы Medium. +- Performance-профили — не названы в AC, не гонял. +- Поведение конвейера `_process.yml`/меток `trivial` на реальных открытых + issue — не проверял вживую; ограничился текстовым сравнением с уже + принятым #695. + +## Вердикт + +Зелёный. AC1–AC3 выполнены и доказаны каждый своим способом (тест+мутант, +чтение текста, тест); находок нет. + +--- + + + +## Материал раунда + +- Ветка: `issue/690-visual-minimum`, коммит `52a56430abbf` — ребейз его осиротит, и это нормально: ниже якоря, которые ребейз не меняет. +- Дерево материала: `3e5463d83784c360485d89dd297cbd4cbb816e5c` + ``` + git log --all --format='%H %T' | grep 3e5463d83784 + ``` +- Тело issue: `4796e50b141f022b6ef98e61809bd29d3dd30e0dcf87f368da80b697565b156b` +- Вердикт конвейера: `green` · High 0