# 02-ТЗ — Управление зависимостями задач (B ждёт A) в очереди **Work Item:** ORCH-026 · **Repo:** orchestrator · **Стадия:** analysis > ТЗ фиксирует ТРЕБОВАНИЯ к изменениям (модули, контракты, артефакты). Конкретный механизм > сериализации и место хранения связей — решение архитектора (ADR в `06-adr/`); ниже отмечены > как «КАНДИДАТ / решает архитектор». Аналитик не предлагает архитектуру. --- ## 1. Задействованные модули `src/` | Модуль | Роль в задаче | Уровень | |--------|---------------|---------| | `src/queue_worker.py` | Планировщик: `_drain_once` / `claim_next_job` — точка учёта зависимостей и сериализации при выборе job. | A + B | | `src/db.py` | Очередь `jobs` / `tasks`; `claim_next_job`, `enqueue_job`, `count_running_jobs`. Кандидат на хранение связей и блокировки claim. | A + B | | `src/merge_gate.py` | merge-lease (ORCH-065), `branch_is_behind_main` / `auto_rebase_onto_main` (ORCH-043) — опора для proactive pre-merge rebase и расширения окна сериализации. | A | | `src/qg/checks.py` | `check_branch_mergeable` (под-гейт ребра `deploy-staging → deploy`) — точка форсированного pre-merge rebase. | A | | `src/stage_engine.py` | `advance_stage` — врезки гейтов; точка интеграции сериализации/верификации. | A | | `src/webhooks/plane.py` | `handle_work_item_created` / `start_pipeline` — приём задачи; точка чтения relations (если источник — Plane). | B | | `src/plane_sync.py` | `set_issue_blocked`, `get_project_states` (`blocked`/`needs_input`), relations API. | B | | `src/notifications.py` | live-карточка: индикация `Blocked` / «ждёт ORCH-NNN». | B | | `src/config.py` | Новые kill-switch + scope-настройки (паттерн `*_enabled` / `*_repos`). | A + B | | `src/reconciler.py` / `src/job_reaper.py` | Не ломать: skip заблокированных задач (как уже делается для Blocked/Needs-Input, ORCH-060/068); реклейм ресурсов сериализации. | A + B | --- ## 2. Требования к изменениям — Уровень A (сериализация merge/деплоя) ### 2.1 Proactive pre-merge rebase (A-2) - На ребре `deploy-staging → deploy`, ДО фактического merge (в составе `check_branch_mergeable` или соседнего под-гейта), ветка задачи **всегда** догоняется на свежий `origin/main` — **не только при `branch_is_behind_main`/конфликте**. - Переиспользовать `merge_gate.auto_rebase_onto_main` (rebase + `push --force-with-lease` ТОЛЬКО ветки задачи). Текстовый конфликт → существующий контракт: `rebase --abort` → откат на `development` (как ORCH-043). - **Инвариант:** никаких push/force-push в `main`. ### 2.2 Расширение окна merge-lease (A-1, A-3, A-4) - **КАНДИДАТ (решает архитектор):** держать per-repo merge-lease (ORCH-065) не только «на момент merge», а на окно **«merge → main-updated»** (для self — до подтверждения `merged_to_main: true` / `done`), чтобы B не дошла до своего merge, пока A не в `main`. - Acquire — **неблокирующий** (как сейчас): занято → **defer** задачи B через `enqueue_job(available_at_delay_s=...)`, bounded бюджет (анти-livelock; ср. `merge_defer_max_attempts`). Откат на `development` НЕ применять для defer. - Release — holder-aware (как `release_merge_lease`), на merged-вебхуке / `deploy→done` / откате / по проактивному реклейму (ORCH-065 `reclaim_stale_lease`). - Сериализация **строго per-repo** (`.merge-lease-.json`) — кросс-репо параллелизм не затрагивается (A-3). ### 2.3 Условность и безопасность (A-5) - Реально только для применимых репо: kill-switch + CSV-scope (паттерн `merge_gate_repos` / `merge_verify_repos`; пусто → только self-hosting `orchestrator`). - `STAGE_TRANSITIONS`, `Confirm Deploy` (ORCH-059), exit-коды deploy-хука, БАГ-8, terminal-sync — **без изменений**. - Контракт **never-raise** для всех новых функций (как соседи в `merge_gate.py`). --- ## 3. Требования к изменениям — Уровень B (декларативные зависимости) ### 3.1 Декларация связи (B-1) - **КАНДИДАТ хранения (решает архитектор, см. BRD §4.1):** - вариант Plane relations: читать `blocked-by` через Plane API в `handle_work_item_created`; - вариант БД: новая таблица `job_deps(task_id, depends_on_task_id)` или поле в `tasks` (idempotent `_ensure_column` миграция, как ORCH-065 `jobs.pid`); - гибрид: Plane — декларация, БД — кэш для планировщика (offline-устойчивость). - Миграция БД (если выбран вариант с таблицей/колонкой) — **только аддитивная** (`CREATE TABLE IF NOT EXISTS` / `_ensure_column`), безопасная на живой прод-БД с общими данными enduro-trails. ### 3.2 Гейт планировщика (B-2) - При выборе job (`claim_next_job` / `_drain_once`) задача с незавершёнными depends-on **не клеймится** (аналог `available_at`-gate): пропускается до тех пор, пока все depends-on не `done`. Не должна занимать слот `max_concurrency`. - Реализация — **leaf-функция** с чистой логикой «готова ли задача к запуску» (тестируемо юнитами, never-raise), по образцу `staging_verdict.py` / `post_deploy.py`. ### 3.3 Защита от дедлоков (B-3) - Детектор циклов в графе depends-on (DFS/обнаружение цикла) — чистая функция, юнит-тестируемая. - Цикл → задача(и) НЕ запускается молча: `set_issue_blocked` + alert (Telegram/Plane) с указанием цикла. Не блокировать поток других задач. ### 3.4 Видимость (B-4) - Заблокированная задача: Plane-статус `Blocked` (`set_issue_blocked`) и/или строка ожидания в Telegram-карточке («⏳ ждёт ORCH-NNN»). Использовать существующий механизм карточки (`notifications.update_task_tracker`), контракт never-raise / silent. - `reconciler` F-1 уже пропускает Blocked/Needs-Input (ORCH-060/068) — убедиться, что новые заблокированные-по-зависимости задачи тоже пропускаются (не «разблокируются» ошибочно). --- ## 4. Изменения API (endpoints) - **Новые HTTP endpoints не требуются.** - **Наблюдаемость:** расширить снимок `GET /queue` блоком о зависимостях/сериализации (по образцу блоков `reconcile` / `reaper` / `post_deploy` / `merge_verify`): кол-во заблокированных задач, держатель merge-lease, defer-счётчики, обнаруженные циклы. Read-only, никогда не источник истины для решений. ## 5. Изменения схемы БД - **КАНДИДАТ (если выбран БД/гибрид для Уровня B):** аддитивная таблица `job_deps` или колонка в `tasks` (см. §3.1). Только `CREATE TABLE IF NOT EXISTS` / `_ensure_column`. Без изменения существующих колонок `jobs`/`tasks`. Restart-safe, безопасно на общей прод-БД. - Уровень A (сериализация) — **без изменения схемы БД** (merge-lease файловый, как ORCH-065). ## 6. Требования к новым QG checks - **Новый зарегистрированный QG-чек НЕ вводится** (паттерн ORCH-071/058: под-гейт — врезка в `advance_stage` или расширение `check_branch_mergeable`, а не новая запись в `QG_CHECKS`). - Реестр `QG_CHECKS` — без изменений. ## 7. Конфигурация (`src/config.py`) Новые настройки по паттерну `*_enabled` (kill-switch) + `*_repos` (CSV scope, пусто → self-hosting). КАНДИДАТ-имена (финализирует архитектор): - Уровень A: `merge_serialize_enabled` / `merge_serialize_repos` (или расширение `merge_gate_*`); опционально `premerge_rebase_always` (вкл proactive rebase). - Уровень B: `task_deps_enabled` / `task_deps_source` (`plane|db|hybrid`). Дефолты — обратная совместимость (для не-self репо — прежнее поведение). ## 8. Артефакты pipeline (создать/обновить В ТОМ ЖЕ PR) - `06-adr/ADR-001-*.md` — решение по сериализации (A) и хранению зависимостей (B). - Обновить `docs/architecture/README.md` (раздел про очередь/merge-gate/сериализацию). - Обновить `CLAUDE.md` (паспорт: конвейер/инварианты, если меняется поведение очереди). - Обновить `CHANGELOG.md` (`## [Unreleased]`). - Если вводится таблица БД — отразить в `08-data-requirements.md` (создаёт архитектор). - `07-infra-requirements.md` — если требуется новый Plane-статус/настройка relations. ## 9. Инварианты (НЕ нарушать) 1. `STAGE_TRANSITIONS`, реестр `QG_CHECKS`, `check_deploy_status`/`check_staging_status`, `Confirm Deploy` (ORCH-059), БАГ-8, terminal-sync — без изменений. 2. Никаких push/force-push в `main`; force только `--force-with-lease` на ветку задачи. 3. Сериализация — строго per-repo; кросс-репо параллелизм сохранён. 4. never-raise во всех новых функциях; restart-safe состояние. 5. ORCH-026 дополняет рубежи ORCH-073, не заменяет. 6. Прод-контейнер orchestrator не рестартится вне штатного `Confirm Deploy`.