--- work_item: ORCH-124 stage: architecture author_agent: architect status: proposed created_at: 2026-06-16 model_used: claude-opus-4-8 --- # 08 — Требования к данным: ORCH-124 — per-task park-сигнал serial-gate Work Item: **ORCH-124** · Repo: **orchestrator** · Стадия: architecture > When-applicable / информационный (гейтом не парсится). ## Изменения схемы БД **Одна аддитивная нуллабельная колонка** на существующей таблице `tasks` (никаких новых таблиц): | Таблица | Колонка | Тип / дефолт | Семантика | |---------|---------|--------------|-----------| | `tasks` | `paused_at` | `TEXT` (по умолчанию отсутствует → `NULL`) | `NULL` = не на паузе; ISO-таймстамп (`datetime('now')`) = задача поставлена оператором на паузу (park) | Миграция — идемпотентный `_ensure_column(conn, "tasks", "paused_at", "TEXT")` в `init_db()`, ровно по образцу `tasks.cancelled_at` / `tasks.cancel_requested_at` / `tasks.track` (`src/db.py:141-149`). На уже мигрированной БД — no-op. **Индекс не требуется.** Горячий SQL `build_claim_clause` сканирует `tasks t2` уже сегодня (по `repo`/`id`); терм `AND t2.paused_at IS NULL` — дополнительный фильтр в существующем `EXISTS`-подзапросе, не новый план доступа. Кардинальность `tasks` per-repo мала; добавление индекса — преждевременная оптимизация (принцип минимума). ## Новые/изменённые сущности - **`tasks.paused_at`** — единственное durable хранилище намерения паузы. Запись — `db.set_task_paused` (`paused_at=datetime('now')`); сброс — `db.clear_task_paused` (`paused_at=NULL`); чтение — `db.is_task_paused` и SQL-предикат serial-gate. Все хелперы never-raise. - **Инвариант оси:** `paused_at` — **ортогональная** ось «пауза», независимая от оси «терминальность» (`stage IN ('done','cancelled')`). serial-gate «активна» = `stage NOT IN ('done','cancelled') AND paused_at IS NULL`. `task_deps`/`stages.py` колонку `paused_at` **не читают** (терминал не трогается, NFR-4). - **Существующие таблицы** (`jobs` / `job_deps` / `repo_freeze` / `agent_runs`) — без изменений. ## Совместимость данных / миграции - **Аддитивно и идемпотентно:** `_ensure_column` — no-op на уже-мигрированной БД; новая колонка дефолтит в `NULL` для всех существующих строк ⇒ все текущие задачи считаются «не на паузе» ⇒ поведение до ORCH-124 сохраняется до первой явной операторской паузы. - **Restart-safe / durable:** значение в БД переживает рестарт процесса/контейнера (BR-2, R-3). - **Общая прод-БД (self-hosting):** колонка добавляется на общей БД; при дефолтном `serial_gate_pause_enabled` и отсутствии паузнутых задач — нулевая регрессия для enduro (`paused_at` везде `NULL`). - **Откат:** колонка инертна при `ORCH_SERIAL_GATE_PAUSE_ENABLED=false` (pause-терм опускается из SQL). Колонку можно оставить (безвредна); деструктивный drop не требуется и не рекомендуется на прод-БД.