18 KiB
CODE-REVIEW-271-r2
- Issue: #271 — «Degree-3 узел достраивает короткий луч до 8×H»
- Этап: code (PROCESS.md §2.7)
- Заход: r2 · блокирующих циклов израсходовано 1 из 4 (r1 — красный, потратил 1; неудавшаяся попытка ревью из-за конфликта с
dev, комментарий issue #271 «Ревью не запускалось», цикл не расходует — код не читали, вердикта не было) - Материал:
git log --oneline origin/dev..HEAD(см. ниже),git diff origin/dev...HEAD - Финальный HEAD этого раунда:
5ad9191bac6cd22ee7097e8835a6d51bf636d843
5ad9191 docs: refresh merged finite-ray evidence
e24f63f merge dev into finite-ray branch
17c4ade docs: refresh finite-ray evidence fingerprint
1794637 test: cover finite wall beside an opening
23b0ce2 docs: review document for #271 (документ r1)
396b391 fix(walls): bound multi-wall repairs to finite rays ← ревьюился в r1
77143d4 docs: review document for #271 (спек-ревью)
482b2be docs(spec): define finite multi-wall ray contract
Предыдущий раунд и характер дельты
r1 (docs/reviews/CODE-REVIEW-271-r1.md, SHA 396b391a93cc228bd6b779b9985db87e853bfa50) —
красный, High: 1, Medium: 1 в скоупе.
После r1 автор дважды пытался вернуться на ревью:
- Комментарий с фиксами (
1794637,17c4ade) — но следующий запуск конвейера обнаружил, что ветка не ребейзится наorigin/devчисто, вернул issue вS6-in-progressдо чтения кода (§10.4). Это не заход и не цикл — код не читали. - Автор влил
origin/devв ветку merge-коммитомe24f63f(не ребейзом) и добавил5ad9191(повторная пересъёмка отпечатка/скриншота после мержа).
Почему разбор остаётся по дельте, а не полным, хотя в историю вошёл «ушедший вперёд dev» (обычно это триггер полного разбора, §2.10/§7.2):
git merge-base origin/dev HEAD=d68e876= самorigin/dev. То естьdev— строгий предок HEAD, слияние прошло без семантического расхождения:git diff origin/dev...HEADпоказывает ровно и только собственные изменения #271 (22 файла, тот же продуктовый файлsrc/wall-thickness.ts), а не смесь с #273.- Влившийся
devпринёс #273 (105a8f7/3ab3cdc/e2de0dbи др.) — подсистемаsrc/plan-optimizer.ts, неsrc/wall-thickness.ts. Слияниеe24f63fподтверждённо не касалосьsrc/wall-thickness.ts:git diff 396b391 e24f63f -- src/wall-thickness.ts— пустой вывод, файл не менялся между тем SHA, который читал r1, и постмерж-веткой. Единственные файлы, которые реально понёс merge-commit (список в самомe24f63f) —plan-optimizer.ts, тесты #273, документация #273, скриншот-манифест и changelog (обе записи #271/#273 сохранены рядом, см. ниже). - Итог: это не «другой код» в смысле §7.2 (не смена контракта, не задета новая
подсистема, объём дельты не сопоставим с задачей) — предмет раунда те же два
файла, что правил автор по итогам r1:
demo/golden/matrix.mjs/harness.mjs(High) и тесты/smoke (Medium), плюс чисто механический мерж соседней задачи.
Закрытие раунда r1
| Находка r1 | Чем закрыта | Где это видно |
|---|---|---|
[High] Собственный семантический golden-контракт AC6 падает на обоих сценариях (junction-patch-resilience-{plan,view}-dark): absentWallProbes[1] = [0.936524285, 0.345833333] лежал внутри легитимного непрерывного интервала стены room_8, а не в пустоте за коротким лучом |
demo/golden/matrix.mjs — absentWallProbes[1] заменён на [0.92, 0.348] (боковая точка приближения к двери, finiteRayDoorApproachProbe), коммит 1794637 |
Перепрогнал сам: node demo/golden/run.mjs --mode=capture --scenario=junction-patch-resilience-plan-dark и -view-dark — оба вернули status: "different" (ожидаемо, PNG-эталон не принят) без ошибки golden finite multi-wall ray contract failed. Раньше (r1) та же команда падала с этой ошибкой. test/golden-matrix.test.mjs:375-378 теперь фиксирует новое значение пробника |
| [Medium, в скоупе] AC4 не имеет собственного fixture/smoke с проёмом рядом с коротким лучом | Новый unit test/wall-thickness.test.mjs:917 («issue #271 keeps a nearby door slot…») на фикстуре 197-junction-patch.json с реальным opening; новые проверки в demo/smoke_junction_patch_resilience.mjs (nearDoorPlanStopsAtFiniteRay, nearDoorPlanKeepsSlotEmpty, nearDoorPlanKeepsSymbol, nearDoorLightStopsAtFiniteRay, nearDoorViewKeepsSlotEmpty, nearDoorViewKeepsSymbol, nearDoorRenderNeverWritesConfig), коммит 1794637 |
Прогнал сам: node --test test/wall-thickness.test.mjs — новый тест зелёный; проверил, что тест умеет падать — вручную откатил фикс (supportExtent = extent вместо Math.min(extent, support.length) в src/wall-thickness.ts:2102) и получил not ok … 'the short 15 cm ray still paints a lateral phantom before the nearby door'; вернул код обратно (git checkout -- src/wall-thickness.ts), дерево снова чистое. node demo/smoke_junction_patch_resilience.mjs — все nearDoor* поля true |
Унаследовано из r1
Без повторной проверки принято из docs/reviews/CODE-REVIEW-271-r1.md
(SHA 396b391), так как src/wall-thickness.ts не менялся с этого SHA
(проверено: git diff 396b391 e24f63f -- src/wall-thickness.ts — пусто):
- AC1 (node map хранит конечную длину, order/permutation-independent) — доказано
test/wall-thickness.test.mjs:840+ мутация. - AC2 (короткий луч
887.5,345.833не достраивается до96.667) — подтверждено прямым вызовом продукт-функций r1-ревьюером. - AC3 (длинные rays/join #249 не обрезаны; area-бейзлайн
197-фикстуры пересчитан осознанно,124568.27…→124244.27…) — эта строка появилась в самом396b391, не в r1→r2 дельте (провереноgit log -Sпо значению). - AC5 (все поверхности используют finite result) — smoke
smoke_junction_patch_resilience.mjs, все*StopsAtFiniteRayEndpointзелёные в r1. - AC7 (мутант ловит регрессию) —
multi-wall-finite-ray-disabled, зафиксирован в самом396b391. - AC8 (приватность/детерминизм), Failure isolation §6.5, Compatibility §7, трейлеры/changelog исходного коммита
396b391— все проверены чтением в r1. - ТЗ и его ревью —
docs/specs/271-finite-multiwall-rays.md(SHA482b2be),docs/reviews/SPEC-REVIEW-271-r1.md— зелёный, комментарий issue #271 (2). Контракт §6.2/§6.3 ТЗ не менялся в этом раунде.
Скоуп этого раунда
Продукт: без изменений — src/wall-thickness.ts не тронут после 396b391.
Дельта раунда: два теста/фикстуры/smoke-проверки, закрывающие High и Medium
из r1 (demo/golden/matrix.mjs, demo/golden/harness.mjs,
test/wall-thickness.test.mjs, test/golden-matrix.test.mjs,
demo/smoke_junction_patch_resilience.mjs, scripts/mutation-gate.mjs,
scripts/smoke-links.mjs), плюс документационный/скриншотный шум от
слияния с dev (docs/CHANGELOG×2, docs/images/screenshots.json,
docs/images/09-device-info.png).
Привязка к продукту не изменилась: J1/J6 (docs/SCOPE.md), как в r1.
Как проверялось
| Гейт | Команда | Результат |
|---|---|---|
| Типы | npx tsc --noEmit |
зелёный, без вывода |
| Юнит | npm test |
1165 passed, 0 failed, 0 skipped |
| Сборка + 3 копии бандла | npm run build && npm run bundle:sync |
зелёный; git status --short после — пусто (байт-в-байт) |
| Документация/отпечаток | node scripts/check-docs.mjs |
«Documentation checks passed (7 files, 10 external links)» |
| Выбор smoke по дельте | node scripts/smoke-select.mjs --base origin/dev --head HEAD |
те же два, что в r1: smoke_junction_patch_resilience.mjs, smoke_multiwall_junction.mjs — оба «зарегистрированная связь» |
| Smoke (High/Medium из r1) | node demo/smoke_junction_patch_resilience.mjs |
OK, все поля true, включая новые nearDoor* |
| Smoke #249 | node demo/smoke_multiwall_junction.mjs |
OK |
| Целевой semantic golden (закрытие High) | node demo/golden/run.mjs --mode=capture --scenario=junction-patch-resilience-plan-dark |
status: "different", без ошибки семантического контракта (в r1 здесь была ошибка) |
| Целевой semantic golden (закрытие High) | то же для -view-dark |
то же — семантика зелёная, только некритичный pixel-diff до приёмки baseline |
| Целевая мутация | node scripts/mutation-gate.mjs --id=multi-wall-finite-ray-disabled |
поймано 1/1 |
| Независимая проверка «тест умеет падать» (AC4) | ручной откат фикса в src/wall-thickness.ts:2102 + node --test --test-name-pattern="issue #271 keeps a nearby door slot" test/wall-thickness.test.mjs, затем git checkout -- |
новый door-тест красится именно на ожидаемом assert; дерево возвращено в чистое состояние |
| Слияние с dev — семантическое пересечение | git merge-base origin/dev HEAD / git diff 396b391 e24f63f -- src/wall-thickness.ts |
dev — строгий предок HEAD; src/wall-thickness.ts не задет мержем; #273 живёт в plan-optimizer.ts |
npm run golden:verify не запускался — инструмент требует полную матрицу и
это осознанный prerelease-гейт (§8), не подмена: как и в r1, вместо него
исполнен целевой --mode=capture --scenario=<id>.
Находки
Блокирующих (High) и Medium-в-скоупе не найдено.
[Low, не блокирует] scripts/mutation-gate.mjs для id: multi-wall-finite-ray-disabled
гоняет --test-name-pattern="issue #271 keeps finite" — этот паттерн матчит
только первый новый тест (AC1/AC2), но не новый door-тест AC4 («issue #271
keeps a nearby door slot…»), закрывающий Medium из r1. Автоматический гейт не
доказывает падение именно этого теста при регрессии. Не блокирует: я
самостоятельно воспроизвёл падение door-теста той же мутацией руками (см.
таблицу «Как проверялось») — «тест умеет падать» подтверждено ревьюером
напрямую, а не одним лишь скриптом. Оставляю на суждение автора — можно
расширить паттерн до "issue #271" в следующей правке кода этой подсистемы;
самостоятельного возврата на цикл это не требует.
Что проверено и корректно
- Закрытие обеих находок r1 — доказано исполнением, не только заявлением автора (таблица выше).
- Слияние с
devне смешало логику #271 и #273: разные файлы, разные подсистемы,dev— предок, а не расходящаяся история. - Трейлеры новых коммитов раунда (
1794637,17c4ade,e24f63f,5ad9191) — всеIssue: #271,User-Visible: no(новое пользовательское поведение не добавляется этим раундом — оно уже задекларировано в396b391,User-Visible: yes, changelog там же). docs/CHANGELOG.md/.ru.md— после мержа обе записи (#271 и #273) стоят рядом, ни одна не потеряна и не задвоена.docs/images/09-device-info.pngменяется дважды в этом раунде (17c4ade, затем обратно похожим значением в5ad9191) — известная и ранее описанная 17-пиксельная/1-канальная anti-aliasing разница, не связанная с геометрией стен (карточка устройства); автор оба раза явно называет её и прикладывает прогон официальной джобыDocs screenshots(32655189647, 32656215095), коммитит человек — соответствует §8. Не новый дефект этого раунда.- Одно число — один источник: этот раунд не добавляет и не меняет ни одной видимой пользователю величины (правка — тестовые/golden-пробники и документация), выборка одного отображаемого числа неприменима.
- Инварианты модели (
npm run invariants) — не требуются повторно: диапазон правок не касается хранения записи толщины/layout/marker.space/open_spans, иsrc/wall-thickness.tsне менялся с r1, где это уже было установлено чтением диффа.
Чего не проверял и почему
- Полный
npm run golden:verify— как и в r1, prerelease-гейт, не принимает--scenario; заменён целевым--mode=captureдля обоих сценариев, которые правил этот раунд. - Полная smoke-матрица (174 сценария) —
smoke-selectвновь называет только 2, оба прогнаны; дельта раунда не расширяет поверхность за пределы multi-wall reconstruction / golden harness. python -m pytest tests_backend—custom_components/**/*.pyне тронут.- Performance-профили — не названы в AC, диапазон правок раунда — тесты и golden-фикстуры, не hot path.
- Официальная джоба
Docs screenshots(запуск в CI) — не перезапускал сам; принял ссылки автора на два зелёных прогона (32655189647,32656215095) как исполненную команду с результатом, как того требует §8/§18 («Verified» без команды не доказательство — здесь команда и её результат названы и проверяемы по ссылке). - Полный аудит r1-подтверждённых AC1/AC2/AC3/AC5/AC7/AC8 — не повторял;
раздел «Унаследовано из r1» выше и обоснование в разделе «Предыдущий раунд»
объясняют, почему код, который их доказывает, не менялся с SHA
396b391.
Итог
Обе находки r1 закрыты и закрытие проверено исполнением, а не заявлением
автора: семантический golden-контракт AC6 теперь проходит на обоих сценариях,
а door-adjacent регресс-покрытие AC4 добавлено и вручную подтверждено как
падающее на откаченном фиксе. Слияние с ушедшим вперёд dev не затронуло
файл src/wall-thickness.ts и не смешало логику с #273 — дельта раунда
оставалась локальной, полный повторный аудит не требовался. Единственное
замечание (Low, гранулярность --test-name-pattern мутационного гейта) не
блокирует и не является Medium — фактическая способность теста падать
подтверждена ревьюером напрямую.
Вердикт: зелёный.