work_item: ORCH-103
stage: analysis
author_agent: analyst
status: ready-for-review
created_at: 2026-06-11
model_used: claude-opus-4-8
title: "Bundled-тираж: bundle-compose + bootstrap + BUNDLED_SETUP.md (структурные анти-дрейф тесты)"
framework: pytest
scope: >
  Автоматическое покрытие — СТРУКТУРНЫЕ инварианты артефактов Bundled-тиража
  (bundle-compose, bootstrap-скрипт, docs/deployment/BUNDLED_SETUP.md) без docker/сети/LLM
  в CI (паттерн tests/test_lite_setup_doc.py). Вне автоматического покрытия — фактический
  e2e-подъём стека: он принимается ВРУЧНУЮ по чек-листу BUNDLED_SETUP §smoke
  (шаги REPLICATION.md §4) на чистом тестовом хосте/VM — см. notes (AC-1/AC-2/AC-3/AC-8).
notes: >
  Ручная приёмка (вне CI): чистый Linux-хост/VM -> docker compose -f <bundle> up -d ->
  один запуск bootstrap (manual-step чекпоинты Plane CE допустимы и проверяются) ->
  health/queue/metrics зелёные -> onboard verify -> тестовая задача доезжает до артефактов
  01-04 (минимальный сигнал), опционально до done; повторный запуск bootstrap безопасен;
  тома чистые, секреты новые. Имена модулей tests/test_bundle_compose.py /
  tests/test_bundled_setup_doc.py / tests/test_bootstrap_script.py — норматив тест-плана;
  имена bundle-каталога/скрипта внутри ассертов следуют ADR-001 архитектора.
  Полный регресс tests/ обязан остаться зелёным БЕЗ ослабления ассертов существующих
  анти-дрейф тестов (test_lite_setup_doc.py, test_no_host_hardcodes.py, канон ORCH-009).

tests:
  # ---------- FR-1 / AC-1: bundle-compose ----------
  - id: TC-01
    type: unit
    description: "Bundle-compose существует и валидно парсится (yaml.safe_load); содержит обязательные сервисы: orchestrator, orchestrator-watchdog, Gitea и Plane-стек (имена — по ADR-001); staging-контур орка не входит в дефолтный up"
    module: tests/test_bundle_compose.py
    expected: PASS

  - id: TC-02
    type: unit
    description: "Корневой docker-compose.yml НЕ изменён: множество сервисов == {orchestrator, orchestrator-watchdog, orchestrator-staging}; в его сервисах/образах/container_name нет подстрок plane/gitea (зеркало TC-04 test_lite_setup_doc.py — существующий анти-дрейф остаётся зелёным)"
    module: tests/test_bundle_compose.py
    expected: PASS

  - id: TC-03
    type: unit
    description: "Все сторонние образы bundle-compose пиннованы: ни одного image с тегом latest или без тега/digest (NFR-6, воспроизводимость)"
    module: tests/test_bundle_compose.py
    expected: PASS

  - id: TC-04
    type: unit
    description: "Изоляция и конфиг-канон bundle: тома — именованные с узнаваемым bundle-префиксом, без bind-путей нашего прод-контура; bundle-конфиг-канон (example-файл) существует, и каждая ${VAR}-интерполяция bundle-compose имеет ключ в каноне (key-set-sync, паттерн .env.watchdog.example)"
    module: tests/test_bundle_compose.py
    expected: PASS

  # ---------- FR-4 / AC-4: BUNDLED_SETUP.md ----------
  - id: TC-05
    type: unit
    description: "docs/deployment/BUNDLED_SETUP.md существует и несёт обязательные разделы FR-4 (включая 'Требования к хосту' с цифрами RAM/диск/CPU, картой портов и упоминанием ~14 контейнеров Plane; bootstrap; smoke; stateless-проверка; остановка/сброс; траблшутинг); исполняемые шаги оформлены fenced-блоками с явной 'Проверка:'"
    module: tests/test_bundled_setup_doc.py
    expected: PASS

  - id: TC-06
    type: unit
    description: "Гигиена новых артефактов (док + bundle-compose + bootstrap): нет FORBIDDEN-литералов (список — импорт из tests/test_no_host_hardcodes.py) и нет высокоэнтропийных секрет-литералов (hex >=32 / alnum >=40, эвристика D8 ORCH-102)"
    module: tests/test_bundled_setup_doc.py
    expected: PASS

  # ---------- FR-2/FR-3 / AC-7: bootstrap переиспользует кирпичи ----------
  - id: TC-07
    type: unit
    description: "Bootstrap-скрипт существует и структурно переиспользует канон: ссылается на scripts/gen_secrets.py и scripts/onboard_project.py; НЕ несёт собственного списка Plane-статусов/лейблов; в обычном прогоне нет delete-операций (docker volume rm / rm -rf допустимы только в отдельном явном reset-режиме, если введён ADR)"
    module: tests/test_bootstrap_script.py
    expected: PASS

  - id: TC-08
    type: unit
    description: "Чистые функции bootstrap (preflight/план шагов): грязное состояние (существующие bundle-тома, занятый порт, нехватка RAM/диска) -> отказ с диагностикой ДО мутаций; чистое -> план полного прогона; контракт exit-кодов 0/2/1 (успех / manual-step-остановка / ошибка)"
    module: tests/test_bootstrap_script.py
    expected: PASS

  # ---------- FR-4/FR-5 / AC-9: env-канон и нулевой дрейф ----------
  - id: TC-09
    type: unit
    description: "Каждый env-ключ ORCH_*/WATCHDOG_*, упомянутый в BUNDLED_SETUP.md, существует в .env.example либо в bundle-конфиг-каноне (нет ключей-фантомов); упоминание ЧИСЛА статусов Plane сверяется импортом len(plane_sync._PLANE_NAME_TO_KEY), а не зашитым литералом"
    module: tests/test_bundled_setup_doc.py
    expected: PASS

  - id: TC-10
    type: unit
    description: "Кросс-ссылки канона: BUNDLED_SETUP.md ссылается на LITE_SETUP.md, ONBOARDING.md и REPLICATION.md (канон не форкается); docs/operations/REPLICATION.md §1 несёт отметку Type B -> BUNDLED_SETUP.md / ORCH-103"
    module: tests/test_bundled_setup_doc.py
    expected: PASS

  # ---------- AC-5: журнал и полный регресс ----------
  - id: TC-11
    type: unit
    description: "CHANGELOG.md содержит запись ORCH-103"
    module: tests/test_bundled_setup_doc.py
    expected: PASS

  - id: TC-12
    type: integration
    description: "Полный регресс pytest tests/ -q зелёный: новые тесты добавлены, существующие анти-дрейф (test_lite_setup_doc.py, test_no_host_hardcodes.py, канон-тесты ORCH-009) проходят БЕЗ изменения их ассертов"
    module: tests/
    expected: PASS
