Addresses reviewer REQUEST_CHANGES (run 768) on ORCH-124 — docs-only, no src/tests touched, fix scope unchanged. P1: update docs/overview/ showcase for the new serial-gate "pause without blocking" axis (changed task-routing functionality, ORCH-011/ORCH-079): - tech-pipeline.md: FIFO exception "pause without blocking" next to freeze - tech-data-model.md: durable signal tasks.paused_at on the Task row - tech-observability.md: paused/reason in serial_gate GET /queue block + operator endpoints POST /serial-gate/pause|resume P2: strip leaked tool-call trailing tags (</content>/</invoke>) from 4 golden-source docs of this PR (06-adr/ADR-001, adr-0051, 08-data-requirements.md, 10-tech-risks.md). CHANGELOG "Доки" bullet extended accordingly. Full suite green (2178 passed); test_system_docs.py green (machine-checked showcase facts intact). Refs: ORCH-124 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
135 lines
12 KiB
Markdown
135 lines
12 KiB
Markdown
# Блок 2. Конвейер: стадии, гейты, маршруты
|
||
|
||
> Источник истины — карта переходов `STAGE_TRANSITIONS` в `src/stages.py` и реестр гейтов
|
||
> `QG_CHECKS` в `src/qg/checks.py`; перечень ниже сверяется с кодом структурным тестом
|
||
> (`tests/test_system_docs.py`). Норматив структуры доков конвейера —
|
||
> [PIPELINE_DOCS](../_standards/PIPELINE_DOCS.md).
|
||
|
||
## Схема конвейера
|
||
|
||
```
|
||
created → analysis → architecture → development → review → testing → deploy-staging → deploy → done
|
||
↑ │
|
||
└──── REQUEST_CHANGES ─────┘ (откат на доработку, max 3)
|
||
```
|
||
|
||
Плюс системный сток **`cancelled`** — терминальное состояние отменённой задачи (кнопка STOP,
|
||
см. ниже). Это не ребро конвейера, а равноправный `done` сток: попасть в него можно с любой
|
||
стадии, выйти — нельзя.
|
||
|
||
## Стадии и гейты выхода
|
||
|
||
Гейт выхода (exit-гейт) — машинная проверка, без которой задача не покидает стадию:
|
||
|
||
| Стадия | Кто работает | Гейт выхода (имя в реестре) | Что проверяет |
|
||
|--------|--------------|------------------------------|----------------|
|
||
| `created` | — | — | вход конвейера (вебхук Plane) |
|
||
| `analysis` | analyst | `check_analysis_approved` | пакет аналитики полон И постановка одобрена человеком |
|
||
| `architecture` | architect | `check_architecture_done` | ADR / инфра-требования зафиксированы |
|
||
| `development` | developer | `check_ci_green` | CI на ветке задачи зелёный |
|
||
| `review` | reviewer | `check_reviewer_verdict` | машинный вердикт ревью: APPROVED |
|
||
| `testing` | tester | `check_tests_passed` | машинный вердикт тестера: PASS |
|
||
| `deploy-staging` | deployer | `check_staging_status` | репетиция выкладки на песочнице успешна |
|
||
| `deploy` | deployer / finalizer | `check_deploy_status` | прод-выкладка реально успешна |
|
||
| `done` | — | — | терминал |
|
||
| `cancelled` | — | — | терминал (сток отмены) |
|
||
|
||
> **Детерминированный staging-раннер (ORCH-115).** На стадии `deploy-staging` для self-hosting
|
||
> `orchestrator` работу ведёт **детерминированный код** (`src/staging_runner.py`), а не LLM-агент
|
||
> `deployer`: он перехватывается в `launch_job` до запуска агента (как Phase A/B/C прод-деплоя),
|
||
> исполняет ту же staging-сюиту, маппит exit-код в `staging_status:` и инициирует **тот же** гейт
|
||
> `check_staging_status`. Это замена *продюсера* артефакта, а не гейта: контракт `15-staging-log.md`,
|
||
> имя/семантика `check_staging_status`, `STAGE_TRANSITIONS` — не изменились. Под kill-switch
|
||
> `staging_runner_enabled` (скоуп `staging_runner_repos`, пусто → self-hosting only); при выключении
|
||
> на стадии снова работает LLM-`deployer` байт-в-байт. Это первый реализованный срез
|
||
> determinization-roadmap (см. `docs/architecture/llm-determinization-roadmap.md`).
|
||
|
||
> **Детерминированный test-раннер (ORCH-116).** На стадии `testing` для self-hosting `orchestrator`
|
||
> работу ведёт **детерминированный код** (`src/test_runner.py`), а не LLM-агент `tester`: он
|
||
> перехватывается в `launch_job` до запуска агента (тем же паттерном, что staging-раннер), исполняет
|
||
> регресс `pytest` в worktree ветки + read-only smoke, маппит exit-код в `result:` и инициирует **тот
|
||
> же** гейт `check_tests_passed`. Это замена *продюсера* артефакта, а не гейта: контракт
|
||
> `13-test-report.md`, имя/семантика `check_tests_passed`/`_parse_tests_verdict`, `STAGE_TRANSITIONS`
|
||
> — не изменились. Под kill-switch `test_runner_enabled` (скоуп `test_runner_repos`, пусто →
|
||
> self-hosting only; репо без тест-контракта → LLM-tester); при выключении снова работает LLM-`tester`
|
||
> байт-в-байт. Это второй реализованный срез determinization-roadmap (гибрид: LLM-фолбэк остаётся на
|
||
> off-control-path триаж, не на вынесение `result:`).
|
||
|
||
## Под-гейты деплойного ребра — врезки, не стадии
|
||
|
||
На переходе `deploy-staging → deploy` исполняются четыре под-гейта в нормативном порядке
|
||
(security → merge → coverage → image-freshness):
|
||
|
||
1. `check_security_gate` — секреты/зависимости, вердикт из security-отчёта;
|
||
2. `check_branch_mergeable` — merge-gate: ветка догнана до свежего `main` (под merge-lease)
|
||
и мержабельна;
|
||
3. `check_coverage_gate` — покрытие тестами не ниже базовой линии/порога (baseline-ratchet);
|
||
4. `check_staging_image_fresh` — staging-образ собран из актуального кода.
|
||
|
||
Это **врезки в переход, а не стадии**: они не появляются в карте `STAGE_TRANSITIONS`, а
|
||
исполняются stage engine'ом внутри ребра. Провал любого из них — откат на доработку. Исключение
|
||
(ORCH-110): **инфра-таймаут** локального re-test merge-gate (а не детерминированный красный тест) —
|
||
это транзиент, а не дефект кода → ограниченный повтор + отдельный инфра-alert, без отката на
|
||
доработку и без расхода developer-retry (красный re-test/конфликт по-прежнему откатывают). На ребре
|
||
`deploy → done` аналогичная врезка merge-verify подтверждает, что код задачи реально слит в
|
||
`main` (слияние — только через PR-API Gitea, см. [интеграции](tech-integrations.md)).
|
||
|
||
## Откаты
|
||
|
||
`REQUEST_CHANGES` от ревьюера, проваленные тесты или красный под-гейт возвращают задачу на
|
||
стадию разработки с дословным перечнем замечаний. Лимит — 3 попытки подряд, дальше задача
|
||
останавливается и требует человека (анти-петля).
|
||
|
||
## Человеческие гейты и их снятие авто-лейблами
|
||
|
||
В штатном прогоне человек принимает ровно два решения:
|
||
|
||
- **Одобрение постановки** (на `analysis`): перевод задачи в статус Approved пропускает её
|
||
дальше;
|
||
- **Подтверждение прод-выкладки** (на `deploy`): отдельный статус **Confirm Deploy** — чтобы
|
||
привычный «approve» не выкатывал прод случайным кликом.
|
||
|
||
Оба решения можно снять декларативно — лейблами **autoApprove** / **autoDeploy** на задаче
|
||
(пакетный авто-режим). Снимается только ожидание человеческого сигнала: ни одна техническая
|
||
проверка не пропускается, autoDeploy физически не может выкатить непрошедшее под-гейты.
|
||
|
||
## Багфикс-маршрут
|
||
|
||
Задача с меткой **Bug** едет коротким путём: облегчённая аналитика (но полный пакет
|
||
документов) и пропуск стадии `architecture` — из аналитики сразу в разработку. Срезается
|
||
только аналитика/проектирование: **все гейты исполняются без изменений**. Сложный баг
|
||
эскалируется обратно в полный цикл.
|
||
|
||
## Последовательность внутри репозитория (serial gate)
|
||
|
||
Новая задача репозитория не входит в работу, пока не завершена более ранняя (FIFO): ветка
|
||
каждой задачи срезается от свежего `main`, уже содержащего код предшественника. Деградация
|
||
прода после выкладки замораживает репозиторий (freeze) до ручного разбора — следующие задачи
|
||
ждут.
|
||
|
||
У FIFO-порядка есть управляемое исключение — **пауза без блокировки**: оператор может явно
|
||
поставить более раннюю задачу на паузу (durable-сигнал `tasks.paused_at`), и тогда срочный
|
||
успешник её обгоняет, не дожидаясь завершения. Пауза — отдельная ось: она ≠ отмена (задача не
|
||
терминальна и возвращается в гейт обратной командой) и **не** обходит ни freeze, ни объявленные
|
||
зависимости. Свежесть базы возобновлённой задачи гарантируют те же механизмы (отложенный срез
|
||
ветки + ребейз на слиянии), что и для обычного FIFO.
|
||
|
||
## Отмена: STOP → `cancelled`
|
||
|
||
Перевод задачи в статус **STOP** останавливает агента, снимает job'ы с очереди, удаляет
|
||
рабочую ветку и worktree и переводит задачу в `cancelled`. Если задача в необратимой фазе
|
||
(идёт слияние/выкладка) — отмена откладывается и применяется после честного завершения шага.
|
||
STOP никогда не трогает `main` и прод-контейнер.
|
||
|
||
## Статусная модель Plane: индикация ≠ управление
|
||
|
||
Статусы в Plane — слой **индикации**: они показывают человеку осмысленную картину хода задачи,
|
||
но никогда не управляют конвейером (машина стадий — только `STAGE_TRANSITIONS`). Управляющих
|
||
статусов ровно три: запуск в работу, Approved/Confirm Deploy (человеческие гейты) и STOP
|
||
(отмена). Полная карта статусов — в [инженерном справочнике](../architecture/README.md).
|
||
|
||
---
|
||
|
||
*Кто работает на каждой стадии и что сдаёт — [агенты](tech-agents.md); как гейты читают
|
||
вердикты — [качество и безопасность](tech-quality-security.md).*
|