work_item: ORCH-112 stage: analysis author_agent: analyst status: ready-for-review created_at: 2026-06-15 model_used: claude-opus-4-8 title: "Гигиена shared deploy-базы: устойчивость self-deploy git pull к грязному дереву" framework: pytest scope: > Покрывается: устойчивость self-deploy `git pull origin main` к грязной shared deploy-базе (модифицированные tracked + untracked файлы), сходимость базы к чистому origin/main после failed/cancelled задач, сохранность deploy-rollback-состояния, kill-switch/область, наблюдаемость, self-hosting safety. Вне покрытия: модель worktree per-task (ORCH-2, не трогается), запрет ручных операций оператора, изменения STAGE_TRANSITIONS/QG_CHECKS/схемы БД (их нет). notes: > TC-01 — ОБЯЗАТЕЛЬНЫЙ регресс-тест воспроизведения инцидента ORCH-111: КРАСНЫЙ до фикса, ЗЕЛЁНЫЙ после. Шелл-симуляции хука моделировать по образцу tests/test_deploy_hook_rollback_sim.py (временный git-репо во временной директории, без сети/прода/ssh). Полный регресс `pytest tests/ -q` обязан оставаться зелёным (NFR-5). Точные имена тест-модулей/функций уточнит разработчик; тип гигиены (resilient-pull / janitor / guard) выберет архитектор — тесты сформулированы так, чтобы проверять ТРЕБУЕМЫЙ ИНВАРИАНТ (база сходится к чистому origin/main, артефакты сохранены), а не конкретный механизм. tests: - id: TC-01 type: integration description: "РЕГРЕСС (обязательный, red→green): shared deploy-база с локальной модификацией tracked-файла src/config.py + untracked файлами — симуляция шага git pull хука приводит базу к чистому origin/main и НЕ падает с 'local changes would be overwritten by merge' (воспроизводит ORCH-111; красный до фикса)." module: tests/test_deploy_checkout_hygiene.py expected: PASS - id: TC-02 type: integration description: "Untracked WIP-файлы (install_lite.py / test_install_lite.py / lite-install.example.yaml) в shared-базе не блокируют операцию и база сходится к чистому origin/main." module: tests/test_deploy_checkout_hygiene.py expected: PASS - id: TC-03 type: integration description: "Сохранность (NFR-2): после гигиены файлы $REPO/.deploy-prev-image-* , deploy-hook.log, sibling .deploy-state-* / .merge-lease-*.json и .git/worktrees/* НЕ удалены; rollback по .deploy-prev-image-* остаётся работоспособным." module: tests/test_deploy_checkout_hygiene.py expected: PASS - id: TC-04 type: integration description: "Happy-path без регресса: на ЧИСТОЙ shared-базе шаг pull — обычный fast-forward; наблюдаемое поведение и exit-коды (0/1/2, ORCH-036) байт-в-байт прежние." module: tests/test_deploy_checkout_hygiene.py expected: PASS - id: TC-05 type: unit description: "Self-hosting safety: путь гигиены никогда не оперирует веткой main на remote, не делает force-push, не рестартит прод и не сносит worktree/ветки других задач; операции ограничены настроенным путём deploy-базы (статический/поведенческий ассерт)." module: tests/test_deploy_checkout_hygiene.py expected: PASS - id: TC-06 type: unit description: "Kill-switch off → деплой/pull байт-в-байт прежний (голый git pull origin main); on → активна устойчивая гигиена. Область applies(repo): self-hosting orchestrator real, прочие репо — no-op." module: tests/test_deploy_checkout_hygiene.py expected: PASS - id: TC-07 type: integration description: "Сходимость после cancel/failed: cancel_task (ORCH-090) / failed-исход не оставляет рабочих остатков в shared-базе, блокирующих будущий деплой; последующий self-deploy проходит без ручного вмешательства." module: tests/test_deploy_checkout_hygiene.py expected: PASS - id: TC-08 type: unit description: "Наблюдаемость: обнаружение грязной базы и факт автоочистки (или отказ) попадают в лог; Telegram-алерт best-effort/never-raise (его сбой не валит деплой), номер задачи кликабельный." module: tests/test_deploy_checkout_hygiene.py expected: PASS - id: TC-09 type: unit description: "Инвариант конвейера: STAGE_TRANSITIONS / реестр QG_CHECKS / имена и семантика check_* / machine-verdict ключи / exit-code-контракт хука — не изменены (структурный анти-регресс)." module: tests/test_deploy_checkout_hygiene.py expected: PASS - id: TC-10 type: unit description: "Документация-инвариант: docs/operations/INFRA.md и docs/architecture/README.md содержат правило «shared main checkout — deploy/worktree-management база, не workspace» (структурная сверка)." module: tests/test_deploy_checkout_hygiene.py expected: PASS