55 lines
4.2 KiB
Markdown
55 lines
4.2 KiB
Markdown
---
|
||
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.
|