- CLAUDE.md: 97->63 lines, drop dev-commands and Don't duplicates already covered by .claude/rules/* - git-pr.md, deploy.md: replace gh CLI with Forgejo MCP/curl - code-reviewer.md: fix mcp__postgres__ -> mcp__postgres-gendesign__ - tech-analyst.md: sonnet -> haiku - deep-code-reviewer.md: 391->135 lines, phase details split into .claude/agents/deep-review-phases/ (loaded on demand) - qa-tester, code-reviewer, deep-code-reviewer: add memory: project - ui-ux.md: split into ui-tokens/ui-conventions/ui-microcopy - scripts/claude-hooks/check-no-print.py + PostToolUse hook - .gitignore: explicit list (git whitelist limitation)
6.2 KiB
6.2 KiB
Deep Review — Phase 5: Verdict + merge
Supporting reference. Verdict шаблон + auto-merge policy.
Verdict format (строго)
## 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 (🔴) — обязательные триггеры
- Hardcoded secret / token / password в commit (даже test files)
- SQL injection vector
- Auth bypass на admin endpoint
- Migration без rollback plan (если меняет / удаляет данные)
- Breaking API change без deprecation / migration path
- Удаление prod данных без явного approval
--no-verify/--force/--amendв недавних коммитах ветки- Прямой push в main (HEAD == main, не feature branch)
ALTER TABLE ... NOT NULL DEFAULTна таблице >1M rows без batched backfillCREATE INDEX(не CONCURRENTLY) на prod таблице >1M rowsDROP COLUMN/DROP TABLEбез 2-stage rollout- Celery task без idempotency маркера (вернёт дубли при retry)
- 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 (все обязательны)
curl -sH "$H" "$REPO/pulls/<N>" | jq '{state,mergeable,draft,head:.head.sha}'→state=open(не уже merged),mergeable=true(no conflicts),draft=false- Head SHA не изменился после твоего review (нет fixup push'ей с момента scan'а файлов)
- CI status passing — Forgejo Actions UI или
curl -sH "$H" "$REPO/commits/<sha>/status"
Merge команда (Forgejo)
# Через 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/ что 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 нужен