--- work_item: ORCH-116 stage: architecture author_agent: architect status: proposed created_at: 2026-06-16 model_used: claude-opus-4-8 --- # 08 — Требования к данным: ORCH-116 — детерминированный test-раннер Work Item: **ORCH-116** · Repo: **orchestrator** · Стадия: architecture ## 1. Изменения схемы БД — НЕТ (NFR-1) Новых таблиц / колонок / индексов / миграций **нет**. Раннер использует **существующие** структуры: | Структура | Использование | Запись? | |-----------|---------------|---------| | `tasks` (`stage`, `branch`, `work_item_id`) | резолв полей задачи по `task_id`; гард стадии `testing` в `should_intercept`; продвижение/откат — через **существующий** `advance_stage` (он же пишет стадию под transition-lease ORCH-114) | раннер сам стадию **не** пишет — только через `advance_stage` | | `jobs` (`status`, `task_content`) | `mark_job(done\|failed)` для строки джоба (через `_run_test_runner_job`); restart-safe счётчик tool-error DEFER — `COUNT(*)` по маркеру `test-runner infra-retry` в `task_content` re-queued джоба | да (`mark_job`, `enqueue_job` — существующие API) | | `agent_runs` | **НЕ создаётся** — детерминированный раннер не спавнит LLM (happy-path без `_spawn`) | нет | | `transition_lease` (ORCH-114) | берётся/освобождается **внутри** `advance_stage` на side-effectful переходе | раннер **не трогает** | ## 2. Restart-safe счётчик DEFER — без колонки (зеркало ORCH-115/110) Бюджет tool-error DEFER (D5) считается **из persisted очереди `jobs`** подсчётом маркера `test-runner infra-retry` в `task_content` re-queued джоба (зеркало `staging_runner._infra_retry_count` / `stage_engine._merge_infra_retry_count`). Это переживает рестарт сервиса **без** новой колонки/таблицы — намеренно, ради NFR-1 (схема БД байт-в-байт). ## 3. Артефакт `13-test-report.md` — контракт frontmatter неизменен (AC-2) Раннер пишет тот же файл с тем же machine-key, что читает гейт: - `result: PASS|FAIL` (UPPERCASE) — канонический ключ `_parse_tests_verdict` (`src/qg/checks.py:265`); имя/регистр/токены **не меняются**. - Обязательная 52c-схема: `work_item` / `stage: testing` / `author_agent: test-runner` / `status: success|failed` / `created_at` / `model_used: n/a`. - **Инвариант D6.1 (данные):** `status:` **читается** тем же парсером (`verdict:`/`status:`/`result:`, negative-token-priority) → значение `status:` **обязано** быть выровнено по вердикту (`success`↔PASS, `failed`↔FAIL); иначе негативный токен в `status:` при `result: PASS` исказит вердикт. Это требование к **значению данных**, не к схеме. ## 4. Счётчики наблюдаемости — in-process, не БД Блок `test_runner` в `GET /queue` питается **in-process** счётчиками `_TEST_RUNNER_COUNTERS` (`runs`/`pass`/`fail`/`tool_error`/`deferred`) — паттерн `_STAGING_RUNNER_COUNTERS`/ `_MERGE_GATE_COUNTERS`. В БД **не** персистятся (обнуляются при рестарте — приемлемо для оперативной наблюдаемости). ## 5. Вывод Требований к изменению данных/схемы **нет**. Совместимость с общей БД (self-hosting + enduro-trails) сохранена: аддитивных объектов не вводится, существующие read/write идут через существующие API.