6.2 KiB
6.2 KiB
type, work_item_id, verdict, version
| type | work_item_id | verdict | version |
|---|---|---|---|
| review | ORCH-053 | APPROVED | 1 |
Review ORCH-053 — Sweeper потерянных webhook (реконсиляция застрявших стадий)
Summary
PR реализует фоновый reconciler застрявших стадий ровно в объёме ТЗ (02-trz.md) и
ADR (06-adr/ADR-001, глобальный adr-0007). Все 17 acceptance-criteria покрыты
кодом и тестами; полный прогон pytest — 563 passed. Реализация строго следует
ключевым инвариантам: продвижение только через неизменный advance_stage(..., finished_agent=None), никакой дублирующей advance/rollback-логики в reconciler.py,
структурная невозможность спама нотификаций, never-raise на единицу работы,
restart-safe daemon-поток, kill-switch'и. Схема БД и реестры STAGE_TRANSITIONS /
QG_CHECKS не тронуты. Документация обновлена в этом же PR. Рекомендация: APPROVED.
Соответствие ТЗ
src/reconciler.py(НОВЫЙ): F-1reconcile_gate_once+ F-2reconcile_plane_once, классReconciler+ module-singleton по образцуqueue_worker. ✓src/config.py: все 6reconcile_*настроек с дефолтами по таблице §5. ✓src/main.py: старт послеworker.start(), стоп передworker.stop(), блокreconcileвGET /queue. ✓src/stage_engine.py: тонкийadvance_if_gate_passed— read-only пред-оценка гейта, advance только черезadvance_stage, на красном гейтеadvance_stageне вызывается вовсе (подавление спама без изменения общего критпути). ✓src/plane_sync.py:list_issues_by_stateс курсорной пагинацией и never-raise →[]. ✓src/webhooks/gitea.py: F-3 БД-fallbacksha→branch(_resolve_branch_via_db), однозначность обязательна,debug→info. ✓src/webhooks/plane.py+src/db.py: F-2 переиспользуетhandle_status_start/handle_verdictбез дублирования; анти-дубльcreate_task_atomicпод process-wide Lock,start_pipelineрефакторен на atomic-claim первым DB-действием. ✓- Схема БД и реестры не менялись (§6/§8 ТЗ). ✓
Соответствие ADR
- §2 (источник истины — гейт; продвижение только через
advance_stage): соблюдено — вreconciler.pyнет собственногоupdate_task_stage/enqueue_jobдля advance (AC-2). - §3 (async-обработчики из sync-потока через
asyncio.run): реализовано в_dispatch. - §4 (atomic-claim под
threading.Lock, без миграции):db.create_task_atomic. - §6 (F-1 не трогает
analysis): ранний возврат вadvance_if_gate_passedи в_reconcile_gate_task(AC-16). - §7 (grace «потерян, а не задержан»): F-1 по
tasks.updated_at(SQLage_s), F-2 поissue.updated_at(_age_seconds_iso). - Нарушений глобальных ADR нет;
adr-0007заведён и внесён вdocs/architecture/adr/README.md.
Качество кода
- Контракт never-raise выдержан на всех уровнях: outer loop, per-task, per-project, per-issue,
_parse_grace_overrides,list_issues_by_state,_resolve_branch_via_db, телеграм-нотификация. - Идемпотентность: active-job guard в F-1 и F-2; самозатухание через обновление
updated_atпосле advance;max_concurrency=1. Подтверждено анализом — F-2 на approved/rejected всегда меняет состояние (analysis approved-via-status всегда проходит; rollback всегда срабатывает), поэтому петли спама нотификаций структурно не возникает. - Защита от ложного матча в F-3 (только при единственной development-задаче repo).
- Docstrings содержательные на всех публичных функциях; тесты не тривиальные (мапятся на
TC-01…TC-21 из
04-test-plan.yaml).
Документация
Обновлена в этом же PR (AC-17 выполнен):
docs/architecture/README.md— компонент Reconciler, раздел resilience, строка в таблице API (/queue… + reconcile), footer-пометка. ✓docs/work-items/ORCH-053/06-adr/ADR-001-stuck-task-reconciler.md— заведён. ✓docs/architecture/adr/adr-0007-reconciler.md+ строка вadr/README.md. ✓CHANGELOG.md— запись в[Unreleased]/Added. ✓docs/operations/INFRA.md— kill-switch'и и env-карта (self-hosting). ✓README.mdи.env.example— env-таблицаORCH_RECONCILE_*. ✓
Findings
P0 — Blocker
- Нет.
P1 — Must fix
- Нет.
P2 — Should fix
- Нет.
P3 — Nice-to-have
- Несоответствие статуса ADR:
06-adr/ADR-001помеченСтатус: Proposed, тогда какdocs/architecture/adr/README.mdуказываетadr-0007какaccepted. Косметика — привести к одному значению при следующем касании. get_project_states(pid)теоретически может вернуть словарь без ключейapproved/rejectedпри частичном резолве состояний проекта →KeyErrorв_reconcile_plane_project. Сейчас изолировано per-projecttry/except(never-raise держится, эффект — пропуск F-2 для проекта). Можно усилить.get(...)-доступом ради явности; не блокер.