--- work_item: ORCH-027 stage: architecture author_agent: architect status: proposed created_at: 2026-06-10 model_used: claude-opus-4-8 --- # 08 — Требования к данным: ORCH-027 — Code coverage как гейт Work Item: **ORCH-027** · Repo: **orchestrator** · Стадия: architecture > When-applicable / информационный (гейтом не парсится). Затрагивается схема БД — вводится > **одна аддитивная таблица** базовой линии покрытия. Существующие таблицы не мигрируются. ## Изменения схемы БД Новая аддитивная таблица `coverage_baseline` (паттерн `repo_freeze`/`job_deps` — `CREATE TABLE IF NOT EXISTS` в `init_db`, `src/db.py`; без `ALTER`/миграции существующих): ```sql CREATE TABLE IF NOT EXISTS coverage_baseline ( repo TEXT PRIMARY KEY, -- репозиторий (напр. "orchestrator") coverage REAL NOT NULL, -- last-known базовая линия покрытия main (%, line coverage) source_sha TEXT, -- SHA main, на котором зафиксирована базовая линия (аудит) updated_at TEXT NOT NULL -- ISO-таймстамп последнего ratchet/bootstrap ); ``` Доступ — через аддитивные read-only/мутирующие хелперы `src/db.py`: - `get_coverage_baseline(repo) -> float | None` (None ⇒ bootstrap-режим, базовой линии ещё нет); - `ratchet_coverage_baseline(repo, coverage, sha) -> bool` — **атомарный compare-and-set**: `INSERT` при отсутствии строки; иначе `UPDATE ... SET coverage=?, source_sha=?, updated_at=? WHERE repo=? AND coverage <= ?` (базовая линия **никогда не понижается**); - `set_coverage_baseline(repo, coverage, sha)` — безусловная установка (ручной override D8 / `POST /coverage/baseline`). ## Новые/изменённые сущности - **`coverage_baseline`** — одна строка на репозиторий; keyed by `repo`. Инвариант: `coverage` монотонно не убывает через `ratchet_coverage_baseline` (только `set_coverage_baseline`/ручной override может понизить — легитимный разовый случай, D8). На общей прод-БД (self-hosting) строки разных репозиториев изолированы первичным ключом. - **Артефакт `18-coverage-report.md`** — НЕ БД-сущность: файл в `docs/work-items//`, несёт frontmatter `coverage_status: PASS|FAIL` + `measured_coverage`/`baseline`/`floor`/ `policy`/`delta`. Source of truth измеренного значения для ratchet (D5). Существующие таблицы (`tasks`, `jobs`, `job_deps`, `repo_freeze`, `agent_runs`, `tracker_messages`, …) — **не изменяются** (NFR-5/AC-8). ## Совместимость данных / миграции - **Аддитивность:** только `CREATE TABLE IF NOT EXISTS` — ни один существующий столбец/таблица не трогается; миграции существующих данных нет. - **Идемпотентность:** `CREATE TABLE IF NOT EXISTS` безопасен при повторном старте; bootstrap (первый `INSERT`) выполняется один раз на репозиторий. - **Restart-safe:** базовая линия персистентна; in-flight измерение при рестарте переигрывается штатным механизмом стадии (idempotent — гейт пересчитает вердикт, ratchet — атомарный compare-and-set, повтор не понизит и не задвоит). - **Атомарность / анти-гонка:** ratchet — единичный SQL `UPDATE ... WHERE coverage <= ?` (или `INSERT`), выполняется под held merge-lease (ORCH-043, per-repo сериализация merge) → двойная защита от параллельных слияний. - **Влияние на общую прод-БД:** одна маленькая таблица (≤ числа репозиториев строк); нулевой риск для enduro-trails и прочих проектов (строки изолированы по `repo`, гейт для них no-op). - При `coverage_gate_enabled=False` таблица может существовать пустой/инертной — нулевая регрессия.