From 48f6f2e6a7fe1e18a8008262b5fa829f42111253 Mon Sep 17 00:00:00 2001 From: "claude[bot]" <209825114+claude[bot]@users.noreply.github.com> Date: Mon, 28 Sep 2026 22:39:31 +0000 Subject: [PATCH] docs: review document for #699 Issue: #699 User-Visible: no --- docs/reviews/CODE-REVIEW-699-r3.md | 174 +++++++++++++++++++++++++++++ 1 file changed, 174 insertions(+) create mode 100644 docs/reviews/CODE-REVIEW-699-r3.md diff --git a/docs/reviews/CODE-REVIEW-699-r3.md b/docs/reviews/CODE-REVIEW-699-r3.md new file mode 100644 index 00000000..1de28bd9 --- /dev/null +++ b/docs/reviews/CODE-REVIEW-699-r3.md @@ -0,0 +1,174 @@ +# CODE-REVIEW-699-r3 + +Issue: #699 · этап: code · трек: show · заход: r3 · блокирующих циклов до этого раунда: 1/2 + +Материал раунда: `git log --oneline origin/dev..HEAD` / `git diff origin/dev...HEAD`, +вершина ветки `issue/699-ratchet-bands` = `4fa3c7977ebbd11907364af626f978deec790aa5`. +Validate на этом SHA — success (run 36491631358). Рабочая копия уже на этом SHA; +`git fetch`/`checkout` не делал. + +Предыдущий раунд: r2, документ `docs/reviews/CODE-REVIEW-699-r2.md`, материал +`23aca8a987142633c6f0c7522538d6601aa942d9`, вердикт **зелёный** (High 0, Medium 0). + +## Почему r3, если r2 был зелёным + +Пока шло ревью r2, `dev` продвинулся на 17 коммитов (влиты #696–#698, #701, +#702). Владелец опубликовал кандидат `4fa3c797` как ребейз того же дерева на +новый `dev@e1700757` и сам заявил: «Дифф изменился при ребейзе… материал ревью +`23aca8a9` и кандидат `4fa3c797` дают разные patch-id: соседние правки в `dev` +изменили содержимое патча» (issue-комментарий 22:18:47, ссылка на §2.10, #492). +Зелёный вердикт цикл не тратит, но материал под ним умер (объекты `23aca8a9` и +дерево `d7500b073db5` не резолвятся в этом дереве — ожидаемо после ребейза, +`git cat-file -t` возвращает «not found», это не находка, см. REVIEWER.md +«Повторный раунд»), поэтому конвейер честно открыл новый заход, а не подтянул +старый вердикт под новый SHA (#312). + +**Проверка гипотезы «дифф на самом деле не изменился».** Я не могу сравнить +деревья байт-в-байт (старые объекты собраны сборщиком мусора), поэтому сверил +по содержимому: прочитал целиком `git diff origin/dev...HEAD` (19 файлов, +856+/146-) и построчно сопоставил с описанием кода в r1/r2 (таблицы находок, +цитаты кода, номера тестов). Результат — по каждому файлу код и тесты +текстуально совпадают с тем, что описывали r1/r2: +`initialViewCeilingViolation`/`lazyGraphCeilingViolation` без ветки `shrank`, +`compareWithBaseline` с `METRIC_BANDS`, CLI `bundle-budget.mjs` с потолком +беты до `assertBundleBudget`, `mutation-registry-check.mjs` — `warned` вместо +`stale`, новый `scripts/ratchets.mjs` (`report`/`tighten`), шаг `tighten` в +`docs/DEVELOPMENT.md` («Prepare the candidate as usual», сразу после +`npm run bundle:release`) — ровно формулировка, которую цитировал r2. Значит +patch-id разошёлся не из-за смыслового отличия, а из-за смещения контекстных +строк при повторном ребейзе (PROCESS.md/докс, которые правили #701 и другие +соседи, лежат рядом с местом вставки #699). Разбор ниже — по этой дельте: она +не локальна формально (ребейз на ушедший вперёд `dev`, §2.10), поэтому я +перечитал файлы целиком и перепрогнал тесты сам (см. «Как проверялось»), а не +ограничился таблицей «чем закрыта» — но новых находок это не даёт, потому что +менять было нечего. + +## Скоуп + +Не изменился с r1 (см. `docs/reviews/CODE-REVIEW-699-r1.md`, «Скоуп»): +инфраструктурная задача, файлов класса A нет, `src/**` не тронут. Двусторонние +храповики с нулевым запасом заменены на полосу над потолком последней беты +(строки двух ядер, gzip четырёх графов, шесть чисел монолита, лимит браузерных +мутантов из жёсткого — в ориентир); `scripts/ratchets.mjs` — инструмент +релиз-менеджера (`report`/`tighten`); шаг `tighten` закреплён в единственном +каноническом release-runbook (`docs/DEVELOPMENT.md`) — это и есть M1 из r1, +закрытый в r2. Оба открытых вопроса ТЗ решены владельцем (полоса ядра = 50, +лимит мутантов — ориентир) и реализованы теми же числами. + +`User-Visible: no` на всех четырёх коммитах (`47bdf883`, `44d4ff4f`, `56ebddf3` +и двух документных `61feca1f`/`bc15c3c9`/`4fa3c797`) — верно, продуктовое +поведение (`src/**`) не меняется; changelog не тронут, и это корректно при +`no` (проверено — `git diff origin/dev...HEAD --stat -- docs/CHANGELOG.md +docs/CHANGELOG.ru.md` пуст). Трейлеры `Issue: #699` / `User-Visible: no` +подтверждены на всех трёх кодовых коммитах (`git show -s --format=... | grep`). + +## Как проверялось + +Дешёвые гейты подтверждены зелёным Validate на этом же SHA (`4fa3c797`, run +36491631358) — `typecheck`, `npm test`, `npm run build` + bundle-policy не +перегонялись повторно. Поверх этого, по диффу и лично мной на этом SHA: + +| Гейт | Прогнан | Результат | +|---|---|---| +| `node --test test/ratchets.test.mjs test/core-file-budget.test.mjs test/monolith-metrics.test.mjs test/bundle-assets.test.mjs test/mutation-gate.test.mjs test/process-digests.test.mjs test/monolith-text-anchors.test.mjs` | да, лично | 133/133 ok | +| `node scripts/mutation-gate.mjs --check` | да, лично | зелёный; `browser guards: 200/200`; 3 предсуществующих WARN (не относятся к #699, те же, что в r1/r2) | +| Защитный AC M1 — «тест умеет падать» перепроверен на этом SHA, не только унаследован | да, лично, исполнением | заменил в `docs/DEVELOPMENT.md` `tighten` → `report` в той же позиции (патч мутанта `release-runbook-forgets-tighten`), `node --test --test-name-pattern="#699 r1 M1" test/ratchets.test.mjs` → **1 fail** (`assert.match` не находит `tighten` после `bundle:release`), откатил (`git checkout -- docs/DEVELOPMENT.md`), `git status --porcelain` — пусто | +| Построчное сопоставление `git diff origin/dev...HEAD` (19 файлов) с описанием кода в r1/r2 | да, лично, чтением | текст диффа совпадает с цитатами и таблицами r1/r2 файл за файлом — см. «Почему r3» выше | +| `git diff origin/dev...HEAD --stat -- docs/CHANGELOG.md docs/CHANGELOG.ru.md` | да | пусто — корректно при `User-Visible: no` | +| Трейлеры `Issue`/`User-Visible` на `47bdf883`, `44d4ff4f`, `56ebddf3` | да, лично | все три — `Issue: #699`, `User-Visible: no` | +| `docs/reviews/INDEX.md` (r1/r2 уже проиндексированы) | да, прочитал | строки #699 r1 (🟡, M1) и r2 (🟢) на месте, согласуются с документами | + +**Не прогонялось и почему:** полный дифф-мутационный прогон (`mutation-gate.mjs` +с реальными патчами, 186 мутантов) — трек show, зелёный Validate на этом SHA, +структурная `--check` чистая, и содержимое диффа не изменилось с r1/r2, где +этот прогон уже проводился (186/186); браузерные смоки — тело issue их не +называет, диф не трогает `src/**`/`demo/`, `smoke-select.mjs` не запускался за +отсутствием сопоставимого диффа; `golden:verify`, `pytest tests_backend`, +`npm run invariants`, performance-профили — не применимы (нет рендера, Python, +геометрии; AC их не называют); не проверял исполнением реальный +`release:prerelease` в GitHub Actions — унаследовано из r1/r2 как непроверенное +(эта часть дельтой r3 не затронута); `npx tsc --noEmit`/`npm test` целиком/ +`npm run build` с трёхсторонней сверкой бандла — не перегонял: зелёный Validate +на этом же SHA подтверждает дешёвые гейты без повтора. + +## Закрытие раунда r1 + +| Находка | Чем закрыта | Где это видно | +|---|---|---| +| **M1**: `node scripts/ratchets.mjs tighten` не был в единственном каноническом release-runbook `docs/DEVELOPMENT.md`; единственное упоминание — предупреждение внутри `release:prerelease` уже в момент публикации. | Шаг `tighten` в чек-листе «Prepare the candidate as usual» сразу после `npm run bundle:release`, до `docs/RELEASE-NOTES.md`/публикации; тест `#699 r1 M1` пере-проверяет и наличие, и порядок; мутант `release-runbook-forgets-tighten`. Перепроверено мной на `4fa3c797`: мутант применён вручную → тест падает (1 fail) → откат чистый. | `docs/DEVELOPMENT.md:525-534` (`Prepare the candidate as usual` → `bundle:release` → `ratchets.mjs tighten (#699 …) commit them with the candidate` → `RELEASE-NOTES.md`); `test/ratchets.test.mjs:69-75`; `scripts/mutation-registry.mjs` — `release-runbook-forgets-tighten`. | + +Низкая находка **L1** (r1, оркестрация `tighten` без автотеста) была снята +ревьюером в r1 с записью (проверено исполнением в изолированном worktree); +дельта r2 и r3 её не касаются. + +## Унаследовано из r1/r2 (без повторной проверки по существу) + +Симметричность полосы по обеим границам на всех трёх видах храповика (ядра, +gzip-графы, числа монолита), корректность реордера в CLI `bundle-budget.mjs` +(потолок беты проверяется до `assertBundleBudget`, один источник байт-каунта), +пять новых мутантов реестра + один перенацеленный (якоря найдены по одному +разу), согласованность `PROCESS.md §8`/`docs/TESTING.md` с кодом, «одно число — +один источник» у потолка initial View (`INITIAL_VIEW_GZIP_CEILING` в +`bundle-budget.mjs`, `ratchets.mjs` читает его же регэкспом) — всё это разобрано +полно в `docs/reviews/CODE-REVIEW-699-r1.md` (материал `709c5b8a38f4`) и не +затронуто дельтой r1→r2→r3 текстуально (см. «Почему r3» выше — построчное +сопоставление). Принимаю без повторного вывода, кроме того, что перепроверил +сам и назвал в таблице выше (юниты, `mutation-gate --check`, M1-мутант). + +## Находки + +Новых находок нет. High: 0, Medium: 0. + +Формальный повод для r3 (смена patch-id при повторном ребейзе, #492) не +породил содержательного отличия: диф `origin/dev...HEAD` на этом SHA +текстуально совпадает с тем, что рецензировали r1 и r2, тесты и мутационный +гейт зелёные лично на этом SHA, а M1 остаётся доказуемо закрытым (мутант +всё ещё ловится). + +## Проверено и корректно + +- Продуктовый код (`src/**`) не тронут — задача инфраструктурная, `User-Visible: + no` верно на всех коммитах, changelog не трогается, и это правильно. +- Рабочая копия чистая до и после моей проверки мутанта (`git status + --porcelain` — пусто оба раза), файлов в репозитории я не создавал (документ + ревью пишется вне репозитория, в `$REVIEW_DOC`). +- Тесты, гейты и трейлеры на текущем SHA `4fa3c797` дают тот же результат, что + описывали r1/r2 на своих (уже нерезолвящихся) SHA — расхождения нет. + +## Чего не проверял + +- Полный дифф-мутационный прогон `mutation-gate.mjs` с реальными патчами (186 + мутантов, 6 шардов) — не перегонял на этом SHA: он уже был выполнен в r1 на + байт-идентичном по содержанию диффе, трек show, Validate зелёный. +- Браузерные смоки — диф не трогает `src/**`/`demo/`, `smoke-select.mjs` не + запускался за отсутствием сопоставимого диффа. +- `golden:verify`, `pytest tests_backend`, `npm run invariants`, + performance-профили — не применимы (нет рендера, Python, геометрии; AC их не + называют). +- Исполнение реального `release:prerelease` в GitHub Actions (печатает ли + `--warn` на практике) — унаследовано из r1/r2 как непроверенное. +- `npx tsc --noEmit`, `npm test` целиком, `npm run build` с трёхсторонней + сверкой бандла — не перегонял: зелёный Validate на `4fa3c797` (run + 36491631358) подтверждает дешёвые гейты без повтора. + +## Вердикт + +Формальный r3 без содержательной дельты: рёбейз сменил patch-id, но не код. +M1 из r1 остаётся закрытым и перепроверен исполнением на текущем SHA. Новых +находок нет. High: 0, Medium: 0 → зелёный, цикл не тратится. + +--- + +--- + + + +## Материал раунда + +- Ветка: `issue/699-ratchet-bands`, коммит `4fa3c7977ebb` — ребейз его осиротит, и это нормально: ниже якоря, которые ребейз не меняет. +- Дерево материала: `3dfcbd4230f3cf2b19d814176b2b5887dbd30564` + ``` + git log --all --format='%H %T' | grep 3dfcbd4230f3 + ``` +- Тело issue: `18b6f2dce7c2f914e9c4d61715360cb529fc34c87cbad12c2a646990fefcb724` +- Вердикт конвейера: `green` · High 0