18 KiB
CODE-REVIEW — issue #566, заход r2
Материал: 733cd5b86b301fd29c1eddebd88d6b09cd231071 (ветка
issue/566-stale-layout-notes, один коммит поверх материала r1: 733cd5b8
на f724cca6). Рабочая копия уже стояла на этом SHA, git fetch/checkout
на другой коммит не выполнялись.
Заход: r2 · блокирующих циклов израсходовано 1 из 4 (r1 был жёлтым и цикл потратил).
Трек: инфраструктурный (§1), тот же, что в r1. Коммит 733cd5b8 трогает
только scripts/model-invariants.mjs, scripts/mutation-registry.mjs,
test/geometry-corpus.test.mjs, test/model-invariants.test.mjs — те же
четыре файла, что были в скоупе r1, новых файлов и подсистем дельта не
касается. Ребейза на ушедший вперёд dev не было (материал лежит прямо на
f724cca6, где его оставил r1), контракт поведения не менялся — менялась
только точность одной уже введённой этим же issue диагностики. Разбор веду
по дельте, а не заново.
Вердикт: жёлтый на входе r1 → зелёный на r2 · High: 0 · Medium: 0
Дельта раунда
git diff f724cca6..733cd5b8 — 260 строк, 5 файлов (из них 201 — сам
документ ревью r1, которым эта дельта была вызвана, содержательных 59):
scripts/model-invariants.mjs:213-244— веткаstale_layout_spaceстала трёхзначной:ownerтеперь'absent' | 'live' | 'unverified'вместо булеваownerGone.unverified(ключ не резолвится ни какrl_, ни какgrp_, ни как маркер) получил собственныйkind: 'unknown_owner'с той же формулировкой, что уже использует веткаunknown_ownerживого пространства пятью строками ниже (src/model-invariants.mjs:269-270).scripts/mutation-registry.mjs— новый мутантinvariants-claim-proof-for-an-unknown-owner(сводитunverifiedкlive), плюс перепривязкаfind-якорей двух прежних мутантов #566 к новым строкам (owner === 'absent',removedMarkerIds.has(key) ? 'absent').test/model-invariants.test.mjs— тест #566 теперь сверяетownerпо каждому из трёхkindотдельно (stale_layout_space/unknown_owner) и, главное, сверяет ТЕКСТdetailдля каждого, включая отрицательное утверждениеassert.doesNotMatch(note.detail, /владелец жив/)дляunknown_owner— именно эта проверка отсутствовала в r1 и пропустила находку.test/geometry-corpus.test.mjs— фикстураc6-stale-layoutменяет ожидание с['references/stale_layout_space', 'references/stale_layout_space']на['references/unknown_owner', 'references/unknown_owner'].
Закрытие раунда r1
| Находка r1 | Чем закрыта | Где это видно |
|---|---|---|
Medium: наблюдение stale_layout_space утверждало «владелец жив» и для ключа, который не резолвится ни во что (только removedMarkerIds.has(key) проверялся, обратное трактовалось как live) |
Введено третье состояние unverified: removedMarkerIds.has(key) ? 'absent' : activeMarkerIds.has(key) ? 'live' : 'unverified'. unverified получает kind: 'unknown_owner' с формулировкой «владелец не найден в конфигурации (возможно устройство HA); пространства тоже нет» — не утверждает то, чего не знает |
scripts/model-invariants.mjs:222-243; воспроизведённый в r1 пример (unknown_device_id_1234 на мёртвом пространстве) при повторной проверке ниже даёт unknown_owner, а не stale_layout_space |
Указанный в r1 механизм пропуска: тест сверял только kind, не текст detail, поэтому асимметрия (первая по ключу запись случайно была живой комнатой) не ловилась |
Тест переписан: assert.deepEqual по owner для каждого kind отдельно, assert.match/assert.doesNotMatch на detail внутри цикла по всем нотам своего вида, а не по первой найденной |
test/model-invariants.test.mjs:150-172, дважды прогнан лично, зелёный |
Предписанная r1 правка: различить live/unverified «по образцу уже существующего unknown_owner», используя activeMarkerIds |
Использован именно activeMarkerIds (тот же Set, что вычислен в начале функции для живого пространства), формулировка detail дословно перекликается с формулировкой соседней ветки unknown_owner |
scripts/model-invariants.mjs:227,241-243 vs scripts/model-invariants.mjs:269-270 |
Побочный эффект находки: фикстура c6-stale-layout (реальный кейс из корпуса #560) — оба «сиротских» ключа там на самом деле незарегистрированные владельцы, а не подтверждённо живые маркеры, то есть сама фикстура иллюстрировала баг |
expectedNotes фикстуры пересмотрены на unknown_owner вместо stale_layout_space — не подогнаны молча, тест явно проверяет новую классификацию на реальных данных |
test/geometry-corpus.test.mjs:253-256; сквозной CLI-прогон ниже подтверждает |
Мутант находки (invariants-claim-proof-for-an-unknown-owner) прогнан лично,
«поймано 1 из 1» — не принято на слово автора.
Унаследовано из r1
Без повторной проверки приняты пункты раздела «Проверено и не вызывает
вопросов» документа docs/reviews/CODE-REVIEW-566-r1.md (материал f724cca6),
поскольку дельта r2 их не касается:
- классификация
rl_/grp_поallRoomIds/allAreas, собранным по всем пространствам, и сравнение с приёмомspace-reference-repair.ts:148— дельта не трогает эту ветку; - сами мутанты #566 (
invariants-blame-every-stale-position,invariants-forgive-a-vanished-position-owner) как факт существования и назначения — но их привязка к коду перепроверена заново в этом раунде (см. «Как проверялось»), поскольку рефакторинг сдвинул их якоря; - три реанимированных мутанта #568-приёма (
inner-span-reads-whole-edge-thickness,safe-resize-legacy-midpoint-fail-open,optimizer-micro-interval-cleanup-disabled) вsrc/wall-thickness.ts/src/plan-optimizer.ts— файлы вне дельты r2, не тронуты; - трейлеры коммитов
dedcedc8/7ecdafef/f724cca6(Issue: #566,User-Visible: no) — не переоцениваю, дельта их не меняет; - сквозной CLI-прогон на корпусе #560 как метод проверки (не только юнит-тест) — метод унаследован, но результат перепрогнан на новом коде (см. ниже), так как дельта прямо меняет вывод этой команды;
- отсутствие golden/check-docs/pytest/perf —
src/**иcustom_components/**/*.pyдельтой r2 тоже не тронуты, вывод не изменился.
Как проверялось
Дешёвый Validate (tsc/test/build/bundle-ratchet, mutation-gate по шардам) на
733cd5b8 подтверждён зелёным CI-прогоном (ссылка дана автором в issue),
поэтому не перегонялся целиком. Сверх этого лично прогнано в песочнице
ревью — то, что относится к точечной дельте r2, плюс сквозная проверка на
реальных данных:
| Гейт | Команда | Результат |
|---|---|---|
| Новый мутант находки | node scripts/mutation-gate.mjs --id=invariants-claim-proof-for-an-unknown-owner |
поймано 1 из 1 |
| Мутант «обвинить всех» (перепривязка) | node scripts/mutation-gate.mjs --id=invariants-blame-every-stale-position |
поймано 1 из 1 |
| Мутант «простить пропавшего» (перепривязка) | node scripts/mutation-gate.mjs --id=invariants-forgive-a-vanished-position-owner |
поймано 1 из 1 |
| Структура реестра | node scripts/mutation-gate.mjs --check |
exit 0, 733 записи ok, find-якоря уникальны |
| Юнит-тесты дельты | tsc -p tsconfig.test.json && node scripts/fix-test-build.mjs && node --test --test-name-pattern="#566|#252|#254" test/model-invariants.test.mjs test/geometry-corpus.test.mjs |
8 + 26 тестов, всё зелёное |
Полный test/geometry-corpus.test.mjs |
node --test test/geometry-corpus.test.mjs |
26/26 зелёных |
| Инварианты сквозным CLI на фикстуре #560 | node scripts/model-invariants.mjs --config test/fixtures/560-corpus/c6-stale-layout.json |
«Инварианты выполнены… Наблюдений (не нарушения): 2. 2 — позиции без записи маркера» (было «2 — позиции живых владельцев на удалённых пространствах» до правки) |
Дословное совпадение find-строк трёх мутантов с текущим кодом |
точечная проверка через String.includes на содержимом файла |
все три совпали |
Сводка по kind в CLI-выводе не хардкодит текст помимо словаря |
чтение scripts/model-invariants.mjs:790-798 (noteSummary) |
подтверждено чтением: titles[kind] общий словарь, переклассификация транслируется без отдельной правки |
check-docs, golden, backend pytest, performance-профили, полный отбор
мутантов (selectForDiff) не запускались — те же основания, что в r1:
src/** и custom_components/**/*.py не тронуты дельтой r2, рендер и
Python-бэкенд не задеты, ничего перфочувствительного в диффе нет; полный
отбор для дельты избыточен — все затронутые дельтой мутанты (3 из отбора)
прогнаны поштучно, остальные 91 из ранее выбранных 94 не касаются
изменённых строк и уже подтверждены зелёными шардами Validate в предыдущих
заходах.
Находки
Нет. Правка 733cd5b8 делает ровно то, что предписал r1: вводит третье
состояние unverified, использует уже вычисленный activeMarkerIds,
дословно перекликается формулировкой с соседней веткой unknown_owner, и
закрывает механизм пропуска (тест теперь сверяет текст причины, а не только
вид). Побочная проверка (noteSummary, реальная фикстура #560) подтверждает,
что переклассификация корректно доходит до пользователя CLI без скрытых мест,
где старое двухзначное деление могло остаться зашитым.
Проверено и не вызывает вопросов
- Мутант находки r1 (
invariants-claim-proof-for-an-unknown-owner) — прогнан лично, «поймано 1 из 1», а не принят на слово. - Перепривязка двух прежних мутантов #566 к сдвинутым строкам — прогнаны
лично после рефакторинга, оба всё ещё «поймано 1 из 1»;
--checkподтверждает уникальность и валидность новыхfind-якорей. - Тест
test/model-invariants.test.mjs— теперь различает три состояния поownerи по текстуdetailдля каждого, включая отрицательную проверку дляunknown_owner; асимметрия из r1 таким тестом уже не проходит. - Фикстура
c6-stale-layout— пересмотрена не формально: два «сиротских» ключа в ней (c6-orphan-1,c6-orphan-2) не зарегистрированы как маркеры вообще, то есть по существу это и естьunverified, а неlive— старое ожидание фикстуры само было артефактом найденного в r1 дефекта. - Комментарии в коде (
scripts/model-invariants.mjs:215-219, 237-240) называют находку r1 по существу («сказать «владелец жив» про ключ, который ни во что не резолвится, значит заявить доказанность там, где её нет») — не общие слова, а прямая привязка к причине правки. - Трейлеры коммита
733cd5b8—Issue: #566,User-Visible: no; верно, правка меняет только текст диагностики CLI-скрипта, не продукт. - Один коммит-заход, как требует процесс после возврата на доработку.
Чего не проверял
tsc --noEmit,npm testцеликом,npm run buildсо сверкой бандла — не перегонял: зелёный Validate на733cd5b8уже есть, дельта r2 не расширяет класс изменений (по-прежнему только инфраструктурные файлы). Полныйnpm testне гонял отдельно от полногоtsc -p tsconfig.test.json, который выполнил для сборки тестов — это тот же шаг, что и в CI.check-docs, golden,pytest tests_backend, performance — не запускал:src/**иcustom_components/**/*.pyдельтой r2 не тронуты.- Полный отбор 94 мутантов, которые дифф затягивает в CI (
selectForDiff) — как и в r1, проверил только те, что относятся к содержанию дельты этого раунда (3: новый плюс два перепривязанных); на остальные полагаюсь на зелёный Validate CI по всем шести шардам. - Полевой конфиг владельца issue (4 записи на 2 пространствах) по-прежнему
недоступен ревьюеру — как и в r1, использовал фикстуру
c6-stale-layoutиз репозитория и подтвердил сквозным CLI-прогоном, а не только юнит-тестом.
Что дальше
Задача закрыта: единственная Medium-находка r1 устранена по существу, новый
код доказан мутантом, тест больше не пропускает асимметрию, которая привела
к находке. High нет, Medium нет. Возврат в S7-code-review не требуется —
вердикт зелёный, к автору не возвращается.
Материал раунда
- Ветка:
issue/566-stale-layout-notes, коммит733cd5b86b30— ребейз его осиротит, и это нормально: ниже якоря, которые ребейз не меняет. - Дерево материала:
7ce15af6d80e3c0746cc4399044e7e9e79da35degit log --all --format='%H %T' | grep 7ce15af6d80e - Тело issue:
b30fafcfa79bb1bfe11625206ac445bb83a257f0b821202f064d1c4cfdcb2dd7 - Вердикт конвейера:
green· High 0