5.1 KiB
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 не активируется — нулевая регрессия.