# 08 — Требования к схеме БД — ORCH-026 **Work Item:** ORCH-026 · **Repo:** orchestrator · **Стадия:** architecture **Связь:** ADR `06-adr/ADR-001-merge-serialization-and-task-deps.md` (Уровень B). > Уровень A (сериализация merge/деплоя) — **БЕЗ изменения схемы БД** (merge-lease файловый, > `.merge-lease-.json`, ORCH-065). Изменения схемы касаются ТОЛЬКО Уровня B. --- ## Новая таблица `job_deps` (аддитивная) Хранит декларативные зависимости «задача `task_id` ждёт задачу `depends_on_task_id`». ```sql CREATE TABLE IF NOT EXISTS job_deps ( task_id INTEGER NOT NULL, -- tasks.id зависимой задачи (B) depends_on_task_id INTEGER NOT NULL, -- tasks.id задачи-предшественника (A) created_at TEXT DEFAULT (datetime('now')), PRIMARY KEY (task_id, depends_on_task_id) ); CREATE INDEX IF NOT EXISTS idx_job_deps_task ON job_deps(task_id); CREATE INDEX IF NOT EXISTS idx_job_deps_depends ON job_deps(depends_on_task_id); ``` ### Поля | Поле | Тип | Назначение | |------|-----|-----------| | `task_id` | INTEGER | `tasks.id` зависимой задачи (B). Не запускается, пока зависимости не `done`. | | `depends_on_task_id` | INTEGER | `tasks.id` предшественника (A). Терминальность — `tasks.stage = 'done'`. | | `created_at` | TEXT | Время декларации (диагностика). | ### Ключ и индексы - **PK `(task_id, depends_on_task_id)`** — идемпотентность вставки (повторная декларация связи — no-op через `INSERT OR IGNORE`), запрет дублей. - `idx_job_deps_task` — гейт планировщика (`NOT EXISTS ... WHERE d.task_id = j.task_id`). - `idx_job_deps_depends` — обратные рёбра для DFS цикл-детектора. ### Семантика готовности (источник истины планировщика) Задача `task_id` **готова к запуску** ⇔ нет ни одной строки `job_deps` для неё, чей `depends_on_task_id` указывает на задачу с `tasks.stage != 'done'`. Терминал — только `done` (совпадает с тем, как `get_active_tasks_for_reconcile` трактует терминальность). ### Связь по `task_id`, а не `work_item_id` `tasks.id` — стабильный локальный автоинкремент-ключ; `work_item_id`/`plane_id` могут ресолвиться/коллизиться (см. `ensure_unique_work_item_id`). FK логический (без `REFERENCES`, как у `jobs.task_id`) — не блокирует аддитивную миграцию и удаление строк tasks (которого в конвейере нет). Зависимости — **только intra-repo** (v1); кросс-репо рёбра не создаются. --- ## Миграция (AC-G4) - Выполняется в `src/db.py::init_db` рядом с прочими: **только** `CREATE TABLE IF NOT EXISTS` + `CREATE INDEX IF NOT EXISTS`. **Идемпотентно**, restart-safe, безопасно на живой общей прод-БД. - **Существующие колонки/таблицы (`jobs`, `tasks`, `agent_runs`, `events`) НЕ изменяются** → данные enduro-trails не затронуты. - Откат фичи — флагом `task_deps_enabled=False` (таблица остаётся, гейт не применяется); сама таблица деструктивно не удаляется. ## Что НЕ меняется - Схема `jobs` (включая `available_at`, `pid`, `attempts`/`transient_attempts`) — без изменений; defer Уровня A/B переиспользует существующий `available_at`-механизм. - Схема `tasks` — без изменений (видимость через существующие `tracker_message_id` и Plane Blocked). - merge-lease — файловый, вне БД.