7.1 KiB
Аудит мета-информации в событиях (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. Найденные пробелы (по убыванию веса)
ToolCalled/ToolResult— 68k событий безtrace_id/level/ts(⅔ всех нетаймовых событий стора; связь с тиком только через декодированиеaggregate_id = "<level>-<seq>:<n>"). УToolResultимя инструмента — заглушка"?"(после параллельных вызовов вообще непонятно, чей результат).TaskCompleted/TaskFailedбезlevel— не видно, какой уровень лестницы закрыл/уронил задачу;trace_idтолько какresult_ref.DigestWritten.summary_ref≠ trace_id напрямую — это trace_id тика, но имя не говорит об этом (путаница при разборе инцидентов).BudgetSpentбезts(после миграции v2 на инкрементальные записи — толькоtimestampколонки; хронология внутри тика не видна).- Двойная кодировка:
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), доверие ко стору у внешних проверяющих (подписи + мета =аудито-готовность). Слабого короткого дохода нет — чистый плюс в базу.