Files
orchestrator/docs/work-items/ORCH-026/01-brd.md

11 KiB
Raw Permalink Blame History

01-BRD — Управление зависимостями задач (B ждёт A) в очереди

Work Item: ORCH-026 Repo: orchestrator (self-hosting) Branch: feature/ORCH-026-b-a Стадия: analysis Источник: предложение Стрим, одобрено Славой (2026-06-04); дополнение Слава+Стрим 2026-06-08 (инцидент эрозии main)


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

1.1 Первопричина (мотивация СЕЙЧАС — инцидент 08.06)

Эрозия main 08.06 (потеря кода ORCH-067/069, фантом-merge) родилась НЕ из логических зависимостей, а из некоординированного параллелизма: несколько self-hosting задач (ORCH-067/069/071) одновременно срезали ветки от main и правили общие файлы (CHANGELOG.md, notifications.py, config.py). Последствия:

  • CHANGELOG-конфликты на auto_rebase → откаты deploy-staging → development (дорого: ORCH-069 = 3 попытки = $3.98);
  • тихое затирание кода соседа при merge ветки, срезанной от устаревшего main (фантом).

ORCH-073 закрыл ПОСЛЕДСТВИЯ (3 рубежа: CHANGELOG merge=union + SHA-in-main verify + регресс-гард маркеров). ORCH-026 должен закрыть ПЕРВОПРИЧИНУ: задачи одного репо не должны мешать друг другу в main.

1.2 Исходный скоуп (плоская очередь ORCH-1)

Очередь (src/queue_worker.py, ORCH-1) — плоская: jobs упорядочены по id (FIFO), гейтятся только available_at и max_concurrency. Нельзя выразить «задача B не стартует, пока не готова A». Декомпозиция эпиков (ORCH-025) порождает заведомо зависимые подзадачи.

1.3 Что уже есть (опора, НЕ переписывать)

  • ORCH-1 — персистентная очередь (jobs), atomic claim, available_at-defer, restart-safe.
  • ORCH-065merge-lease (src/merge_gate.py): per-repo файловый лиз .merge-lease-<repo>.json, неблокирующий acquire, holder-aware release, проактивный реклейм мёртвого/устаревшего держателя. Сейчас лиз держится только на ребре deploy-staging → deploy (от merge-gate до фактического merge).
  • ORCH-043 — merge-gate: branch_is_behind_main, auto_rebase_onto_main (rebase только когда ветка отстаёт или при конфликте), retest_branch.
  • ORCH-073 — merge-verify: verify_merged_to_main (SHA-in-main), check_main_regression.
  • Plane-статусы Blocked / Needs Input + set_issue_blocked (src/plane_sync.py).
  • Telegram live-tracker (src/notifications.py) — одна карточка на задачу, уже умеет показывать статус Blocked.

2. Цель (бизнес-результат)

Задачи одного репозитория перестают повреждать main друг друга, а очередь умеет выражать логические зависимости между задачами — БЕЗ потери параллелизма между разными репозиториями и без риска для self-hosting прода.


3. Два уровня требований (объединить в одной задаче; приоритет — Уровень A)

Уровень A — Сериализация merge/деплоя внутри ОДНОГО репо (КРИТИЧНО, корень эрозии)

Закрывает первопричину инцидента 08.06.

  • A-1. В рамках ОДНОГО репо merge-в-main + деплой должны быть сериализованы: пока задача A не слита в main (и для self-hosting — не задеплоена), задача B того же репо НЕ доходит до своего merge/деплоя от устаревшего main.
  • A-2. B перед своим merge-gate обязана ребейзнуться на СВЕЖИЙ main (где уже есть A) — proactive pre-merge rebase, а не только при текстовом конфликте (как сейчас в ORCH-043). Цель: B всегда несёт актуальный код предшественников → структурный анти-фантом на уровне планировщика (дополняет рубежи ORCH-073, не заменяет).
  • A-3. Сериализация — только внутри одного репо. Задачи РАЗНЫХ репо (orchestrator vs enduro-trails) параллелятся свободно (общая БД/очередь — пропускная способность не падает).
  • A-4. Механизм — минимально-инвазивный и restart-safe (как ORCH-1/065): переживает рестарт прод-контейнера, не оставляет навсегда захваченных ресурсов (опора на проактивный реклейм ORCH-065).
  • A-5. Совместимость с self-hosting safety: не ронять/не рестартить прод-контейнер вне штатного deploy; гейт Confirm Deploy (ORCH-059) сохранён; никаких push/force-push в main.
  • A-6. Защита от взаимоблокировки: B при занятой сериализации defer (повторная постановка с задержкой через available_at), а НЕ откат на development и НЕ вечное ожидание; bounded defer-бюджет (анти-livelock, как merge_defer_max_attempts).

Уровень B — Декларативные зависимости (исходный скоуп ORCH-26)

  • B-1. Задача может объявить связь blocked-by / blocks (depends-on).
  • B-2. Планировщик очереди (ORCH-1) не запускает заблокированную задачу, пока все её depends-on не достигли терминального состояния (done).
  • B-3. Защита от дедлоков: циклические зависимости детектируются; задача в цикле не «пропадает молча» — выставляется Blocked + alert (Telegram/Plane).
  • B-4. Видимость: заблокированная задача видна — Plane-статус Blocked и/или ожидание в Telegram-карточке (что и кого ждёт).

4. Открытые вопросы для архитектора (НЕ решаются на этапе анализа)

Аналитик фиксирует требования; выбор механизма — за архитектором (ADR в 06-adr/).

  1. Где хранить связи (Уровень B): Plane relations (родное, видимо в UI, но требует сетевого запроса и зависит от Plane) vs таблица в БД (job_deps/поля tasks, надёжно и offline, но дубль источника) vs гибрид (Plane — источник декларации, БД — кэш для планировщика). Рекомендация анализа: гибрид с offline-fallback (см. §6).
  2. Механизм сериализации (Уровень A): глобальный per-repo merge-lock vs FIFO merge-queue vs обязательный pre-merge rebase + расширение окна merge-lease (от «момента merge» до «main-updated»). Выбрать минимально-инвазивный, restart-safe, переиспользующий ORCH-065/043.
  3. Граница окна сериализации для self-hosting: для не-self репо «merged в main» = конец окна; для self (orchestrator) деплой асинхронный (Phase B/C, ORCH-036/071) — нужно решить, до какого события держать лиз (до merged_to_main: true / до done).
  4. Совместимость B и A: depends-on (B) на уровне постановки в очередь vs merge-сериализация (A) на уровне merge-gate — разные точки конвейера; убедиться, что не конфликтуют.

5. Вне скоупа (Non-goals)

  • Изменение машины стадий STAGE_TRANSITIONS (сериализация/зависимости — врезки/гейты, не новые стадии — паттерн ORCH-043/058/071).
  • Приоритизация/перепланирование задач по весам (только зависимости и сериализация).
  • Кросс-репо зависимости (A-3 явно запрещает кросс-репо сериализацию; кросс-репо логические зависимости — возможный follow-up, не v1).
  • Отмена/замена рубежей ORCH-073 — ORCH-026 их дополняет на уровне планировщика.

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

  • Owner (Слава) — одобряет BRD; держатель self-hosting прод-риска.
  • Стрим — автор предложения.
  • Конвейер агентов — потребитель: developer/deployer работают с веткой, которую затрагивает сериализация; reviewer проверяет обновление доки.

7. Критерии успеха (бизнес-уровень)

  • Две зелёные задачи одного репо больше не способны затереть код друг друга в main на уровне планировщика (без участия рубежей-последствий ORCH-073).
  • Задача может объявить зависимость; заблокированная задача не стартует раньше времени и видна наблюдателю.
  • Пропускная способность разных репо не деградирует.
  • Прод-контейнер orchestrator не падает и не рестартится вне штатного Confirm Deploy.

Точные PASS/FAIL — 03-acceptance-criteria.md.