Files
orchestrator/docs/overview/tech-data-model.md
claude-bot 170a8700c7
All checks were successful
CI / test (push) Successful in 1m9s
CI / test (pull_request) Successful in 1m9s
fix(stage-engine): address ORCH-114 review — env/docs canon + in-region rollback CAS
Resolves the REQUEST_CHANGES findings on ORCH-114 (durable transition-ownership
lease + expected-stage CAS):

P1 — documentation = golden source:
- .env.example: add ORCH_TRANSITION_LEASE_ENABLED / ORCH_TRANSITION_LEASE_REPOS
  (canon of 100% start keys, ORCH-101), next to the other gate kill-switches.
- CLAUDE.md: add the ORCH-114 passport section (mechanism, invariant, flags,
  ADR links) so a future agent editing advance_stage/reaper/webhooks finds the
  ownership invariant in the first mandatory-read doc (ORCH-078 traceability index).

P2 — should-fix:
- docs/overview/ (system showcase, ORCH-011): add transition_lease to
  tech-data-model.md (helper tables), tech-observability.md (/queue blocks) and
  tech-architecture.md (components).
- ADR-001 D4 alignment: the four side-effectful-edge rollback handlers
  (_handle_merge_gate_rollback / _handle_security_gate / _handle_coverage_gate /
  _handle_image_freshness) now write `development` through the expected-stage CAS
  via a shared _rollback_stage_cas helper (defence against the rollback↔done
  contradiction, BR-6) instead of a bare unconditional update_task_stage. Under the
  held lease the sole owner always wins; a lost race aborts WITHOUT side effects.
  Kill-switch off / out-of-scope repo -> degenerates to the prior write -> 1:1.
- Test isolation: make tests/test_webhooks.py order-independent by pinning the
  proj-1 registry per-test (mirrors test_webhook_dedup.proj_registry); it had only
  passed by relying on import order. Drop the needless module-level ORCH_DB_PATH
  setdefault in test_orch114 (fresh_db already isolates db_path).

New regression tests (TC-11): in-region rollback writes route through CAS;
rollback CAS wins when at expected stage; rollback CAS-lost does NOT clobber `done`;
kill-switch-off rollback degenerates to the unconditional write.

ruff clean (src/stage_engine.py, src/transition_lease.py); full suite 2052 passed.

Refs: ORCH-114
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 18:16:49 +03:00

5.8 KiB
Raw Blame History

Блок 4. Структура объектов: каноническая модель

Источник истины — фактическая схема SQLite в src/db.py и реестр проектов в src/projects.py; подробное описание таблиц — internals, «Database Schema».

Каноническая модель

Project ──1:N──► Work-Item / Task ──1:N──► Job ──1:N──► Agent-run
   │                    │
   │                    └── артефакты задачи (docs/work-items/<ID>/)
   └── Plane-проект ↔ git-репозиторий ↔ префикс задач

Project — проект в реестре

Связка «Plane-проект ↔ git-репозиторий ↔ префикс задач» (например, ORCH-). Реестр живёт в конфиге (src/projects.py): один инстанс платформы обслуживает несколько проектов; по префиксу задачи платформа находит репозиторий и настройки.

Work-Item / Task — задача конвейера

Строка таблицы tasks: текущая стадия (stage), маршрут (track: полный или багфикс), рабочая ветка, счётчики откатов, отметки отмены. Натуральные ключи — ID задачи в Plane и человекочитаемый номер (ORCH-NNN). На каждой стадии задача накапливает артефакты — номерные документы в docs/work-items/<ID>/ (от бизнес-запроса до deploy-лога; манифест — PIPELINE_DOCS).

Job — единица работы в очереди

Строка таблицы jobs: что запустить (агент какой стадии), для какой задачи, в каком статусе (queuedrunning → терминал). Очередь даёт: атомарный захват (два worker'а не возьмут один job), зависимости между job'ами, ретраи с экспоненциальным backoff и breaker после исчерпания бюджета, ограничение параллелизма.

Agent-run — один запуск агента

Строка таблицы agent_runs: какой агент, какой моделью и эффортом, сколько длился, сколько стоил (токены/доллары). Из этих строк складывается честная стоимость задачи в живой карточке и аналитика по ролям.

События вебхуков и дедуп

Входящие события Plane/Gitea фиксируются с ключом дедупликации: повторная доставка того же события (ретраи источника, сетевые икоты) не порождает повторной работы.

Вспомогательные таблицы

Таблица Зачем
repo_freeze durable-заморозка репозитория после деградации прода (serial gate)
coverage_baseline базовая линия покрытия тестами; растёт только вверх (ratchet)
tracker_messages леджер всех Telegram-карточек задачи (зачистка сирот)
lessons машинный журнал уроков — структурированные отклонения конвейера
transition_lease durable-владение side-effectful переходом стадии: один владелец на задачу, liveness по pid+boot-id (предотвращает двойное применение необратимых эффектов)

Все изменения схемы — аддитивные и идемпотентные (CREATE TABLE IF NOT EXISTS, ensure-column при старте): обновление платформы не требует ручных миграций.

Словарь терминов

Термин Значение
Стадия Позиция задачи в конвейере; карта стадий — STAGE_TRANSITIONS (блок 2)
Гейт (exit-гейт) Машинная проверка выхода со стадии; реестр — QG_CHECKS
Под-гейт Проверка-врезка внутри перехода (не стадия); см. деплойное ребро в блоке 2
Job Единица работы в очереди; задача порождает job'ы по мере продвижения
Worktree Изолированная рабочая копия репозитория для ветки задачи
Lease (merge-lease) Эксклюзивная блокировка «кто сейчас мержит этот репозиторий» — сериализация слияний
Track (маршрут) Вариант пути задачи: полный цикл или багфикс с пропуском проектирования
Freeze Заморозка очереди репозитория после инцидента до ручного разбора

Как объекты двигаются по конвейеру — блок 2; кто их создаёт — агенты; как за ними наблюдать — блок 7.