# Deep Review — Phase 5: Verdict + merge

> Supporting reference. Verdict шаблон + auto-merge policy.

## Verdict format (строго)

```markdown
## Deep Code Review — verdict

### Summary
- **Status**: ✅ APPROVE / ⚠️ MINOR / 🟡 MEDIUM / 🟠 HIGH / 🔴 BLOCK
- **Files reviewed**: N (P0: a, P1: b, P2: c, P3: d)
- **Lines**: +X / -Y
- **Time spent**: ~M min
- **PR**: #N (если есть)

### 🔴 Critical (BLOCK push/merge)
- [ ] `path/file.py:42` — описание + конкретный fix (code snippet)
- [ ] `data/sql/95_foo.sql:12` — `ALTER TABLE ... NOT NULL DEFAULT 0` на 50M rows заблокирует таблицу. Split: ADD NULL → backfill batched → SET NOT NULL отдельным PR

### 🟠 High (должен быть пофиксен до merge)
- [ ] `path/file.ts:84` — race condition: state update в onSettled() при unmounted component
- [ ] `backend/app/api/v1/parcels.py:201` — N+1: цикл с `await db.execute(...)`, переделать на `IN (:ids)`

### 🟡 Medium (желательно fix, но не блокирующее)
- [ ] `file.py:120` — `except Exception: pass` swallow'ит ошибки

### 🟢 Low / nits (можно отдельным PR)
- [ ] `file.py:50` — naming `data` слишком generic, `parcels_by_district`

### Cross-file impact analysis
- `backend/app/services/site_finder/foo.py` изменил signature `find_parcels()` →
  callers обновлены: `api/v1/parcels.py:88` ✅, но `tasks.py:142` всё ещё передаёт старый kwarg ❌
- `frontend/src/types/site-finder.ts` regen нужен — `npm run codegen` не запущен в этом PR

### Vault cross-check
- Похожий fix был в `fixes/Bug_Worker_Ready_EarlyReturn.md` — паттерн использован корректно ✅
- Decision `decisions/2026-05-12-no-mutable-defaults.md` — этот PR не нарушает
- Если bug fix, но нет entry в `fixes/` → ⚠️ нужна docs (medium severity)

### Performance findings
- `EXPLAIN ANALYZE` на новом query `parcels.find_by_district`:
  - Seq Scan на `rosreestr_parcels` (5.2M rows) — нужен index `(district_id, status)`
  - Estimated cost 12.4k → с индексом 0.8

### Positive observations
- ✅ `ON CONFLICT DO UPDATE` использован корректно в bulk_upsert
- ✅ `CREATE INDEX CONCURRENTLY` в миграции

### Recommended next steps
1. Worker (backend-engineer): fix 🔴 #1 + 🟠 #1, push fixup commit
2. После fixup: run `npm run codegen` в frontend
3. Перед merge: проверить EXPLAIN на проде через MCP postgres
4. Создать vault entry `fixes/<this-bug>.md`

### Сomplexity / blast radius score
- **Risk**: Low / Medium / High / Critical
- **Reversibility**: Easy revert / DB migration needs manual rollback / Data loss on revert
- **Recommended merge window**: anytime / business hours only / pre-deploy freeze
```

## Когда BLOCK (🔴) — обязательные триггеры

1. Hardcoded secret / token / password в commit (даже test files)
2. SQL injection vector
3. Auth bypass на admin endpoint
4. Migration без rollback plan (если меняет / удаляет данные)
5. Breaking API change без deprecation / migration path
6. Удаление prod данных без явного approval
7. `--no-verify` / `--force` / `--amend` в недавних коммитах ветки
8. **Прямой push в main** (HEAD == main, не feature branch)
9. `ALTER TABLE ... NOT NULL DEFAULT` на таблице >1M rows без batched backfill
10. `CREATE INDEX` (не CONCURRENTLY) на prod таблице >1M rows
11. `DROP COLUMN` / `DROP TABLE` без 2-stage rollout
12. Celery task без idempotency маркера (вернёт дубли при retry)
13. Scraper без dedup ключа в `ON CONFLICT`

## Когда APPROVE (✅)

- Нет critical / high issues
- Cross-file impact проверен — все callers consistent
- Conventions OK (psycopg v3, httpx, ruff, TS strict)
- Backward compat сохранён
- Performance не регрессирует (или регрессия документирована и acceptable)
- Vault entry создана для нетривиальных fixes / decisions
- Tests есть для новой бизнес-логики (если applicable per scope)
- Pre-flight: на feature branch, нет force / no-verify в истории

## Auto-merge policy (PR review mode)

При review открытых Forgejo PR — если verdict **✅ APPROVE** (нет 🔴/🟠/🟡):
**мержи сам, любой scope** (user override 2026-05-16: «после аппрув в ревью можешь мерджить все что угодно»).

### Pre-merge checks (все обязательны)

1. `curl -sH "$H" "$REPO/pulls/<N>" | jq '{state,mergeable,draft,head:.head.sha}'`
   → `state=open` (не уже merged), `mergeable=true` (no conflicts), `draft=false`
2. Head SHA не изменился после твоего review (нет fixup push'ей с момента scan'а файлов)
3. CI status passing — Forgejo Actions UI или `curl -sH "$H" "$REPO/commits/<sha>/status"`

### Merge команда (Forgejo)

```bash
# Через MCP (preferred):
mcp__forgejo__merge_pull_request  (Do=squash, delete_branch_after_merge=true)

# Или curl:
curl -sH "$H" -H "Content-Type: application/json" \
  -X POST "$REPO/pulls/<N>/merge" \
  -d '{"Do":"squash","delete_branch_after_merge":true}'

# Post-merge confirmation comment:
curl -sH "$H" -H "Content-Type: application/json" \
  -X POST "$REPO/issues/<N>/comments" \
  -d '{"body":"Merged via deep-code-reviewer — verdict ✅ APPROVE."}'
```

Forgejo API возвращает пустой body при успехе merge → verify через GET pulls/<N> что `state == merged`.

### Когда НЕ мержить даже при APPROVE

- `mergeable=false` (conflicts) → comment "approved but has conflicts — rebase needed"
- CI failing → comment "approved but CI red — wait for green"
- Draft PR → comment "approved, ready when undrafted"
- Head SHA changed после твоего scan'а → НЕ мержь stale verdict, re-review нужен
