Files
orchestrator/docs/work-items/ORCH-087/08-data-requirements.md
claude-bot 194d6c820e
All checks were successful
CI / test (push) Successful in 24s
architect(ET): auto-commit from architect run_id=426
2026-06-09 08:31:45 +03:00

4.5 KiB
Raw Blame History

08 — Требования к схеме БД — ORCH-087

Все изменения аддитивны и идемпотентны, безопасны на живой ОБЩЕЙ прод-БД (enduro-trails + orchestrator из одного инстанса). Существующие колонки/данные не трогаются. Решение — ADR-001.

1. Новая таблица tracker_messages (G1 — anti-orphan, Подход Б)

Реестр ВСЕХ Telegram message_id, созданных трекером для задачи, и их состояние. Позволяет подчищать осиротевшие карточки, ссылку на которые потерял одиночный tasks.tracker_message_id.

CREATE TABLE IF NOT EXISTS tracker_messages (
    task_id    INTEGER NOT NULL,           -- логический FK tasks.id (без REFERENCES, как jobs.task_id)
    message_id INTEGER NOT NULL,           -- Telegram message_id отправленной карточки
    created_at TEXT    DEFAULT (datetime('now')),
    deleted    INTEGER NOT NULL DEFAULT 0, -- 0 = живая (надо подчистить), 1 = удалена/исчерпана
    PRIMARY KEY (task_id, message_id)
);
CREATE INDEX IF NOT EXISTS idx_tracker_messages_live
    ON tracker_messages(task_id) WHERE deleted = 0;
  • Миграция: conn.executescript(...) с CREATE TABLE/INDEX IF NOT EXISTS в init_db() (рядом с блоком job_deps). Повторный init_db — no-op.
  • PRIMARY KEY(task_id, message_id)INSERT OR IGNORE идемпотентен (дубль mid не падает).
  • Частичный индекс WHERE deleted=0 ускоряет sweep (выборка только живых).
  • Логический FK (без REFERENCES tasks(id)) — миграция не падает на pre-existing БД, как job_deps.
  • deleted=1 присваивается при: успешном delete, «уже нет» (message to delete not found), «нельзя удалить» (48ч, message can't be deleted_DELETE_GONE_MARKERS). Transient-fail (False) → запись остаётся deleted=0, повтор на следующем апдейте.

Helper'ы доступа (src/db.py, never-raise)

Функция Назначение
record_tracker_message(task_id, message_id) INSERT OR IGNORE свежий mid (deleted=0)
mark_tracker_message_deleted(task_id, message_id) UPDATE … SET deleted=1
list_live_tracker_messages(task_id) -> list[int] все deleted=0 mid задачи (для sweep)

get_tracker_message_id / set_tracker_message_id — без изменений (обратная совместимость).

2. Новая колонка agent_runs.effort (G4 — эффорт в строке стадии)

-- идемпотентная миграция в init_db(), рядом с _ensure_column(... "agent_runs", "model" ...)
ALTER TABLE agent_runs ADD COLUMN effort TEXT;   -- через _ensure_column (no-op если есть)
  • Миграция: _ensure_column(conn, "agent_runs", "effort", "TEXT").
  • Хранит ФАКТИЧЕСКИ применённый --effort запуска (то, что ушло в CLI), стампится в launcher._spawn после effort = resolve_agent_effort(...). Не пересчитывается на рендере.
  • NULL/"" для старых строк и для запусков с опущенным флагом (effort=="") → рендер опускает эффорт-суффикс (деградация без падения, AC-9).
  • Значения: подмножество VALID_EFFORTS (low|medium|high|xhigh|max) либо NULL.

3. Гарантии совместимости (общая прод-БД)

  • Никаких ALTER/DROP существующих колонок; только новая таблица + новая колонка.
  • CREATE TABLE IF NOT EXISTS / _ensure_column → повторный запуск инертен (AC-10).
  • Данные enduro-trails не читаются и не пишутся этими миграциями (таблицы изолированы по task_id, колонка effort заполняется только новыми запусками).
  • Restart-safe: всё состояние в БД; рестарт орка не теряет реестр и не плодит сирот по новой схеме.