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:
| Prefix | Domain | Examples |
|---|---|---|
task.* | Task lifecycle | task.created, task.completed, task.failed |
hypothesis.* | Hypothesis validation | hypothesis.proposed, hypothesis.validated, hypothesis.killed |
research.* | Research workflows | research.requested, research.completed |
approval.* | HITL Gateway | approval.required, approval.granted, approval.denied |
escalation.* | Escalation flows | escalation.triggered, escalation.resolved |
policy.* | Policy layer | policy.violation_detected, policy.audit_log |
system.* | System-level | system.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 на все*.executedevents для 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
Процессы
- Process-TaskLifecycle — tasks emit events на каждом transition
- Process-Escalation — escalation через approval.required events
- Process-Rollback — rollback events trigger reverse actions
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
Связанные документы
- Reference-Org-Blueprint — section §6 Event-Driven Communication
- Orchestration-Model — orchestrator consumes events для scenario transitions
- Memory-Model — events emit’ят persist signals для RAG/structured
- Observability — метрики из event metadata
- Policy-Layer — inspects actions, not events (boundary)
- HITL-Gateway —
approval.*events routed к Gateway - Agent-Judge — subscribed на
task.completed - Manifesto — принцип #5 асинхронность
- ADR-0020-reference-architecture-blueprint