B6 built the project registry by importing src.projects locally (host-path hack
+ importlib.reload), so it evaluated ORCH_PROJECTS_JSON from the launcher's
process-env. On the deployer's canonical host run that var is unset → built-in
default (ET+ORCH) → false FAIL even when staging isolation is healthy.
- Add read-only additive endpoint GET /projects (src/main.py) returning
known_plane_project_ids + {plane_project_id, repo, work_item_prefix, name}
of the live process; no secrets. Existing routes unchanged.
- Rewrite B6 to fetch GET {base}/projects via the same stdlib _get helper as
A/B4/B5/C; drop the host-path hack and importlib.reload (launch-invariant).
- Isolate the verdict in pure _evaluate_b6(known) -> (passed, detail); contract
unchanged (PASS iff SANDBOX in known and prod ET/ORCH absent). Endpoint
degradation (non-200 / missing key / bad body / network) → deterministic FAIL.
- src/projects.py and .env* untouched.
Docs (golden source): API table + staging-gate B6 mechanic in
docs/architecture/README.md; B6 description + isolation row in
docs/operations/STAGING_CHECK.md; CHANGELOG entry.
Tests: tests/test_staging_check_b6.py (TC-01..TC-07), tests/test_projects_endpoint.py.
Refs: ORCH-048
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
11 KiB
Архитектура Orchestrator
Обзор
Мульти-агентный оркестратор разработки. Принимает webhooks от Plane (управление задачами) и Gitea (git-события), ведёт задачи по конвейеру стадий через Quality Gates, на каждой стадии запускает Claude CLI агента. Поддерживает несколько проектов (multi-repo) и self-hosting (дорабатывает сам себя).
Компоненты
- Webhook Receivers (
src/webhooks/plane.py,gitea.py) — приём событий, HMAC-проверка, дедупликация (_dedup.py). Роуты:POST /webhook/plane,POST /webhook/gitea. - State Machine (
src/stages.py) —STAGE_TRANSITIONS: переходы, агент и QG каждой стадии. Хелперы:get_next_stage,get_agent_for_stage,get_qg_for_stage,get_previous_stage. - Stage Engine (
src/stage_engine.py) — исполнение переходов, диспетчеризация QG (_run_qg), откаты, синхронизация с Plane. - Review/Test Parsers (
src/review_parse.py, ORCH-046) — defensive-извлечение дословного must-fix текста из артефактов для встраивания вtask_descзаворота:extract_review_findings(P0/P1 из12-review.md),extract_test_failures(фрагмент тела13-test-report.md). Контракт «never raise»: любая ошибка →"". - Quality Gates (
src/qg/checks.py) — проверки выхода со стадии, реестрQG_CHECKS. - Agent Launcher (
src/agents/launcher.py) — запуск Claude CLI агентов в изолированном git worktree, мониторинг, auto-advance. - Queue (
src/queue_worker.py, ORCH-1) — персистентная очередь задач (SQLitejobs), atomic claim, max_concurrency, ретраи, restart-safe. - Project Registry (
src/projects.py, ORCH-6) — Plane project id → repo + prefix; фильтрация вебхуков по проекту. - Plane Sync (
src/plane_sync.py) — синхронизация статусов/комментариев в Plane.
Конвейер и Quality Gates
created → analysis → architecture → development → review → testing → deploy-staging → deploy → done
↑ │
└──── REQUEST_CHANGES ──────┘ (откат на development, max 3 retries)
| Стадия | Агент (выход) | Quality Gate | Артефакт |
|---|---|---|---|
| created | analyst | — | — |
| analysis | architect | check_analysis_approved |
01-brd / 02-trz / 03-acceptance-criteria / 04-test-plan.yaml |
| architecture | developer | check_architecture_done |
06-adr/ |
| development | reviewer | check_ci_green |
код + PR |
| review | tester | check_reviewer_verdict |
12-review.md (verdict:) |
| testing | deployer | check_tests_passed |
13-test-report.md |
| deploy-staging | deployer | check_staging_status |
15-staging-log.md (staging_status:) |
| deploy | — | check_deploy_status |
14-deploy-log.md (deploy_status:) |
| done | — | — | — |
Реестр QG (QG_CHECKS): check_analysis_approved, check_analysis_complete, check_architecture_done, check_ci_green, check_review_approved, check_tests_passed, check_reviewer_verdict, check_tests_local, check_deploy_status, check_staging_status.
Канон гейтов: машинные вердикты читаются ТОЛЬКО из YAML-frontmatter, никогда из прозы. Лог-файлы мержатся в origin/main отдельным PR; гейт читает из origin/main.
Условный 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.
Агрегат staging-чеков пишет деплоер прогоном scripts/staging_check.py против живого orchestrator-staging (8501). Чек B6 «Registry: sandbox present, prod ET/ORCH absent» читает реестр работающего инстанса по HTTP (GET /projects), а не локальным импортом src.projects в process-env скрипта — иначе host-запуск без ORCH_PROJECTS_JSON давал ложный FAIL (ORCH-048, docs/work-items/ORCH-048/06-adr/ADR-001-b6-registry-via-http-endpoint.md). Вердикт изолирован в чистой функции _evaluate_b6(known); недоступность эндпоинта → детерминированный FAIL (без ложного PASS).
Откаты
- Reviewer REQUEST_CHANGES → откат на
development+ retry (MAX_DEVELOPER_RETRIES = 3). - Tester
check_tests_passedFAIL → откат наdevelopment+ retry. - Deploy / deploy-staging FAILED → откат на
development. get_previous_stageиспользует порядок ключейSTAGE_TRANSITIONS.
Обогащение task_desc при заворотах (ORCH-046)
При откате на development task_desc (попадает в .task-dev.md developer-агента) несёт дословный must-fix текст, а не только ссылку — чтобы агент видел суть претензий сразу и не повторял ту же ошибку:
- reviewer REQUEST_CHANGES → дословные пункты P0/P1 из секции
## Findingsфайла12-review.md(extract_review_findings); - tester
check_tests_passedFAIL →reasonгейта + фрагмент тела13-test-report.md(приоритет:## Вывод pytest→ FAIL-строки## Результаты→## Итог;extract_test_failures).
Ссылка на полный файл-артефакт сохраняется всегда («Полный контекст»). Парсеры src/review_parse.py — defensive (never-raise); при отсутствующем/битом артефакте task_desc graceful-фоллбэк на прежнюю ссылку-строку, последовательность отката и retry-счётчик не меняются (ADR docs/work-items/ORCH-046/06-adr/ADR-001-embed-findings-in-task-desc.md).
Plane Sync: единый status-коммент агентов (ORCH-016)
Все агенты (analyst / architect / developer / reviewer / tester / deployer) пишут финальный коммент через один хелпер usage.build_status_comment(...) (ADR docs/work-items/ORCH-016/06-adr/ADR-001-unified-status-comment.md). Формат HTML, разделители <br>:
{ICON} {RoleName} — {описание стадии}
[Verdict|Status: VALUE] # reviewer/tester/deployer, из YAML-frontmatter артефакта
[Длительность: 4m 12s] # явный duration_s от launcher, либо fallback из agent_runs
<b>Документы:</b><ul><li><a href="…">label</a></li>…</ul>
[<sub>8.5M in / 45.8k out · $7.29</sub>] # тех-хвост usage; опускается при нулях
- Длительность считается launcher'ом (
_monitor_agent) и пробрасывается в_post_usage_comments; для analyst (коммент строится вstage_engine) используется DB-фоллбэкusage.get_agent_duration(task_id, agent). - Vердикт-парсер —
src/frontmatter.read_frontmatter_value(...)(defensive, никогда не raise). Машинные ключи: reviewer →verdict:(12-review.md); testing-гейтcheck_tests_passed(13-test-report.md) → любое из трёх равноправных:result:(канон промпта тестера),verdict:,status:(ORCH-047, ADR-001); deployer →deploy_status:(14-deploy-log.md),staging_status:(15-staging-log.md). Negative-токен в любом поле авторитетен (перебивает positive). - Формат коммента не меняет реестр гейтов и стадий; коммент — отображение, не управление.
База данных (SQLite)
events— входящие вебхуки (дедуп)tasks— задачи и их стадииagent_runs— запуски агентов (run_id, usage, cost)jobs— очередь задач (ORCH-1)
Изоляция (git worktree, ORCH-2)
Каждая задача исполняется в отдельном git worktree, ветки не пересекаются. Репозитории проектов разделены под /repos/<project>.
API
| Method | Path | Описание |
|---|---|---|
| GET | /health |
health check |
| GET | /status |
активные задачи (stage != done) |
| GET | /queue |
очередь: counts + max_concurrency + последние jobs |
| GET | /projects |
read-only реестр проектов живого инстанса: known_plane_project_ids + список {plane_project_id, repo, work_item_prefix, name} (без секретов). Источник достоверности для staging-чека B6 (ORCH-048) |
| POST | /webhook/plane |
Plane webhook |
| POST | /webhook/gitea |
Gitea webhook (push, PR, CI status) |
Деплой и эксплуатация
Топология, контейнеры, порты, env-карта, self-hosting риски — docs/operations/INFRA.md. Деплой-хук — DEPLOY_HOOK.md. Staging — STAGING.md.
ADR
Сквозные архитектурные решения — adr/. Per-work-item решения — docs/work-items/<id>/06-adr/.
Детали реализации
Схема БД, потоки данных, resilience-слой, детали Dockerfile — internals.md.
Актуально на 2026-06-06 (ORCH-048: + GET /projects). Обновлять при изменении src/stages.py, src/qg/checks.py, src/main.py.