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

44 lines
5.8 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
work_item: ORCH-099
stage: architecture
author_agent: architect
status: proposed
created_at: 2026-06-10
model_used: 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/except``breaker: 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), без рестарта прод-контейнера.