68 lines
4.7 KiB
Markdown
68 lines
4.7 KiB
Markdown
---
|
||
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/<id>/`,
|
||
несёт 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` таблица может существовать пустой/инертной — нулевая
|
||
регрессия.
|