Issue: #426 Issue: #427 Issue: #428 Issue: #431 Issue: #432 Issue: #434 User-Visible: no
16 KiB
SPEC-REVIEW-434-r2
- Issue: https://github.com/Matysh/houseplan-card/issues/434
- Этап: ревью ТЗ (PROCESS.md §2.4)
- ТЗ:
docs/specs/434-v171-polish-audit.md - Проверяемый SHA:
904a989af70481eb7f34c1e3cfc99de115ba869f(=git rev-parse HEAD, совпадает с SHA, названным автором в хендоффе r2) - Заход: r2 · блокирующих циклов израсходовано 1 из 4 (полный трек, лимит 4)
- Вердикт: зелёный
Скоуп раунда
Повторный раунд по §2.9/2.10: предмет разбора — дельта ТЗ между материалом r1
(5566d6f9898e3c6d21f3e92a2ddf94536c86edc4) и текущим 904a989a, а не задача
целиком. Дельта проверена командой:
git diff 5566d6f9898e3c6d21f3e92a2ddf94536c86edc4..904a989af70481eb7f34c1e3cfc99de115ba869f -- docs/specs/434-v171-polish-audit.md
git diff --stat на этом же диапазоне подтверждает, что дельта не касается
ничего, кроме файла ТЗ, — второй изменённый файл в диапазоне,
docs/reviews/SPEC-REVIEW-434-r1.md, это публикация документа предыдущего
раунда конвейером (класс C, не предмет разбора).
Дельта локальна: она правит ровно одну тему — контракт job-level
timeout-minutes для job smoke (пункт 8 / AC9 / раздел 7.7 / «Производительность»
/ «Риски» / таблица «чем краснеет» / тест-план / «Принятые предположения»).
Условия «разбор остаётся полным» (ребейз на ушедший вперёд dev, смена
контракта поведения, новая подсистема, объём дельты сопоставим с исходной
задачей) не выполнены: ни ребейза, ни новой подсистемы, дельта — 40 строк
правки внутри уже существующего AC9, без изменения продуктового контракта
(изменение чисто CI/gate, не видимое пользователю). Сокращённый объём разбора
обоснован.
Закрытие раунда r1
| Находка r1 | Чем закрыта | Где это видно |
|---|---|---|
[Medium, в скоупе] ТЗ утверждало неизменный timeout-minutes: 20 у job smoke, хотя эти 20 минут принадлежат performance_smoke, а у smoke собственного лимита нет вовсе (дефолт GitHub 360 мин) |
Текст ТЗ переписан по всем перечисленным в находке местам: п.8 «Подтверждённые причины», раздел 7.7 «Bounded smoke execution», «Производительность», «Риски», AC9, «чем краснеет» (AC9), тест-план (шаг 8), «Принятые технические предположения». Факт теперь сформулирован верно, и в скоуп задачи добавлено решение: job smoke получает собственный timeout-minutes: 20 — новая независимая граница, отдельная от performance_smoke |
docs/specs/434-v171-polish-audit.md:73-76 («сама job smoke не имеет timeout-minutes и потому наследует 360-минутный default… Единственные 20 минут в workflow относятся к другой job — performance_smoke»); :247-250 («Job smoke получает собственный timeout-minutes: 20: это отдельная граница, которой сейчас нет…»); :384-389 (AC9 текст); :420 (таблица «чем краснеет», мутация «удаляет smoke.timeout-minutes»); :446-448 (тест-план п.8); :470-472 (риски); :517-519 (принятые предположения) |
Факт перепроверен независимо от заявления автора: grep -n timeout .github/workflows/validate.yml на актуальном HEAD даёт ровно одно
совпадение — строка 715, job performance_smoke (заголовок job на строке 705,
timeout-minutes: 20 на 715). Job smoke (заголовок строка 486, цикл
for f in demo/smoke_*.mjs строка 554) действительно не содержит
timeout-minutes нигде в своём теле. Формулировка ТЗ после правки точна.
Проверка дельты по существу (не только «текст поменялся»)
Так как дельта меняет именно AC9 (появляется новое обязательство — job-level timeout), доказательство которого дельта задевает, AC9 разобран заново, а не унаследован:
- Согласованность формулировок. Все шесть затронутых мест (см. таблицу
выше) описывают одну и ту же границу одинаково: 20 минут, независимая от
performance_smoke, покрывает весь shard «при системном зависании либо серии отдельных отказов» (:470-472), а не заменяет per-file timeout. Противоречий между разделами не найдено. - Реалистичность значения 20 минут. Комментарий в самом
.github/workflows/validate.yml:492-494фиксирует, что последовательный прогон всех смоков занимал ~7.5 минут до шардирования на 3 части, то есть штатный шард сейчас укладывается в ~2.5 минуты — у 20-минутного лимита восьмикратный запас на холодный раннер, сопоставимый с обоснованием того же значения уperformance_smoke(:711-713, «15 минут не хватало... холодный кэш»). Патологический сценарий, где job-level timeout прервёт shard до того, как последовательно доработают все per-file timeout (215 файлов / 3 шарда ≈ 72 на шард × 190 c ≈ 228 минут в предельном случае «все зависли») — ТЗ его не скрывает, а называет прямо как ожидаемое поведение защиты «при серии отдельных отказов», а не как гарантию довести до конца каждый файл. Технической ошибки или недосказанности здесь нет. - Проверяемость AC9 после правки. «Чем краснеет» (
:420) называет два независимых свидетеля — мутацию per-file wrapper (plain node "$f") и отдельно мутациюsmoke.timeout-minutes(удаление поля) — и требует, чтобы workflow-контрактный тест реагировал на оба независимо («не находит одну из двух независимых границ»). Это не создаёт пустого столбца и не путает test-time симуляцию (per-file probe) со статическим YAML-контрактом (job-level timeout, аналог которому —test/validate-workflow.test.mjs, подтверждённый как рабочий прецедент ещё в r1). Инженерно реализуемо тем же способом, что и остальной AC9. - Затронутые модули учитывают файл workflow.
docs/specs/434-v171-polish-audit.md:339-340прямо называет.github/workflows/validate.ymlв списке затронутых модулей — правка AC9 не «повисает» без соответствующего файла в скоупе.
Новых дефектов дельта не вносит.
Унаследовано из r1
Всё, что не задето дельтой, принимается без повторной проверки — документ
docs/reviews/SPEC-REVIEW-434-r1.md (материал: ветка issue/434-v171-polish-audit,
коммит 5566d6f9898e, дерево 1e1861969610794ffa6a9d8458b52ef3695496b8,
блоб ТЗ e0229c0cd6550a1c44b978335c52bd2b264b1c52):
- Обязательные разделы §7.1 присутствуют полностью; продуктовые «Сценарий» и «Что человек увидит до и после» отвечают на оба обязательных вопроса (персона/поверхность/момент; видимое изменение без терминов реализации) — и эти разделы дельтой r2 не тронуты (см. diff — правки только в §7.7, «Производительность», «Риски», AC9, таблице и тест-плане).
- Восемь из девяти пунктов «Подтверждённые причины» (все, кроме п.8, который
и есть предмет дельты) построчно сверены с
origin/devдвумя независимыми агентами и подтверждены дословно, включая:read_catalog/blob.is_file()(п.1), отсутствие capability-гарда вspace-card.ts:732(п.2), кэш по id-set без ревизии config (п.3), отсутствующий негативный тест «sidecar без blob» (п.4),reused:trueбез catalog-записи (п.5), locale gate снимок прошлого рендера (п.6, номера строк помечены как приблизительные), отсутствие отдельного witness уsnapshotBindings.has(binding)(п.7), throw до discard в support preview (п.9). - AC1–AC8, AC10–AC12 однозначны, способ доказательства назван для каждого; таблица «чем краснеет» (#435) заполнена без пустых столбцов для всех, кроме AC9, которую r2 перепроверил заново (см. выше).
- Маршрут (full) обоснован верно — критерий лёгкого трека не проходит из-за нескольких независимых поверхностей и подсистем.
- Не-скоуп корректно исключает соседние более крупные рефакторинги (LanguageRuntime/support pipeline/шардирование, изменения schema/API version, видимого текста/UI).
- Изменение семантики
reusedне является изменением видимого контракта — поле нигде не читается вsrc/**. - AC3 (удаление orphan-блобов) не противоречит правилу SCOPE.md «никогда не
удалять файл по предположению»: причина удаления — явный вызов
houseplan/assets/deleteс точным id, а не вывод из отсутствия ссылок. - Раздел «Откат» корректно называет границы (миграции нет, восстановленные sidecar остаются валидными записями); эти строки дельтой не менялись.
- Технические прецеденты (
scripts/mutation-gate.mjsуже содержит Python-мутанты,test/validate-workflow.test.mjs— рабочий образец YAML-контрактного теста) подтверждены наorigin/devв r1 и остаются в силе — AC9 после правки использует тот же прецедент.
Что проверено в r2 (сверх наследования)
- Дельта ТЗ (
docs/specs/434-v171-polish-audit.md, r1→r2) построчно прочитана целиком. - Факт из находки r1 перепроверен заново на актуальном HEAD:
grep -n timeout .github/workflows/validate.yml(1 совпадение, строка 715, jobperformance_smoke); контекст jobsmoke(строки 486–586) иperformance_smoke(строки 705–720) прочитан целиком,timeout-minutesв телеsmokeдействительно отсутствует. - Реалистичность выбранного значения 20 минут сверена с комментарием в самом
workflow-файле (фактическое время шардированного прогона) и числом реальных
smoke-файлов (
ls demo/smoke_*.mjs | wc -l→ 215). - Согласованность формулировки новой границы across всех шести затронутых разделов ТЗ.
git diff --statмежду SHA r1 и r2 — подтверждено, что кроме ТЗ и публикации документа r1 больше ничего не менялось (продуктовый код не затронут, разбор кода в этом раунде не требуется).
Чего не проверял
- Гейты (
typecheck/test/build/backend pytest) не запускались: диапазон правок — документация класса C (ТЗ + документ предыдущего ревью), кода нет. - Не проверялся сам код реализации — его по-прежнему нет, это ревью ТЗ.
- Разделы, не затронутые дельтой (см. «Унаследовано из r1»), не разбирались заново по существу — они наследуются от r1 согласно §2.10.
- Не оценивался точный сценарий частичного отказа (например, ровно 6–7 зависших файлов из 72 в шарде) на предмет того, какие именно файлы успеют отработать до срабатывания job-level timeout — ТЗ прямо не гарантирует «довести шард до конца при серии отказов», и это осознанно названо принятым поведением защиты, а не заявленным AC.
Материал раунда
- Ветка:
issue/434-v171-polish-audit, SHA904a989af70481eb7f34c1e3cfc99de115ba869f. - Дельта:
git diff 5566d6f9898e3c6d21f3e92a2ddf94536c86edc4..904a989af70481eb7f34c1e3cfc99de115ba869f -- docs/specs/434-v171-polish-audit.md. - Предыдущий раунд:
docs/reviews/SPEC-REVIEW-434-r1.md, материал — веткаissue/434-v171-polish-audit, коммит5566d6f9898e, дерево1e1861969610794ffa6a9d8458b52ef3695496b8, блоб ТЗe0229c0cd6550a1c44b978335c52bd2b264b1c52.
Материал раунда
- Ветка:
issue/434-v171-polish-audit, коммит904a989af704— ребейз его осиротит, и это нормально: ниже якоря, которые ребейз не меняет. - Дерево материала:
37d24151e91b534280e7ce0d4a437cd082afdc30git log --all --format='%H %T' | grep 37d24151e91b - ТЗ
docs/specs/434-v171-polish-audit.md, блобe235fcef2bcd817c39c0c5a9134fd2ec8f6eb2f1git log --all --find-object=e235fcef2bcd817c39c0c5a9134fd2ec8f6eb2f1 -- docs/specs/434-v171-polish-audit.md