work_item: ORCH-113
stage: analysis
author_agent: analyst
status: ready-for-review
created_at: 2026-06-15
model_used: claude-opus-4-8
escalate: full-cycle
title: "job-reaper не повторяет финализацию deploy-staging при живом finalizer'е: живость + идемпотентность + строгое владение"
framework: pytest
scope: >
  Покрывает: распознавание живого финализирующего монитора в Tier-2 reaper на стадии deploy-staging
  (не reap по одному finished_age_s); идемпотентность и строгое владение исполнением edge-гейтов
  (не более одного локального re-test/merge-gate на (job, stage)); сохранение добивания РЕАЛЬНО
  мёртвого finalizer'а; отсутствие ложного отката deploy-staging -> development и расхождения состояния
  после успешного deploy; сохранение инвариантов (STAGE_TRANSITIONS/QG_CHECKS/check_*/machine-verdict/
  схема существующих таблиц байт-в-байт; never-raise; kill-switch; сквозной бюджет ORCH-065/109/110).
  Вне покрытия: инфра-толерантность merge-gate к таймауту re-test и tree-kill осиротевших процессов
  (ORCH-110); починка конкретных мигающих тестов; поведение enduro/не-self репо (только проверяется
  отсутствие регрессии / no-op).
notes: >
  TC-05 — ОБЯЗАТЕЛЬНЫЙ регресс-тест инцидента ORCH-111 (deployer job 1914 / run_id 683): КРАСНЫЙ на
  коде до фикса (reaper при живом долгом finalizer'е deploy-staging независимо запускает второй прогон
  edge-гейтов и откатывает задачу), ЗЕЛЁНЫЙ после фикса. Подпроцессы (pytest re-test / coverage /
  docker), сеть, Plane и Gitea — мокаются; «живой/мёртвый finalizer» и «долгая финализация > grace»
  моделируются управляемо, без обращения наружу. Полный регресс tests/ должен оставаться зелёным.
  Точные имена символов/колонок/флагов уточняет архитектор (06-adr); модули-плейсхолдеры выровнены под
  манифест PIPELINE_DOCS.

tests:
  - id: TC-01
    type: unit
    description: "Tier-2 reaper на deploy-staging: exit_code=0 и finished_age_s >= grace, но finalizer ЖИВ (сигнал живости присутствует) -> reaper НЕ вызывает _gate_driven_advance/advance_stage; второй прогон edge-гейтов не запускается; логируется defer (AC-1/FR-1)."
    module: tests/test_orch113_reaper_finalizer_liveness.py
    expected: PASS

  - id: TC-02
    type: unit
    description: "Строгое владение: при попытке повторной обработки того же (job, stage) актор без владения состоянием НЕ исполняет merge-gate/локальный re-test/advance (claim/ownership проигран -> ноль побочных эффектов), AC-2/FR-2."
    module: tests/test_orch113_reaper_finalizer_liveness.py
    expected: PASS

  - id: TC-03
    type: unit
    description: "Мёртвый finalizer на deploy-staging (сигнал живости отсутствует/протух) -> reaper по-прежнему добивает job за ограниченное время по существующему контракту (retry в пределах бюджета, иначе failed+Telegram; Tier-3 backstop срабатывает) — reaper не no-op для deploy-staging (AC-3/FR-4)."
    module: tests/test_orch113_reaper_finalizer_liveness.py
    expected: PASS

  - id: TC-04
    type: integration
    description: "Идемпотентность под гонкой: монитор финализирует deploy-staging и параллельно срабатывает reaper-тик -> тяжёлый прогон edge-гейтов (merge-gate/re-test) исполняется РОВНО ОДИН раз для (job, stage); нет второго re-test и нет ложного rollback (AC-2/AC-4/FR-2/FR-5)."
    module: tests/test_orch113_reaper_finalizer_liveness.py
    expected: PASS

  - id: TC-05
    type: integration
    description: "ОБЯЗАТЕЛЬНЫЙ регресс ORCH-111: долгая (> grace) финализация deploy-staging при staging_status=SUCCESS, deploy/finalizer параллельно доходит до успеха/merge PR -> reaper НЕ откатывает deploy-staging -> development и НЕ инкрементирует developer-retry; у задачи единственное консистентное состояние. КРАСНЫЙ до фикса, ЗЕЛЁНЫЙ после (AC-4/FR-5)."
    module: tests/test_orch113_reaper_finalizer_liveness.py
    expected: PASS

  - id: TC-06
    type: unit
    description: "Регресс-гард совместимости: kill-switch выключен ИЛИ стадия не deploy-staging -> поведение reaper байт-в-байт прежнее (Tier-2 grace, claim-before-act, dead-pid/Tier-3 пути неизменны), NFR-4/AC-5."
    module: tests/test_orch113_reaper_finalizer_liveness.py
    expected: PASS

  - id: TC-07
    type: unit
    description: "Сквозной инвариант бюджета (ORCH-065/109/110): при дефолтном конфиге reaper_max_running_s (5400) > Σ(deploy-staging gate-work) + grace; любая правка grace/таймаутов фикса инвариант не нарушает (NFR-6/AC-5)."
    module: tests/test_orch113_reaper_finalizer_liveness.py
    expected: PASS

  - id: TC-08
    type: unit
    description: "never-raise: сбой/исключение в новом пути распознавания живости/владения деградирует безопасно — reaper-тик не падает, прочие job обрабатываются, прод не трогается, main не пушится (NFR-1/NFR-3/AC-5)."
    module: tests/test_orch113_reaper_finalizer_liveness.py
    expected: PASS
