architect(ET): auto-commit from architect run_id=183
All checks were successful
CI / test (push) Successful in 14s

This commit is contained in:
2026-06-06 17:16:00 +00:00
parent 77e7205ce8
commit ad1589084b
7 changed files with 379 additions and 2 deletions

View File

@@ -34,17 +34,29 @@ created → analysis → architecture → development → review → testing →
| 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.
**Реестр 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, check_branch_mergeable (ORCH-043).
**Канон гейтов:** машинные вердикты читаются ТОЛЬКО из 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](adr/adr-0003-staging-gate.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 завершился»).
Назначение: ветка валидируется относительно того `main`, из которого создана; параллельная задача могла уйти вперёд → семантический конфликт слияния (зелёная ветка ломает обновлённый `main`). Merge-gate гарантирует проверку против **актуального** `origin/main` перед слиянием:
- **Догон:** ветка отстаёт (⇔ `origin/main` не предок HEAD) → `rebase origin/main` в worktree + `push --force-with-lease` (ТОЛЬКО ветка задачи; `main` — никогда). Текстовый конфликт → `rebase --abort` → откат на `development`.
- **Re-test:** `python -m pytest` (`merge_retest_target`, дефолт `tests/`) в worktree догнанной ветки, тайм-аут `merge_retest_timeout_s`. Красный/тайм-аут → откат на `development`.
- **Сериализация (merge-lock):** файловый **merge-lease** на репо (`<repos_dir>/.merge-lease-<repo>.json`), живёт от гейта до фактического merge. Acquire **неблокирующий** (anti-deadlock при `max_concurrency=1`): busy → **defer** (повторная постановка deployer'а на `deploy-staging` с задержкой через `available_at`), а не откат. Release — на PR-merged вебхуке / `deploy→done` / откате / по возрасту (crash-реклейм). Restart-safe; без изменения схемы БД.
- **Условность (как ORCH-35):** реален для `orchestrator`; прочие репо — no-op. Флаги `merge_gate_enabled` / `merge_gate_repos` — поэтапный раскат. Контракт **never-raise**.
Подробнее: [adr-0006](adr/adr-0006-merge-gate.md), детально — `docs/work-items/ORCH-043/06-adr/ADR-001-merge-gate.md`.
## Откаты
- Reviewer REQUEST_CHANGES → откат на `development` + retry (`MAX_DEVELOPER_RETRIES = 3`).
- Tester `check_tests_passed` FAIL → откат на `development` + retry.
- Deploy / deploy-staging FAILED → откат на `development`.
- Merge-gate FAIL (конфликт rebase / красный re-test, ORCH-043) → откат на `development` + retry; `merge-lock busy`**defer** (не откат, dev-retry не тратится).
- `get_previous_stage` использует порядок ключей `STAGE_TRANSITIONS`.
### Обогащение `task_desc` при заворотах (ORCH-046)
@@ -97,4 +109,4 @@ created → analysis → architecture → development → review → testing →
Схема БД, потоки данных, resilience-слой, детали Dockerfile — [internals.md](internals.md).
---
*Актуально на 2026-06-05 (main `f1b3146`). Обновлять при изменении src/stages.py, src/qg/checks.py, src/main.py.*
*Актуально на 2026-06-06. Обновлять при изменении src/stages.py, src/qg/checks.py, src/main.py. ORCH-043: merge-gate — design (см. adr-0006), реализация в ветке feature/ORCH-043.*

View File

@@ -10,6 +10,7 @@ Per-work-item решения живут в `docs/work-items/<id>/06-adr/ADR-NNN-
| adr-0003 | Условный staging-гейт перед прод-деплоем | accepted | 2026-06-05 | ORCH-35 |
| adr-0004 | Поллинг с ретраем в check_ci_green (фикс CI-race) | accepted | 2026-06-05 | ORCH-045 |
| 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 |
## Формат
**Контекст → Решение → Альтернативы → Последствия → Связи.** Статус: proposed / accepted / superseded.

View File

@@ -0,0 +1,53 @@
# adr-0006: Merge-gate — догон `main` + re-test + сериализация слияний
- **Статус:** proposed
- **Дата:** 2026-06-06
- **Задача:** ORCH-043
- **Детальный ADR:** `docs/work-items/ORCH-043/06-adr/ADR-001-merge-gate.md`
## Контекст
Ветка валидируется относительно того `main`, из которого создана, а не относительно `main`
на момент слияния. Параллельная задача могла влиться раньше → **семантический конфликт
слияния** (git мержит без текстового конфликта, но `main` сломан). Для self-hosting это
красный `main` инструмента, обслуживающего все проекты. Слияние в `main` делает
deployer-агент в начале стадии `deploy`; замена механизма PR-merge — вне объёма.
## Решение
Детерминированный merge-gate (`check_branch_mergeable`, без LLM) на ребре
`deploy-staging → deploy`, ДО запуска deployer'а, который мержит. `STAGE_TRANSITIONS` не
меняется (минимальный blast-radius); в `QG_CHECKS` добавлен `check_branch_mergeable`.
- **Догон:** ветка отстаёт ⇔ `origin/main` не предок HEAD → `rebase origin/main` в worktree
+ `push --force-with-lease` (ТОЛЬКО ветка задачи; `main` — никогда). Текстовый конфликт →
`rebase --abort` → откат на `development`.
- **Re-test:** `python -m pytest tests/` в worktree догнанной ветки, тайм-аут
`merge_retest_timeout_s`. Красный/тайм-аут → откат на `development`.
- **Сериализация (BR-5):** файловый **merge-lease** на репо
(`<repos_dir>/.merge-lease-<repo>.json`), живёт от гейта до фактического merge.
Acquire **неблокирующий** (anti-deadlock при `max_concurrency=1`): busy → **defer**
(re-enqueue deployer с задержкой через `available_at`), не rollback. Release — на
PR-merged вебхуке / `deploy→done` / откате / по возрасту (crash-реклейм). Restart-safe.
- **Условность (как ORCH-35):** реален для `orchestrator`; прочие репо — no-op. Флаги
`merge_gate_enabled` / `merge_gate_repos` для поэтапного раската.
## Альтернативы
- **Новая стадия `merge-gate`** (кандидат B) — «пустая» стадия без агента не имеет триггера
(`advance_stage` срабатывает только на завершении агента/вебхуке); потребовала бы chaining
в движке (не restart-safe) или синтетический job-тип. Отклонено.
- **Перенос merge в детерминированный шаг оркестратора** (кандидат C) — запрещён объёмом
(замена механизма PR-merge вне scope). Отклонено.
- **Блокирующий lock** — дедлок при одном worker-слоте. Отклонено в пользу defer.
## Последствия
- Сценарий «две зелёные ветки ломают `main`» закрыт: re-test против актуального `main` +
сериализация слияний.
- Плата: merge-gate — «скрытый» под-гейт ребра (нет в `STAGE_TRANSITIONS`); сериализация
опирается на PR-merged вебхук со страховкой реклеймом по возрасту; defer перепрогоняет
staging; длинный re-test держит worker-слот.
- Сквозное изменение конвейера → `arch:major-change`; прод-деплой ORCH-043 строго через
staging-гейт (8501).
## Связи
adr-0001 (`is_self_hosting_repo`), adr-0003 (условный staging-гейт — образец условности),
adr-0002 (очередь / `available_at` для defer), ORCH-2 (worktree-изоляция), ORCH-046
(дословный reason в `task_desc` при откате).