developer(ET): auto-commit from developer run_id=642
Some checks failed
CI / test (push) Failing after 1m0s
CI / test (pull_request) Failing after 59s

This commit is contained in:
2026-06-12 02:56:23 +03:00
parent 725791790d
commit 52e2e5fda1
3 changed files with 78 additions and 4 deletions

View File

@@ -245,7 +245,7 @@ Type B). Анти-дрейф — `tests/test_bundle_compose.py` / `test_bundled_
[adr-0038](adr/adr-0038-bundled-replication-canon.md), детально —
`docs/work-items/ORCH-103/06-adr/ADR-001-bundled-stack-compose-and-bootstrap.md`.
**Интерактивный installer Lite (ORCH-104 — design).** Lite получает инструмент, симметричный
**Интерактивный installer Lite (ORCH-104).** Lite получает инструмент, симметричный
Bundled-bootstrap'у: **`scripts/setup_lite.py`** — python stdlib-only wizard, автоматизирующий
маршрут LITE_SETUP §2§12 (скан предусловий с офером доустановки per-package consent'ом;
discovery docker-инсталляций Plane/Gitea строго по image-префиксам с выбором пользователя;

View File

@@ -6,6 +6,8 @@
> Хост-специфика в командах — только плейсхолдеры `<...>` и `$ENV_VAR`.
> Тираж **stateless**: данные/задачи/секреты исходного (боевого) хоста **НЕ переносятся**
> ни на одном шаге — всё создаётся заново (§12).
> **Быстрый путь — `scripts/setup_lite.py`** (§1.1): интерактивный installer проводит по
> §2§12 за один прогон; ручной маршрут ниже остаётся каноном и fallback'ом.
---
@@ -32,6 +34,35 @@ compose-файле, но строго за профилем `staging` и в ба
- контейнерные пути (`/app/data`, `/repos`, `/opt/claude-code`) — layout контейнера,
не хост-значения; не параметризуются.
### 1.1. Быстрый путь: `setup_lite.py` (рекомендуется)
Вместо ручного прохода §2§12 запустите **интерактивный installer** — он сканирует
предусловия хоста и предлагает доустановить недостающее, обнаруживает ваши инсталляции
Plane/Gitea (при нескольких — даёт выбрать), запрашивает обязательные ключи **в момент
установки с немедленной верификацией**, автодетектит хост-параметры, собирает
`.env`/`.env.watchdog` от канонов (свежие webhook-секреты — кирпичом `gen_secrets.py`),
поднимает ровно орк+watchdog и регистрирует ваш проект строго кирпичом `onboard_project.py`.
```bash
cd <путь-чекаута> # корень репо orchestrator
python3 scripts/setup_lite.py # apply (дефолт): интерактивная установка
python3 scripts/setup_lite.py plan # read-only диагностика (ноль мутаций)
python3 scripts/setup_lite.py verify # read-only пост-проверка контура
```
**Контракт:** дефолт-режим `apply` — установка «одной командой»; безопасность дефолта
структурна — фаза 0 любого `apply``plan` (read-only скан), каждая мутация хоста — с
**явного согласия** (per-action consent с печатью точной команды), существующий чужой
`.env`/`.env.watchdog` **не перетирается** без `--force` (guard managed-маркера), в
non-TTY без `--yes` — честный выход без зависания. Exit-коды: `0` — все шаги PASS; `2`
остановка на ручном шаге (повторный запуск продолжит с него — resume); `1` — ошибка.
Секреты вводятся скрыто и **никогда не печатаются**; delete-операций скрипт не выполняет
(лечение — всегда инструкция). Любой ручной шаг ссылается на соответствующий § ниже —
ручной маршрут §2§13 остаётся полным каноном и fallback'ом для MANUAL-шагов.
**Проверка:** `python3 scripts/setup_lite.py plan` завершается без блокеров (exit 0) —
PASS; есть блокеры (exit 2) — устраните по выводу и повторите.
---
## 2. Предусловия хоста
@@ -588,9 +619,10 @@ PR-merge API оркестратора, ручной merge не требуетс
---
*Golden source Lite-тиража (ORCH-102, ADR-001). **Норматив сопровождения (NFR-5):**
меняешь шаги тиража (env-ключи, compose-сервисы, маршрут онбординга, smoke) → обнови
этот док В ТОМ ЖЕ PR (правило агентов №2). Полноту и гигиену дока держит структурный
*Golden source Lite-тиража (ORCH-102, ADR-001). **Норматив сопровождения (NFR-5, расширен
ORCH-104):** меняешь шаги тиража (env-ключи, compose-сервисы, маршрут онбординга, smoke) →
обнови этот док **И установочный скрипт `scripts/setup_lite.py`** В ТОМ ЖЕ PR (правило
агентов №2). Полноту и гигиену дока держит структурный
анти-дрейф тест `tests/test_lite_setup_doc.py`; кирпичи-каноны: REPLICATION.md (карта
env §2, секреты §3, smoke §4), ONBOARDING.md (статусы §1, онбординг), SETUP_WEBHOOKS.md
(формат вебхуков), `.env.example` / `.env.watchdog.example` (канон ключей).*

View File

@@ -426,3 +426,45 @@ def test_replication_boundaries_reference_lite_setup():
def test_changelog_has_orch_102_entry():
assert "ORCH-102" in CHANGELOG.read_text(encoding="utf-8")
# ---------------------------------------------------------------------------
# TC-27 (ORCH-104, FR-11 / D12): LITE_SETUP.md вводит установочный скрипт как
# рекомендованный быстрый путь и сохраняет ручной маршрут (пиннинг «13 разделов»
# в порядке держит test_doc_exists_with_all_13_sections_in_order — не трогается).
# ---------------------------------------------------------------------------
def test_doc_introduces_setup_lite_fast_path():
text = _doc_text()
assert "setup_lite.py" in text, (
"LITE_SETUP.md не вводит установочный скрипт setup_lite.py (ORCH-104 FR-11)"
)
# быстрый путь — подраздел §1.1 ВНУТРИ §1 (нумерация ## 1.…## 13. не меняется)
body1 = _section_bodies()["## 1. Рамка Lite"]
assert "1.1" in body1 and "setup_lite.py" in body1, (
"быстрый путь обязан быть подразделом §1.1 внутри §1 (D12)"
)
# ручной маршрут сохранён как канон/fallback — упомянут явно
assert "fallback" in text.lower() or "ручной маршрут" in text, (
"ручной маршрут §2§13 обязан остаться каноном/fallback (FR-11)"
)
# норматив сопровождения расширен на скрипт (D12)
assert "scripts/setup_lite.py" in text
def test_setup_lite_fast_path_block_is_clean():
"""§1.1 fenced-блок проходит те же сканы, что весь док: без боевых литералов,
без секретоподобных значений, без неизвестных env-токенов."""
body1 = _section_bodies()["## 1. Рамка Lite"]
blocks = _fenced_blocks(body1)
assert blocks, "§1.1 обязан нести fenced-блок с командой запуска (D12)"
for i, block in enumerate(blocks):
for literal in FORBIDDEN:
assert literal not in block, f"§1.1 блок #{i}: боевой литерал {literal!r}"
for rx in (_SECRET_HEX_RE, _SECRET_ALNUM_RE):
assert rx.search(block) is None, f"§1.1 блок #{i}: секретоподобное значение"
# упомянутые в §1.1 env-токены (если есть) — только из канона .env.example
canon = _env_keys(ENV_EXAMPLE)
mentioned = set(_ENV_TOKEN_RE.findall(body1))
assert not (mentioned - canon), (
f"§1.1 упоминает env-токены вне .env.example: {sorted(mentioned - canon)}"
)