16 KiB
SPEC-REVIEW-272-r1
- Issue: #272 — «Multi-wall стыки beta.5 всё ещё оставляют белые треугольные отверстия вне probe #261»
- Этап: ТЗ на ревью (PROCESS.md §2.4)
- Заход: r1 · блокирующих циклов израсходовано 0 из 4 (первый заход, полный разбор)
- Артефакт ТЗ:
docs/specs/272-no-multiwall-holes.md, коммит9e4a9470b63718d75cb6e11b13717ccc24cbe4e6(веткаissue/272-no-multiwall-holes) - Ревьюер: свежая сессия, без устных пояснений автора
Скоуп ревью
Не «согласиться», а найти, где ТЗ невыполнимо или непроверяемо. Проверено:
соответствие docs/SCOPE.md, обязательные разделы §7.1 PROCESS.md, однозначность
и доказательность каждого AC, отсутствие догадок, выданных за факт, и совпадение
технических утверждений о коде с реальным src/wall-thickness.ts.
Как проверялось
- Прочитаны
docs/SCOPE.md,AGENTS.md,PROCESS.md(§§1–14 целиком) — подтверждён формат вердикта, лимит циклов, обязательные разделы ТЗ. - Прочитаны тело issue #272 и оба комментария (аналитика владельца, «ТЗ готово
к ревью»). Issue не помечен
small→ ТЗ обязано жить вdocs/specs/, что и сделано. - Прочитан канонический
docs/WALL-THICKNESS.mdцеликом и сверен построчно с утверждениями ТЗ о контракте multi-wall bevel (R = 1.25 × H,MITRE_LIMIT, #249/#261/#197 инварианты). - Прочитаны связанные issue #249, #258, #261 (закрыты), #270, #271 (открыты,
S4-spec-review, без меткиsmall) — сверено, что ТЗ #272 не искажает их историю и корректно описывает состояние #270 (не слито, без семантикиenclosedHolesв коде). - Прочитан
src/wall-thickness.ts: константыMITRE_LIMIT/MULTI_WALL_JOIN_LIMIT(строки 46, 49),multiWallBevelTrianglesAt,bevelMultiWallBody,bevelMultiWallPaper(строки 1969–2130) — построчно сверены с разделом 3 ТЗ («вычитает full-origin pairwise triangles», «union-ит ray rectangles», «добавляет tiny core», «клипует к envelope»). Совпадает. grepпоdemo/golden/matrix.mjs,demo/golden/harness.mjs,test/golden-matrix.test.mjs,test/wall-thickness.test.mjs— подтверждено существованиеdiscardedWedgeProbe,retainedWedgeProbe,multiWallJunction; подтверждено отсутствиеenclosedHolesгде-либо в дереве (только в тексте issue #270, не в коде) — заявление ТЗ о статусе #270 точное.- Сверен формат ТЗ с предыдущим ТЗ того же автора по той же подсистеме
(
docs/specs/261-white-wedges-root-cause.md) как образец принятого прежде документа — раздел «Acceptance criteria и доказательства» там даёт явную строку «Доказательство:» на каждый без исключения AC (AC1…AC7). - Гейты этого этапа (ревью ТЗ) не подразумевают прогон кода — код не менялся.
typecheck/test/buildне прогонялись, так как это ревью документа, а не реализации; продуктовый код изменений не содержит (диапазонorigin/dev..HEAD— один документ).
Находки
Medium (в скоупе) — 1: у большинства AC нет явной строки «Доказательство»
docs/specs/272-no-multiwall-holes.md, раздел 8, AC2–AC7. Только AC1 несёт
явную строку **Доказательство:** test/wall-thickness.test.mjs и анонимная fixture.. AC2 («#249 остаётся ограниченным внешним bevel»), AC3, AC5, AC6, AC7
описывают ожидаемое поведение и упоминают артефакты в свободной прозе
(discardedWedgeProbe, retainedWedgeProbe, golden-сцену, mutation), но не
называют явно способ доказательства в терминах §2.5 PROCESS.md
(unit/backend/smoke/golden/«ревью кода»). AC4 называет метод
(«Targeted production-bundle smoke») в тексте, но тоже без выделенной строки.
Почему это находка, а не стиль. PROCESS.md §2.5 (DoR) требует буквально:
«у каждого [AC] указано, чем он доказывается». Собственный прецедент того же
автора по той же подсистеме, docs/specs/261-white-wedges-root-cause.md
(предыдущее принятое ТЗ по multi-wall bevel), даёт явную строку
«Доказательство:» на каждый без исключения AC — AC1…AC7. #272 отступает от
уже установленной и принятой конвенции без объяснения. Без явной строки
«Готово к разработке» (§2.5) невозможно механически сверить, что каждый AC
имеет названное доказательство — а не восстановить его по смыслу абзаца, что и
есть определение непроверяемости, которое ревью ТЗ обязано ловить.
Воспроизведение: сравнить docs/specs/272-no-multiwall-holes.md:186-245
(AC1–AC7) с docs/specs/261-white-wedges-root-cause.md:211-291 (AC1–AC7 того
же автора, та же подсистема) — расхождение в формате видно построчно.
Исправление: добавить к AC2, AC3, AC4, AC5, AC6, AC7 явную строку «Доказательство: …», называющую конкретный тест-файл/гейт (по образцу AC1 и по образцу #261), не переписывая уже верное содержание критериев.
Medium (в скоупе) — 2: «объявленный exterior sector» не определён алгоритмически
docs/specs/272-no-multiwall-holes.md, §6.3, пункт 3: «пустые samples,
связанные с границей окна или с объявленным exterior sector, считаются
внешним фоном». Раздел 6.3 — это ядро контракта: он формально отделяет
законную внешнюю пустоту (после bevel #249) от настоящей дыры внутри стыка,
то есть именно то различие, ошибка в котором была причиной, по которой #261 и
старый golden-порог пропустили дефект (см. #270). Первая часть критерия
(«связаны с границей окна») — детерминированный flood-fill, вычислимый
геометрически и без произвола. Вторая часть, «объявленный exterior sector», не
определена: неясно, вычисляется ли она автоматически из угловой геометрии
узла (node.rays, разрыв между соседними лучами за пределами R — то, что
уже строит multiWallBevelTrianglesAt()), или назначается вручную на fixture,
по аналогии с уже существующими вручную объявленными discardedWedgeProbe /
retainedWedgeProbe.
Почему это важно именно здесь. Если «объявленный сектор» — вручную
назначаемый параметр теста, то AC1 (автоматический vector inventory по
minimized fixtures из настоящих экспортов с 12–14 узлами) либо не масштабируется
без ручной разметки каждого узла, либо тест может «объявить» настоящую дыру
законным внешним сектором и молча её принять — то есть повторить ровно тот
класс слепоты, который эта задача должна закрыть (мера #270: seen-but-under-
threshold). Если это вычисляемая величина — соответствующее правило (например,
«угловой разрыв между соседними лучами за пределами retained-overlap R»)
стоит явно назвать в тексте контракта, а не оставлять читателю выбирать между
двумя разными по надёжности реализациями.
Исправление: одна фраза в §6.3.3, фиксирующая происхождение «exterior sector» как вычисляемой из геометрии узла величины (или прямая ссылка на то же правило связности, что уже сформулировано в §6.1), либо явное решение исполнителя занести в блок §13 «принято предположительно» с формулировкой, исключающей произвольное ручное объявление на реальных, не golden, fixtures.
Low — 1: неполное попадание в Core user jobs (снято, без правки документа)
Аналитика владельца и §1 ТЗ ссылаются на J1 и J6 (docs/SCOPE.md). J6
описывает эволюцию плана (drag/resize/merge/split, multi-client sync,
optimistic locking) — этот баг чисто визуальный и в J6 не попадает
содержательно; корректна только ссылка на J1 («живой обзор... сейчас»). Не
блокирует и не меняет объём работы ни на строку — оставляю без правки
документа с этой записью.
Что проверено и корректно
- Формат и полнота разделов (§7.1 PROCESS.md): сценарий/персона, «что человек увидит до/после», проблема, scope/не-scope, контракт поведения, UX/touch/i18n/данные и миграция (все явно «не меняются»), AC1–AC8, риски, откат, release-артефакты — все присутствуют и совпадают по структуре с принятым прежде ТЗ #261 той же подсистемы.
- Технические утверждения о коде не являются догадкой. Раздел 3 (зона
причины:
multiWallBevelTrianglesAt/bevelMultiWallBody/bevelMultiWallPaper) и раздел WALL-THICKNESS.md (R = 1.25 × H,MITRE_LIMIT = 4) построчно сверены сsrc/wall-thickness.ts:46,49,1969-2130— совпадают. - История связанных issue не искажена. #249/#258/#261 закрыты и не переоткрываются (#272 — новый issue, верно); #270 корректно описана как не слитая инфраструктурная основа без продуктового решения; #271 — как рекомендованный, но не обязательный порядок мержа, зафиксированный в §13 как явное техническое предположение с указанной причиной.
- Продуктовых вопросов владельцу нет и не должно быть. Владелец сам подтвердил дефект в комментарии-аналитике («видимые белые треугольники — дефект») и сам написал ТЗ; открытых вопросов, требующих решения «что видит пользователь», в тексте не осталось — §13 корректно фиксирует только технические предположения, подлежащие оспариванию ревьюером, а не владельцем.
- Не-scope согрёт риски: отказ от
R/MITRE_LIMIT, округление bevel, Optimize-очистка (#273) явно исключены, что не даёт задаче расползтись на соседние подсистемы. - AC6 (mutation) ссылается на реальный существующий механизм
scripts/mutation-gate.mjs— не изобретённый специально для этого ТЗ инструмент. - Privacy/determinism (AC7) и запрет на коммит приватных экспортов (§2)
соответствуют
docs/SCOPE.md(«never delete/never leak user data» — здесь зеркально «never commit private exports») и практике репозитория.
Чего не проверял
- Не запускал
npm run typecheck/npm test/npm run build— на этапе ревью ТЗ продуктовый код не менялся (диапазонorigin/dev..HEADсодержит только документ спеки), гонять их бессмысленно. - Не пытался воспроизвести приватные
1.json/2.json— они не коммитятся по условию задачи; принял описанные в issue числа узлов (12/14) и координаты probe на веру автора аналитики, как и разрешает процесс для зафиксированных владельцем измерений. - Не оценивал сложность самого geometric boolean алгоritma, который будет писать разработчик — ТЗ прямо и правильно оставляет конкретный алгоритм реализации техническим решением (§13.2), и это его законное место, а не моя работа на этапе ревью ТЗ.
- Не проверял
docs/ARCHITECTURE.md/docs/TESTING.mdцеликом, только что они существуют — они процитированы ТЗ как канонические документы, но #272 не меняет их контракт, только тестовые артефакты, которые эти файлы описывают на верхнем уровне.
Вердикт
Жёлтый: AC выполнимы и в основном доказуемы, но раздел 8 нарушает собственную установленную конвенцию доказательности AC (§2.5 PROCESS.md) на 6 из 8 критериев, а ключевое различие «внешний фон vs дыра» (§6.3.3) содержит один неопределённый термин ровно в той точке контракта, ради которой заведена вся задача. Оба High-блокеров нет; обе находки — Medium, в скоупе, чинятся правкой текста ТЗ без пересмотра архитектуры решения.