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

5.1 KiB
Raw Blame History

work_item, stage, author_agent, status, created_at, model_used
work_item stage author_agent status created_at model_used
ORCH-114 architecture architect proposed 2026-06-15 claude-opus-4-8

08 — Требования к данным: ORCH-114 — Durable transition-ownership lease + expected-stage CAS

Work Item: ORCH-114 · Repo: orchestrator · Стадия: architecture

When-applicable / информационный (гейтом не парсится). Сверено по src/db.py.

Изменения схемы БД

Ровно один новый объект — аддитивная таблица transition_lease (CREATE TABLE IF NOT EXISTS в init_db(), паттерн repo_freeze/coverage_baseline/lessons):

CREATE TABLE IF NOT EXISTS transition_lease (
    task_id       INTEGER PRIMARY KEY,   -- одна задача = ≤1 активный владелец side-effectful перехода
    owner         TEXT NOT NULL,         -- актор-держатель: monitor|reaper|reconciler|webhook|finalizer
    owner_pid     INTEGER,               -- pid процесса-держателя (liveness, как merge-lease os.getpid())
    owner_boot_id TEXT,                  -- нонс старта процесса; рестарт ⇒ смена ⇒ прежний lease мёртв
    run_id        INTEGER,               -- agent_runs.id если применимо (контекст)
    stage         TEXT,                  -- from-стадия захвата (наблюдаемость/контекст)
    acquired_at   TEXT NOT NULL DEFAULT (datetime('now'))
);

Индекс не требуется (доступ по PK task_id); snapshot() для GET /queue — full-scan по малой таблице (в любой момент строк ≈ числу активных side-effectful переходов, единицы).

Изменений существующих таблиц НЕТ. tasks / jobs / agent_runs / events / job_deps / repo_freeze / coverage_baseline / lessons — схемы байт-в-байт (NFR-3, AC-11). Колонка epoch/version НЕ добавляется (ADR-001 D2: для одно-процессной модели стадия и есть версия CAS; epoch — форвард-расширение, не вводится сейчас).

Новые/изменённые сущности

  • Таблица transition_lease — durable-владение side-effectful переходом задачи. Инвариант: активная строка для task_id ⇔ некий актор держит владение переходом этой задачи. Живой владелец ⇔ owner_boot_id == <boot-id текущего процесса> И merge_gate.pid_alive(owner_pid); иначе устарел → реклеймится. Захват — атомарный rowcount-guard (паттерн claim_next_job/reap_running_job): INSERT … ON CONFLICT(task_id) берётся только при отсутствии живого владельца (иначе rowcount==0 → busy).
  • Функция update_task_stage_cas(task_id, expected_stage, new_stage) -> bool (новая, в db.py): UPDATE tasks SET stage=?, updated_at=datetime('now') WHERE id=? AND stage=?; возвращает cur.rowcount==1 (выиграл CAS) / False (проиграл — стадия уже не та, что читали → аборт без побочных эффектов). Прежний update_task_stage сохраняется без изменений (путь kill-switch-off и записи вне side-effectful области).

Совместимость данных / миграции

  • Аддитивно/идемпотентно/restart-safe: CREATE TABLE IF NOT EXISTS в init_db() — повторный старт no-op; на живой общей прод-БД данные enduro-trails не затрагиваются (новая таблица изолирована).
  • Никакого backfill существующих строк не требуется (таблица заполняется рантаймом при захвате владения).
  • Рестарт-семантика: durable-строки lease переживают рестарт физически; новый процесс получает новый owner_boot_id → ранее записанные строки трактуются как устаревшие и реклеймятся (ADR-001 D3/D7); recover_on_startup() зачищает их наблюдаемо (после requeue_running_jobs).
  • Откат (NFR-8): при transition_lease_enabled=False таблица не читается/не пишется и остаётся инертной; удалять её при откате не требуется. Поведение БД-слоя — байт-в-байт до-ORCH-114.
  • enduro-trails: при transition_lease_repos="" (self-hosting only) механизм для enduro не активируется — нулевая регрессия.