From 5784a0e27107d543175426216208692577b24445 Mon Sep 17 00:00:00 2001 From: "claude[bot]" <209825114+claude[bot]@users.noreply.github.com> Date: Fri, 4 Sep 2026 17:45:17 +0000 Subject: [PATCH] docs: review document for #454 Issue: #454 User-Visible: no --- docs/reviews/CODE-REVIEW-454-r4.md | 111 +++++++++++++++++++++++++++++ 1 file changed, 111 insertions(+) create mode 100644 docs/reviews/CODE-REVIEW-454-r4.md diff --git a/docs/reviews/CODE-REVIEW-454-r4.md b/docs/reviews/CODE-REVIEW-454-r4.md new file mode 100644 index 00000000..a20c39b7 --- /dev/null +++ b/docs/reviews/CODE-REVIEW-454-r4.md @@ -0,0 +1,111 @@ +# CODE-REVIEW — issue #454 · заход r4 + +- Issue: https://github.com/Matysh/houseplan-card/issues/454 +- Материал: `git rev-parse HEAD` = `2a883217c156c349e4cca9bc3bd5a75d85b7b928` + (ветка `issue/454-review-round-counter`). +- Предыдущий раунд: r3, жёлтый, документ `docs/reviews/CODE-REVIEW-454-r3.md`, + материал `4b443d8c` (там же был rev-parse HEAD того раунда). +- Дельта r3→r4: `git diff 4b443d8c..HEAD` — три коммита: + - `9e7ae520` docs: публикация документа r3 (сам ревью-файл, не код); + - `d5e11452` fix: закрытие M1 (комментарий засчитывается вердиктом только по + документу своей задачи), 5 файлов, +174/−27; + - `2a883217` chore: пересборка бандла под новый отпечаток исходников — + несвязанная поддержка (см. «Вне дельты» ниже), уже с `Baseline-Reviewed`. + Ребейза не было, дельта локальна (диапазон `origin/dev...HEAD` не изменился + по существу с r3, кроме этих трёх коммитов) → разбор по дельте (PROCESS.md + §2.9/§2.10), а не заново. + +## Закрытие раунда r3 + +| Находка | Чем закрыта | Где видно | +|---|---|---| +| **M1** (Medium, в скоупе) — резервный счёт по комментариям матчил голую подстроку маркера (`CODE-REVIEW`/`SPEC-REVIEW`) в любой прозе, включая цитаты чужих задач и чужого этапа; на самих данных #454 это дало код-ревью-раунду имя `r3` вместо `r1`, а заявление ТЗ §3 «перерасчёт невозможен по построению» не выполнялось для `attemptComments`/`spentComments` | Правило заменено на два условия: комментарий обязан (а) объявлять вердикт строгой строкой `verdictDeclaration`, (б) называть документ **этой** задачи и **этого** этапа — `-` вместо голого ``. Формулировка §3 ТЗ смягчена до факта («удвоение невозможно, завышение одной из компонент — возможно»). Добавлен `::warning::` при расхождении `attemptComments`/`attemptFiles`, привязка к номеру задачи и уточнение гарантии — все три направления, предложенные в r3, взяты одновременно | `scripts/review-doc-guard.mjs:452-486` (`stageVerdictComments`, `commentCounters`), коммит `d5e11452`; `.github/workflows/process.yml:97-190` (счёт по комментариям вынесен из inline-jq в модуль, `--comments`/`--spent-list`); `docs/specs/454-review-round-counter.md` §3 и таблица AC5; тест `вердикт этапа опознаётся по документу ЭТОЙ задачи (#454 AC5, #89)` и `чужой номер задачи не засчитывается своим (#454 AC5)`, `test/review-doc-guard.test.mjs:456-472`; мутант `review-comment-source-ignores-issue-number` (`scripts/mutation-gate.mjs:2442-2455`) | + +**Перепроверено исполнением, не со слов автора.** Собрал реальные данные #454 (`gh issue view 454 --json comments`, файл `docs/reviews/CODE-REVIEW-454-r3.md` — единственный опубликованный код-ревью-документ на ветке) и прогнал новый CLI `node scripts/review-doc-guard.mjs --counters --marker=CODE-REVIEW --num=454 ...` буквально так, как его вызывает `process.yml`: + +``` +::notice::раунды по файлам 3; заход: файлы 4, комментарии 2; циклы: файлы 0, комментарии 1 +attempt=4 +spent=1 +``` + +`attemptComments=2` (было 3 на живом логе `guard` r3-прогона) — оба посторонних совпадения (зелёный SPEC-REVIEW r2-вердикт и хендофф-комментарий «Реализация готова», оба цитировавшие чужие `CODE-REVIEW-*` документы в прозе) больше не матчат `own`-фильтр, потому что ни один не содержит буквальную подстроку `CODE-REVIEW-454`. Единственный засчитанный — сам r3-вердикт (жёлтый), `spentComments=1`. `attemptFiles=4` (раунд 3 существует → следующий r4), `spentFiles=0` — документ `CODE-REVIEW-454-r3.md` не объявляет вердикт машиночитаемой строкой внутри себя (раздел «## Вердикт» там — проза без строки `Вердикт: жёлтый · …`, это отдельный, унаследованный из ТЗ §2 класс «документ есть, строка `Вердикт:` в нём нет» — не новый дефект дельты и не относится к M1). `max(4,2)=4`, `max(0,1)=1` — совпадает с «заход r4 · циклов 1/4» из шапки задачи. M1 закрыта. + +## Унаследовано из r3 + +Без повторной проверки принимаю (документ `docs/reviews/CODE-REVIEW-454-r3.md`, материал `4b443d8c`): + +- AC1 (`attempt` = max(номер)+1), AC2/AC2b (фикстуры #449 реальная и реконструированная), AC3 (имя файла не повторяется), AC4 (зелёный цикл не тратит), AC6 (отказ публикации не занижает счёт), AC7 (нет ветки/мусор на входе не роняет guard), AC9 (логика в тестируемом модуле, не в inline-shell) — дельта их не касается, файлы/тесты, доказывающие их, не менялись между `4b443d8c` и `HEAD` (проверено `git diff 4b443d8c..HEAD -- test/review-doc-guard.test.mjs` — новые тесты только про AC5/комментарии). +- AC8 (`process.yml` идентичен в `main` и `dev`) — план зеркалирования после мержа обоснован в r3 и не изменился. +- Класс изменения B, `User-Visible: no` на всех коммитах — трейлеры проверены отдельно ниже для новых коммитов дельты, старые (`8d826320`, `dc76c5b2`, `4b443d8c`) не перепроверял. +- Наблюдение r3 (не находка): `docs/specs/README.md` — строка `#454` вставлена не по возрастанию номера. Косметика, не блокирует, не повторяю как находку. + +## Вне дельты, но заслуживает упоминания — `2a883217` + +Коммит `2a883217` (пересборка бандла) не относится к предмету #454 (счёт раундов ревью), это независимая починка красного `dev`, найденная и исправленная автором по собственной инициативе между r3 и r4 (дефект: `package.json`, изменённый в #455, не был прогнан через `bundle:sync`, фингерпринт разошёлся). Проверил сам, а не поверил описанию: + +- `git show 2a883217 -M` для `houseplan-card-*.js` (крупнейший переименованный чанк, 96 изменённых строк из 5676): все 44 изменившиеся пары строк дают **одинаковую длину** старой и новой стороны (проверено построчно, включая гигантские минифицированные строки 20037/74688/193139 байт) — сильный признак того, что правки это подстановка фингерпринта и имён чанков, а не смена логики; я не нашёл ни одной пары разной длины. +- Трейлеры коммита: `User-Visible: no`, `Issue: #454`, `Baseline-Reviewed: .../actions/runs/33895243347` (ссылка на упавший прогон, который и обнаружил расхождение — `process-gate` требует `Release` либо `Baseline-Reviewed` для коммита только класса D, оба варианта допустимы по `scripts/process-gate.mjs:246-249`, содержательной проверки «зелёности» самой ссылки правило не делает). +- Дифф не трогает `src/**`, `custom_components/**/*.py` — не App-код. + +Не блокирует и не относится к AC #454; упоминаю для полноты, не как находку. + +## Как проверялось — гейты + +**Дешёвые гейты уже подтверждены Validate на `2a883217`** (green, run 33900588440) — `tsc`, `npm test`, `npm run build` со сверкой бандла перегонять не обязан, но перегнал сам для дельты (код изменился с r3): + +| Гейт | Команда | Результат | +|---|---|---| +| Typecheck | `npx tsc --noEmit` | чисто, без вывода | +| Unit-тесты | `npm test` | 1940 pass / 0 fail / 1 skip | +| Mutation gate | `node scripts/mutation-gate.mjs --check` | exit 0; все 4 `review-*` мутанта, включая новый `review-comment-source-ignores-issue-number`, пойманы (`ok`) | +| check-docs | `node scripts/check-docs.mjs` | passed (7 files, 12 links) — не обязателен (`src/**` не тронут), прогнан для полноты | +| Реальный прогон CLI на живых данных #454 | `node scripts/review-doc-guard.mjs --counters --marker=CODE-REVIEW --num=454 --comments= --docs=` | `attempt=4, spent=1` — совпадает с ожидаемым и с шапкой задачи | + +Не гонял: `npm run golden:verify`, `demo/smoke_*.mjs`, `python -m pytest tests_backend`, performance-профили, `npm run invariants` — дельта не трогает `src/**`, рендер, геометрию, `custom_components/**/*.py` ни бэкенд. `smoke-select.mjs` не запускал по той же причине (диапазон вне поверхностей демо-стенда). + +## AC — таблица доказательств (только задетые дельтой) + +| AC | Критерий | Доказано | Комментарий | +|---|---|---|---| +| AC5 | Вердикт чужого этапа/чужой задачи не влияет на счёт (#89) — по имени файла **и** по прозе комментария | unit + мутант, перепроверено исполнением на реальных данных #454 | `stageVerdictComments`/`commentCounters` (`review-doc-guard.mjs:452-486`), тесты `test/review-doc-guard.test.mjs:456-472`, мутант `review-comment-source-ignores-issue-number`. Живой прогон подтвердил: `attemptComments` упал с 3 (r3) до 2 (r4) — оба ложных совпадения исчезли | +| AC9 | Логика в тестируемом модуле, не в inline-shell | unit, чтением | тест «guard считает раунды скриптом, а не inline-shell» по-прежнему проходит после смены аргументов `--comment-attempt/--comment-spent` → `--comments/--spent-list` | + +Остальные AC не задеты дельтой — см. «Унаследовано из r3». + +## Что проверено и корректно + +- M1 закрыта: причина (голая подстрока маркера) устранена, решение подтверждено и юнитом, и мутантом, и независимым прогоном на реальных данных задачи, а не только словами автора. +- Регекс `own = new RegExp(\`${marker}-${num}(?![0-9])\`)` устойчив к коллизиям номеров-подстрок (проверил вручную: `num=454` не матчит `CODE-REVIEW-4540-...`, не матчит `CODE-REVIEW-1454-...`; `num=45` не матчит `CODE-REVIEW-454-...` — во всех случаях out благодаря негативному lookahead и жёсткой смежности марker-num). +- CLI-обвязка (`--comments`, `--spent-list`) согласована с форматом `gh issue view --json comments` — проверил `gh issue view 454 --json comments` вживую: ключ `comments`, элементы несут `.body`/`.url`, ровно то, что читает `commentCounters`/`payload.comments || payload`. +- `spent_list` теперь строится тем же кодом, что и число (не рассинхронизируется). +- Трейлеры коммитов `d5e11452`, `9e7ae520`, `2a883217`: `Issue: #454` есть у всех, `User-Visible: no` корректно для класса B/D, changelog не требуется. +- `process.yml` идентичен между `HEAD` и веткой на момент проверки; расхождение с `main` ожидаемо и объяснено (зеркалирование после мержа). + +## Чего не проверял + +- `golden:verify`, `smoke_*.mjs`, `pytest tests_backend`, performance, `npm run invariants` — diff не касается рендера/геометрии/бэкенда/perf. +- Реальный прогон изменённого `guard`-джоба целиком на GitHub Actions (сам workflow ещё не в `main`/`dev`) — логика проверена юнитами, мутантом и прямым вызовом CLI на данных, снятых с живого API; часть про `git ls-remote`/постраничный лимит `contents` не менялась в этой дельте и не перепроверялась повторно (наследую из r3). +- Побайтовое сравнение бандла `2a883217` вне одного (крупнейшего) чанка `houseplan-card-*.js` — остальные переименованные чанки различаются 2 строками (импорт по новому имени), не разбирал их так же подробно; риск оценил как низкий (переименование = констант-строка, тот же паттерн). + +## Вердикт + +Один Medium закрыт без нового Medium/High. Дельта локальна, гейты зелёные (сам прогнал + Validate на `HEAD` уже зелёный), AC5 передоказан на реальных данных задачи. + +Документ: `docs/reviews/CODE-REVIEW-454-r4.md` (публикуется шагом конвейера). + +--- + + + +## Материал раунда + +- Ветка: `issue/454-review-round-counter`, коммит `2a883217c156` — ребейз его осиротит, и это нормально: ниже якоря, которые ребейз не меняет. +- Дерево материала: `a7f0666a126e40cb40f4ba8eb33b0278f3fe3ec1` + ``` + git log --all --format='%H %T' | grep a7f0666a126e + ``` +- ТЗ `docs/specs/454-review-round-counter.md`, блоб `2d236d4f481565d3188ceb2670f97df003783084` + ``` + git log --all --find-object=2d236d4f481565d3188ceb2670f97df003783084 -- docs/specs/454-review-round-counter.md + ```