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