work_item: ORCH-026 description: > План тестов для управления зависимостями задач (Уровень B) и сериализации merge/деплоя внутри одного репо (Уровень A). Стек: pytest. Имена модулей/функций — кандидаты; финализирует архитектор/разработчик. Все новые функции — never-raise. tests: # ---------------- Уровень A: сериализация merge/деплоя ---------------- - id: TC-A01 type: unit description: > Proactive pre-merge rebase: ветка догоняется на свежий origin/main ДАЖЕ когда branch_is_behind_main вернул бы False (нет конфликта). Проверить, что rebase вызывается всегда перед merge (AC-A2). module: tests/test_orch026_premerge_rebase.py expected: PASS - id: TC-A02 type: unit description: > Расширенное окно merge-lease: пока A держит lease (окно merge→main-updated), acquire для B того же репо возвращает busy → defer (не откат). holder-aware release не удаляет чужой lease (AC-A1, AC-A6). module: tests/test_orch026_merge_serialize.py expected: PASS - id: TC-A03 type: unit description: > Сериализация строго per-repo: lease/гейт orchestrator не влияет на задачу enduro-trails — обе claimable параллельно (AC-A3). module: tests/test_orch026_merge_serialize.py expected: PASS - id: TC-A04 type: unit description: > Restart-safe + проактивный реклейм: мёртвый держатель lease (pid не жив) реклеймится reclaim_stale_lease; конвейер не встаёт навсегда (AC-A4). module: tests/test_orch026_merge_serialize.py expected: PASS - id: TC-A05 type: unit description: > Anti-livelock defer: B defer-ится с available_at-задержкой и bounded бюджетом; исчерпание → эскалация (Blocked/alert), не бесконечный цикл (AC-A6). module: tests/test_orch026_merge_serialize.py expected: PASS - id: TC-A06 type: unit description: > Условность/kill-switch: при выключенном флаге и для репо вне scope поведение merge/деплоя 1:1 как до ORCH-026 — no-op (AC-A7, AC-G2). module: tests/test_orch026_conditionality.py expected: PASS - id: TC-A07 type: unit description: > Self-hosting safety: новая логика никогда не делает push/force-push в main; force только --force-with-lease на ветку задачи; STAGE_TRANSITIONS не изменены (AC-A5). module: tests/test_orch026_conditionality.py expected: PASS - id: TC-A08 type: integration description: > Сквозной сценарий: две задачи одного репо проходят deploy-staging→deploy; B не доходит до merge, пока A не в main; после A→done B ребейзится на свежий main (несёт код A) и мержится. main не теряет код A (AC-A1/AC-A2). module: tests/test_orch026_serialize_integration.py expected: PASS # ---------------- Уровень B: декларативные зависимости ---------------- - id: TC-B01 type: unit description: > Чтение/декларация связи blocked-by из выбранного источника (Plane/БД/гибрид); связь корректно резолвится в depends_on_task_id (AC-B1). never-raise при недоступности источника → консервативно (нет связи или fail-closed по решению ADR). module: tests/test_orch026_task_deps.py expected: PASS - id: TC-B02 type: unit description: > Гейт готовности (leaf-функция): задача с незавершённым depends-on НЕ ready; все depends-on в done → ready. Чистая логика, юнит-тестируемая (AC-B2). module: tests/test_orch026_task_deps.py expected: PASS - id: TC-B03 type: unit description: > Детект циклов: A→B→A (и длиннее) детектируется детерминированно; ацикличный граф → циклов нет. Чистая функция (AC-B3). module: tests/test_orch026_dep_cycles.py expected: PASS - id: TC-B04 type: unit description: > Цикл → set_issue_blocked + alert (Telegram/Plane), без падения воркера и без блокировки потока других задач (AC-B3, AC-G1). module: tests/test_orch026_dep_cycles.py expected: PASS - id: TC-B05 type: unit description: > claim_next_job не клеймит заблокированную задачу (не занимает слот max_concurrency); как только depends-on done — задача становится claimable (AC-B2). module: tests/test_orch026_task_deps.py expected: PASS - id: TC-B06 type: unit description: > Видимость: заблокированная задача отражается в Plane-статусе Blocked и/или строке ожидания Telegram-карточки; инвариант «одна карточка на задачу» сохранён (AC-B4). notifications never-raise / silent. module: tests/test_orch026_dep_visibility.py expected: PASS - id: TC-B07 type: unit description: > reconciler F-1 НЕ разблокирует задачу, заблокированную по зависимости (как для Blocked/Needs-Input); reaper не реапит корректно ожидающую (AC-B5). module: tests/test_orch026_task_deps.py expected: PASS - id: TC-B08 type: integration description: > Сквозной сценарий: B объявлена blocked-by A; при постановке в очередь B не стартует, пока A не done; после A→done воркер запускает B. Telegram/Plane показывают Blocked у B до разблокировки (AC-B1/B2/B4). module: tests/test_orch026_deps_integration.py expected: PASS # ---------------- Общие / миграция / регресс ---------------- - id: TC-G01 type: unit description: > Аддитивная миграция БД (если выбран вариант с таблицей/колонкой): идемпотентна, безопасна на существующей БД с данными, не меняет существующие колонки (AC-G4). module: tests/test_orch026_migration.py expected: PASS - id: TC-G02 type: unit description: > Наблюдаемость GET /queue: новый блок (заблокированные задачи / держатель lease / defer-счётчики / циклы) присутствует и read-only; не источник истины. module: tests/test_orch026_queue_observability.py expected: PASS - id: TC-G03 type: integration description: > Регресс: полный pytest tests/ -q остаётся зелёным — merge-gate (ORCH-043), merge-verify (ORCH-073), reconciler (ORCH-053/068), reaper (ORCH-065) не деградировали (AC-G5). module: tests/ expected: PASS