Files
orchestrator/docs/work-items/ORCH-099/10-tech-risks.md

5.8 KiB
Raw Permalink Blame History

work_item, stage, author_agent, status, created_at, model_used
work_item stage author_agent status created_at model_used
ORCH-099 architecture architect proposed 2026-06-10 claude-opus-4-8

10 — Технические риски: ORCH-099 — FND/F1a: лёгкий /metrics (сырьё для sidecar)

Work Item: ORCH-099 · Repo: orchestrator · Стадия: architecture

Информационный (гейтом не парсится). Перечисляет риски реализации и их митигейшн.

Реестр рисков

ID Риск Вер. Влия. Митигейшн
TR-1 Гонка чтения /proc/<pid>/stat: процесс умер между выборкой running-job и чтением proc → FileNotFoundError/частичная строка Сред. Низ. _read_cpu_ticks never-raise → cpu_ticks: null (NFR-2, FR-3, AC-6); прочие поля и эндпоинт целы. Парс proc-stat читает поля после ') ' (устойчивость к пробелам в comm).
TR-2 PID-namespace mismatch: jobs.pid относится не к тому PID-namespace, где орк читает /proc Низ. Сред. Агент — дочерний процесс орка (launcher subprocess в том же контейнере/ns), pid стамплется орком (ORCH-065) → /proc/<pid> валиден в том же ns. Несовпадение → null (деградация, не падение).
TR-3 Расхождение часов орк↔sidecar искажает расчёт CPU-доли Низ. Низ. Контракт by-design: sidecar считает дельту по (cpu_ticks, generated_at) из двух ответов орка → всё в домене часов орка, skew-иммунно (ADR D2).
TR-4 Дрейф контракта /metrics↔ожидания F1b при будущих расширениях Сред. Сред. schema_version (старт 1) + аддитивно-толерантная политика (sidecar игнорирует незнакомые ключи, толерирует отсутствие опциональных); контракт документирован в README в одном репо (BR-7, NFR-6).
TR-5 cost.running = null (токены ещё не застамплены) ошибочно прочитан sidecar'ом как «ноль стоимости» Сред. Низ. Документировать: null ≠ ноль (= «не завершён, не застамплен»); авторитет по спенду — cost.aggregate (ADR D7).
TR-6 Контеншн на CircuitBreaker._lock при опросе breaker-снимка Низ. Низ. snapshot() держит lock кратко (только чтение полей, src/queue_worker.py:113); раздел обёрнут own try/exceptbreaker: null при любой проблеме. Частота опроса sidecar — секунды, не микросекунды.
TR-7 Рост стоимости SUM-агрегата по agent_runs при разрастании таблицы Низ. Низ. agent_cost_totals() — один индексируемый full-scan SUM, n мал (десятки–сотни строк на текущем горизонте); точка расширения — временное окно/repo-срез без бампа версии (ADR D2/D7).
TR-8 Соблазн «протащить» в /metrics логику алертинга/порогов Низ. Сред. Scope-граница BRD (вне объёма) + NFR-1 (read-only) + reviewer-контроль; мозг (пороги/алерты) — строго F1b.
TR-9 Незаметная мутация состояния (случайный не-read-only вызов в сборщике) роняет инвариант read-only Низ. Выс. Сборщик использует только SELECT-helper'ы; AC-5/TC-09 — тест «снимок БД до/после идентичен»; reviewer сверяет дифф на отсутствие INSERT/UPDATE/DELETE/CREATE/ALTER и запуска процессов.

Сводный вывод

Доминирующий класс — гонки/деградация чтения runtime-данных (/proc, in-memory breaker), все закрыты конструктивным never-raise по разделам (эталон serial_gate.snapshot()) → деградация в null, не отказ. Контрактные риски (TR-4/TR-5) закрыты schema_version + документированием. Наивысшее потенциальное влияние (TR-9, нарушение read-only) митигируется тестом «БД до/после идентична» (TC-09) и reviewer-сверкой диффа.

Изменение полностью аддитивно, read-only, never-raise, обратимо (kill-switch + удаление модуля). Остаточный риск для прод-конвейера (self-hosting, общий с enduro-trails) — near-zero: эндпоинт физически не способен мутировать состояние или уронить процесс (NFR-1/NFR-2/NFR-4). Эскалация в анализ не требуется. Формальный лейбл arch:major-change проставляется консервативно (новый компонент наблюдаемости + публичный контракт), хотя по существу изменение низкорисковое; прод-деплой — строго через staging-гейт (8501), без рестарта прод-контейнера.