work_item: ORCH-110
stage: analysis
author_agent: analyst
status: ready-for-review
created_at: 2026-06-15
model_used: claude-opus-4-8
escalate: full-cycle
title: "merge-gate re-test timeout: tolerance + no orphan-process leak + re-test contract"
framework: pytest
scope: >
  Покрывает: классификацию инфра-таймаута re-test merge-gate как транзиента (без ложного отката),
  tree-kill оркестратор-спавненных pytest-прогонов (re-test + coverage), сохранение красно-откат-пути,
  согласование бюджета re-test со сквозными инвариантами, контракт необходимости re-test, kill-switch
  и наблюдаемость. Вне покрытия: алерт sidecar-watchdog (ORCH-111), правка конкретного
  test_install_lite_script.py, поведение enduro (только проверяется no-op).
notes: >
  TC-10 — ОБЯЗАТЕЛЬНЫЙ регресс-тест инцидента ORCH-109/PR#129: красный на текущем коде (инфра-таймаут
  re-test → ложный rollback / выживший процесс), зелёный после фикса. Подпроцессы в тестах мокаются
  (управляемый "медленный/спавнящий детей pytest"), без обращения к сети/Plane/Gitea. Полный регресс
  tests/ должен оставаться зелёным. Точные имена символов/флагов уточняет архитектор (06-adr);
  модули-плейсхолдеры ниже выровнены под манифест PIPELINE_DOCS.

tests:
  - id: TC-01
    type: unit
    description: "retest_branch: таймаут возвращает (False, 're-test timeout after <T>s') И завершает всё дерево подпроцесса (внуки не переживают таймаут)."
    module: tests/test_orch110_retest_lifecycle.py
    expected: PASS

  - id: TC-02
    type: unit
    description: "coverage_gate.measure_coverage: таймаут завершает всё дерево подпроцесса (сиблинг-источник утечки, BR-3); возврат None сохранён."
    module: tests/test_orch110_retest_lifecycle.py
    expected: PASS

  - id: TC-03
    type: unit
    description: "check_branch_mergeable: исход 'timeout' различим от 'red re-test' в reason/классификации (без смены имени/семантики зарегистрированного check_*)."
    module: tests/test_orch110_merge_gate_classify.py
    expected: PASS

  - id: TC-04
    type: unit
    description: "Маршрутизация исхода: инфра-таймаут → defer/повтор/инфра-alert путь (НЕ _handle_merge_gate_rollback на development, без инкремента developer-retry)."
    module: tests/test_orch110_merge_gate_routing.py
    expected: PASS

  - id: TC-05
    type: unit
    description: "Анти-над-толерантность: детерминированно КРАСНЫЙ re-test по-прежнему → откат на development + developer-retry + release lease (BR-6 сохранён)."
    module: tests/test_orch110_merge_gate_routing.py
    expected: PASS

  - id: TC-06
    type: unit
    description: "Ограниченность (anti-loop): повторы/defer инфра-таймаута лимитированы по попыткам и суммарному времени; исчерпание → один инфра-alert, не бесконечный bounce."
    module: tests/test_orch110_merge_gate_routing.py
    expected: PASS

  - id: TC-07
    type: unit
    description: "Kill-switch off → байт-в-байт прежнее поведение (таймаут → rollback на development, прежний текст alert); not-self repo (enduro) → no-op."
    module: tests/test_orch110_killswitch.py
    expected: PASS

  - id: TC-08
    type: unit
    description: "Бюджет/инварианты: malformed/непозитивный merge_retest_timeout_s → дефолт + WARNING; соблюдён reaper_max_running_s > max(agent_timeout, бюджеты)+grace и согласование с merge_lock_timeout_s."
    module: tests/test_orch110_budget_invariants.py
    expected: PASS

  - id: TC-09
    type: unit
    description: "never-raise: любая ошибка в новом транзиент-пути → безопасный дефолт + WARNING; исключение не уходит в advance_stage."
    module: tests/test_orch110_merge_gate_routing.py
    expected: PASS

  - id: TC-10
    type: integration
    description: "РЕГРЕСС инцидента: tester PASS + зелёный CI + ветка не-behind, но re-test таймаут — задача НЕ откатывается ложно и НЕ упирается в 'Merge-gate still failing after N developer retries'; доходит до deploy или поднимает инфра-alert. Красный до фикса, зелёный после."
    module: tests/test_orch110_false_rollback_regression.py
    expected: PASS

  - id: TC-11
    type: integration
    description: "Контракт необходимости re-test (FR-4/AC-6): при не-behind + зелёном CI по HEAD локальный re-test ведёт себя по выбранному в ADR контракту (skip/scope/trust-CI) и не является избыточной единственной точкой ложного отказа. Финальная форма — после решения архитектора."
    module: tests/test_orch110_retest_contract.py
    expected: PASS

  - id: TC-12
    type: integration
    description: "Наблюдаемость: инфра-таймаут отражён в логах/GET /queue (read-only) и Telegram-уведомлении с кликабельным номером; отличим от код-фейл-отката; без дубля с ORCH-111."
    module: tests/test_orch110_observability.py
    expected: PASS
