60 lines
5.8 KiB
Markdown
60 lines
5.8 KiB
Markdown
# adr-0017: Per-repo serial gate (пакетный автономный режим, serial e2e)
|
||
|
||
Статус: **proposed** · Дата: 2026-06-09 · Источник: **ORCH-088** (Этап 1)
|
||
Детально: `docs/work-items/ORCH-088/06-adr/ADR-001-serial-gate.md`.
|
||
|
||
## Контекст
|
||
Цель эпика ORCH-088 — масштаб автономности: накидать вечером 10–20 задач и получить к утру пакет,
|
||
последовательно проведённый через весь конвейер (analysis → … → deploy → done). Корневая проблема —
|
||
**stale-анализ**: ветка задачи N+1 срезается на входе в анализ (`start_pipeline._create_gitea_branch`)
|
||
от `main`, ещё не содержащего код предшественника N. Физическое код-затирание уже закрыто (ORCH-026
|
||
auto_rebase + merge-lease); остаётся **логический** разрыв. Plane API v1 не имеет bulk/relations ⇒
|
||
очередь/зависимости хранятся у оркестратора (gate по локальной БД).
|
||
|
||
## Решение
|
||
**Per-repo serial gate** — новая задача репо не входит в `analysis` (не режет ветку, не запускает
|
||
analyst), пока в том же репо есть незавершённая задача (`stage != 'done'`) или репо заморожен.
|
||
Три механизма, аддитивно, под kill-switch, с областью репо, never-raise, restart-safe:
|
||
|
||
1. **Gate-в-claim** (`db.claim_next_job`) — analyst-job (`jobs.agent='analyst'`) применимого репо не
|
||
выбирается, если `EXISTS` другая незавершённая задача репо ИЛИ активна строка `repo_freeze`. По
|
||
образцу `task_deps` `NOT EXISTS` (ORCH-026); только локальная БД (offline hot-path). Job'ы уже
|
||
активной задачи проходят свободно; rework-analyst не блокирует себя (`t2.id != jobs.task_id`).
|
||
2. **Отложенный срез ветки** — для применимого репо `start_pipeline` создаёт task-row + enqueue
|
||
analyst, но **не** создаёт Gitea-ветку/docs; срез релоцируется на момент claim analyst-job
|
||
(launcher), когда `origin/main` уже содержит предшественника (`done` ⇔ SHA-в-main, ORCH-071/073).
|
||
`ensure_worktree` режет от свежего `origin/main` ⇒ AC-6 структурно. Идемпотентно (409 = no-op).
|
||
3. **Durable per-repo freeze** (`repo_freeze`) — post-deploy `DEGRADED`/rollback (ORCH-021) →
|
||
`set_repo_freeze` + Telegram-алерт; gate закрыт безусловно до **ручного** снятия
|
||
(`POST /serial-gate/unfreeze`). Деградировавшая задача уже `done` (BR-7) ⇒ нужен отдельный сигнал.
|
||
|
||
Чистая логика — leaf `src/serial_gate.py` (never-raise). Флаги `serial_gate_enabled` (kill-switch),
|
||
`serial_gate_repos` (CSV; **пусто ⇒ все репо**, в отличие от self-hosting-only ORCH-35/43/58),
|
||
`serial_gate_freeze_enabled`. Наблюдаемость — блок `serial_gate` в `GET /queue`.
|
||
|
||
## Альтернативы
|
||
- **Гейт в `start_pipeline` + re-trigger при `done`** — больше состояния/путей, риск зависших задач;
|
||
relocation на claim переиспользует restart-safe `jobs`-очередь.
|
||
- **Freeze как колонка `tasks`** — неверная семантика (freeze per-repo, задача уже `done`).
|
||
- **Self-hosting-only область** — лишает enduro анти-stale-base (FR-3).
|
||
- **Отдельная таблица очереди ожидания** — избыточно; `jobs(queued)`+gate достаточно.
|
||
- **Снятие freeze Plane-жестом** — перегрузка статусов (анти-паттерн ORCH-059).
|
||
|
||
## Последствия
|
||
- **+** AC-6 закрыт структурно; AC-2/AC-3 «бесплатны» (ожидание = `queued` job без ветки);
|
||
переиспользование проверенных паттернов; cross-repo параллелизм сохранён; `STAGE_TRANSITIONS` /
|
||
`QG_CHECKS` / `check_*` / merge-gate / merge-verify / image-freshness / post-deploy / deploy-хук /
|
||
`max_concurrency` — **без изменений**.
|
||
- **NFR-1:** hot-claim тотальный сбой → **fail-open** (не заклинить очередь всех проектов); freeze в
|
||
Python-слое → **fail-closed** (безопасность прода).
|
||
- **−** Срез ветки/docs мигрируют из async в sync-путь launcher (обёртка); Blocked-задача держит пакет
|
||
(Этап 1, осознанно); freeze снимается только вручную.
|
||
- Откат: `serial_gate_enabled=False` ⇒ claim/старт 1:1 как до ORCH-088; таблица `repo_freeze` инертна.
|
||
- **Вне скопа** (Этап 1): merge-очередь FIFO, pre-merge rebase как отдельная фича, фазы A/B/C,
|
||
любой параллелизм задач внутри одного репо, зависимость от ORCH-83.
|
||
|
||
## Связи
|
||
- Переиспользует: adr-0002 (очередь ORCH-1), adr-0015 (claim-gate/auto_rebase/merge-lease ORCH-026),
|
||
adr-0010 (post-deploy monitor — источник DEGRADED), adr-0013/0014 (merge-verify ⇒ `done`⇔SHA-в-main).
|
||
- Новая аддитивная таблица `repo_freeze` (`docs/work-items/ORCH-088/08-data-requirements.md`).
|