architect(ET): auto-commit from architect run_id=687
This commit is contained in:
@@ -447,13 +447,47 @@ Self-hosting зацикливался на `deploy-staging`: `scripts/staging_ch
|
||||
Назначение: ветка валидируется относительно того `main`, из которого создана; параллельная задача могла уйти вперёд → семантический конфликт слияния (зелёная ветка ломает обновлённый `main`). Merge-gate гарантирует проверку против **актуального** `origin/main` перед слиянием:
|
||||
- **Догон:** ветка отстаёт (⇔ `origin/main` не предок HEAD) → `rebase origin/main` в worktree + `push --force-with-lease` (ТОЛЬКО ветка задачи; `main` — никогда). Текстовый конфликт → `rebase --abort` → откат на `development`.
|
||||
- **Безусловный pre-merge rebase (ORCH-026, A-2):** при `premerge_rebase_always` (дефолт `True`, скоуп `merge_gate_repos`) short-circuit `branch_is_behind_main` пропускается — `auto_rebase_onto_main` вызывается **всегда** под лизом. На актуальной ветке это no-op (`rebase` не меняет HEAD, `push --force-with-lease` → «Everything up-to-date», CI не триггерится); на отстающей — реальный догон. Детерминированный структурный анти-фантом на уровне планировщика (дополняет рубежи ORCH-073, не заменяет). Kill-switch `premerge_rebase_always=False` → прежнее поведение (ребейз только при behind).
|
||||
- **Re-test:** `python -m pytest` (`merge_retest_target`, дефолт `tests/`) в worktree догнанной ветки, тайм-аут `merge_retest_timeout_s`. Красный/тайм-аут → откат на `development`.
|
||||
- **Re-test:** `python -m pytest` (`merge_retest_target`, дефолт `tests/`) в worktree догнанной ветки, тайм-аут `merge_retest_timeout_s`. **Красный** → откат на `development`. **ORCH-110 (design):** (1) re-test исполняется лишь когда rebase реально сдвинул HEAD (`main` уехал); доказанный no-op rebase (ветка уже актуальна, HEAD уже прошёл CI+tester+staging) **пропускает** локальный re-test; (2) **таймаут** re-test — инфра-транзиент (ограниченный повтор + отдельный инфра-alert), а НЕ код-фейл (раньше шёл в откат на `development` + расход developer-retry); (3) спавненный pytest бежит в отдельной группе процессов и при таймауте убивается **деревом** (`os.killpg`) — нет осиротевших процессов (см. ниже).
|
||||
- **Сериализация (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-026 (A-1):** это окно = «merge → main-updated» (для self `done` ⇔ SHA-in-main, ORCH-073) — пока A не в `main`, B того же репо получает `merge-lock busy` → defer. Окно сериализации per-repo НЕ переписывается; кросс-репо параллелизм сохранён (лиз — per-repo файл).
|
||||
- **Условность (как 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`.
|
||||
Безусловный pre-merge rebase + связь с зависимостями задач — [adr-0015](adr/adr-0015-task-deps-and-merge-serialization.md) (ORCH-026).
|
||||
|
||||
#### Merge-gate re-test: толерантность к инфра-таймауту + tree-kill + контракт re-test (ORCH-110 — design)
|
||||
Инцидент ORCH-109/PR#129: при зелёном tester `PASS` (1899 passed / 516.7s), зелёном CI и актуальной
|
||||
ветке локальный re-test merge-gate упал по **таймауту** (600s) из-за CPU-голодания от **осиротевших**
|
||||
pytest-процессов (жили > 2 суток). Таймаут классифицировался как код-фейл → ложный откат
|
||||
`deploy-staging → development` + 3 сожжённых developer-retry → manual-gate. ORCH-110 бьёт по двум
|
||||
корням, одному контракту и бюджету — **аддитивно, под kill-switch, never-raise, скоуп self-hosting**;
|
||||
исходная защита merge-gate от семантического конфликта сохранена (красный re-test по-прежнему
|
||||
откатывает). `STAGE_TRANSITIONS`/`QG_CHECKS`/`check_*`/machine-verdict/схема БД — **не тронуты**.
|
||||
- **Tree-kill (root, D1):** новый leaf `src/proc_group.py::run_in_process_group` спавнит
|
||||
оркестратор-порождённые pytest-прогоны (`merge_gate.retest_branch` + `coverage_gate.measure_coverage`)
|
||||
в отдельной группе процессов (`start_new_session`) и при таймауте/прерывании убивает **всё дерево**
|
||||
(`os.killpg`, каскад SIGTERM→grace→SIGKILL, зеркало `launcher.stop_process`). Контракты возврата 1:1
|
||||
(меняется лишь побочный эффект — нет сирот); fallback на прежний `subprocess.run` при kill-switch off
|
||||
/ не-POSIX. Kill-switch `subprocess_tree_kill_enabled`.
|
||||
- **Классификация + маршрутизация (D2/D3):** чистый `merge_gate.classify_retest_failure(reason) →
|
||||
timeout|red|lock-busy|other`; инфра-таймаут → `_handle_merge_gate_infra_retry` (ограниченный
|
||||
повтор/defer по образцу `_handle_merge_gate_defer`, **без** отката на `development`, **без** расхода
|
||||
developer-retry; исчерпание → отдельный **инфра-alert**, не «developer must fix»); красный re-test →
|
||||
прежний `_handle_merge_gate_rollback`. Kill-switch `merge_retest_infra_tolerance_enabled`, бюджеты
|
||||
`merge_retest_infra_max_retries` (2) / `merge_retest_infra_retry_delay_s` (120s).
|
||||
- **Контракт re-test (D4):** локальный re-test исполняется ⇔ rebase реально сдвинул HEAD; доказанный
|
||||
no-op rebase пропускает re-test (как уже делает путь `premerge_rebase_always=False` для не-behind
|
||||
ветки), offline, без сетевого CI-запроса; fail-safe — на неопределённости re-test бежит. Kill-switch
|
||||
`merge_retest_skip_when_current_enabled`.
|
||||
- **Бюджет (D5):** `merge_retest_timeout_s` 600 → 900 (запас 74% над 516.7s) + валидация (непозитив →
|
||||
дефолт + WARNING); сквозной инвариант `reaper_max_running_s (5400) > Σ(deploy-staging gate-work
|
||||
≈4460)+grace` проверен — `reaper_max_running_s` **не меняется**.
|
||||
- **Наблюдаемость (D6):** счётчики + блок `merge_gate` в `GET /queue`; координация с ORCH-111
|
||||
(`proc_blocking`, adr-0041) без дубля: ORCH-110 предотвращает/толерирует у источника, ORCH-111
|
||||
наблюдает.
|
||||
|
||||
Подробнее: [adr-0042](adr/adr-0042-merge-gate-retest-infra-tolerance-and-tree-kill.md), детально —
|
||||
`docs/work-items/ORCH-110/06-adr/ADR-001-merge-gate-retest-infra-tolerance-and-tree-kill.md`.
|
||||
|
||||
### Coverage-гейт: защита от деградации покрытия тестами (ORCH-027 — design)
|
||||
Существующие тестовые гейты (`check_ci_green`, `check_tests_passed`, merge-gate re-test) судят
|
||||
только по факту прохождения тестов, не по **полноте** — фича «300 строк, 0 тестов» проходит
|
||||
|
||||
Reference in New Issue
Block a user