infra: idempotent review controller, verdict reuse, single mutant build, current docs

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
This commit is contained in:
Claude
2026-09-09 00:06:27 +03:00
parent ea6061e9fa
commit 24c1b723f9
14 changed files with 344 additions and 48 deletions
+5 -4
View File
@@ -259,7 +259,7 @@ export function initialViewCeilingViolation(bytes, {
over: bytes - ceiling,
text: `initial View graph ${bytes} B gzip выше потолка ${ceiling} B на ${bytes - ceiling} B.`
+ ' Поднимите потолок в этом же коммите, объяснив рост, либо вынесите код в ленивый'
+ ' граф (#367). Молча расти этому графу больше нечем.',
+ ' граф (история: #367 → #474). Молча расти этому графу больше нечем.',
};
}
if (bytes < ceiling - band) {
@@ -268,7 +268,7 @@ export function initialViewCeilingViolation(bytes, {
under: ceiling - bytes,
text: `initial View graph ${bytes} B gzip ниже потолка ${ceiling} B на ${ceiling - bytes} B`
+ ` — больше полосы ${band} B. Опустите потолок: незафиксированный выигрыш граф`
+ ' отыграет обратно, и это уже происходило (#367).',
+ ' отыграет обратно, и это уже происходило (#367, закрыт).',
};
}
return null;
@@ -290,10 +290,11 @@ export function lowHeadroomWarning(headroom, {
? ` Признание долга покрывает потолок до ${acknowledgedCeiling} Б, а он уже ${ceiling} Б —`
+ ' граф вырос с тех пор, вопрос вернулся.'
: ' Погасить можно решением владельца: LOW_HEADROOM_ACKNOWLEDGED_CEILING в'
+ ' scripts/bundle-budget.mjs. Пока не погашено — это долг (#367).';
+ ' scripts/bundle-budget.mjs. Живого issue у долга нет: #367 закрыт рекалибровкой,'
+ ' его рычаг сделан в #474 (#499) — следующий рост заводит новый.';
return `запас бюджета ${headroom} Б, меньше порога ${threshold} Б:`
+ ' следующая средняя фича упрётся в стену. Рекалибровка это не лечит —'
+ ' смотрите ленивые графы (#367).' + stale;
+ ' смотрите ленивые графы (история: #367 → #474).' + stale;
}
export function assertBundleBudget(