Replace the LLM `deployer` agent on the `deploy-staging` stage (self-hosting orchestrator) with a deterministic staging-runner intercepted in launch_job BEFORE _spawn (the deploy-finalizer / post-deploy-monitor reserved-agent precedent). The runner executes the SAME staging suite, maps the exit-code to `staging_status:` via the existing self_deploy.map_exit_code_to_status contract, writes 15-staging-log.md, and initiates the UNCHANGED check_staging_status gate exactly as a finished LLM-deployer would. Invariant (NFR-1): this replaces only the *producer* of the artifact — the artifact contract, the gate / _parse_staging_status / check_staging_status name, STAGE_TRANSITIONS, the machine-verdict key `staging_status:` and the DB schema are byte-for-byte unchanged. Additive, under a kill-switch + repo-scope CSV, never-raise, fail-safe back to the LLM path. Two-level outcome (D5, anti ORCH-110): suite executed -> verdict -> advance (FAILED -> the existing deploy-staging -> development rollback + developer-retry, same as a FAILED LLM verdict); tool-error (suite did not execute) -> bounded DEFER -> fail-closed FAILED + alert on exhaustion (infra != code fault; never a silent advance / false green). First implemented slice of the LLM determinization roadmap (ORCH-118 A6, replace-deterministic-now). - New leaf src/staging_runner.py (never-raise; proc_group tree-kill + timeout) - launch_job intercept + _run_staging_runner_job (mirror _run_deploy_finalizer_job) - config: ORCH_STAGING_RUNNER_* keys (enabled/repos/timeout/infra-retry budget) - GET /queue staging_runner observability block - docs: llm-call-sites/roadmap/usage-policy (A6 implemented; machine blocks + single-transport invariant intact), deployer.md (LLM branch -> fallback), CLAUDE.md, CHANGELOG.md, overview (tech-pipeline/tech-agents/tech-quality-security), .env.example - tests/test_orch115_staging_runner.py (TC-01..TC-13); LLM anti-drift green (TC-14) Refs: ORCH-115 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
83 lines
7.3 KiB
Markdown
83 lines
7.3 KiB
Markdown
# Блок 6. Качество и безопасность
|
||
|
||
> Реестр гейтов и их распределение по стадиям — [блок 2](tech-pipeline.md); механизм
|
||
> machine-verdict доков — [PIPELINE_DOCS §3](../_standards/PIPELINE_DOCS.md); машинный
|
||
> контракт стадий — [HANDOFF_PROTOCOL](../_standards/HANDOFF_PROTOCOL.md).
|
||
|
||
## Философия Quality Gates
|
||
|
||
**Вердикты — машинные, никогда проза.** Гейт читает вердикт ТОЛЬКО из YAML-frontmatter
|
||
артефакта (ключи вида `verdict:`, `result:`, `staging_status:`, `deploy_status:`,
|
||
`security_status:` — имена и регистр неизменны байт-в-байт). Агент не может «уговорить» гейт
|
||
красивым отчётом: нет ключа — нет прохода. Парсинг frontmatter сведён к единому контракту
|
||
`src/frontmatter.py` — одна точка чтения для всех гейтов.
|
||
|
||
**Гейт ≠ маршрутизация.** Маршруты задач (багфикс-трек, авто-лейблы, serial gate) — свойство
|
||
планировщика; ни один из них не ослабляет ни одного гейта. Любая новая способность платформы
|
||
проектируется так, чтобы реестр гейтов и карта стадий не трогались.
|
||
|
||
**Анти-петля.** Откаты на доработку ограничены (max 3 подряд); инструментальные сбои
|
||
вспомогательных проверок по умолчанию fail-open с предупреждением (не запирают конвейер),
|
||
критичные проверки — fail-closed.
|
||
|
||
## Специальные гейты деплойного ребра
|
||
|
||
- **Security-гейт** (`check_security_gate`) — детерминированная (без LLM) проверка секретов и
|
||
зависимостей перед продом; вердикт — `security_status:` в отчёте задачи.
|
||
- **Coverage-гейт** (`check_coverage_gate`) — покрытие тестами измеряется на финальном коде
|
||
ветки; базовая линия по репозиторию растёт только вверх (ratchet при подтверждённом
|
||
слиянии) — покрытие не может деградировать молча.
|
||
|
||
Оба — врезки в переход ([блок 2](tech-pipeline.md)), включаются по конфигу и скоупятся по
|
||
репозиториям.
|
||
|
||
## Канон секретов
|
||
|
||
- Секреты живут **только в `.env`-файлах на хосте** и никогда не коммитятся; в git — только
|
||
канон-примеры с пустыми плейсхолдерами.
|
||
- Для нового хоста секреты **выпускаются свежими** (`scripts/gen_secrets.py`), боевые не
|
||
копируются.
|
||
- Анти-регресс машинный: структурные тесты сканируют исполняемый код на боевые хост-литералы,
|
||
а документацию — на секретоподобные значения; находка рвёт CI.
|
||
|
||
## Где уместен LLM: карта вызовов и нормативная политика
|
||
|
||
Платформа держит **доказательную карту** всех мест, где поток управления потребляет суждение
|
||
LLM, и **нормативную политику** «LLM — только там, где нужно настоящее суждение». Карта разводит
|
||
три факта: консультация ≠ транспорт/слот; **control-path** (вердикт LLM ветвит поток управления)
|
||
≠ **artifact-producer** (детерминированный гейт судит артефакт независимо); и деривируемость
|
||
вердикта из tool-сигналов. Путь называется **avoidable LLM control path**, когда он одновременно
|
||
control-path и его вердикт деривируем из exit-кодов (тогда консультацию можно заменить
|
||
детерминированным раннером). Поимённо: avoidable = `{tester, deployer}`; настоящее суждение
|
||
сохраняется у `{analyst, architect, developer, reviewer}`. Карта — снимок, прибитый структурными
|
||
анти-дрейф тестами. **Первый срез реализован (ORCH-115):** на `deploy-staging` для self-hosting
|
||
`orchestrator` LLM-`deployer` заменён детерминированным `src/staging_runner.py` (вердикт
|
||
`staging_status:` = маппинг exit-кода staging-сюиты); LLM-ветвь остаётся fallback'ом, гейт
|
||
`check_staging_status` не тронут. Замена второго кандидата (`tester`) — follow-up по роли.
|
||
|
||
- Карта вызовов LLM: [`../architecture/llm-call-sites.md`](../architecture/llm-call-sites.md)
|
||
- Нормативная политика: [`../architecture/llm-usage-policy.md`](../architecture/llm-usage-policy.md)
|
||
- Порядок замен: [`../architecture/llm-determinization-roadmap.md`](../architecture/llm-determinization-roadmap.md)
|
||
|
||
## Self-hosting-страховки
|
||
|
||
Платформа дорабатывает сама себя тем же конвейером — прод-инстанс при этом обслуживает и
|
||
другие проекты. Страховки:
|
||
|
||
- **Песочница обязательна:** перед прод-выкладкой платформы изменение репетируется на
|
||
staging-инстансе (отдельный порт/БД); guard не даёт staging-операциям коснуться прод-порта.
|
||
- **Прод-выкладка — только по явному человеческому статусу Confirm Deploy** (обычный approve
|
||
прод не выкатывает); деплой идёт детачнутым процессом с финализатором — честный исход
|
||
фиксируется даже при рестарте.
|
||
- **`main` неприкосновенен:** слияние только через PR-API, force-push запрещён всем.
|
||
- **Прод-контейнер никогда не роняется задачей**: агенты проверяют изменения локально и на
|
||
песочнице; рестарт прода — только штатным деплой-маршрутом.
|
||
- **Пост-деплой наблюдение:** после выкладки платформа следит за своим здоровьем; деградация
|
||
замораживает репозиторий и зовёт человека.
|
||
|
||
---
|
||
|
||
*Операционные детали и топология прода — `docs/operations/` (см.
|
||
[инженерный справочник](../architecture/README.md)); наблюдение за здоровьем —
|
||
[блок 7](tech-observability.md).*
|