# 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-065** — `merge-lease` (`src/merge_gate.py`): per-repo файловый лиз `.merge-lease-.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`.