simbiot-harness/docs/events-meta-audit-2026-10-15.md

7.1 KiB
Raw Permalink Blame History

Аудит мета-информации в событиях (t-261015083454, принцип m-516174369)

Дата: 2026-10-15. Стор: ~2.8M событий. Принцип Alex: события должны сохраняться с максимумом мета-информации — событие без контекста теряет ценность при разбирательстве инцидентов и аналитике burn/AUM.

1. Системные поля (у всех событий, таблица events)

Поле Есть Оценка
id, timestamp (UTC ISO), version ✅ ок
aggregate / aggregate_id ✅ ок, но двойная кодировка меты (см. §3)
sig / key_id / prev_sig (ed25519-цепочка) ✅ криптоаудит t-260930083716
trace_id, level, источник, context ❌ в payload точечно, неравномерно

2. Аудит payload по типам (выборка последних 150 на тип)

Тип (кол-во) trace_id level ts источник прочая мета
CycleTicked (1.35M) — ✅ agg_id — — seq
ReflexObserved (1.33M) — ✅ agg_id ✅ — load1
ToolCalled (34.7k) ❌ ❌ ❌ — tool, input
ToolResult (34.7k) ❌ ❌ ❌ — tool=«?»-заглушка, result
BudgetSpent (28.6k) ✅ ✅ — ✅ model, tokens
DigestWritten (21.3k) — (summary_ref) ✅ — stub-флаг period, text
InvocationStarted (1.4k) ✅ ❌ ✅ — model
TaskSubmitted (230) — — — ✅ source id, size, est_minutes
TaskClaimed (434) — ✅ — — session_id
TaskCompleted (317) — (result_ref) ❌ — — answer
TaskFailed (12) — ×2/12 — ×1/12 error
EscalationRaised (96) — ✅ from/to — ✅ source severity, task_id, context
MessageReceived (1238) — — ✅ date ✅ username 19 полей, эталон
MessageTranscribed (65) — — — ✅ engine transcript
RagQueried (412) / PortalMcpCalled (64) ✅ ✅ ✅ ms — query/result_preview
CycleError (51) — ✅ — — error, trace
AumMeasured (16) — — ✅ — aum, burn_24h/7d, policy

3. Найденные пробелы (по убыванию веса)

  1. ToolCalled/ToolResult — 68k событий без trace_id/level/ts (⅔ всех нетаймовых событий стора; связь с тиком только через декодирование aggregate_id = "<level>-<seq>:<n>"). У ToolResult имя инструмента — заглушка "?" (после параллельных вызовов вообще непонятно, чей результат).
  2. TaskCompleted/TaskFailed без level — не видно, какой уровень лестницы закрыл/уронил задачу; trace_id только как result_ref.
  3. DigestWritten.summary_ref ≠ trace_id напрямую — это trace_id тика, но имя не говорит об этом (путаница при разборе инцидентов).
  4. BudgetSpent без ts (после миграции v2 на инкрементальные записи — только timestamp колонки; хронология внутри тика не видна).
  5. Двойная кодировка: level дублируется в aggregate_id и payload — данные об оси «уровень» живут в двух местах с разной полнотой.

4. Внедрено в этом тике (коммит f3ab66e)

  • harness/runtime.py _wire_trace_hooks: trace_id, ts, level теперь в каждом trace-событии (InvocationStarted/ToolCalled/ ToolResult); ToolResult дополнительно duration_ms (из AfterToolCallEvent.duration), ok: bool, exception (до 500с), имя инструмента из tool_use (заглушка "?" убрана).
  • harness/_llm_worker.py: проброс level в _wire_trace_hooks.
  • harness/scheduler.py: TaskCompleted/TaskFailed получают level + trace_id тика-воркера.
  • Проверено: смоук-скрипт (мета во всех 4 типах), 5 смежных тестов PASS (task_batch 11, timeout_kill 2, ttft_retry, tool_budget, task_claim_race).

Прирост мета-покрытия: trace-события (доля LLM-активности без мета- контекста) — с 0% → 100% новых событий; TaskCompleted/TaskFailed — с 0% → 100% level.

5. План на следующие итерации (не внедрено — вне бюджета тика)

# Что Зачем Где
1 ts в BudgetSpent (воркер уже пишет после каждого вызова) хронология spend внутри тика, детект всплесков burn _llm_worker._emit_budget_incremental
2 trace_id в DigestWritten (рядом с summary_ref) и переименование семантики summary_ref в доках единая ось «тик → трасса → spend» scheduler.py
3 source (cli/poller/scheduler/daemon) в TaskClaimed, MessageSeen, ReplySent отличать ручные команды от автоматических scheduler.py, commands.py
4 host/pid/commit в InvocationStarted (или в CycleTicked раз в тик) мульти-инстансность: кто именно писал (инцидент rogue-key t-261008084600) runtime.py
5 duration_ms в CycleTicked/DigestWritten находить медленные тики без парсинга логов scheduler.py
6 Унификация: helper es.meta(level=…) для единообразной меты во всех append_event убрать ручную возню, единый контракт es.py

Ретро-заполнение старых событий не делаем: стор append-only + подписи ed25519 — перезапись сломает тампер-цепочку. Граница: события до f3ab66e — «до мета-стандарта», после — полные.

6. AUM-фильтр

Аудит меты — инвестиция в долгосрочную базу: разбор инцидентов (часы диагностики → минуты по SQL-запросу), честный burn-контроль 9router (193.68 у.е./7д — прямой минус AUM), доверие ко стору у внешних проверяющих (подписи + мета =аудито-готовность). Слабого короткого дохода нет — чистый плюс в базу.