5.5 KiB
5.5 KiB
Требования к схеме БД — ORCH-087
Все изменения — строго аддитивные и идемпотентные (CREATE TABLE IF NOT EXISTS
/ _ensure_column), restart-safe на живой ОБЩЕЙ прод-БД (SQLite). Данные
enduro-trails не трогаются. Существующие колонки/таблицы не ломаются. Точка врезки —
src/db.py::init_db (рядом с прочими _ensure_column/executescript).
1. Колонка agent_runs.effort (BR-EFF, обязательно)
_ensure_column(conn, "agent_runs", "effort", "TEXT")
- Тип
TEXT, nullable. Хранит РЕАЛЬНО ушедшее в--effortзначение (low|medium|high|xhigh|max) илиNULL, если флаг не подавался (резолв вернул ""). - Заполняется в
launcher._spawnсразу послеresolve_agent_effort(agent, project_id)черезUPDATE agent_runs SET effort=? WHERE id=run_id(effort or None). - Читается в
render_task_tracker(добавитьeffortв SELECTagent_runs). - Исторические строки (до миграции) →
effort IS NULL→ суффикс эффорта в карточке опускается; допустим fallback наresolve_agent_effort(run["agent"]). - Идемпотентность:
_ensure_column— no-op при уже существующей колонке (AC-E.1, TC-09).
2. Таблица-леджер tracker_messages (BR-G1, вариант A1 ADR-001)
CREATE TABLE IF NOT EXISTS tracker_messages (
task_id INTEGER NOT NULL,
message_id INTEGER NOT NULL,
created_at TEXT DEFAULT (datetime('now')),
deleted_at TEXT, -- NULL = карточка ещё жива (незакрыта)
PRIMARY KEY (task_id, message_id)
);
CREATE INDEX IF NOT EXISTS idx_tracker_messages_open
ON tracker_messages(task_id) WHERE deleted_at IS NULL;
- Авторитетный учёт ВСЕХ созданных карточек задачи;
deleted_at IS NULL⇔ карточка считается живой и подлежит зачистке на следующем bump. - Логический FK на
tasks.idбезREFERENCES(зеркалитjobs.task_id/job_deps) — миграция не падает на pre-existing БД. - Частичный индекс
WHERE deleted_at IS NULL— дешёвая выборка незакрытых mid в горячем пути рендера/зачистки. PRIMARY KEY (task_id, message_id)— идемпотентность INSERT (повторный mid не дублируется); защита от двойного учёта при гонке.
Новые геттеры/сеттеры в src/db.py (предложение, точная сигнатура — за разработчиком):
| Функция | Назначение |
|---|---|
add_tracker_message(task_id, message_id) |
INSERT нового mid (после успешного send). INSERT OR IGNORE для идемпотентности. |
get_open_tracker_messages(task_id) -> list[int] |
Все message_id с deleted_at IS NULL. |
mark_tracker_message_deleted(task_id, message_id) |
UPDATE … SET deleted_at=datetime('now') для успешно удалённых / «already gone». |
Контракт — как у существующих хелперов БД (never-raise по месту вызова в notifications: ошибка БД не валит конвейер).
Сосуществование со скаляром tasks.tracker_message_id
tasks.tracker_message_idСОХРАНЯЕТСЯ без изменения семантики — указатель на ТЕКУЩУЮ карточку (читателиget_tracker_message_id/set_tracker_message_idне трогаются). Обратная совместимость полная.- Леджер
tracker_messages— НАДмножество: источник истины для зачистки сирот. - Одноразовый бэкфилл скаляра в леджер не требуется (старые сироты всё равно за 48ч-окном Telegram). Новый поток ведёт леджер с нуля.
3. Что НЕ меняется
tasks(кроме отсутствия изменений — скаляр сохранён),jobs,events,job_deps, прочие колонкиagent_runs(model, токены, cost, exit_code) — без изменений.- Никаких
DROP/ALTER … DROP/переименований/перетипизаций (SQLite-небезопасно на живой БД). STAGE_TRANSITIONS/QG_CHECKS— вне зоны БД, не затрагиваются.
4. Идемпотентность и restart-safety (проверка)
- Двойной вызов
init_db→ без ошибок (IF NOT EXISTS/_ensure_columnno-op) — TC-09. - Леджер переживает рестарт орка: незакрытые mid читаются из БД → следующий bump подчищает старые карточки (TC-05, AC-1.3).
- Миграция на БД с существующими данными enduro: только добавляет колонку/таблицу, данные нетронуты (AC-X.5).