Event Bus Pattern

Async pub/sub коммуникация между агентами вместо прямых RPC-вызовов. Реализация принципа Manifesto #5 — “Асинхронность превыше синхронности” — на уровне системной инфраструктуры.

Зачем

В monolithic / RPC-first подходе Agent A напрямую вызывает Agent B. Проблемы:

  • Tight coupling — A должен знать кто B, где он, как отвечает
  • Cascading failures — B недоступен → A висит → сценарий стоит
  • Sync blocks — A ждёт B синхронно, teряется параллелизм
  • Single-consumer — только A знает результат B, другим недоступно
  • Hard to replay — для debug нужно voctor конкретный RPC-ход
  • Добавление нового subscriber требует изменять A (violation Open-Closed)

Event bus pattern: A emit-ит event → bus → N subscribers независимо реагируют.

Ответственности

  • Pub/sub delivery — гарантированная доставка events subscribers
  • Schema enforcement — event envelope валидация
  • Ordering — per-scenario ordering guarantees (FIFO within trace_id)
  • Persistence — events persisted для replay / audit
  • Trace propagation — trace_id, span_id, parent_span_id preserved
  • Dead letter queue — unprocessable events не теряются

Что НЕ делает

  • Не содержит бизнес-логику (просто transport)
  • Не решает конфликты между subscribers (их дело)
  • Не обеспечивает exactly-once semantics automatically (idempotency — на subscriber)
  • Не bypass-ит Policy-Layer — policy инспектирует tool calls, не events

Event envelope schema

Standardized структура для всех events:

event_id: uuid              # unique для этого event
trace_id: uuid              # scenario-level, корневой
span_id: uuid               # этот span
parent_span_id: uuid        # causality chain
timestamp: iso8601
 
source_agent: "agent-intel-director"
event_type: "research.completed"   # namespaced: <domain>.<verb>
criticality: "L2"                  # из Rules-Criticality
 
payload:
  # domain-specific
  task_id: "..."
  confidence: 0.87
  outcome_summary: "..."
  artifacts: [ref1, ref2]
 
metadata:
  model: "haiku-4-5"
  tokens_in: 2341
  tokens_out: 892
  cost_usd: 0.0034
  duration_ms: 1420

Все поля кроме payload — mandatory. payload — event-specific schema, валидируется по event_type.

Event types (starter namespace)

Категоризация по domain:

PrefixDomainExamples
task.*Task lifecycletask.created, task.completed, task.failed
hypothesis.*Hypothesis validationhypothesis.proposed, hypothesis.validated, hypothesis.killed
research.*Research workflowsresearch.requested, research.completed
approval.*HITL Gatewayapproval.required, approval.granted, approval.denied
escalation.*Escalation flowsescalation.triggered, escalation.resolved
policy.*Policy layerpolicy.violation_detected, policy.audit_log
system.*System-levelsystem.budget_exceeded, system.rate_limit_hit

Новые namespaces добавляются через ADR. Нельзя emit-ить events вне registered types — Event Bus отвергает.

Subscription patterns

Single-consumer (command pattern)

Один agent реагирует. Для state-changing actions.

task.created → orchestrator (единственный subscriber)

Fan-out (notification pattern)

Много subscribers реагируют независимо. Для information distribution.

research.completed → orchestrator (advance scenario)
                   → Agent-Judge (quality check)
                   → Observability (metrics)
                   → Memory (persist outcome)

Filtered subscription

Subscriber указывает filter по payload.

Agent-Judge subscribes:
  event_type: "task.completed"
  AND payload.criticality >= L2

Loose coupling guarantees

Паттерн соблюдается если:

  • Emitter не знает subscribers (no hardcoded list)
  • Subscriber не знает emitter (только event_type + payload schema)
  • Добавление нового subscriber не требует изменений emitter
  • Удаление subscriber не ломает scenario (другие subscribers продолжают)

Критический anti-pattern: subscriber expect-ит что другой subscriber что-то сделал до него. Это hidden coupling через event ordering. Если нужна координация — оркестрируй через orchestrator, не через implicit order.

Policy-sensitive subscribers

По мере роста появляются agents которые должны узнавать обо всех действиях:

  • Compliance-like agent [future] — subscribes на все *.executed events для audit
  • Security monitor — subscribes на system.* + critical * events
  • Agent-Judge — subscribes на task.completed для quality loop

Эти subscribers решают cross-functional blindspot failure pattern из Reference-Org-Blueprint §9 — “policy blindspots”.

Ordering & idempotency

Within trace_id: FIFO ordering гарантировано. События scenario видны subscribers в порядке emission.

Across trace_ids: no ordering guarantees. Events разных scenarios могут пересекаться.

Idempotency: каждый subscriber обязан обрабатывать re-delivery того же event_id как no-op. Event Bus может deliver дважды в edge cases (network failure + replay).

Persistence & replay

Все events persisted в event store (append-only, immutable — Law 6 trace requirement).

Use cases replay:

  • Debug — восстановить what happened в scenario
  • Post-mortem — анализ failure
  • Re-processing — subscriber был down, now catch-up
  • Learning loops — Process-OutcomeLabeling reads historical events

Retention — минимум 90 дней, critical events (L4/L5) — indefinite.

Rate limiting & backpressure

Event Bus применяет:

  • Rate limits per emitter — prevent runaway agent from flooding
  • Rate limits per subscriber — prevent DoS subscriber от too-many events
  • Backpressure — если subscriber медленный, emitter получает hint slow down
  • Circuit breaker — subscriber failing repeatedly → temporarily unsubscribe, alert

Dead letter queue

Events которые не могут быть обработаны:

  • Schema validation fail
  • Subscriber permanently rejected (after retries)
  • TTL expired

→ dead letter queue для human review. Не теряются silently.

Model

Event Bus сам — не LLM agent. Deterministic infrastructure. Implementation options (решение через отдельный ADR):

  • Redis Streams (simple, fast, для MVP)
  • NATS (cluster-ready, persistent, mature)
  • Kafka (enterprise-scale, overhead для current phase)

Текущий phase MVP — рекомендуется Redis Streams + migration path к NATS когда scale требует.

Стоимость: negligible LLM-cost, dominated infrastructure.

Связанные rules

  • Rules-DataAccess — subscription permissions (какой agent может subscribe на какие events)
  • Rules-Budget — cost accounting через event metadata
  • Rules-Security — event encryption в transit и at rest

Процессы

Open Questions

  • Choice of implementation (Redis vs NATS vs Kafka) — нужен отдельный ADR
  • Event schema versioning — как migrate когда schema меняется
  • Cross-region event delivery [future] — когда Synth Nova multi-region
  • Event sourcing vs log only — storing full state vs command history

Связанные документы