---
work_item: ORCH-103
stage: analysis
author_agent: analyst
status: ready-for-review
created_at: 2026-06-11
model_used: claude-opus-4-8
---

# 03 — Критерии приёмки (Acceptance Criteria): ORCH-103 — Bundled-тираж: весь стек одним комплектом + bootstrap-скрипт

Work Item: **ORCH-103** · Repo: **orchestrator** · Стадия: analysis

Формат: каждый критерий имеет **PASS** (что должно быть истинно для приёмки) и **FAIL**
(что считается провалом). AC-1…AC-5 — из постановки Владельца (сохранены 1:1 по смыслу);
AC-6…AC-9 — производные обязательные. AC-1/AC-2/AC-3 в части e2e — **ручная приёмка** на
чистом тестовом хосте/VM по BUNDLED_SETUP.md (в CI docker/LLM не гоняются); остальное
проверяется по файлам репозитория и структурным тестам.

---

## AC-1 — Единый bundle поднимает ВЕСЬ стек; bootstrap доводит одной командой/визардом

**Условие:** на чистом Linux-хосте с docker+compose по шагам BUNDLED_SETUP.md: одна команда
`docker compose -f <bundle-compose> … up -d` поднимает все сервисы стека (орк + watchdog +
Gitea + Plane-стек); затем ОДИН запуск bootstrap-скрипта доводит инсталляцию до рабочего
состояния (init Gitea/Plane → онбординг sandbox-проекта → git-доступ агентов → конфиг орка →
health). Интерактивные manual-step чекпоинты допустимы только там, где Plane CE API не
позволяет автоматизацию, каждый — с инструкцией и проверкой результата.
- **PASS:** все контейнеры bundle в состоянии Up/healthy; bootstrap завершается `exit 0`;
  `GET /health` орка — 200/ok, `GET /queue` и `GET /metrics` отдают валидный JSON;
  `onboard_project.py verify` зелёный (22 статуса, лейблы, репо, webhook); ни одного
  НЕдокументированного ручного действия (правка compose/конфигов руками сверх инструкции).
- **FAIL:** хотя бы один сервис не поднялся/в рестарт-цикле; bootstrap падает или завершается
  с нерабочим конвейером; для доводки потребовались действия, отсутствующие в BUNDLED_SETUP.md;
  manual-step пропускается молча без проверки результата.

---

## AC-2 — После bootstrap smoke проходит (тестовый проект + задача доезжает)

**Условие:** smoke-процедура BUNDLED_SETUP §smoke (шаги REPLICATION.md §4 поверх
bundle-инсталляции): создать issue в sandbox-проекте Plane → перевести в «To Analyse».
- **PASS:** webhook доезжает (job появляется в `GET /queue`); конвейер запускает analyst;
  в рабочей ветке Gitea появляются артефакты `01-brd.md`/`02-trz.md`/`03-acceptance-criteria.md`/
  `04-test-plan.yaml` (минимальный сигнал — шаг 5 REPLICATION §4); обратное направление
  работает (орк пишет статус/коммент в Plane). Опционально-расширенно: задача доводится до
  `done` (шаг 6).
- **FAIL:** webhook не доходит (нет job); analyst не стартует; артефакты `01–04` не появляются;
  орк не может писать в Plane/Gitea API (одностороння связность — R-4).

---

## AC-3 — Stateless: чистые Plane/Gitea/БД, новые секреты

**Условие:** инсталляция стартует с нуля и не содержит ничего нашего.
- **PASS:** все тома bundle созданы заново при первом `up` (чистые БД Plane/Gitea/орка:
  `GET /queue` — нулевые счётчики, в Plane/Gitea нет наших задач/репо/пользователей); ВСЕ
  секреты инсталляции сгенерированы на месте (`gen_secrets.py` + bundle-креды bootstrap);
  в репо нет ни одного реального секрета/дефолтного пароля (структурный тест: секрет-эвристика
  + плейсхолдеры в bundle-конфиг-каноне); боевые данные/секреты/БД не копируются ни одним шагом
  инструкции.
- **FAIL:** инструкция/скрипт предлагает перенос наших данных или переиспользование боевых
  секретов; в репо обнаружен реальный секрет/дефолтный пароль/высокоэнтропийный литерал;
  на свежей инсталляции видны чужие задачи/счётчики.

---

## AC-4 — BUNDLED_SETUP.md + требования к хосту задокументированы

**Условие:** `docs/deployment/BUNDLED_SETUP.md` существует и написан по канону тиражных доков
(ORCH-102).
- **PASS:** док несёт обязательные разделы FR-4 (рамка, **требования к хосту с явными цифрами
  RAM/диск/CPU и картой портов**, предусловия, секреты, запуск, bootstrap с перечнем
  manual-step, LLM, Telegram, онбординг, smoke, stateless-проверка, остановка/сброс,
  траблшутинг); каждый исполняемый шаг = fenced-команда + «Проверка:» PASS/FAIL; явно указано
  «Plane ≈ 14 контейнеров — ресурсоёмко»; цифры требований подтверждены замером на тестовом
  развёртывании (не «с потолка»); хост-специфика — только плейсхолдеры; общие шаги — ссылками
  на LITE_SETUP/ONBOARDING/REPLICATION (без копипасты канона).
- **FAIL:** дока нет/раздел «Требования к хосту» отсутствует или без цифр; шаги без
  команд/проверок; FORBIDDEN-литералы (IP/`/home/slin`/`mva154`/`duckdns`) или секреты в
  тексте/fenced-блоках; канон LITE_SETUP скопирован вместо ссылок.

---

## AC-5 — pytest зелёный; CHANGELOG

**Условие:** полный регресс и журнал изменений.
- **PASS:** `pytest tests/ -q` — 0 failed (включая существующие анти-дрейф
  `test_lite_setup_doc.py`, `test_no_host_hardcodes.py`, канон-тесты ORCH-009 — без правки их
  ассертов); `CHANGELOG.md` содержит запись `ORCH-103`.
- **FAIL:** хотя бы один тест красный; существующий анти-дрейф тест «починен» ослаблением
  ассертов; CHANGELOG не обновлён.

---

## AC-6 — Корневой compose и рантайм не тронуты

**Условие:** изоляция от боевого контура (NFR-1/NFR-2, BR-1/BR-8).
- **PASS:** `git diff main` НЕ содержит изменений `src/**`, корневого `docker-compose.yml`,
  `Dockerfile`, `.gitea/workflows/**`; bundle-compose — отдельный файл; множество сервисов
  корневого compose неизменно (`orchestrator`/`orchestrator-watchdog`/`orchestrator-staging`);
  ни один артефакт задачи не исполняется в нашем контуре автоматически (нет правок
  деплой-хука/CI, нет cron/врезок).
- **FAIL:** любая правка рантайма/корневого compose/Dockerfile; сервисы `plane*`/`gitea*`
  добавлены в корневой compose; артефакт bundle задействован в нашем прод/staging-контуре.

---

## AC-7 — Нулевой дрейф канонов: кирпичи переиспользованы

**Условие:** BR-6 — единственный источник истины для статусов/лейблов/секретов/smoke.
- **PASS:** bootstrap вызывает `scripts/gen_secrets.py` (webhook-секреты) и
  `scripts/onboard_project.py` (статусы/лейблы/репо/вебхуки) — структурный тест подтверждает
  ссылки; собственного списка статусов/лейблов в bundle-артефактах нет (упоминание числа
  статусов в доке сверяется импортом `plane_sync._PLANE_NAME_TO_KEY` в тесте, не литералом);
  smoke-раздел ссылается на REPLICATION §4.
- **FAIL:** bootstrap/док несут собственную копию канона (свой список статусов, свой генератор
  webhook-секретов, свой smoke-чеклист с нуля) — дрейф при будущих изменениях канона.

---

## AC-8 — Идемпотентность и fail-safe bootstrap

**Условие:** BR-7 — повторный запуск и грязный хост.
- **PASS:** повторный запуск bootstrap на уже-инициализированном bundle завершается успешно
  (ensure/skip, без дублей и без разрушения состояния); preflight на грязном/непригодном хосте
  (существующие тома bundle, занятый порт, нехватка RAM/диска) → явный отказ с понятной
  подсказкой ДО любых мутаций; delete-операций нет (teardown — только отдельный
  явный режим/процедура, не часть обычного прогона); exit-коды: 0 — успех, 2 — manual-step/
  предусловие, 1 — ошибка; секреты в логи не печатаются; повторный запуск не перетирает
  существующие секреты без явного флага.
- **FAIL:** повторный запуск ломает/дублирует состояние; bootstrap молча переиспользует чужие
  тома или продолжает после провального preflight; обычный прогон удаляет данные; секрет виден
  в stdout/логе.

---

## AC-9 — Секрет-гигиена и переносимость новых артефактов

**Условие:** NFR-3/NFR-4/NFR-6 по файлам репо.
- **PASS:** структурные тесты подтверждают: в bundle-compose/доке/скрипте нет
  FORBIDDEN-литералов (список — импорт из `test_no_host_hardcodes.py`) и высокоэнтропийных
  литералов (hex ≥32 / alnum ≥40); все сторонние образы bundle-compose пиннованы (не `latest`);
  все env-ключи, упомянутые в BUNDLED_SETUP.md, существуют в канонах (`.env.example` ∪
  bundle-конфиг-канон); сгенерированные на хосте конфиги — в `.gitignore`.
- **FAIL:** найден хост-литерал/секрет; образ без пина; ключ-фантом в доке (нет в канонах);
  сгенерированный конфиг коммитится.

---

## Сводная матрица AC ↔ BR/FR

| AC | Покрывает | Способ проверки |
|----|-----------|-----------------|
| AC-1 | BR-1, BR-2 / FR-1, FR-2 | ручной e2e на тестовом хосте + структурные тесты (TC-01..04, TC-08) |
| AC-2 | BR-3 / FR-2, FR-6 | ручной e2e (smoke REPLICATION §4) |
| AC-3 | BR-4 / FR-3 | ручной e2e + структурные тесты (TC-06, TC-09) |
| AC-4 | BR-5 / FR-4 | структурный тест дока (TC-05) + ревью |
| AC-5 | BR-9 / FR-5, FR-6 | `pytest tests/ -q` (TC-12) + CHANGELOG (TC-11) |
| AC-6 | BR-1, BR-8 / NFR-1, NFR-2 | git diff + существующий анти-дрейф (TC-02) |
| AC-7 | BR-6 / FR-2, FR-3 | структурный тест bootstrap/дока (TC-07, TC-10) |
| AC-8 | BR-7 / FR-2 | unit-тесты чистых функций preflight/плана (TC-08) + ручной повторный прогон |
| AC-9 | NFR-3, NFR-4, NFR-6 / FR-1, FR-4 | структурные тесты гигиены (TC-03, TC-06, TC-09) |
