Review pipeline (process.yml):
- concurrency moves from the workflow to the guard/review jobs and the guard
runs only for S4-spec-review / S7-code-review. Any other label used to enter
the issue's concurrency group and evict the pending review run (sample of
150 runs since 2026-09-01: 92 empty guard-only runs, 30 cancelled).
- the guard reads the issue's current labels instead of the event snapshot; a
label removed before the run starts is a withdrawn request, no comment.
- a green verdict is re-applied without calling the model when the latest
review document carries the pipeline-recorded verdict `green`/High 0 and the
tree differs from its anchor in nothing outside docs/reviews/** (#437 r4
re-reviewed an unchanged tree for 7 minutes). The verdict from
structured_output is now written into the anchor block for that purpose.
- the reviewer is pinned to the captured material SHA in the prompt; the
broken escaping in the "merge cancelled" comment (empty SHAs) is fixed.
Mutation gate: nine browser guards started with `npm run bundle:sync` although
the runner already builds the mutant bundle — a second rollup plus a
`tsc --noEmit` that fails on a non-strict mutant before the smoke even runs.
Prefix removed; `--check` refuses guards that build the bundle themselves.
Docs: SCOPE (Project v2 dropped, three editors), STATUS (#437 merged, HACS zip
automated), USER-GUIDE ru/en (static card shows live states; kiosk double tap
on free background fits all), #34 → #425 references, #367 named as closed in
bundle-budget messages, PROCESS §10.4 and AGENTS.md describe the controller.
Issue: #499
User-Visible: no
#387 закрыл классификацию — какие job запускать. Здесь остаток того же
дефекта: гейты, которые судят сам диапазон коммитов. Провенанс, процессный
гейт и «новый код не добавляет any» брали диапазон от головы предыдущего
пуша, а concurrency отменяет прогон предыдущего пуша штатно. Тогда его
коммиты не судит никто: свой прогон отменён, а следующий пуш сравнивает уже
с ними. Окно не закрывается никогда.
Уязвим был прямой пуш в dev — основной режим конвейера. На ветках дефекта
нет: no-new-any там всегда считает от merge-base, а resolveValidationRange
подменяет осиротевший before на origin/dev (#315).
База стала последним предком с успешно завершённым Validate. Фолбэк, когда
такого нет, сознательно оставлен прежним — before, но с пометкой в summary
«диапазон недоказуем». Расширять диапазон здесь нельзя: гейт, который сам
красит прогон, лишил бы следующий пуш зелёного предка и запер dev в
красноте навсегда. Фолбэк обязан не зависеть от собственного успеха гейта.
Дыра сужается с «всегда, когда прогон предыдущего пуша отменён» до «когда
во всём окне обхода нет ни одного успешного прогона».
Находки no-new-any теперь называют коммит, добавивший строку: диапазон стал
шире, и без имени источника сообщение обвиняло бы того, кто пушнул
следующим, — ровно то, что чинили в #386 для golden.
Issue: #388
User-Visible: no
В src/** сейчас 1034 вхождения явного any в 49 файлах — больше, чем называл
аудит (330), потому что монолит с тех пор разделился и его обвязка уехала в
houseplan-editor-runtime.ts. Разовая замена такого объёма — месяц риска ради
нуля пользовательской ценности, поэтому долг снимается при плановом извлечении
подсистем (#34). Задача гейта одна: не давать долгу расти.
Судятся только добавленные строки диапазона. Изменённая строка со старым any
выглядит в диффе добавленной, и это намеренно: тронул — либо типизируй, либо
обоснуй на той же строке `// any-ok: <причина>`. Голый маркер, пустая причина и
шаблоны вроде todo, hack, потом не проходят.
Ложных срабатываний нет по построению, а не по старанию: текст разбирается
парсером TypeScript, и нарушением считается узел AnyKeyword. Регулярка по строке
ловила бы слово any в прозе внутри шаблона html и в комментариях; здесь
комментарии, строковые литералы, многострочные шаблоны и идентификаторы
company, anyOf, manyRooms узлами такого вида не являются вовсе.
Проверено исполнением на настоящем дереве, а не только юнитами: пробные коммиты
в src/wall-thickness.ts показали, что добавленный any падает с файлом и строкой,
типизированная строка в файле с 122 старыми any проходит, any-ok с конкретной
причиной проходит, а голый и «todo» — нет, и что any в прозе, строке и
идентификаторах не даёт ни одного срабатывания.
В job frontend checkout получил полную историю без блобов: diff-aware проверке
нужен диапазон, а содержимое старых ревизий — нет.
Заодно закрыта ловушка в test/validate-workflow.test.mjs: имя job искалось через
indexOf(' frontend:'), а эта строка встречается внутри ` frontend: ${{ ...
}}` в outputs job changes, поэтому срез уходил не туда. Теперь имя ищется с
начала строки.
Четыре мутанта проверены руками, два добавлены в реестр: гейт, судящий все
строки, и гейт, принимающий голый маркер.
Issue: #342
User-Visible: no