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

# 03 — Критерии приёмки (Acceptance Criteria): ORCH-102 — ORCH-10a Lite-тираж

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

Формат: каждый критерий имеет **PASS** (что должно быть истинно для приёмки) и **FAIL**
(что считается провалом). Любой машинный/ручной reviewer проверяет их буквально по файлам
репозитория. AC-1…AC-5 — дословно из бизнес-запроса (уточнены до проверяемости);
AC-6…AC-7 — детализация скоупа (анти-дрейф / инварианты).

---

## AC-1 — `docs/deployment/LITE_SETUP.md`: полная пошаговая, без доп-вопросов

**Условие:** инструкция существует и покрывает сквозной маршрут Lite-тиража; каждый шаг —
команда/проверка; человек, не видевший платформу, разворачивает по ней без доп-вопросов.
- **PASS:**
  - файл `docs/deployment/LITE_SETUP.md` существует (путь — по исходу А-3; отклонение от пути
    бизнес-запроса зафиксировано в ADR задачи);
  - покрыты ВСЕ разделы нормативного перечня ТЗ §FR-1: рамка Lite/границы; предусловия хоста
    (зависимости, uid/gid: `ORCH_RUN_UID/GID`, `ORCH_DOCKER_GID` через `getent group docker`,
    владение `ORCH_HOST_REPOS_DIR`); перенос кода (чекаут `orchestrator`, без данных);
    конфигурация (`.env` с нуля от `.env.example` + `gen_secrets.py`, обязательные ключи нового
    хоста включая `ORCH_PROJECTS_JSON`); Plane (workspace/проект, точная модель статусов с
    fail-closed `Confirm Deploy`/`STOP`, API-токен, webhook+HMAC `X-Plane-Signature` + каверза
    Plane CE); Gitea (репо, токен со scope, per-repo webhook `X-Gitea-Signature`, один глобальный
    секрет, норматив защиты `main` по исходу А-1); LLM (claude CLI: дистрибутив/node/аутентификация/
    `ORCH_CLAUDE_BIN`/модели ORCH-41); Telegram (бот трекера + отдельный watchdog-бот +
    получение chat-id); запуск compose + health-чек (`/health`, `/queue`, `/metrics`);
    регистрация проекта (`onboard_project.py` → `ORCH_PROJECTS_JSON` → управляемый рестарт);
    smoke; stateless-проверка; траблшутинг (≥ 5 типовых отказов: симптом → диагностика → лечение);
  - **каждый** нормативный шаг несёт исполняемую команду (fenced code block) И явную проверку
    результата (маркер «Проверка:» / PASS-FAIL / ожидаемый вывод);
  - копируемые команды generic: хост-специфика только плейсхолдерами `<...>`/`$ENV_VAR`;
    боевых литералов (`mva154`, `duckdns`, `82.22.50.71`, реальные токены) в код-блоках нет;
  - «без доп-вопросов» подтверждено операционально: приёмочный smoke-прогон по инструкции
    выполнен на чистом контуре и зафиксирован (см. AC-4) + траблшутинг покрывает типовые отказы.
- **FAIL:** файла нет; ИЛИ отсутствует любой нормативный раздел FR-1; ИЛИ есть шаг без
  команды/проверки («настройте webhook» без как-проверить); ИЛИ в копируемых командах боевые
  URL/пути/секреты; ИЛИ инструкция отсылает за обязательным шагом во внешний (вне репо) источник.

---

## AC-2 — Compose-подмножество: только орк+watchdog

**Условие:** Lite разворачивает ровно `orchestrator`+`orchestrator-watchdog`; Plane/Gitea-контейнеров
нет; свойство зафиксировано и защищено.
- **PASS:**
  - `docker compose config --services` (без активных профилей, пустой env) →
    ровно `orchestrator` и `orchestrator-watchdog`;
  - `orchestrator-staging` присутствует в файле строго за `profiles: [staging]` (дефолтный
    `up -d` его не поднимает);
  - в `docker-compose.yml` нет сервисов/образов Plane/Gitea (ни `plane*`, ни `gitea*`);
  - LITE_SETUP.md документирует это свойство (что поднимется после `up -d` и почему staging
    опционален — исход А-5);
  - структурный тест compose-подмножества (TC-04) существует и зелёный;
  - если по исходу А-2 введён отдельный lite-compose — он покрыт тем же тестом, а existing
    `docker-compose.yml` не форкается без обоснования в ADR.
- **FAIL:** дефолтный запуск поднимает что-то кроме орк+watchdog; ИЛИ staging вне профиля;
  ИЛИ в compose появился Plane/Gitea-сервис; ИЛИ свойство не задокументировано; ИЛИ тест
  отсутствует/красный.

---

## AC-3 — Stateless: чистая БД, ни одной нашей задачи/секрета

**Условие:** инструкция предписывает чистый старт и не допускает переноса наших данных/секретов;
сама дока секретов не содержит.
- **PASS:**
  - LITE_SETUP.md нормативно фиксирует: БД создаётся пустой при первом старте (`data/` чист,
    переносить нечего); `.env`/`.env.staging`/`.env.watchdog` собираются с нуля; явная строка
    «данные/задачи/секреты боевого хоста НЕ переносятся» (зеркало REPLICATION.md §5);
  - секреты — только выпуск НОВЫХ: `gen_secrets.py` (webhook) + чек-лист внешних токенов
    (ссылка на REPLICATION.md §3); ни один шаг не предписывает копирование боевого секрета;
  - инструкция содержит проверку чистоты развёрнутого инстанса: первый `GET /queue` — нулевые
    счётчики jobs, ни одной задачи (`ORCH-*`/`ET-*`) в системе;
  - в самом доке и тестах задачи нет реальных секретоподобных значений (только плейсхолдеры);
    security-гейт (ORCH-022, `17-security-report.md`) — `PASS`.
- **FAIL:** любой шаг предписывает/допускает перенос БД/задач/боевого `.env`/секрета; ИЛИ нет
  нормативной stateless-строки; ИЛИ нет проверки чистоты; ИЛИ в доке обнаружен реальный
  секрет/боевой токен; ИЛИ security-гейт `FAIL`.

---

## AC-4 — Smoke на чистом окружении проходит

**Условие:** smoke существует как воспроизводимая процедура/чек-лист и подтверждён прогоном.
- **PASS:**
  - LITE_SETUP.md несёт smoke-раздел: чек-лист с явным PASS/FAIL на каждый шаг, построенный на
    REPLICATION.md §4 (ссылка, без форка процедуры): конфиг резолвится → `/health` →
    `/queue`+`/metrics` → тестовый проект (`onboard_project.py plan/apply/verify`) → тестовая
    задача → «конвейер доехал» (минимум: `analysis` отработала, артефакты `01–04` в ветке);
  - итог процедуры — однозначный вердикт (все шаги PASS ⇒ тираж PASS);
  - приёмочный прогон выполнен на чистом контуре — минимум staging-песочница
    (`ORCH_STAGING_PORT`, изолированная БД `./data/staging`) + одноразовый sandbox-проект
    (прецедент ORCH-101 AC-3 / ONBOARDING.md §5.2) — и зафиксирован в артефактах задачи
    (`13-test-report.md` и/или `15-staging-log.md`: дата, контур, шаги, вердикт);
  - процедура нигде не требует боевых данных/секретов (stateless, согласовано с AC-3).
- **FAIL:** smoke-раздела нет; ИЛИ шаги без явных PASS/FAIL («посмотреть, что всё ок»); ИЛИ
  процедура форкает REPLICATION.md §4 с расхождениями; ИЛИ заявленный прогон не зафиксирован в
  артефактах; ИЛИ прогон провален и не разобран.

---

## AC-5 — pytest зелёный; CHANGELOG; перекрёстные доки

**Условие:** регресс чист, документация согласована (правила агентов №2/№6).
- **PASS:**
  - полный `pytest tests/ -q` зелёный (включая новые структурные тесты задачи и существующие
    `test_no_host_hardcodes` / `test_replication_smoke` / `test_infra_parametrization` /
    `test_onboarding_*` — не ослаблены и не правлены под задачу без согласования);
  - `CHANGELOG.md` содержит запись ORCH-102;
  - `docs/operations/REPLICATION.md` §1: строка «Type A — Lite» обновлена (статус ✅/ссылка на
    LITE_SETUP.md) — границы 10-common vs Lite vs Bundled остаются честными;
  - `README.md`/`CLAUDE.md` обновлены, если фактический объём того требует (новая операторская
    способность — Lite-тираж; README не выдаёт нерешённое за решённое и наоборот).
- **FAIL:** любой тест красный; ИЛИ нет записи в CHANGELOG; ИЛИ REPLICATION.md §1 продолжает
  числить Lite «отдельной задачей» без ссылки; ИЛИ обзорные доки противоречат факту.

---

## AC-6 — Канон не форкается; анти-дрейф защита

**Условие:** инструкция — маршрутизатор поверх golden source'ов, её полнота защищена тестом.
- **PASS:**
  - канонические данные (22 статуса, карта env, формат вебхуков, онбординг, smoke) даны ссылкой
    на golden source (`ONBOARDING.md` §1 / `REPLICATION.md` §2–§4 / `SETUP_WEBHOOKS.md`); при
    дублировании таблицы — анти-дрейф тест сверяет дубль с источником истины (импорт из
    `src/plane_sync.py` / парсинг `.env.example`), не строковой копией;
  - `tests/test_lite_setup_doc.py` существует и проверяет минимум: наличие дока; обязательные
    кирпичи (ТЗ FR-6.1); согласованность упомянутых env-ключей с `.env.example` (FR-6.2);
    compose-подмножество (FR-6.3); stateless-норматив и отсутствие боевых литералов/секретов в
    код-блоках (FR-6.4); перекрёстность REPLICATION→LITE_SETUP и запись CHANGELOG (FR-6.5);
  - тест детерминирован (повторные прогоны стабильны, без сети/LLM).
- **FAIL:** таблица статусов/env скопирована без анти-дрейф сверки; ИЛИ тест отсутствует/не
  ловит исчезновение обязательного раздела/кирпича; ИЛИ упомянутый в доке env-ключ отсутствует
  в `.env.example`; ИЛИ тест флапает/ходит в сеть.

---

## AC-7 — Self-hosting безопасность и неизменность конвейера

**Условие:** задача не дестабилизирует общий прод и не меняет рантайм.
- **PASS:**
  - дифф задачи — `docs/**`, `tests/**`, `CHANGELOG.md` (+ согласованные обзорные доки,
    + `.env.watchdog.example` при исходе А-4); `src/**` не изменён — либо каждое отклонение
    обосновано в ADR задачи;
  - `STAGE_TRANSITIONS` / `QG_CHECKS` / `check_*` / machine-verdict ключи / схема БД —
    без изменений;
  - прод-контейнер `orchestrator` в рамках задачи не перезапускается; выкат — только штатным
    конвейером (deploy-staging 8501 → ручной Confirm Deploy);
  - инструкция не противоречит инвариантам платформы: ADR D10 ORCH-009 (без branch protection),
    C-1 ORCH-100 (watchdog-бот ≠ бот орка), ORCH-040 (uid/gid/HOME группа), ORCH-058
    (staging-порт ≠ прод-порт), INV-4 (мерж только через PR-merge API), конвенции тиража
    REPLICATION.md §1 (репо `orchestrator`, имена сервисов).
- **FAIL:** немотивированные правки `src/**`/compose/Dockerfile; ИЛИ дифф трогает машину
  стадий/QG/вердикты/схему БД; ИЛИ рестарт прода вне штатного деплой-пути; ИЛИ шаг инструкции
  предписывает запрещённое инвариантами (включить branch protection, переиспользовать токен орка
  для watchdog, скопировать боевой секрет и т.п.).

---

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

| AC | Покрывает |
|----|-----------|
| AC-1 | BR-1, BR-2 / FR-1, FR-4, NFR-6 |
| AC-2 | BR-3 / FR-2 |
| AC-3 | BR-4 / FR-3, NFR-3 |
| AC-4 | BR-5 / FR-5 |
| AC-5 | BR-7 / FR-7, NFR-2 |
| AC-6 | BR-6, BR-8 / FR-6, NFR-4, NFR-5 |
| AC-7 | NFR-1, NFR-2 / §7 ТЗ (инварианты) |
