architect(ET): auto-commit from architect run_id=297
All checks were successful
CI / test (push) Successful in 18s
All checks were successful
CI / test (push) Successful in 18s
This commit is contained in:
@@ -42,6 +42,16 @@ created → analysis → architecture → development → review → testing →
|
||||
### Условный staging-гейт (ORCH-35)
|
||||
`check_staging_status` реален только для self-hosting (`is_self_hosting_repo(repo)` → `orchestrator`); для остальных проектов → no-op `(True, "Staging gate N/A")`. Для orchestrator парсит `staging_status:` из `15-staging-log.md`; FAILED → откат на `development`. Подробнее: [ADR-0003](adr/adr-0003-staging-gate.md).
|
||||
|
||||
### Толерантность staging-вердикта к инфра-FAIL (ORCH-061 — design)
|
||||
Self-hosting зацикливался на `deploy-staging`: `scripts/staging_check.py` давал ложный FAILED на C9a/C9b (ветка в sandbox / analyst-job в очереди), вызванный **отсутствием sandbox-настроек** (bot-аккаунты не члены SANDBOX-проекта), а не регрессом кода → откат `deploy-staging → development` → петля. ORCH-061 классифицирует проверки suite на **REAL** (pipeline) и **SANDBOX_INFRA** (узкий allowlist `{C9a, C9b}`) и делает вердикт толерантным к инфра-FAIL, сохраняя fail-closed для реальных проверок:
|
||||
- Чистая логика — leaf-модуль `src/staging_verdict.py` (`classify_check`, `compute_staging_verdict`, never-raise). Упала хоть одна REAL → FAILED/exit1; упали ТОЛЬКО SANDBOX_INFRA и толерантность вкл → SUCCESS/exit0 (waived); waiver применяется только когда все REAL (вкл. C7/C8) зелёные.
|
||||
- `scripts/staging_check.py` помечает проверки категориями, считает вердикт через `staging_verdict`, печатает `INFRA-WAIVED` (наблюдаемость).
|
||||
- Kill-switch `staging_infra_tolerance_enabled` (env `ORCH_STAGING_INFRA_TOLERANCE_ENABLED`, дефолт `true`, в `.env.staging`); `false` → 1:1 прежнее строгое поведение.
|
||||
- `check_staging_status` / `_parse_staging_status` / `STAGE_TRANSITIONS` / реестр `QG_CHECKS` — **без изменений** (новый QG-чек не вводится); условность ORCH-35 и схема БД сохранены.
|
||||
- Инвариант: «no changes to commit» на action-стадиях (`deploy-staging`/`deploy`) не есть недовыполнение — продвижение определяется exit0 + гейт-вердиктом (launcher не откатывает; добавлена observability-строка).
|
||||
|
||||
Подробнее: [adr-0009](adr/adr-0009-staging-infra-tolerance.md), детально — `docs/work-items/ORCH-061/06-adr/ADR-001-staging-infra-tolerance.md`.
|
||||
|
||||
### Merge-gate: догон `main` + re-test + сериализация слияний (ORCH-043)
|
||||
Детерминированный под-гейт (`check_branch_mergeable`, без LLM) на ребре **`deploy-staging → deploy`**: исполняется ПОСЛЕ `check_staging_status` и ДО запуска deployer'а, который вливает PR в `main` (deployer мержит в начале стадии `deploy`). Стадии (`STAGE_TRANSITIONS`) НЕ меняются — это «под-гейт» ребра, а не отдельная стадия (триггер — то же событие «staging-deployer завершился»).
|
||||
|
||||
@@ -201,4 +211,4 @@ never-raise на единицу работы; тишина при синхрон
|
||||
Схема БД, потоки данных, resilience-слой, детали Dockerfile — [internals.md](internals.md).
|
||||
|
||||
---
|
||||
*Актуально на 2026-06-07. Обновлять при изменении src/stages.py, src/qg/checks.py, src/main.py. Статусы доработок: ORCH-036 (исполняемый самодеплой `deploy`, adr-0007) — реализовано; ORCH-043 (merge-gate, adr-0006) — design, ветка feature/ORCH-043; ORCH-053 (reconciler, adr-0007, src/reconciler.py) — реализовано; ORCH-060 (F-1 skip escalated/Blocked/Needs-Input, `docs/work-items/ORCH-060/06-adr/ADR-001`) — реализовано в ветке feature/ORCH-060 (Guard 1 `developer_retry_count>=MAX_DEVELOPER_RETRIES` + Guard 2 `plane_sync.fetch_issue_state` Blocked/Needs-Input, флаг `ORCH_RECONCILE_SKIP_BLOCKED_ENABLED`); ORCH-058 (провенанс staging-образа: check_staging_image_fresh + staging_check свежего образа + хук-guard, adr-0008) — реализовано в ветке feature/ORCH-058 (обновлять также при изменении src/image_freshness.py, scripts/orchestrator-deploy-hook.sh, Dockerfile).*
|
||||
*Актуально на 2026-06-07. Обновлять при изменении src/stages.py, src/qg/checks.py, src/main.py. Статусы доработок: ORCH-036 (исполняемый самодеплой `deploy`, adr-0007) — реализовано; ORCH-043 (merge-gate, adr-0006) — design, ветка feature/ORCH-043; ORCH-053 (reconciler, adr-0007, src/reconciler.py) — реализовано; ORCH-060 (F-1 skip escalated/Blocked/Needs-Input, `docs/work-items/ORCH-060/06-adr/ADR-001`) — реализовано в ветке feature/ORCH-060 (Guard 1 `developer_retry_count>=MAX_DEVELOPER_RETRIES` + Guard 2 `plane_sync.fetch_issue_state` Blocked/Needs-Input, флаг `ORCH_RECONCILE_SKIP_BLOCKED_ENABLED`); ORCH-058 (провенанс staging-образа: check_staging_image_fresh + staging_check свежего образа + хук-guard, adr-0008) — реализовано в ветке feature/ORCH-058 (обновлять также при изменении src/image_freshness.py, scripts/orchestrator-deploy-hook.sh, Dockerfile); ORCH-061 (толерантность staging-вердикта к инфра-FAIL C9a/C9b, adr-0009, `docs/work-items/ORCH-061/06-adr/ADR-001`) — design, ветка feature/ORCH-061 (обновлять также при изменении src/staging_verdict.py, scripts/staging_check.py, флаг staging_infra_tolerance_enabled).*
|
||||
|
||||
@@ -12,6 +12,14 @@ Per-work-item решения живут в `docs/work-items/<id>/06-adr/ADR-NNN-
|
||||
| adr-0005 | Контейнеры бегут под uid:gid хоста (1000:1000) | accepted | 2026-06-06 | ORCH-040 |
|
||||
| adr-0006 | Merge-gate (догон main + re-test + сериализация слияний) | proposed | 2026-06-06 | ORCH-043 |
|
||||
| adr-0007 | Reconciler застрявших стадий (sweeper потерянных webhook) | accepted | 2026-06-06 | ORCH-053 |
|
||||
| adr-0007 | Исполняемый самодеплой стадии `deploy` (файл adr-0007-executable-self-deploy) | accepted | 2026-06-06 | ORCH-036 |
|
||||
| adr-0008 | Провенанс staging-образа перед BUILD-ONCE retag | accepted | 2026-06-06 | ORCH-058 |
|
||||
| adr-0009 | Толерантность staging-вердикта к инфраструктурным FAIL | accepted | 2026-06-07 | ORCH-061 |
|
||||
|
||||
> ⚠️ Историческая коллизия: номер `0007` занят двумя файлами —
|
||||
> `adr-0007-reconciler.md` (ORCH-053) и `adr-0007-executable-self-deploy.md`
|
||||
> (ORCH-036). Оба accepted; для новых сквозных ADR использовать следующий
|
||||
> свободный номер (текущий максимум — `0009`).
|
||||
|
||||
## Формат
|
||||
**Контекст → Решение → Альтернативы → Последствия → Связи.** Статус: proposed / accepted / superseded.
|
||||
|
||||
56
docs/architecture/adr/adr-0009-staging-infra-tolerance.md
Normal file
56
docs/architecture/adr/adr-0009-staging-infra-tolerance.md
Normal file
@@ -0,0 +1,56 @@
|
||||
# adr-0009: Толерантность staging-вердикта к заведомо инфраструктурным FAIL
|
||||
|
||||
- **Статус:** accepted
|
||||
- **Дата:** 2026-06-07
|
||||
- **Задача:** ORCH-061
|
||||
- **Детально:** `docs/work-items/ORCH-061/06-adr/ADR-001-staging-infra-tolerance.md`
|
||||
|
||||
## Контекст
|
||||
Self-hosting `orchestrator` зацикливался на `deploy-staging`: `staging_check.py`
|
||||
давал 2 ложных FAIL (C9a — ветка в sandbox, C9b — analyst-job в очереди), вызванных
|
||||
отсутствием sandbox-настроек (bot-аккаунты не члены SANDBOX-проекта), а не регрессом
|
||||
кода. `staging_check.py` делал `sys.exit(1)` при любом FAIL → deployer писал
|
||||
`staging_status: FAILED` → `check_staging_status` FAILED → откат `deploy-staging →
|
||||
development` → петля (жгла developer-ретраи и кредиты). Прод-деплой орка приходилось
|
||||
доводить вручную — блокер автономного внедрения (ORCH-54).
|
||||
|
||||
## Решение
|
||||
Классифицировать проверки staging-suite на **REAL** (pipeline) и **SANDBOX_INFRA**
|
||||
(заведомо инфраструктурные, узкий allowlist `{C9a, C9b}`) и сделать вердикт
|
||||
толерантным к инфра-FAIL, сохранив fail-closed для реальных проверок:
|
||||
|
||||
- Новый leaf-модуль `src/staging_verdict.py` (pure, never-raise, stdlib):
|
||||
`classify_check(label)` + `compute_staging_verdict(items, infra_tolerant)`.
|
||||
Правило: упала хоть одна REAL → FAILED/exit1; упали ТОЛЬКО SANDBOX_INFRA и
|
||||
толерантность вкл → SUCCESS/exit0 (waived); толерантность выкл → legacy strict
|
||||
(любой FAIL → FAILED).
|
||||
- `scripts/staging_check.py` помечает проверки категориями, считает вердикт через
|
||||
`staging_verdict`, печатает `INFRA-WAIVED` при вайвере (наблюдаемость).
|
||||
- Kill-switch `staging_infra_tolerance_enabled` (env
|
||||
`ORCH_STAGING_INFRA_TOLERANCE_ENABLED`, дефолт `True`; в `.env.staging`).
|
||||
- `check_staging_status` / `_parse_staging_status` / `STAGE_TRANSITIONS` / реестр
|
||||
`QG_CHECKS` — **без изменений**; новый QG-чек не вводится. Условность ORCH-35
|
||||
сохранена (не-self → no-op N/A).
|
||||
- Инвариант FR-3: «no changes to commit» на action-стадиях (`deploy-staging`/`deploy`)
|
||||
не есть недовыполнение — продвижение определяется exit0 + гейт-вердиктом
|
||||
(launcher уже не откатывает; добавлена observability-строка).
|
||||
|
||||
## Альтернативы
|
||||
- Только починить sandbox-инфру (направление а) — хрупко, не структурно, вне
|
||||
автономной досягаемости таска; оставлено как опциональное hardening.
|
||||
- «Зелёный по умолчанию» при недоступности проверок — запрещён (fail-closed).
|
||||
- Новый QG-чек / структурный артефакт `15-staging-log.md` — избыточно, меняло бы
|
||||
контракты/реестр; толерантность размещена в suite до артефакта.
|
||||
|
||||
## Последствия
|
||||
- Петля устранена; страховка цела (реальный регресс → FAILED → откат).
|
||||
- Чистая вердикт-логика юнит-тестируема без live staging/docker.
|
||||
- Контракты гейтов/стадий/вердиктов/реестра и схема БД неизменны.
|
||||
- Риск: узкое окно — реальный регресс именно в создании ветки/постановке
|
||||
analyst-job может быть заваивен; митигировано allowlist'ом `{C9a,C9b}` + условием
|
||||
«все REAL (вкл. C7/C8) зелёные» + INFRA-WAIVED-логом. Разблокирует ORCH-54.
|
||||
|
||||
## Связи
|
||||
adr-0003 (условный staging-гейт — база `is_self_hosting_repo` / `check_staging_status`),
|
||||
adr-0006 (merge-gate), adr-0007 (исполняемый self-deploy), adr-0008 (провенанс
|
||||
staging-образа). Блокирует ORCH-54.
|
||||
@@ -0,0 +1,222 @@
|
||||
# ADR-001 — Толерантность staging-вердикта к инфра-FAIL + инвариант «no-changes на action-стадии»
|
||||
|
||||
- **Статус:** Accepted
|
||||
- **Дата:** 2026-06-07
|
||||
- **Задача:** ORCH-061 (BUG, P0) · Репо: `orchestrator` (self-hosting)
|
||||
- **Связи:** ORCH-35/adr-0003 (условный staging-гейт), ORCH-36/adr-0007 (исполняемый self-deploy), ORCH-58/adr-0008 (провенанс staging-образа), ORCH-43/adr-0006 (merge-gate); блокирует ORCH-54.
|
||||
- **Сквозной ADR:** [adr-0009-staging-infra-tolerance](../../../architecture/adr/adr-0009-staging-infra-tolerance.md)
|
||||
|
||||
---
|
||||
|
||||
## Контекст
|
||||
|
||||
На стадии `deploy-staging` self-hosting `orchestrator` зацикливается:
|
||||
`check_staging_status` даёт FAILED → `_handle_qg_failure_rollbacks` откатывает
|
||||
`deploy-staging → development` → developer перезапускается → конвейер заново →
|
||||
снова `deploy-staging` → снова FAILED. Петля жжёт developer-ретраи и LLM-кредиты,
|
||||
а прод-деплой орка приходится доводить вручную (ORCH-58, ORCH-60). Это прямой
|
||||
блокер автономного внедрения (ORCH-54).
|
||||
|
||||
Подтверждены две независимые причины (BRD §2):
|
||||
|
||||
**Причина №1 — ложный FAILED.** `scripts/staging_check.py` в sandbox даёт
|
||||
8/10 PASS, 2 ложных FAIL на e2e-блоке C:
|
||||
- **C9a** — ветка не появляется в `orchestrator-sandbox`;
|
||||
- **C9b** — analyst-job не появляется в staging-очереди.
|
||||
|
||||
Оба завязаны на отсутствие sandbox-настроек (bot-аккаунты `ORCH_PLANE_BOT_*` не
|
||||
добавлены членами SANDBOX-проекта — проект создан после провижининга ботов). Это
|
||||
**отсутствие инфраструктуры sandbox, а не регресс кода**. Но `staging_check.py`
|
||||
суммирует `all_ok = passed == total` и делает `sys.exit(1)` при любом FAIL →
|
||||
deployer пишет `staging_status: FAILED` → откат.
|
||||
|
||||
**Причина №2 — «no changes to commit» на action-стадии.** Стадии деплоя по природе
|
||||
действие (рестарт/retag), а не правка `src/`. Отсутствие git-изменений не должно
|
||||
трактоваться как недовыполнение; критерий успеха action-стадии — exit0 +
|
||||
health/staging-вердикт, а не наличие коммита.
|
||||
|
||||
### Что есть сейчас в коде (точки дефекта)
|
||||
|
||||
- `scripts/staging_check.py`: `Results.summary()` → `all_ok = passed == total`;
|
||||
`main()` → `sys.exit(0 if all_ok else 1)`. Все проверки равнозначны — инфра-FAIL
|
||||
неотличим от регресса.
|
||||
- `src/qg/checks.py` → `check_staging_status` / `_parse_staging_status`: читает
|
||||
`staging_status:` (SUCCESS|FAILED) из `15-staging-log.md`. Условный (ORCH-35):
|
||||
для не-self репо → `(True, "Staging gate N/A …")`.
|
||||
- `src/stage_engine.py` → `_handle_qg_failure_rollbacks`: ветка
|
||||
`agent=="deployer" and qg=="check_staging_status"` → откат на `development`.
|
||||
- `src/agents/launcher.py` → `_monitor_agent`: ветка «no changes to commit» (строка
|
||||
~583) **уже** просто логирует и идёт в `_try_advance_stage` (НЕ откатывает).
|
||||
|
||||
## Рассмотренные направления (BRD §6)
|
||||
|
||||
- **(а) Починить sandbox-инфру** — добавить bot-токены SANDBOX, чтобы C9a/C9b
|
||||
проходили честно (10/10).
|
||||
- *Минусы:* хрупко (зависит от членства ботов в Plane-проекте, поддерживается
|
||||
руками вне кода); не предотвращает структурно будущие инфра-only FAIL;
|
||||
автономный self-deploy-таск не может надёжно выполнить Plane-admin действия сам.
|
||||
Не закрывает Причину №1 на уровне инварианта.
|
||||
- **(б) Отвязать вердикт от заведомо инфраструктурных проверок** — классифицировать
|
||||
проверки suite и сделать вердикт толерантным к инфра-FAIL, сохранив fail-closed
|
||||
для реальных проверок.
|
||||
- *Плюсы:* структурно, юнит-тестируемо (чистая вердикт-логика), управляемо
|
||||
(kill-switch), наблюдаемо (FR-7); сохраняет страховку (FR-4) по построению.
|
||||
|
||||
## Решение
|
||||
|
||||
Выбран механизм **(б)** как основной, с явной фиксацией инварианта по Причине №2.
|
||||
Направление (а) переведено в **необязательное hardening** (см. `07-infra-requirements.md`):
|
||||
с (б) оно перестаёт быть блокером.
|
||||
|
||||
### 1. Классификация проверок + толерантный вердикт (Причина №1, FR-2/FR-4)
|
||||
|
||||
Новый **leaf-модуль `src/staging_verdict.py`** — чистая логика, без I/O, контракт
|
||||
**never-raise**, только stdlib (импортируем и из orchestrator, и из
|
||||
`staging_check.py`, который уже импортирует `src.*` внутри контейнера — паттерн B6/ORCH-048):
|
||||
|
||||
```
|
||||
REAL = "real" # реальная pipeline-проверка
|
||||
SANDBOX_INFRA = "sandbox_infra" # заведомо зависит от sandbox-инфры
|
||||
|
||||
# Узкий allowlist известных инфра-проверок (по префиксу метки):
|
||||
SANDBOX_INFRA_CHECKS = frozenset({"C9a", "C9b"})
|
||||
|
||||
def classify_check(label: str) -> str:
|
||||
"""SANDBOX_INFRA если метка начинается с известного инфра-префикса, иначе REAL.
|
||||
Never-raise: на любом непонятном вводе → REAL (консервативно, fail-closed)."""
|
||||
|
||||
def compute_staging_verdict(items, infra_tolerant: bool) -> StagingVerdict:
|
||||
"""items: список (label, passed: bool, category: str).
|
||||
real_failed = [REAL-проверки с passed=False]
|
||||
infra_failed = [SANDBOX_INFRA-проверки с passed=False]
|
||||
- real_failed непусто -> FAILED, exit 1 (страховка)
|
||||
- infra_failed непусто и infra_tolerant -> SUCCESS, exit 0 (waived)
|
||||
- infra_failed непусто и НЕ infra_tolerant -> FAILED, exit 1 (legacy strict)
|
||||
- иначе -> SUCCESS, exit 0
|
||||
Never-raise: на битом вводе → консервативный FAILED."""
|
||||
```
|
||||
|
||||
`StagingVerdict` несёт `status` (`"SUCCESS"|"FAILED"`), `exit_code` (`0|1`),
|
||||
`waived` (список заваиверенных меток) и `summary` (человекочитаемая строка).
|
||||
|
||||
**Ключевой инвариант страховки (FR-4):** любая упавшая REAL-проверка ⇒ exit 1 ⇒
|
||||
FAILED ⇒ откат. В частности C7 (создать issue) и C8 (триггер `/webhook/plane`) —
|
||||
REAL. Waiver применяется к C9a/C9b **только** когда все REAL-проверки (включая
|
||||
C7/C8) зелёные. Вход в конвейер по-прежнему валидируется C7/C8; C9a/C9b проверяют
|
||||
лишь downstream-артефакты, которым нужна sandbox-инфра. Так blast-radius waiver'а
|
||||
сведён к двум именованным проверкам.
|
||||
|
||||
### 2. Правки `scripts/staging_check.py`
|
||||
|
||||
- `Results.add(label, passed, detail="", category=None)` — при `category is None`
|
||||
авто-классификация через `staging_verdict.classify_check(label)`; хранит категорию
|
||||
в элементе.
|
||||
- `Results.summary()` печатает разбивку по категориям (REAL / SANDBOX_INFRA).
|
||||
- `main()`:
|
||||
- резолвит флаг толерантности `_resolve_tolerance()` (см. ниже);
|
||||
- `verdict = compute_staging_verdict(results.items, infra_tolerant)`;
|
||||
- при `verdict.waived` печатает явную строку
|
||||
`INFRA-WAIVED: <labels> (known sandbox-infra; real checks green)` (FR-7);
|
||||
- `sys.exit(verdict.exit_code)`.
|
||||
- `_resolve_tolerance()`: читает `settings.staging_infra_tolerance_enabled` (через
|
||||
`from src.config import settings` — тот же паттерн, что B6). На ошибке импорта →
|
||||
**strict (False)** (fail-safe: не вайвить при нечитаемом конфиге) + warning.
|
||||
Опциональный CLI-флаг `--strict` принудительно выключает толерантность для ручных
|
||||
«честных» прогонов.
|
||||
|
||||
Прежние режимы (`--mode stub|full-real`) и проверки A/B/C7/C8 — без изменений.
|
||||
«Всегда 0» исключено: упавшая REAL-проверка всегда даёт exit 1 (TRZ §7).
|
||||
|
||||
### 3. Kill-switch (FR-6, AC-7)
|
||||
|
||||
`src/config.py`:
|
||||
```python
|
||||
# ORCH-061: толерантность staging-вердикта к заведомо инфраструктурным FAIL
|
||||
# (C9a/C9b) в sandbox. True -> упавшие ТОЛЬКО sandbox-инфра проверки вайверятся
|
||||
# (real-проверки fail-closed). False -> 1:1 прежнее строгое поведение (любой FAIL
|
||||
# -> staging_status FAILED -> откат). Env ORCH_STAGING_INFRA_TOLERANCE_ENABLED.
|
||||
staging_infra_tolerance_enabled: bool = True
|
||||
```
|
||||
|
||||
Дефолт **True** (как `merge_gate_enabled` / `image_freshness_enabled` /
|
||||
`self_deploy_enabled`): инвариант страховки (FR-4) держится независимо от флага —
|
||||
реальные провалы всё равно fail-closed; флаг существует, чтобы мгновенно вернуть
|
||||
legacy-строгость без передеплоя кода. Флаг живёт в `.env.staging` контейнера
|
||||
(`ORCH_` prefix), поэтому достижим скриптом внутри `orchestrator-staging`.
|
||||
`False` → suite строгий → 1:1 поведение до ORCH-061 (AC-7).
|
||||
|
||||
### 4. Что НЕ меняется (контракты, AC-8)
|
||||
|
||||
- `check_staging_status` / `_parse_staging_status` — **без изменений**: читают
|
||||
`staging_status:` (только YAML, `SUCCESS|FAILED`). Толерантность реализована
|
||||
ДО артефакта (в exit-code suite → вердикт deployer), внутри существующего пути
|
||||
staging-вердикта, не отдельной стадией (TRZ §6).
|
||||
- **Новый QG-чек НЕ добавляется** → реестр `QG_CHECKS` и снапшот-тест
|
||||
(`tests/test_qg_registry_snapshot.py`) неизменны (AC-8 / TC-11).
|
||||
- `STAGE_TRANSITIONS`, `get_previous_stage`, exit-code хука деплоя (0/1/2),
|
||||
`map_exit_code_to_status`, `check_deploy_status`, БАГ-8 — без изменений.
|
||||
- Условность self-hosting (AC-6): `staging_check.py` канонически бежит только для
|
||||
`orchestrator`; `check_staging_status` для не-self репо остаётся
|
||||
`(True, "Staging gate N/A …")`. Поведение прочих репо байт-в-байт неизменно.
|
||||
|
||||
### 5. Инвариант «no-changes на action-стадии» (Причина №2, FR-3/AC-4)
|
||||
|
||||
`launcher._monitor_agent` **уже** не откатывает на «no changes to commit» (просто
|
||||
логирует и идёт в `_try_advance_stage`; продвижение определяется гейтом). ORCH-061:
|
||||
- **Фиксируем инвариант** как покрытый тестами контракт: на `deploy-staging`/`deploy`
|
||||
для self-deploy продвижение определяется exit0 + гейт-вердиктом, НИКОГДА наличием
|
||||
коммита (TC-06).
|
||||
- **Наблюдаемость (FR-7/AC-11):** в ветке «no changes» логировать явную строку,
|
||||
отличающую action-стадию (ожидаемо: артефакт-вердикт, не обязательно код) от
|
||||
code-стадии. Резолв стадии задачи по `(repo, branch)`; при
|
||||
`stage ∈ {deploy-staging, deploy}` и `self_deploy.self_deploy_applies(repo)` →
|
||||
`staging/deploy: no code changes (expected on action stage)`.
|
||||
- **Regression-guard (TC-07):** на `development` (code-стадия) поведение «no changes»
|
||||
неизменно — изменение FR-3 не протекает на не-action стадию.
|
||||
|
||||
Изменение минимальное (self-hosting safety, AC-12): не трогает прод-контейнер 8500,
|
||||
сборки/recreate — только staging (8501).
|
||||
|
||||
## Затронутые файлы (для developer)
|
||||
|
||||
| Файл | Изменение |
|
||||
|------|-----------|
|
||||
| `src/staging_verdict.py` | **новый** leaf-модуль: `classify_check`, `compute_staging_verdict`, `StagingVerdict` (pure, never-raise). |
|
||||
| `scripts/staging_check.py` | категории в `Results`, вердикт через `staging_verdict`, INFRA-WAIVED-лог, `--strict`. |
|
||||
| `src/config.py` | флаг `staging_infra_tolerance_enabled` (env `ORCH_STAGING_INFRA_TOLERANCE_ENABLED`). |
|
||||
| `src/agents/launcher.py` | observability-лог action-stage no-changes (без смены логики продвижения). |
|
||||
| `.openclaw/agents/deployer.md` | уточнение: exit0 может включать «infra-waived»; контракт `staging_status:` SUCCESS\|FAILED неизменен. |
|
||||
| `docs/operations/STAGING_CHECK.md` | поведение C9a/C9b, флаг, INFRA-WAIVED, `--strict`. |
|
||||
| `docs/architecture/README.md` | пометка ORCH-061 в разделе staging-гейта (уже внесена архитектором). |
|
||||
| `CHANGELOG.md` | запись ORCH-061. |
|
||||
| `tests/` | TC-01…TC-14 (см. `04-test-plan.yaml`). |
|
||||
|
||||
## Последствия
|
||||
|
||||
**Плюсы**
|
||||
- Петля устранена структурно: ложный инфра-FAIL → SUCCESS (waived) → нет отката (G1/G2).
|
||||
- Страховка цела: любая реальная pipeline-проверка fail-closed → FAILED → откат (G4/FR-4).
|
||||
- Чистая вердикт-логика юнит-тестируема без live staging/docker (NFR-тестируемость).
|
||||
- Контракты гейтов/стадий/вердиктов/реестра не тронуты (AC-8); схема БД не меняется (AC-9).
|
||||
- Мгновенный откат к legacy через kill-switch (AC-7).
|
||||
- Разблокирует автономный self-deploy (ORCH-54).
|
||||
|
||||
**Минусы / ограничения**
|
||||
- C9a/C9b теперь могут заваиверить **реальный** даунстрим-регресс именно в создании
|
||||
ветки / постановке analyst-job (узкий риск). Митигировано: waiver только когда C7/C8
|
||||
и все прочие REAL зелёные; allowlist жёстко = {C9a, C9b}; INFRA-WAIVED логируется и
|
||||
виден оператору. См. `10-tech-risks.md` (R-1).
|
||||
- Толерантность скрывает «нездоровье sandbox» как зелёное-с-допущением; отличимо
|
||||
только по INFRA-WAIVED-логу/комментарию (наблюдаемость обязательна, FR-7).
|
||||
- Honest 10/10 в sandbox (направление а) остаётся желательным hardening, но не блокером.
|
||||
|
||||
## Альтернативы (отклонены)
|
||||
|
||||
- **Только (а) — починить sandbox-инфру:** хрупко, не структурно, вне автономной
|
||||
досягаемости таска. Оставлено как опциональное hardening.
|
||||
- **«Зелёный по умолчанию» при недоступности проверок:** запрещён FR-4 (fail-closed).
|
||||
- **Новый QG-чек `check_staging_infra_tolerant`:** избыточно — менял бы реестр
|
||||
`QG_CHECKS` и снапшот; толерантность лучше живёт в suite/вердикте до артефакта.
|
||||
- **Толерантность внутри `check_staging_status` через структурный артефакт:**
|
||||
потребовал бы сменить контракт `15-staging-log.md` и научить deployer писать
|
||||
per-check категории — больше движущихся частей; отклонено в пользу решения в suite.
|
||||
37
docs/work-items/ORCH-061/07-infra-requirements.md
Normal file
37
docs/work-items/ORCH-061/07-infra-requirements.md
Normal file
@@ -0,0 +1,37 @@
|
||||
# 07 — Требования к инфраструктуре: ORCH-061
|
||||
|
||||
Work Item: **ORCH-061** · Репо: `orchestrator`
|
||||
|
||||
Топология/контейнеры/порты **не меняются** (TRZ §3, §9). Self-hosting-безопасность
|
||||
сохранена: прод-контейнер `orchestrator` (8500) не перезапускается/не роняется в
|
||||
рамках задачи; любые сборки/recreate — только staging (8501). См.
|
||||
`docs/operations/INFRA.md`.
|
||||
|
||||
## IR-1 — Конфиг-флаг (kill-switch)
|
||||
Новый флаг `staging_infra_tolerance_enabled` (env
|
||||
`ORCH_STAGING_INFRA_TOLERANCE_ENABLED`, дефолт `true`).
|
||||
|
||||
- Должен присутствовать в окружении контейнера **`orchestrator-staging`**
|
||||
(`.env.staging`), т.к. `scripts/staging_check.py` читает его через
|
||||
`src.config.settings` при каноническом запуске `docker exec` внутри стенда.
|
||||
- Для прод-инстанса (`.env`) флаг безвреден (на прод-пути staging-suite не
|
||||
исполняется), но рекомендуется держать значения консистентными.
|
||||
- `false` → мгновенный возврат к строгому (legacy) поведению без передеплоя кода.
|
||||
- Канон секретов/env: значения в `.env`/`.env.staging` на хосте, в гит НЕ
|
||||
коммитятся; задокументировать ключ в `.env.example` (канон ORCH-9).
|
||||
|
||||
## IR-2 — Опциональное hardening sandbox (направление «а», НЕ блокер)
|
||||
Первопричина ложных C9a/C9b — bot-аккаунты агентов (`ORCH_PLANE_BOT_*`) не добавлены
|
||||
членами Plane-проекта **SANDBOX** (`8c5a3025-…`), созданного после провижининга
|
||||
ботов. С выбранным механизмом (б) это перестаёт блокировать конвейер, но честный
|
||||
10/10 в sandbox желателен:
|
||||
|
||||
- Добавить bot-аккаунты агентов членами SANDBOX-проекта в Plane (даст честный
|
||||
C9b: коммент analyst'а перестанет получать 403; и устранит инфра-причину C9a/C9b).
|
||||
- Действие — ручное (Plane-admin), вне автоматической досягаемости таска; выполняется
|
||||
оператором при возможности. После него C9a/C9b проходят честно и waiver не нужен.
|
||||
- Это hardening, а не требование приёмки ORCH-061 (приёмка — на механизме «б»).
|
||||
|
||||
## IR-3 — Без новой инфраструктуры
|
||||
Новые сервисы/порты/тома/сетевые правила/cron — **не требуются**. Никаких
|
||||
изменений в `docker-compose.yml`, образах, реестре проектов.
|
||||
20
docs/work-items/ORCH-061/08-data-requirements.md
Normal file
20
docs/work-items/ORCH-061/08-data-requirements.md
Normal file
@@ -0,0 +1,20 @@
|
||||
# 08 — Требования к данным / схеме БД: ORCH-061
|
||||
|
||||
Work Item: **ORCH-061** · Репо: `orchestrator`
|
||||
|
||||
## DR-1 — Схема БД не меняется (AC-9)
|
||||
Никаких миграций. Таблицы `events`, `tasks`, `agent_runs`, `jobs` — без изменений
|
||||
колонок/индексов/таблиц.
|
||||
|
||||
## DR-2 — Никакого нового персистентного состояния
|
||||
Решение (ADR-001) — чистая вердикт-логика (`src/staging_verdict.py`) + конфиг-флаг +
|
||||
правка exit-code suite. Состояние конвейера не вводится:
|
||||
- толерантность вычисляется на лету при прогоне `staging_check.py`;
|
||||
- restart-safe-состояние не требуется (вердикт фиксируется в существующем артефакте
|
||||
`15-staging-log.md` через прежний контракт `staging_status: SUCCESS|FAILED`).
|
||||
|
||||
## DR-3 — Артефакт-контракт неизменен
|
||||
`15-staging-log.md` по-прежнему несёт frontmatter `staging_status: SUCCESS|FAILED`
|
||||
(только YAML). `14-deploy-log.md` (`deploy_status:`) — без изменений. Гейты читают
|
||||
ТОЛЬКО frontmatter. Толерантность реализована ДО записи артефакта (на уровне
|
||||
exit-code suite → вердикт deployer), поэтому формат и парсинг артефактов не трогаются.
|
||||
23
docs/work-items/ORCH-061/10-tech-risks.md
Normal file
23
docs/work-items/ORCH-061/10-tech-risks.md
Normal file
@@ -0,0 +1,23 @@
|
||||
# 10 — Технические риски: ORCH-061
|
||||
|
||||
Work Item: **ORCH-061** · Репо: `orchestrator` (self-hosting)
|
||||
|
||||
| # | Риск | Вероятн. | Влияние | Митигация |
|
||||
|---|------|----------|---------|-----------|
|
||||
| **R-1** | Waiver C9a/C9b маскирует **реальный** регресс именно в создании ветки / постановке analyst-job (ложно-зелёный staging). | Низкая | Высокое | Allowlist жёстко `{C9a, C9b}`; waiver применяется ТОЛЬКО когда ВСЕ REAL-проверки зелёные, включая C7 (создать issue) и C8 (триггер `/webhook/plane`) — вход в конвейер всегда валидируется реально. `INFRA-WAIVED`-строка в логе/комменте делает допущение видимым (FR-7). Honest 10/10 (IR-2) убирает риск совсем. |
|
||||
| **R-2** | Ослабление страховки: реальный pipeline-FAIL пройдёт как SUCCESS. | Низкая | Критич. | Инвариант `compute_staging_verdict`: любая упавшая REAL → exit1 → FAILED → откат (FR-4/AC-3/TC-05). Покрыто юнит-тестом отдельным кейсом. |
|
||||
| **R-3** | Флаг не достигает скрипта (читается не из того env) → толерантность «молча» не работает или, наоборот, не выключается. | Средняя | Среднее | Скрипт читает `settings.staging_infra_tolerance_enabled` через `from src.config import settings` — тот же канал, что B6/ORCH-048 (внутри `orchestrator-staging`, env `.env.staging`). На ошибке импорта — fail-safe в strict (False) + warning. Документировать ключ в `.env.staging`/`.env.example` (IR-1). Тест kill-switch (TC-09). |
|
||||
| **R-4** | Классификатор ошибочно пометит REAL-проверку как SANDBOX_INFRA (расширение allowlist в будущем). | Низкая | Высокое | `classify_check` — узкий префиксный allowlist; добавление новой инфра-метки требует осознанного PR + теста (TC-03). По умолчанию неизвестная метка → REAL (консервативно). |
|
||||
| **R-5** | Регресс совместимости: изменение exit-code suite ломает другие потребители (deploy-хук, ручные прогоны). | Низкая | Среднее | Exit-code семантика сохранена для honest-прогонов (всё PASS → 0; реальный FAIL → 1). Меняется лишь трактовка «только инфра-FAIL» (теперь 0 при толерантности). Deployer-маппинг exit0→SUCCESS/≠0→FAILED не меняется; deployer.md уточняется. `--strict` даёт ручной honest-режим. |
|
||||
| **R-6** | never-raise нарушен: исключение из `staging_verdict`/классификатора. | Низкая | Среднее | `src/staging_verdict.py` — pure, без I/O; контракт never-raise (на битом вводе → консервативный FAILED). Логика вне пути `advance_stage` (исполняется в subprocess suite), поэтому в конвейер исключение структурно не попадает (AC-10). |
|
||||
| **R-7** | FR-3: правка no-changes протекает на code-стадию (`development`) и маскирует «developer ничего не сделал». | Низкая | Среднее | Observability-строка ограничена `stage ∈ {deploy-staging, deploy}` и `self_deploy_applies(repo)`; логика продвижения launcher не меняется. Regression-guard TC-07. |
|
||||
| **R-8** | Self-hosting: правки случайно затронут прод 8500 / не-self репо. | Низкая | Критич. | Изменения только на self-deploy-пути и в suite (бежит лишь для `orchestrator`-staging). `check_staging_status` для не-self репо неизменно `(True, N/A)` (AC-6/TC-08). Сборки/recreate — только 8501. Прод 8500 не трогается (AC-12). |
|
||||
|
||||
## Контрактные инварианты (не нарушать)
|
||||
- `STAGE_TRANSITIONS`, `get_previous_stage` — без изменений.
|
||||
- Реестр `QG_CHECKS` — без изменений; новый QG-чек НЕ вводится (снапшот-тест зелёный, TC-11).
|
||||
- Frontmatter `staging_status:` / `deploy_status:` — только YAML, `SUCCESS|FAILED`.
|
||||
- Exit-code хука деплоя (0/1/2) и `map_exit_code_to_status` — без изменений.
|
||||
- БАГ-8 (`deploy → development`) и ORCH-35 (`deploy-staging → development`) для
|
||||
**реальных** провалов — сохранены.
|
||||
- Схема БД — без миграций.
|
||||
Reference in New Issue
Block a user