Files
orchestrator/docs/work-items/ORCH-088/08-data-requirements.md

4.7 KiB
Raw Permalink Blame History

08 — Требования к схеме БД: ORCH-088 (Serial gate, freeze-хранилище)

Work Item: ORCH-088 · Repo: orchestrator · Стадия: architecture Связь: ADR 06-adr/ADR-001-serial-gate.md (D2/D3/D4), ТЗ 02-trz.md §5.

Общая прод-БД (self-hosting обслуживает enduro-trails из того же инстанса). Все миграции — только аддитивные и идемпотентные (CREATE TABLE IF NOT EXISTS / _ensure_column). Изменение существующих таблиц-контрактов (tasks, jobs, job_deps, agent_runs) запрещено.


1. Новая таблица repo_freeze (FR-5)

Durable per-repo признак заморозки пакета после post-deploy DEGRADED/rollback. Append-only журнал: активная заморозка ⇔ существует строка репо с cleared_at IS NULL.

CREATE TABLE IF NOT EXISTS repo_freeze (
    id           INTEGER PRIMARY KEY AUTOINCREMENT,
    repo         TEXT NOT NULL,                       -- ключ области (per-repo)
    frozen_at    TEXT NOT NULL DEFAULT (datetime('now')),
    reason       TEXT,                                -- напр. "post-deploy DEGRADED 3/5"
    work_item_id TEXT,                                -- задача-источник деградации (уже stage='done')
    cleared_at   TEXT                                 -- NULL = freeze активен; снят оператором → datetime
);
CREATE INDEX IF NOT EXISTS idx_repo_freeze_active ON repo_freeze (repo, cleared_at);

Семантика

  • Активный freeze репо R: EXISTS (SELECT 1 FROM repo_freeze WHERE repo=R AND cleared_at IS NULL).
  • Выставление (set_repo_freeze): INSERT новой строки (cleared_at=NULL). Повторный DEGRADED при уже активном freeze — допускается доп. строка (журнал) либо no-op при существующей активной (выбор разработчика; на gate не влияет — EXISTS идемпотентен).
  • Снятие (clear_repo_freeze): UPDATE repo_freeze SET cleared_at=datetime('now') WHERE repo=? AND cleared_at IS NULL (закрывает все активные строки репо). Идемпотентно (повтор → 0 rows).
  • Read (gate/snapshot): только cleared_at IS NULL-строки; is_repo_frozenfail-closed (ошибка чтения → True, AC-9).

Использование в горячем claim

db.claim_next_job читает repo_freeze инлайн внутри serial_gate-фрагмента (только локальная БД, offline — NFR-2):

OR EXISTS (SELECT 1 FROM repo_freeze f WHERE f.repo = jobs.repo AND f.cleared_at IS NULL)

(внутри AND NOT ( jobs.agent='analyst' AND … ) — см. ADR D1). Тотальный сбой построения фрагмента → fail-open для claim (AC-8); реально выставленная строка блокирует через сам SQL.


2. Активная задача репо — без новых колонок

«Репо занят» вычисляется из существующих столбцов tasks(repo, stage):

EXISTS (SELECT 1 FROM tasks WHERE repo=? AND id != ? AND stage != 'done')

Новых колонок/таблиц для «активной задачи» и «очереди ожидания» не вводится: ожидание = существующий jobs.status='queued' analyst-job + gate в claim (ТЗ §5).


3. Идемпотентность и restart-safety

  • Миграция repo_freeze выполняется в общем init-пути схемы (db.init_db/_ensure_*), безопасна к повторному запуску (IF NOT EXISTS).
  • Всё состояние gate/freeze — в БД (нет in-memory) ⇒ после рестарта поведение идентично (NFR-3/AC-3): активная задача определяется из tasks, freeze — из repo_freeze, ожидающая задача — queued job.
  • При выключенных флагах (serial_gate_enabled=False / serial_gate_freeze_enabled=False) таблица инертна; enduro и существующие контракты не затрагиваются (NFR-4/AC-11).

4. Неизменяемые контракты

tasks, jobs, job_deps, agent_runs, tracker_messages — схема без изменений. STAGE_TRANSITIONS / QG_CHECKS — не БД, но также не меняются (NFR-5).