docs: review document for #695

Issue: #695
User-Visible: no
This commit is contained in:
claude[bot]
2026-09-28 20:07:11 +00:00
parent f6c76b7351
commit d8465b3a09
+175
View File
@@ -0,0 +1,175 @@
# CODE-REVIEW #695 r2
Материал: `origin/dev..HEAD`, ровно `f6c76b7351b1d0b9a61954b0153a44bb098bc7f3`
(рабочая копия уже на нём). Диапазон трёх коммитов: `57ce1072` (реализация r1,
уже разобрана в CODE-REVIEW-695-r1), `51854aea` (публикация документа r1,
служебный коммит конвейера), `f6c76b73` (правка Medium из r1 — материал этого
раунда). Дельта этого раунда — ровно `57ce1072..f6c76b73`:
`.github/workflows/_process.yml`, `scripts/mutation-registry.mjs`,
`scripts/task-packet.mjs`, `test/review-doc-guard.test.mjs`,
`test/task-packet.test.mjs`.
## Скоуп
Единственная блокирующая находка r1 (Medium, в скоупе) — канон §5.1
(«инфраструктурная задача (§1) без трековой метки — как `track:show`») не
был реализован ни в `_process.yml` (лимит циклов), ни в `task-packet.mjs`
(отображаемый трек). Автор заявляет это закрытым коммитом `f6c76b73`
(комментарий «Сделано (r1)»). Разбор по PROCESS.md §2.10 — по дельте: полный
пересчёт находки r1, остальное (таблица треков §5, `trackFromLabels()` для
явно помеченных задач, якоря конспектов, трейлеры) унаследовано без повтора —
дельта их не задевает (ни один из пяти изменённых файлов не входит в
доказательную базу этих пунктов r1, кроме `task-packet.mjs`, где тронута
только инфраструктурная ветвь `track`, разобранная ниже).
## Как проверялось
| Гейт | Команда | Результат |
|---|---|---|
| Validate на материале | CI run на `f6c76b73` (ссылка в задаче ревью) | зелёный; дешёвые гейты (`tsc`, `npm test`, `build`+`bundle-policy`) не перегонял — приняты по этой ссылке (#343) |
| Целевой юнит-набор | `node --test test/task-packet.test.mjs test/review-doc-guard.test.mjs` | 80/80 и 64/64 pass, 0 fail |
| `process-gate.mjs` (офлайн) | `node scripts/process-gate.mjs --range origin/dev..HEAD` | «гейт пройден, предупреждений 0» |
| `mutation-gate --check` | `node scripts/mutation-gate.mjs --check` | `guard-infra-keeps-ask-limit` — ok; `packet-infra-track-ignores-show-default` — ok; `browser guards: 200/200`; 3 предупреждения — все про `#650` (baseline, не связаны с диффом — совпадают с r1) |
| Мутант `guard-infra-keeps-ask-limit` | вручную заменил `limit=2` на `limit=4 # mutant` в `_process.yml`, прогнал `--test-name-pattern="r1 #695" test/review-doc-guard.test.mjs`, вернул файл (`git diff --stat` после — пусто) | **краснеет**: `AssertionError`, тест ловит мутацию |
| Мутант `packet-infra-track-ignores-show-default` | вручную заменил тернарник `hasTrackLabel(labels) ? trackFromLabels(labels) : 'show'` на `trackFromLabels(labels)` в `task-packet.mjs`, прогнал `--test-name-pattern="r1 #695" test/task-packet.test.mjs`, вернул файл | **краснеет**: `AssertionError: expected 'инфраструктурный · show', actual 'инфраструктурный · ask'` |
| Исполнение bash-ветки guard (не только чтение) | Извлёк новый блок `.github/workflows/_process.yml:224-242` в отдельный скрипт с mock `gh`/`has`, прогнал 6 сценариев (нет меток+только инфра-файлы; нет меток+файл класса A; явный `track:ask`; явный `track:show`; отказ `gh api`; legacy `small`) | все 6 дали ожидаемый `limit` — см. таблицу «Что проверено» |
| Синтаксис bash-шага | `python3 -c "yaml.safe_load(...)"` извлёк `run:` строку `guard`, `bash -n` на неё | синтаксис корректен |
| Node-однострочник guard | Прогнал ровно ту же `node --input-type=module -e '...'` строку на трёх наборах путей (только `scripts/`+`test/`; с `src/houseplan-card.ts`; пустой список) | exit 0 / 1 / 1 — соответствует логике «инфраструктура доказана только непустым списком путей без класса A» |
| `smoke-select.mjs` | `node scripts/smoke-select.mjs --base 57ce1072 --head f6c76b73` | «Исполняемого frontend-диффа нет (src/**/*.ts не тронут)» — смоки не выбираются, выбирать нечего |
| Трейлеры и провенанс коммита | `git show -s --format=full f6c76b73` | `Issue: #695`, `User-Visible: no`, корректно: изменение автоматизации/скриптов, ни одного пользовательского поведения продукта не задето |
| Сверка со сформированным пакетом | `node scripts/task-packet.mjs --issue 695` | трек issue #695 (само помечено `track:show` владельцем) печатается как `инфраструктурный · show` — согласуется с явной меткой |
Не прогонял (и почему): golden/скриншоты, браузерные смоки (подтверждено
`smoke-select.mjs` — нечего выбирать), `pytest tests_backend`, инварианты
модели, `check-docs.mjs` (диапазон не касается `src/**`), performance-профили —
диапазон не затрагивает ни одного файла класса A и не меняет геометрию/рендер.
Полный `npm test` (3223 теста) не перегонял целиком — принят по зелёному
Validate на этом SHA (#343); перегонял точечно только изменённые тестовые
файлы и мутации по ним, плюс собственноручный харнесс исполнения bash-ветки
(таблица выше) — этого требует #454 (inline-shell без исполнения не
доказывает поведение), выполнено сверх минимума, а не вместо него.
## Закрытие раунда r1
| Находка r1 | Чем закрыта | Где это видно |
|---|---|---|
| Medium: §5.1 («инфраструктура без трековой метки — `track:show`») не реализован ни в `_process.yml` (лимит циклов), ни в `task-packet.mjs` (отображаемый трек); зелёный тест `task-packet.test.mjs:171` прямо утверждал старое поведение | `_process.yml`: новая ветка `guard` (строки 224-242) — при отсутствии `track:*`/`small`/`trivial` берёт диффа ветки против `dev` через `compare` API, классифицирует пути `classify()` из `process-gate.mjs`; при непустом списке (< 300, потолок ответа) без единого файла класса A ставит `limit=2`. `task-packet.mjs`: `infraTrack = hasTrackLabel(labels) ? trackFromLabels(labels) : 'show'` (строка 189), трек инфраструктурной задачи теперь печатается как `` инфраструктурный · ${infraTrack} `` вместо голого `'инфраструктурный'`. Тест `task-packet.test.mjs:171` (`#632`), на который указывала находка, переписан: `assert.equal(packet.track, 'инфраструктурный · show', ...)` — прежнее ожидание `'инфраструктурный'` больше не в коде. | `.github/workflows/_process.yml:224-242`; `scripts/task-packet.mjs:143-144,189-191`; `test/task-packet.test.mjs:110,180,231-241`; `test/review-doc-guard.test.mjs:971-982`; оба новых мутанта (`scripts/mutation-registry.mjs`) реально ловят регресс — проверено воспроизведением (таблица «Как проверялось»), не по названию. Исполнение bash-ветки (6 сценариев харнессом) подтверждает: без метки трека и без класса A → `limit=2`; с любой явной меткой трека → блок не трогает `limit`; при отказе `gh api` или файле класса A → `limit` остаётся консервативным (не понижается ошибочно). |
Находка полностью закрыта: и механизм (§1: «ни одного файла класса A» —
ровно та же формула, что в PROCESS.md §1), и обе точки, которые r1 назвал
нереализованными, и тест, который r1 предъявил как доказательство обратного
поведения, — всё сходится с текстом §5.1 дословно («инфраструктурная задача
(§1) без трековой метки — как `track:show`»).
## Унаследовано из r1 (без повторной проверки — дельта не задевает)
- **Таблица треков §5 и её колонки**, согласованность PROCESS.md / AGENTS.md /
`docs/process/AUTHOR.md` / `docs/process/REVIEWER.md` — документ
`CODE-REVIEW-695-r1.md`, дерево `2faf4770f1ba6a32a599552db9c611bfb5cc5a18`.
Ни один из этих четырёх файлов не входит в дельту `57ce1072..f6c76b73`.
- **`trackFromLabels()` для явно помеченных задач** (`track:ship` /
`track:show` / `track:ask` / legacy `trivial`/`small` / без меток → `ask`),
приоритет меток, лимит циклов для явно помеченных `track:show`/`track:ship`/
`track:ask` в `_process.yml:87-99` — там же, дерево `2faf4770f1ba6a3...`.
Дельта r2 добавляет только новую ветку ПОСЛЕ этой логики (строки 224-242) и
не меняет ни один из проверенных r1 путей; сама функция `trackFromLabels`
в дельте не тронута (diff `scripts/task-packet.mjs` добавляет только
`hasTrackLabel` и меняет строку сборки `track`, не трогая тело
`trackFromLabels`).
- **Якоря конспектов (AC2 #634), ключевые формулировки, обратная
совместимость легаси-меток `small`/`trivial`, трейлеры провенанса,
отсутствие продуктового кода в диффе** — там же, дерево
`2faf4770f1ba6a3...`; ни один из файлов этой доказательной базы
(`PROCESS.md`, `AUTHOR.md`, `REVIEWER.md`, `test/process-digests.test.mjs`)
не входит в дельту r2.
## Что проверено и корректно
- **Механический признак §1 применён идентично канону**: и в `_process.yml`
(список файлов диффа `dev...branch`, ни одного `classify() === 'A'`), и в
`PROCESS.md` §1 («ни одного файла класса A») — то же условие, что уже
реализовано в `branchIsInfrastructure()` (`task-packet.mjs`, не тронут
этим диффом) и в самом `process-gate.mjs`. Никакого нового, отличного от
канона определения «инфраструктуры» дифф не вводит.
- **Приоритет явной метки владельца сохранён**: guard пропускает новую ветку
целиком (`&& ! has track:ship && ! has track:show && ! has track:ask && !
has small && ! has trivial`), если стоит любая из пяти меток — идентичный
набор в JS (`hasTrackLabel`). Подтверждено исполнением (харнесс, сценарии
3, 4, 6) и юнит-тестом `'метка владельца главнее'`.
- **Fail-safe при неполном доказательстве**: пустой список файлов, отказ
`gh api`, наличие файла класса A или обрезанный (≥300) ответ compare — во
всех случаях `limit` остаётся 4 (не понижается ошибочно), задача не
наказывается лимитом 2 без доказанной инфраструктуры. Подтверждено
исполнением (харнесс, сценарии 2, 5) и отдельным прогоном
node-однострочника на пустом списке.
- **Мутанты `guard-infra-keeps-ask-limit` и
`packet-infra-track-ignores-show-default`** реально ловят регресс —
проверено ручным воспроизведением обеих мутаций (не по названию `ok` в
`mutation-gate --check`, а прогоном упавшего теста).
- **Синтаксис нового bash-блока и YAML-документа** — `bash -n` и
`yaml.safe_load` не нашли ошибок; блок стоит внутри уже существующего
`if [ -n "$stage" ]`, использует уже установленное `limit` до последующих
проверок `EXHAUSTED`/`spent -ge limit` (строки 270-299) — порядок
вычисления корректен, «состояния гонки» с более поздним использованием
`limit` нет.
- **Трейлеры коммита** — `Issue: #695`, `User-Visible: no` (корректно: не
задето ни одно пользовательское поведение продукта), ветка
`issue/695-track-labels`.
- **Согласованность с самим issue #695**: у issue стоит метка `track:show` —
собранный пакет (`task-packet.mjs --issue 695`) печатает
`инфраструктурный · show`, то есть явная метка отражена корректно и
задокументированный пример (issue #695 сам себе) воспроизводится.
## Чего не проверял
- **Живой прогон `_process.yml` guard job** на реальном GitHub Actions
раннере с настоящим `gh api compare` — не воспроизводил; логика проверена
чтением синтаксиса, ручным bash-харнессом с мок-`gh`/`has` (6 сценариев,
см. таблицу) и юнит-тестом на текст блока. **Записываю явно: для самого
факта исполнения на реальном GitHub API — проверено чтением и
контролируемым харнессом, не живым запуском workflow.** Это не новый
пробел этой задачи — тот же пробел зафиксирован в r1 для всей ветки guard
job (тестов, исполняющих `_process.yml` напрямую, в репозитории нет ни для
старой, ни для новой логики).
- **Поведение конвейера по треку** (мутанты на диффе кандидата `ship`,
слияние без ревью модели, ребейз-семантика) — вне скоупа #695, это #696,
не проверял.
- **`process-labels/labels.tsv`** (папка владельца, вне git-дерева) — файл
недоступен ревью, как и в r1.
- **golden/скриншоты, браузерные смоки** (кроме факта, что `smoke-select.mjs`
ничего не выбрал), `pytest tests_backend`, инварианты модели,
performance-профили — диапазон не касается визуала, геометрии или Python.
- **Ребейз-устойчивость якорей мутантов** `guard-infra-keeps-ask-limit` /
`packet-infra-track-ignores-show-default` на дальнейших ребейзах — не
тестировал долгосрочную устойчивость find/replace патчей, только их
текущую верность материалу.
## Вердикт
Единственная находка r1 (Medium, в скоупе) закрыта построчно: оба места,
которые она называла нереализованными, реализованы правилом, дословно
совпадающим с §5.1; тест, который r1 предъявил как живое доказательство
старого поведения, переписан и подтверждает новое; оба новых мутанта реально
ловят регресс — проверено воспроизведением, а не по имени `ok`; сама bash-
ветка проверена не только чтением, но и контролируемым исполнением на шести
сценариях. Новых находок дельта `57ce1072..f6c76b73` не даёт: правка узкая,
ограничена ровно заявленным скоупом, не трогает ни один файл класса A, не
меняет ни одну ранее проверенную ветвь `trackFromLabels`/таблицы §5.
Вердикт: зелёный · заход r2 · блокирующих циклов 1/4 · High: 0 · Medium: 0
---
---
<!-- material-anchors: сгенерировано конвейером (#414) -->
## Материал раунда
- Ветка: `issue/695-track-labels`, коммит `f6c76b7351b1` — ребейз его осиротит, и это нормально: ниже якоря, которые ребейз не меняет.
- Дерево материала: `2645a194ffcd661ca9d05eb38db68d9e378faae9`
```
git log --all --format='%H %T' | grep 2645a194ffcd
```
- Тело issue: `c74209278f8dd164514eda40d8841d6eefdeffd3b490a90f47b20e3ff2b667e7`
- Вердикт конвейера: `green` · High 0