Files
orchestrator/docs/overview/tech-quality-security.md
claude-bot b50cf1dd08
All checks were successful
CI / test (push) Successful in 1m8s
CI / test (pull_request) Successful in 1m8s
feat(staging): deterministic staging-runner replacing LLM deployer on deploy-staging (ORCH-115)
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>
2026-06-16 01:59:43 +03:00

83 lines
7.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Блок 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).*