Files
orchestrator/docs/work-items/ORCH-060/01-brd.md
claude-bot 365c67f45d
All checks were successful
CI / test (push) Successful in 17s
analyst(ET): auto-commit from analyst run_id=288
2026-06-07 11:28:57 +00:00

6.8 KiB
Raw Blame History

BRD: Reconciler не должен трогать escalated / max-retries задачи

Work Item ID: ORCH-060 Стадия: analysis → architecture Связано: ORCH-053 (reconciler), ORCH-046 (retry-счётчик), ORCH-047 (BLOCKED-вердикт)

1. Контекст и проблема

ORCH-053 ввёл фоновый reconciler (src/reconciler.py) — sweeper, доигрывающий пропущенные webhook-переходы. Слой F-1 (reconcile_gate_once_reconcile_gate_task) для каждой не-терминальной задачи (stage != 'done') без активного job и старше grace делает read-only пред-оценку канонического QG; если гейт зелёный → advance_if_gate_passedadvance_stage(..., finished_agent=None).

Дефект. Задача, исчерпавшая лимит developer-ретраев (_developer_retry_count(task_id) >= MAX_DEVELOPER_RETRIES = 3), escalated — но эскалация в обработчиках Gitea (src/webhooks/gitea.py:280 для CI-failure, :371 для review REQUEST_CHANGES) выполняет ТОЛЬКО notify_error(...):

  • стадия НЕ меняется (остаётся development);
  • терминального маркера в БД нет (нет blocked-флага в таблице tasks);
  • активного job нет.

Для reconciler такая задача неотличима от «застрявшей из-за потерянного webhook». Если CI к этому моменту зелёный (типичный кейс: разработчик починил CI, но reviewer продолжал слать REQUEST_CHANGES → ушли в лимит), F-1 каждые reconcile_interval_s (120 с) видит зелёный check_ci_green и разблокирует задачу development → review. Reviewer снова REQUEST_CHANGES → откат на development → снова эскалация (стадия не меняется). Следующий тик — снова разблокировка. Бесконечный цикл.

Реальный инцидент (наблюдение 0607.06.2026). ET-013 разблокирована reconciler'ом 10 раз за ночь, в итоге всё равно escalated — бесполезный поллинг каждые 2 минуты, лишние запуски агентов (токены, деньги), шум в Telegram (reconcile_notify_unblock), нагрузка на конвейер общего инстанса (self-hosting: один инстанс обслуживает ORCH + enduro-trails).

Симметричный риск: задача, которую человек/агент явно перевёл в Plane-статус Blocked или Needs Input (ручной гейт), не должна автоматически разблокироваться reconciler'ом до вмешательства человека.

2. Бизнес-цель

Reconciler (F-1) обязан пропускать (не трогать) задачи, которые:

  1. исчерпали лимит developer-ретраев (_developer_retry_count >= MAX_DEVELOPER_RETRIES), и/или
  2. находятся в явном «человеческом»/терминальном Plane-статусе Blocked / Needs Input.

Такие задачи ждут ручного вмешательства; автоматический sweeper их игнорирует.

3. Заинтересованные стороны

  • Owner проекта — прекращение «фантомной» активности и шума по escalated-задачам.
  • Другие проекты на инстансе (enduro-trails) — снижение паразитной нагрузки общей очереди.
  • Агенты-разработчики оркестратора — корректная семантика терминального состояния.

4. Объём (Scope)

Входит

  • Гард в F-1 (_reconcile_gate_task / advance_if_gate_passed), который ДО оценки гейта и вызова advance_stage пропускает escalated-задачи (retry-count >= лимит) — детерминированно, без сети.
  • Гард, пропускающий задачи в Plane-статусе Blocked / Needs Input.
  • Тесты (unit) на оба условия + регресс happy-path и отсутствия спама/нотификаций.
  • Обновление документации: docs/architecture/README.md (описание F-1), per-work-item ADR, CHANGELOG.md.

Не входит

  • Изменение порога MAX_DEVELOPER_RETRIES или логики самой эскалации в gitea.py.
  • Изменение F-2 plane-side по существу (F-2 уже реагирует только на in_progress/approved/rejected, то есть Blocked/Needs Input им не доигрываются — достаточно регресс-теста, фиксирующего это поведение).
  • Реестры STAGE_TRANSITIONS / QG_CHECKS, схема прочих стадий.

5. Допущения и ограничения

  • Инвариант reconciler (ORCH-053): схема БД и реестры не меняются. Решение должно либо обойтись без миграции, либо архитектор обязан явно обосновать необходимость нового столбца как терминального маркера.
  • Never-raise: гард не должен ломать тик; любая ошибка вычисления условия → безопасный фоллбэк (не трогать задачу — консервативно).
  • self-hosting: нельзя ронять/рестартить прод-контейнер; изменение — чисто логика sweeper'а, деплой через staging (8501) по канону.
  • Источник истины по retry — agent_runs (как у _developer_retry_count).

6. Критерий успеха (бизнес)

После выката на конкретной escalated-задаче (как ET-013): за ночь — 0 строк reconciler: <wi> ... разблокирована, 0 повторных запусков агентов, 0 Telegram-нотификаций разблокировки; задача спокойно ждёт человека в development/Blocked. При этом штатные «честно застрявшие» задачи (retry < лимита, не Blocked) reconciler по-прежнему доигрывает.