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
