# 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-<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`.
