The label step after integration ran one gh call
`--add-label "$TO" --remove-label "$FROM"`. For the rereview outcome
TO == FROM == S7-code-review, and gh added and removed the same label:
#699 was left without a status and no new round started (run
36491087708).
- scripts/status-label.mjs: the same label is removed and set again
through relabel from process-reconcile (#555), so the labeled event
starts the next round and a failed restore fails the step; a
different label is still one call.
- _process.yml: the step calls the script.
- PROCESS.md: the exact-candidate rule names the relabel.
- test/status-label.test.mjs; mutants rereview-relabel-in-one-call and
process-label-step-combined-again.
Issue: #706
User-Visible: no
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018qZfe7YS4rqEMKoVeS3GKd
CODE-REVIEW-700-r1 Medium: `gh issue list … || true` turned a failed read
into an empty answer, and the step went on to gh issue create — a second
[workflow-sync] issue next to the open one on every network or rate-limit
failure. A failed read now warns and exits 0; creating stays reserved for
«read succeeded, nothing open».
Mutant workflow-sync-issue-duplicated-on-read-failure.
Issue: #700
User-Visible: no
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018qZfe7YS4rqEMKoVeS3GKd
11 of 85 returns in #600–#691 were the thin-workflow mirror check, and any
push could turn red because a foreign site behind a docs link was down.
- validate.yml preflight: on refs/heads/issue/* the workflow_sync mismatch
is a warning in the summary, not a failed verdict; push to dev, the beta
candidate and the release keep it red.
- On push to dev a mismatch opens one owner issue titled [workflow-sync]
(or comments on the open one), like the nightly mutation gate (#472);
preflight gets issues: write for that.
- check-docs --external=warn: external link failures become warnings; the
docs step passes it on task branches only.
Canon: PROCESS.md §10.4 («Workflow из ветки по умолчанию»).
Issue: #700
User-Visible: no
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018qZfe7YS4rqEMKoVeS3GKd
Сверка PROCESS.md, ролевых выжимок, AGENTS.md, TESTING.md, CONTRIBUTING.md
и скриптов по 26 найденным расхождениям (D1–D26): трейлеры по классам
изменений, gate:small как единственный источник состава, пороги ревью,
путь реестра мутантов, golden по ci:golden, порядок чтения промпта ревью.
- scripts/change-classes.mjs: классы A/B/C/D — один модуль для
process-gate и проверки трейлеров.
- commit-msg: коммит только с файлами класса C (документация) трейлеров
не требует; указанные трейлеры по-прежнему проверяются.
- Маршрут автора без docs/STATUS.md: 5345 → 4703 слова.
- Промпт ревью читает SCOPE → AGENTS → REVIEWER, как ROUTES.reviewer.
Issue: #701
User-Visible: no
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018qZfe7YS4rqEMKoVeS3GKd
The screenshot fingerprint and golden baselines stop being a tax on every
task branch:
- Task branches no longer commit docs/images/** or golden baselines. On a
branch the screenshot freshness stays a preflight warning; the review
prompt, REVIEWER.md and AUTHOR.md drop check-docs as a per-task gate.
- beta-derived.yml refreshes them on dev in one bot commit before the beta
candidate: canonical docs capture + docs:accept --reviewed, golden from
the golden-images artifact of a completed Validate on dev +
golden:accept --reviewed. A changed frame or scene is accepted only when
named in the inputs; undeclared differences refuse. Baseline commits carry
Release: and Baseline-Reviewed:; the subject is not a candidate subject.
- classify-changes: the Release: trailer on an issue/* branch no longer
switches on the heavy set. ci:full / ci:golden do: process-track emits
full=true, the review gate dispatches Validate with full=true and does not
accept a light proof.
Canon: PROCESS.md §3 п.13, §5.1, §8, §11.4; CONTRIBUTING.md.
Issue: #697
User-Visible: no
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018qZfe7YS4rqEMKoVeS3GKd
show/ship stop paying for diff mutants and for every move of dev:
- scripts/process-track.mjs resolves the track from the current labels and
the diff (show for unlabelled infra, ask for unlabelled product work) and
checks the mechanical ship limits; outside them the pipeline comments and
relabels track:ship -> track:show in the same round.
- Validate on the review material is light on show/ship: a completed push
run on the exact SHA is proof, a dispatch asks mutants=false. ask and the
ci:mutants label keep the mutant dispatch.
- show/ship skip the pre-review rebase when git merge-tree with dev is
clean; the candidate is rebased once at merge and still passes Validate
before the push to dev. The light merge waits for the push run of the
candidate and dispatches only when none appears.
- ship inside the limits merges after the light Validate without a model
review; the issue gets a machine marker hp:ship-merge.
- ship-review.yml + scripts/ship-review.mjs read the code of all ship
tasks of a beta range in one model session and publish
docs/reviews/SHIP-REVIEW-<tag>.md; both beta publication paths refuse a
range with ship tasks the document does not cover or that carries a High.
- show reviews judge correctness and AC; the spec review installs neither
npm ci nor Chromium, the show review installs Chromium only when the issue
names a smoke.
Canon: PROCESS.md §5, §5.1, §10.4, new §11.7; REVIEWER.md, AUTHOR.md and
AGENTS.md digests.
Issue: #696
User-Visible: no
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018qZfe7YS4rqEMKoVeS3GKd
CODE-REVIEW-695-r1 Medium: PROCESS §5.1 says an infrastructure task (§1)
without a track label reads as track:show, but neither the pipeline guard
nor the task packet did that.
- _process.yml guard: with no track:* and no small/trivial label, the
diff of the task branch against dev (compare API) with no class A file
gives the show cycle limit 2. A truncated compare answer (300 files)
proves nothing and keeps the limit 4.
- task-packet.mjs: an infrastructure packet names the track it runs on:
«инфраструктурный · show» without a label, the owner's label otherwise.
- Mutants guard-infra-keeps-ask-limit and
packet-infra-track-ignores-show-default.
Issue: #695
User-Visible: no
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018qZfe7YS4rqEMKoVeS3GKd
The analysis of 85 closed tasks #600-#691 showed that the light track
cost as much as the full one (115 min and 12 events vs 102 and 13) and
that the owner had no label to choose the route. The owner accepted the
proposal on 2026-09-28.
- PROCESS §5 is the track table: track:ship (S1 -> S5, one line under
"## ТЗ", <= 30 src lines, batch review before the beta), track:show
(default, S2 -> S5, up to three AC, no spec review, 2 code cycles),
track:ask (full route). The owner's label beats the criteria, which
become a hint; any agent may raise a track, only the owner lowers it.
- §5.1: ci:full / ci:golden / ci:mutants order heavy checks on any track;
small and trivial read as track:show, no label as track:ask, an
infrastructure task as track:show.
- §2, §2.2, §2.4, §2.5, §4, §7.1, §7.2, §9, §11 follow; AUTHOR/REVIEWER
digests and AGENTS.md follow with the digest test and its mutants.
- task-packet.mjs reports the track via trackFromLabels(); the pipeline
reads track:show/track:ship for the cycle limit of 2 and lets an
explicit track:ask win. Pipeline behaviour by track is #696.
Issue: #695
User-Visible: no
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018qZfe7YS4rqEMKoVeS3GKd
Волна 3 эпика #674. AGENTS.md 650 → 187 строк: карта пакета, маршрут чтения,
правило №1, классы и треки одной строкой со ссылками, трейлеры, рабочие
деревья, хендофф и ожидание вердикта; пересказы PROCESS.md — ссылками на
разделы. Неверный список «Gate jobs» снят (списки jobs не копируются в прозу,
шапка PROCESS.md). Правила, жившие только в AGENTS, получили дом: жёлтый
вердикт при выполненных AC — PROCESS §2.7; свежесть бандла, съёмка только в
Linux (#455, HP_ALLOW_FOREIGN_CAPTURE) и смоки из AC до S7 (#151) —
TESTING.md; причуда демо-стенда и среда-зависимый smoke_opening_measure —
DEVELOPMENT › Smoke tests; отказ публикации без `Release:` и при несвежем
отпечатке бандла, отмена Validate новым пушем, кандидат беты не
promotion-only, fail-closed реестра Labs — DEVELOPMENT; предупреждение и
ошибка свежести скриншотов — CONTRIBUTING.
PROCESS.md: §13 (внедрение с открытым ⏳), §14 (блок со ссылкой на
несуществующий docs/PROCESS.md) и §7.3 (история) удалены. Ссылки «§7.2» на
правило полного разбора после ребейза ведут в §2.10, на сверку SHA перед
выводом — в §2.7; то же в сообщениях scripts/branch-state.mjs,
merge-candidate.mjs, review-doc-guard.mjs, pre-push-gate.mjs, в промпте
_process.yml и TESTING.md. Число `any` в прозе → `node scripts/no-new-any.mjs
--total` (новый режим, юнит-тест; было «1034 в 49 файлах», сейчас 862 в 52),
дата-число замороженного списка якорей монолита снято. Устаревшая команда
пересъёмки скриншотов в §8 заменена ссылкой на действующий путь.
STATUS.md 113 → 61 строка: сгенерированный снимок, текущий цикл и девять
строк решений; Workflow, CI, Toolchain, Tests, Scope, open items и политика
документации — ссылками (PROCESS §2.6, DEVELOPMENT › Release, TESTING);
локали en/ru/de/fr; закрытые «coverage, mypy strict» сняты.
DEVELOPMENT.md: file-sync и «Reproducible scripts» (прототип) удалены;
раздел Release — единственный дом релизной механики: введение, правила
тела стабильного релиза (#328, release:notes), шаг continuity:screencast,
источники версии по release-contract. CONTRIBUTING: ссылка на Release вместо
пересказа, замеры клона без чисел. TESTING: any-гейт — ссылкой на PROCESS §8.
entry-cost: автор 11 125 → 5 407 слов, ревьюер 8 464 → 4 285.
Issue: #680
User-Visible: no
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018qZfe7YS4rqEMKoVeS3GKd
Волна 4 эпика #674.
docs/testing-notes/: восемь ручных чек-листов по поверхностям и индекс
удалены — ни одного отмеченного пункта, ручной фазы в PROCESS.md §2 нет.
Правило #650 (пустое совпадение --test-name-pattern) перенесено в
TESTING.md; пункты [manual] без автоматического свидетеля сведены в раздел
«Чего не проверяет автоматика» (реальный HA, сенсорное устройство, ресурсы
сервера, несколько клиентов, визуальная оценка, пользовательское
содержимое). В TESTING.md снят блок чек-листов v1.43–1.44 и приложения по
issue в разделе golden (#197/#249/#272/#275/#288/#261) — сцены объявлены в
demo/golden/matrix.mjs. Остался реестр браузерных гвардов #659
(mutation-browser-guards.md). test/testing-notes-index.test.mjs →
test/testing-doc.test.mjs: лимит 800 строк, правила #85, раздел ручных
проверок и живые ссылки TESTING.md; каталог testing-notes содержит только
реестр. Мутант testing-notes-index-drops-section (удалял строку индекса) →
testing-doc-drops-manual-section. golden-matrix: копия 67 id сцен #242/#250
в чек-листе снята, список и способ его измерения — в demo/golden/matrix.mjs.
docs/design/505-summary-panel удалён вместе с
demo/capture_summary_panel_505.mjs и маршрутом /reference/ фикстуры
диалога. docs/design/600-settings-dialogs: reference/, screenshots/,
pairs/, ARCHIVE-README, ISSUE-FORM, OPEN-POINTS удалены; SPEC,
IMPLEMENTATION-GUIDE, field-maps, ACCEPTANCE остаются; вывод
capture_design_pairs_600.mjs и verify_ha_form_shell_609.mjs --capture —
в artifacts/. docs/design: 68 файлов / 4,08 МБ → 13 / 0,70 МБ.
README-ha-dialog-505.md → README-ha-dialog.md (путь в release-review.yml);
demo/guard/README.md: запись гварда — в verify-guard.mjs, не в README.
docs/design/649-25d-stage6 не тронут — пункт после стабильного v1.78.0.
Issue: #681
User-Visible: no
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018qZfe7YS4rqEMKoVeS3GKd
Волна 2 эпика #674 — у каждого правила один дом, остальные места ссылаются.
DECOR-EDITOR.md ← BACKDROP.md + LIVE-TEXT.md: один документ с нумерованными
разделами (§3 подложка, §5 текст с живыми значениями), на которые теперь
указывают комментарии кода вместо несуществовавших «BACKDROP §2/§3»;
исправлено утверждение, что space-card не рисует декор (он рисует подложку
и картинки декора, но не фигуры, мебель и текст). LIGHT.md ← матрица
настроек света (перевод, тест назван явно: test/devices.test.mjs «issues
84/88»). DEVICE-PRESENTATION.md ← правила «что показывает маркер» из
FILTERING.md (порядок cover → light sources → device role, шторы,
медиаплееры); «в одном pull request» → «в одном коммите». CANVAS.md: §9.5
«Оптимизировать планы» → CONFIG-COMPATIBILITY.md, overlay и планарные грани
Walls → WALL-THICKNESS.md §10–11, таблицы «было/стало» сняты. TESTING-DEMO.md
→ demo/stand/README.md: карта демо-дома и «чего на стенде нет», ручной
чек-лист снят (ручной фазы в процессе нет). ISOMETRIC.md — только текущее;
история Stage 2/4 — docs/adr/570-isometric-stage4-visual-handoff.md.
SUN.md: удалённый контракт фона снят, правило бумаги — в текущем разделе.
UX-MODES.md: декор над заливками, а не «под комнатами»; «hidden isometric»;
follow-up из #3 — все выпущены. Шапки VACUUM, WARM-REMOUNT («Выровнять всё
по сетке» → «Оптимизировать планы»), WALL-THICKNESS, STYLING-HOOKS,
CONFIG-COMPATIBILITY (#33), PDF-EXPORT — без устаревших статусов и планов.
README EN/RU: абзац про пересъёмку скриншотов → CONTRIBUTING.md, RADAR и
PDF-EXPORT в списке документации, RU догнал EN (2.5D, повторное
использование загруженного изображения, STAIRS). Один список канонических
документов подсистем в AGENTS.md и промпте ревьюера (_process.yml).
WALL-THICKNESS.md ссылается на ADR 282.
Правки src/** и validation.py — только пути документов в комментариях.
Issue: #679
User-Visible: no
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018qZfe7YS4rqEMKoVeS3GKd
`ubuntu-latest` с 19.10.2026 переезжает на Ubuntu 26, а golden, скриншоты
документации и перф-бюджеты сняты на текущем образе: все 43 job на раннере
теперь явно на `ubuntu-24.04`, один образ на все workflow. 26 job получили
`timeout-minutes` по наблюдённой длительности с запасом; гейт релиза — 180,
больше суммы собственных ожиданий (60 + 60 + 45). Расписания ушли с круглых
минут (ночь 02:17, мутанты 00:43, метрики 05:23, полный перф 04:11), ночь
пишет в summary сдвиг старта и предупреждает, если он больше часа.
test/workflow-hygiene.test.mjs держит все три правила по тексту workflow
(разбор `parseJobSettings` в scripts/workflow-jobs.mjs) и исполняет шаг
сдвига старта настоящим bash; порядок осознанного подъёма образа —
docs/DEVELOPMENT.md.
Issue: #658
User-Visible: no
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018qZfe7YS4rqEMKoVeS3GKd
Решения владельца: 1б — индекс ревью не пересобирается в ветке задачи,
только коммитами, идущими в dev; 2б — бандл меняет только кандидат
беты/релиза, стенд dev берёт его из артефакта Validate.
- scripts/bundle-policy.mjs: коммит, трогающий dist/** или
custom_components/houseplan/frontend/**, обязан нести Release:
(хук commit-msg и история в CI через validate-commit-provenance;
коммиты с датой автора до 2026-09-27 не судятся); --verify судит
целостность свежей сборки всегда, побайтовую сверку с закоммиченной
копией — только на коммите, меняющем бандл, или кандидате; --clean.
- release-prerelease: публикация отказывает, если отпечаток исходников
в закоммиченном манифесте не равен отпечатку дерева (хотфикс поверх
кандидата без пересборки).
- bundle-sync: по умолчанию только demo/srv/assets; --release
(npm run bundle:release) — ещё и custom_components.
- rebase-on-dev: конфликт в бандле берёт копию dev, без пересборки
и amend.
- validate.yml: job dev_build публикует card-bundle головы dev в
сиротскую ветку dev-build (scripts/dev-build.mjs); стенд накладывает
её demo/stand/update-dev-bundle.sh.
- _process.yml: индекс ревью больше не пересобирается при приведении
к dev и при публикации документа в ветку задачи.
- golden-wsl-artifact/golden-container: сборка перед съёмкой не
считается правкой источника, после — bundle:clean.
- test/bundle-tree-committed: судит закоммиченный снимок, не диск.
- 11 мутантов в реестре; PROCESS/AGENTS/DEVELOPMENT/AUTHOR/REVIEWER.
Issue: #657
User-Visible: no
PROCESS.md §11.5: перед стабильным релизом — одно ревью поверхностей всей
линии бет «с нуля», без ТЗ и документов раундов, по SCOPE и USER-GUIDE.
- scripts/release-review.mjs: вход линии — прошлый стабильный тег, issue по
трейлерам в схеме RELEASE-MEMBERSHIP.json, продуктовые файлы; бриф промпта.
- .github/workflows/release-review.yml (workflow_dispatch, исполняется с dev):
prepare → model_review (модель без прав на запись, github_token #556) →
publish (docs/reviews/RELEASE-REVIEW-vX.Y.Z.md в dev токеном процесса,
индекс тем же коммитом, review-doc-guard). Повтор на тот же тег не тратит
модель, если документ уже в dev.
- release.yml: job independent-review ставит ревью в очередь сразу после
candidate, continue-on-error; ни один job выпуска от него не зависит
(решение владельца 2026-09-25).
- REVIEWER.md, AGENTS.md, DEVELOPMENT.md; тесты и четыре мутанта.
Issue: #638
User-Visible: no
- scripts/no-new-private-writes.mjs: смоки и demo/helpers/** не добавляют
записей в приватное состояние карточки (присваивание, ++/--, delete по
цепочке с сегментом _x; от this — нет) и вызовов _setMode/_openRoomEdit/
_openMarkerDialog/_openSpaceDialog. Зачёт правки по полю, перенос блока —
movedLinesByFile из no-new-any; исключение // private-ok: <причина>.
--count — остаток на HEAD. Подключён в gate:small и в шаг frontend рядом с
no-new-any, с той же базой.
- demo/helpers/hp-test.mjs: 10 операций через контрактные хуки и события
фикстуры (setMode, setTool, switchSpace, openRoomEdit, openMarkerDialog,
openSpaceDialog, setServerConfig, setLayout, input, close); ставится
launch*() из demo/serve.mjs. В бандле фасада нет.
- demo/srv/demo.html: доставка houseplan_config_updated/_layout_updated,
__pushServerConfig/__pushServerLayout; после доставки запись со старым
expected_rev — conflict, как у настоящего сервера.
- HP_SMOKE_CHECKS=1 печатает имена проверок в finish().
- smoke_area_relocation, smoke_glow, smoke_grid_snap переведены на фасад без
потери утверждений; новый smoke_test_facade доказывает каждую операцию.
- 7 мутантов, docs/TESTING.md (раздел + правило №6), PROCESS.md §2.7, AGENTS.md.
Issue: #629
User-Visible: no
Six workflows run from the default branch (issues, schedule, workflow_run):
process, process-resume, process-reconcile, mutation-gate, nightly,
process-metrics. Their bodies move to _<name>.yml (on: workflow_call); the
original files keep only triggers, run-name, permissions, concurrency and one
job `uses: Matysh/houseplan-card/.github/workflows/_<name>.yml@dev` with
`secrets: inherit`. A pipeline change becomes one commit to dev.
- caller job permissions = union of body job permissions (#556 minimum kept
per job inside the body); caller `if` repeats the body guard for process and
process-resume so unrelated events stay skipped;
- dispatch inputs forwarded via workflow_call inputs of the same names;
- _mutation-gate.yml keys evidence/marker on job.workflow_sha (the body SHA):
in a called workflow github.workflow_sha belongs to the caller in main;
- action-pins: narrow exception for this repo's _*.yml at @dev with a reason;
- preflight workflow_sync compares all six thin callers (was 3 of 6);
performance.yml excluded: its schedule judges main with main's own body;
- tests read bodies from _*.yml; new test/default-branch-workflows.test.mjs;
six mutants; PROCESS.md §10.4, AGENTS.md, REVIEWER.md updated.
Issue: #623
User-Visible: no
A pipeline doc commit carries the review document and the rebuilt
INDEX.md; while the task waits, dev receives other tasks' documents with
their own INDEX.md, and the rebase of the branch conflicts in the index
every time. 24.09 this bounced green #617, #618, #629, #642 to S6.
scripts/rebase-generated.mjs: shared rebase helper. At every stop, if ALL
conflicting paths are docs/reviews/INDEX.md (or paths the caller
resolves itself), the index is rebuilt from the directory in the stop
tree, staged, and the rebase continues; any other path aborts and
returns the full list. CLI exit 3 = refusal with paths on stdout.
Wired into process.yml «Привести ветку к dev» (helper taken from dev via
git archive; conflict/conflicts outputs, lease, ref wait and
--commit-if-stale kept), merge-candidate rebaseOnto (claude[bot]
identity, --commit-if-stale kept) and rebase-on-dev.mjs (index next to
GENERATED_ROOTS; bundle still dev copy + rebuild).
Issue: #643
User-Visible: no
#620. Mutants were ~70 % of CI machine time.
1. mutation-gate.yml: a green full run (aggregator verified all six shards)
leaves a cache marker keyed by material tree + workflow SHA. A scheduled
night with the same tree and workflow, marker not older than 7 days, skips
the shards and writes "reused from run N" to the run summary. Red runs
leave no marker, so the next night runs again and still files the issue
(#472). Manual dispatch always runs the full registry. Decision is a pure
function in scripts/mutation-nightly-reuse.mjs.
2. changed_mutants: the shard plan (already computed before setup, #518) now
names the environment of its guards (plan-browser=/plan-python=, from
scripts/mutation-environment.mjs). Python + backend deps only for shards
with pytest guards, Chromium only for shards whose guards reach
Playwright; pip wheels cached. Every shard still runs and reports, so the
six mutant jobs of the review proof are unchanged.
Item 3 of the issue (smoke guards -> node --test) is out of scope here.
Issue: #620
User-Visible: no
Вход агента до первого файла кода стоил ≈ 26 700 слов (аудит 22.09).
- docs/process/AUTHOR.md и REVIEWER.md — выжимки PROCESS.md: каждый пункт
ссылается на раздел канона, ключевые формулировки дословные;
test/process-digests.test.mjs сверяет якоря, ссылки и правила.
- scripts/entry-cost.mjs — маршрут чтения по роли и бюджет (автор ≤ 12 000
слов, AC1); AGENTS.md «Read this first» называет те же маршруты.
- docs/STATUS.md: блок Snapshot генерирует scripts/status-snapshot.mjs
(версии — release-contract, счётчики — inventory, теги — git); feature
surface и ранние milestones перенесены дословно в docs/STATUS-FEATURES.md.
- docs/TESTING.md — действующая инструкция (684 строки, AC3); ручные
чек-листы и приложения по issue перенесены дословно в docs/testing-notes/
с индексом и тестом на полноту.
- Промпт ревьюера в process.yml читает конспект вместо пересказа правил;
машинные требования (строка вердикта, REVIEW_DOC, запрет fetch, таблица
«чем краснеет», разделы повторного раунда) сохранены и закреплены тестом.
- PROCESS.md: правила не менялись; добавлены ссылка на конспекты в шапке и
уточнение в §10.4, что ревьюер конвейера читает конспект.
- 7 мутантов в реестре.
Issue: #634
User-Visible: no
Карточка и редакторский рантайм держали ≈380 неиспользуемых импортов, 56
мёртвых объявлений и дублей типов (warm-boot, LS_*, GLOW_*, debounce,
navigate, lruRead — копии карточки в рантайме) и 112 приватных членов
карточки, которых не читал никто — делегаты `_editorRuntimeOrThrow()._x()`,
оставшиеся от выноса #425, и аксессоры glow-состояния. Всё это снято; в 9
других файлах — по одиночной ошибке. Делегаты и поля, которых касаются
браузерные смоки (`card._x(...)`), оставлены и посчитаны отдельно.
Гейт `npm run lint:unused` (scripts/unused-locals-gate.mjs, в gate:small и
Validate после сборки): `tsc --noUnusedLocals` чист, кроме приватных членов
карточки из порта HouseplanEditorHostPort / `host.` (portPrivates) и членов,
которых зовёт харнесс (harnessPrivates); храповик по шести числам
scripts/monolith-metrics.mjs против scripts/monolith-baseline.json —
delegates 260→159, portMembers 350, hostRefs 4948, portPrivates 96,
harnessPrivates 107, bundleBytes 2 510 141→2 500 387. `npm run inventory`
печатает те же числа. Заморозка 54 тестов, читающих монолит как текст
(test/monolith-text-anchors.test.mjs); PROCESS.md §2.7 — правило.
Логический исходник для контрактных тестов (test/houseplan-source.mjs)
дописывает члены рантайма без делегата в карточке — контракт продукта не
зависит от наличия заглушки. Потолки ядер и initial gzip опущены на выигрыш
(292 000 → 290 400). Бандл пересобран, три копии синхронны.
Issue: #624
User-Visible: no
Прогон 35870123732 на 49bae62e: тест «индекс свеж» покраснел на материале,
который конвейер сам же ребейзнул на dev (#614) — process.yml исполняется из
main и о `--commit-if-stale` ещё не знает; так красился бы любой раунд, пока
правка не отзеркалена, а на issue-ветках коммиты конвейера индекс ветки знать
не обязан. Свежесть судится там, где её держит конвейер: шаг preflight
`reviews-index --check` только на push в dev, в вердикте предполёта; skipped
не считается отказом. Юнит-тест байтовой свежести снят, вместо него — свидетель
на проводке. PROCESS.md §2.10: правка docs/reviews руками сопровождается
пересборкой в том же коммите. INDEX.md пересобран на текущем дереве.
Issue: #635
User-Visible: no
r2 H1: INDEX.md — снимок каталога, и ребейз ветки на dev, получивший чужие
документы ревью, устаревал его молча. Теперь `--commit-if-stale` пересобирает
и коммитит индекс коммитом конвейера после приведения к dev (process.yml) и
после ребейза кандидата (merge-candidate.mjs); тест «индекс свеж» сравнивает
закоммиченный файл с пересборкой и красит Validate при расхождении.
r2 M1: находка без заголовка — первый абзац секции, склеенный из перенесённых
строк, без маркера буллета и кода `**M1.**`; «не найдено», служебные скобки
«(унаследовано…)» — не находка. Нумерованные пункты тоже забирают перенесённые
строки. Мутант reviews-index-paragraph-tail. PROCESS.md §2.10 дополнен.
Issue: #635
User-Visible: no
scripts/reviews-index.mjs собирает docs/reviews/INDEX.md: одна строка на
документ — issue, этап, раунд, вердикт (явная строка, раздел «Вердикт»,
свободная форма хвоста; 936 из 986 распознаны), High/Medium по строке вердикта
или заголовкам находок, до шести заголовков находок. Индекс детерминирован,
не индексирует сам себя, перечисляет файлы вне схемы имён; `--check` — гейт
свежести. process.yml публикует INDEX.md тем же коммитом, что документ ревью.
docs/LESSONS.md — датированные уроки со ссылками на источники (12 записей из
аудитов и разборов недели). PROCESS.md §2.10 — где искать решения.
Тесты: разбор имён, вердиктов, счётчиков, находок; фикстурный каталог;
живой каталог (100 % покрытие, >90 % вердиктов); контракт шага конвейера.
Мутанты reviews-index-skips-self-check, reviews-index-verdict-substring.
Issue: #635
User-Visible: no
У `contents` API потолок 1 000 записей с молчаливой обрезкой; каталог подошёл к
нему (986 файлов). Guard теперь спускается по дереву commit → docs → reviews и
трактует `truncated` как отказ листинга (счёт по файлам отключается, страховка
по комментариям остаётся). Предупреждение о потолке снято. Тесты: фикстура на
2 400+ имён со своими документами в хвосте; свидетель на проводке workflow.
Issue: #621
User-Visible: no
scripts/process-metrics.mjs — чистые функции над снимками GitHub: по issue
(таймлайн меток) вход по первой статусной метке, S4→S5, вход→S7, S7→S8,
повторные постановки S7; раунды ревью — по документам docs/reviews, не по
событиям метки (конвейер с #636 ставит S7 сам); прогоны Actions по workflow —
исходы, wall-time, события (прогоны конвейера сведены в одну строку); минуты
S4/S7 конвейера без skipped; при наличии jobs — job-минуты и доля «Мутанты».
Markdown-отчёт со сводкой и таблицей по issue; CLI на gh (только чтение).
process-metrics.yml — понедельник 05:00 UTC и по кнопке; отчёт в step summary
и артефакт на 90 дней; прав на запись нет.
Тесты на фикстурах, в т. ч. воспроизведение формы аудита 22.09 (30 issue:
15 r1/13 r2/2 r3 → 1,57; Validate 226/178/37/11). Мутанты
metrics-count-skipped-pipeline-runs, metrics-rounds-by-s7-events.
Issue: #637
User-Visible: no
Стадия prepare спала ≈ 28 минут на раунд, пока шёл Validate с мутантами на
материале (модель работает 10–12); за неделю ≈ 420–500 job-минут простоя и
потолок бюджета стадии 55 минут.
- validate-gate.mjs: `--no-wait` — гейт диспатчит прогон, убеждается, что тот
встал на материал (#539 сохранён), и возвращает `pending` (код 2) вместо
ожидания; завершённый зелёный/красный отдаёт сразу, как прежде.
- process.yml prepare: третий исход `proceed=pending`: запечатанный маркер
`review-pending-<issue>-<run>-<attempt>` (issue, stage, branch, material_sha,
validate run) и выход; модель и интеграция не запускаются; возврат автору —
только на явном `false`.
- process-resume.yml + scripts/process-resume.mjs: на `workflow_run: completed`
Validate по ветке issue/* — если метка S7 стоит, активного прогона нет и
последний прогон оставил маркер на этот SHA, переставить S7 (HP_PROCESS_TOKEN);
новый прогон находит завершённый dispatch сразу. Без маркера не будит.
- process-reconcile.mjs: читает маркер и состояние Validate на материале;
идёт — wait, завершился/пропал без продолжения — retry; без маркера — прежний
escalate. Общий loadSealedArtifact, экспорт processRuns/artifactNames.
- preflight сверяет process-resume.yml между main и dev наравне с process.yml.
- Тесты: validate-gate (4), process-resume (8, включая контракт трёх workflow),
process-reconcile (2); мутанты gate-no-wait-still-sleeps,
resume-wakes-round-without-marker, resume-ignores-active-run,
reconcile-wakes-pending-while-validate-active. PROCESS.md §10.4, AGENTS.md.
Issue: #636
User-Visible: no
Шард 2/4 прогона 35565222849 снят по timeout-minutes: реестр вырос до 810
мутантов (~203 на шард), длительность за 11 дней 42 → 61 мин при потолке 60.
Отчёт назвал его «ok»: лог без строк FAIL считался зелёным, а обрыв по
таймауту строк FAIL не содержит. Агрегатор проверял identity, но не
завершённость — evidence шага `if: always()` было на месте.
- mutation-gate.yml: matrix из шести шардов, `--shard=i/6`, `--shards=6`;
шаг прогона получил id, его `outcome` пишется в evidence.
- mutation-gate-report.mjs: шард `ok` только с итоговой строкой
`поймано N из M`, N = M, без FAIL и с исходом шага `success`; лог без
итога или исход `cancelled`/`skipped` — `interrupted`, отказ; агрегатор
отвергает прерванный шард как неполный. `outcome` в evidence необязателен
ради старых артефактов, но, если назван, обязан быть из известного набора.
- тесты: обрыв → interrupted, исходы шага, evidence с outcome; делитель
шардов один во всех местах workflow; фикстуры зелёных логов получили итог.
- мутанты: mutation-report-truncated-log-is-ok,
mutation-evidence-ignores-cancelled-step.
- docs/TESTING.md: шесть шардов, итоговая строка.
Потолок 60 минут остаётся стражем от зависшего Chromium. Ledger в ночном
прогоне не включён: ночь гоняет всё.
Issue: #604
User-Visible: no
`mutantsRequested` отвечает true лишь на PR и `workflow_dispatch mutants=true`
(конвейер ревью, слияние кандидата). Трейлер `Release:` и `full=true` включают
тяжёлые гейты — смоки, golden, performance_smoke — но не мутантов: к бете каждая
задача прогнана ими на ревью и на слитом после ребейза кандидате, ночь покрыта
полным реестром (mutation-gate.yml, #513), а ручной полный прогон ради
артефакта эталонов и приёмка эталонов с трейлером на ветке задачи платили
шестью job впустую. `schedule` мутантов тоже не запрашивает.
Политика release в ci-proof — `mutants: false`: иначе proof кандидата беты
без запрошенных mutant-jobs объявлялся бы stale. review и merge по-прежнему
требуют шесть исполненных job (#541).
Тесты: #510 AC1 переписан под новый список, ci-proof — release без мутантов
green, лёгкий stale, review/merge без запроса stale. Мутанты протокола:
`mutants-run-on-every-push` перепривязан, новые `mutants-run-on-beta-candidate`,
`mutants-run-on-full-dispatch`, `release-proof-demands-mutant-jobs`.
PROCESS.md §10.4, AGENTS.md, docs/TESTING.md, комментарии workflow.
Issue: #601
User-Visible: no
Приёмка эталонов на beta.3 (`ad4000f9`) стоила второго полного Validate —
22 минуты, из них 17–22 на шард мутантов. Причина одна: корпус отпечатка
(`source-fingerprint.mjs`) называет `demo/golden` строкой-каталогом, а
замыкание входов раскрывало каталог во все текстовые файлы под ним, включая
`baselines-index.json`. Индекс становился входом smoke, performance_smoke и
каждого гарда через `serve.mjs`: на реальной паре C→B ключи smoke/perf были
DIFFERENT, отпечатки 181 из 183 браузерных свидетелей менялись, журнал их не
пропускал.
- `check-inputs.mjs`: `BASELINE_OVERLAY` — раскрытие каталога не выдаёт
overlay; явный корень golden и явная ссылка на файл — как были. На паре
C→B: ключи smoke/perf/parity/backend same, golden DIFFERENT; отпечатки
743 из 744 равны; план мутантов B с журналом C — 0–1 на шард вместо 38–44
- `ci-proof.mjs`: составное evidence — product tree без overlay, overlay
(tree, sha256 индекса, run из `Baseline-Reviewed`), content-ключи всех
реюзных job (исполненных тоже); `evaluateCiProof({expected, reviewedRun})`
сверяет с локальным расчётом, fail-closed на ключ, tree, индекс, reviewed
run, маркер с чужим ключом; proof без evidence при ожиданиях — stale
- `release-gate.mjs` / `release-prerelease.mjs`: ожидания считаются на
checkout кандидата (`candidateExpectations`), чужой checkout — notice
- мутанты: `baseline-overlay-leaks-into-every-key`,
`proof-trusts-evidence-it-could-verify`,
`reused-marker-key-unchecked-against-candidate`,
`product-tree-identity-counts-baselines`; перенацелен
`ci-proof-ignores-run-attempt`
- docs: TESTING (правило overlay), DEVELOPMENT (evidence в release proof),
STATUS
Issue: #573
User-Visible: no
Проверка #479 обязана быть строгой на кандидате беты и на релизном гейте.
Фактически она не была строгой ни разу: preflight сравнивал со строкой
`heavy=true` ВЕСЬ вывод `classify-changes.mjs --heavy`, а вывод двухстрочный —
`heavy=…` и `mutants_requested=…`. В `$(…)` строки схлопываются через пробел,
сравнение не совпадало никогда, режим оставался `warn`.
Видно построчно в логе прогона 35091507839 на кандидате `4c44ef60`:
скриншоты документации: режим warn (heavy=true
WARN screenshot source fingerprint is stale; ...
ok документация
То есть проверка увидела устаревший индекс и пропустила кандидата. Обе беты
после `699ab471` уехали с ним; на чистом checkout того же SHA
`node scripts/check-docs.mjs --strict` падает с ERROR.
Правило, которое из этого следует: формат `$GITHUB_OUTPUT` — построчный
`ключ=значение`, читать его надо по ключу либо не читать вовсе. Где нужен один
ответ, CLI отдаёт один ответ: `--screenshots-mode` печатает `warn` или
`strict`, и в shell не остаётся ни разбора, ни развилки.
Свидетели в `test/classify-changes.test.mjs`: режим по каждому событию, форма
вызова в workflow (сравнение со строкой `heavy=true` не должно вернуться) и
прямая проверка того, что вывод `--heavy` многострочный — то есть целиком
сравнивать его нельзя. Мутант `screenshot-freshness-never-strict` возвращает
прежнее «никогда не strict» и обязан краснеть.
Issue: #586
User-Visible: no
Относительная половина «Полных бенчмарков» сравнивала кандидата с прошлой
вершиной `main`. Для стабильного релиза это давало круг, в котором гейт не
может покраснеть дважды: прогон идёт только на push в `main`, кандидат обязан
там оказаться, и следующий коммит той же линейки берёт базой первый — то есть
линейку саму. На выпуске v1.76.0 это видно построчно: прогон 35097102695 на
`c3d64789` честно показал resizePreview 603 → 981 и panZoom 91 → 205 в скрытой
изометрии, а прогон на `9683a590` был зелёным и был бы зелёным без всякой
правки бюджетов.
Теперь база выбирается по намерению коммита: head несёт трейлер `Release:` без
пре-релизного суффикса — сравниваем с предыдущим стабильным тегом. Бета,
обычный push и ручной `comparison_ref` не меняются.
Решение вынесено из shell в `scripts/performance-baseline.mjs` по тому же
доводу, что и разбор вердикта ревью (#556): отрицательные случаи — тега нет,
тег стоит на самой голове, база перестала быть предком, база старше
HP-PERF-01 — в YAML не прогнать ни одним тестом. Обращения к git инжектируются,
фикстуры описывают дерево. Отказы по-прежнему уводят в сторону БОЛЬШЕГО
сравнения: непригодная база → родитель → последний достижимый релизный тег.
Проверено исполнением на этом репозитории: стабильный кандидат v1.76.0 →
`2c6410bb` (v1.75.0); бета v1.76.0-beta.5 и обычный push → `push before`;
dispatch с `comparison_ref=v1.74.0` → `e63460f0`.
Свидетели: `test/performance-baseline.test.mjs` (10 проверок, включая AC2 —
второй коммит линейки не сравнивается сам с собой) и мутант
`stable-candidate-compares-against-itself`, который возвращает прежнее
поведение и обязан краснеть; проверено подменой руками — AC2 падает, оригинал
проходит.
AC4: других релизных гейтов, судящих о родителя, нет. `validate.yml` берёт
`github.event.before` только для ДИАПАЗОНА файлов, и там база уже заменена
доказанно зелёным предком (#387/#388), а не сырым родителем.
npm test 2731/2730/0 fail, typecheck чистый, check-docs зелёный (кроме
известного отпечатка скриншотов, #586).
Issue: #587
User-Visible: no
Объявленные `permissions:` у `model_review` не были потолком: без переданного
`github_token` claude-code-action меняет OIDC на собственный App-токен, дефолт
которого — contents/issues/pull_requests: write, и `ghs_…` от claude[bot]
оказывался прямо в окружении Bash-инструмента модели. Ревью r1 показало это
живым доказательством в собственной же сессии.
Теперь шагу Review передан ambient `secrets.GITHUB_TOKEN`: обмена не происходит,
`id-token` не нужен, список прав становится настоящим. У модели остаётся ровно
одно право записи — `issues: write` под комментарий вердикта (§7.2) и issue по
§12; записи в репозиторий у неё больше нет.
Issue: #556
User-Visible: no
Три вещи, которые аудит 12.09 назвал в §10.
**Перемещаемые ссылки.** `home-assistant/actions/hassfest@master` и
`hacs/action@main` — это произвольный будущий коммит чужой ветки, а ревьюера с
Read/Write/Bash запускал перемещаемый major `anthropics/claude-code-action@v1`.
Все 116 `uses:` в девяти воркфлоу закреплены полным SHA с комментарием-версией;
`scripts/action-pins.mjs` это проверяет, а предполётный вердикт Validate —
исполняет. Локальная переиспользуемая workflow пина не требует и исключена
явно.
**Права.** Один блок `permissions` на весь конвейер выдавал `issues: write` и
OIDC каждой стадии, включая единственную недоверенную — работу модели. Теперь
права выдаются по job: модели только чтение и OIDC для самой
`claude-code-action`, писать в issue умеют детерминированные стадии.
**Граница.** Разбор запечатанного результата переехал из inline-shell в
`scripts/review-result-gate.mjs` — не ради красоты, а потому что в YAML его
нельзя прогнать ни одним отрицательным случаем. Проверяются те же вещи, что и
раньше, и в том же объёме: точный набор файлов, контрольные суммы, схема
паспорта и совпадение КАЖДОГО из семнадцати полей с тем, что посчитала
детерминированная стадия. Сверху — пятнадцать враждебных фикстур: неполный
набор, лишний файл, подменённое содержимое, чужой run и попытка, устаревший
material_sha и tree, чужие задача, этап, раунд и ветка, вердикт вне словаря,
пустой документ, manifest не о тех файлах, неразбираемый JSON.
Настоящих секретов и привилегированных операций фикстуры не трогают.
Issue: #556
User-Visible: no