Event bus reference (AsyncAPI 3.0)
Connectors lift normalized observations onto the engine’s internal event bus as events; modules and output connectors subscribe by event type and react — without any of them importing one another. This page is that contract, expressed as AsyncAPI 3.0 — the async counterpart of the REST API reference.
The bus model
Section titled “The bus model”- Transport. The v1 default is an in-process Go-channel bus inside the single
olivaresbinary. TheBusinterface exposes no channel, so a distributed implementation (NATS) can be slotted in for multi-host deployments without changing a single subscriber. NATS is the planned distributed binding, not required for the default. - Subscription. A subscriber registers a handler filtered by a set of event types; an empty set means every event. The bus owns the goroutine that runs the handler.
- Delivery. Asynchronous and at-least-once: each subscriber has its own buffered queue drained by a dedicated goroutine; a slow subscriber applies backpressure; a handler panic is isolated. Consumers de-duplicate on the natural-key timestamp after a connector restart.
- Minimal-data. Every event carries the fact, never raw payloads, secrets
or PII. An edge is
(origin → resource, R/RW); a finding carries a hash of the redacted detail, never the detail. - Durable intake.
audit.recordedand the durablework.*types never ride the process-local bus. Their source outbox supplies a stable ID and settles only after Eventing persists the event. An exact replay is a no-op; reusing the same ID for different type, source, time or payload is rejected.
The envelope
Section titled “The envelope”Every event shares the immutable Event envelope; the observation rides in
Payload.
| Field | Type | Meaning |
|---|---|---|
ID |
string | Unique event id, assigned by the engine for bus traffic and required from a durable source before intake. |
Type |
string | The discriminator — one of the channel addresses below. |
Tenant |
string | The originating tenant as a string reference; the engine resolves it internally. |
Source |
string | Name of the component (connector/module) that emitted it. |
Time |
timestamp | When the underlying fact occurred, in the connector’s clock. |
Payload |
object | The fact — one of the payload schemas below. |
Channels
Section titled “Channels”The catalog combines first-party sealed observations, module-defined live-bus events and the durable-intake-only channels listed below. Each type carries its own stability tier, driven from the in-code catalog (see API stability: stable = 24-month deprecation→sunset window, beta = 12-month, binding from GA; a beta payload may still gain fields, never lose them silently).
Channel (Type) |
Payload | Purpose | Transport | Stability |
|---|---|---|---|---|
edge.observed |
EdgeObservation |
an origin touched a resource (R/RW) — the spine of the access map | typed gRPC oneof |
stable |
cost.sampled |
CostSample |
a model/provider usage-cost fact | typed gRPC oneof |
stable |
finding.reported |
FindingReport |
a guardrail/red-team/forensic finding | typed gRPC oneof |
stable |
guardrail.observed |
ObservedText |
a redacted excerpt of observed agent text (detective input) | JSON fallback | beta |
approval.requested |
ApprovalRequest |
a pending approval was opened and awaits decision | JSON fallback | beta |
policy.changed |
PolicyChange |
a governance policy was created, updated or deleted | JSON fallback | beta |
metric.sampled |
MetricSample |
a usage/productivity metric sample; its subject may be a developer reference | typed gRPC oneof |
beta |
approval.resolved |
ApprovalResolution |
a pending approval reached a terminal outcome | JSON fallback | beta |
workflow.signal |
WorkflowSignal |
a DAG-workflow eventing-emit step ran |
JSON fallback | beta |
work.item.created |
WorkEventFact |
a durable WorkItem creation fact | durable intake | beta |
work.item.transitioned |
WorkEventFact |
a durable WorkItem update, archive or governed state transition | durable intake | beta |
work.owner.changed |
WorkEventFact |
canonical owner or ownership epoch changed | durable intake | beta |
work.dependency.changed |
WorkEventFact |
a dependency was added, reactivated or tombstoned | durable intake | beta |
work.acceptance.changed |
WorkEventFact |
an acceptance criterion was created, updated, evaluated or waived | durable intake | beta |
work.message.available |
DirectNoticeAvailableV1 or WorkflowMessageCarrierV1 |
a DirectNotice or workflow work-task Message carrier became available | durable intake | beta |
work.message.acknowledged |
DirectNoticeAcknowledgedV1 |
a Delivery received an explicit Ack, punctual or late | durable intake | beta |
work.message.retracted |
MessageLifecycleV1 |
a Message was retracted | durable intake | beta |
work.message.expired |
MessageLifecycleV1 |
a Message reached its expiry boundary | durable intake | beta |
work.message.overdue |
MessageLifecycleV1 |
a Message crossed its acknowledgement deadline | durable intake | beta |
work.message.rerouted |
MessageDerivedV1 |
a governed reroute derived a new Message carrier | durable intake | beta |
work.message.escalated |
MessageDerivedV1 |
an overdue Message produced a bounded escalation | durable intake | beta |
work.protocol.reply.available |
WorkflowMessageCarrierV1 |
an authenticated protocol reply became one bounded local Message carrier | durable intake | beta |
work.protocol.message.received |
WorkflowMessageCarrierV1 |
an authenticated inbound protocol Message became one bounded local Message carrier | durable intake | beta |
work.handoff.carrier.available |
WorkflowMessageCarrierV1 |
a workflow created the Message/Delivery carrier for a future Handoff | durable intake | beta |
work.decision.recorded |
WorkEventFact |
an append-only decision and its current head projection were recorded | durable intake | beta |
work.decision.request.responded |
DecisionRequestEvent |
a DecisionRequest received an explicit governed response | durable intake | beta |
work.decision.request.expired |
DecisionRequestEvent |
a DecisionRequest crossed its deadline | durable intake | beta |
work.handoff.offered |
HandoffEventV1 |
a governed Handoff was offered | durable intake | beta |
work.handoff.accepted |
HandoffEventV1 |
a Handoff target accepted the offer | durable intake | beta |
work.handoff.rejected |
HandoffEventV1 |
a Handoff target rejected the offer | durable intake | beta |
work.handoff.withdrawn |
HandoffEventV1 |
a Handoff owner withdrew the offer | durable intake | beta |
work.handoff.expired |
HandoffEventV1 |
a Handoff crossed its acknowledgement deadline | durable intake | beta |
work.lease.acquired |
WorkEventFact |
a lease was acquired, taken over or renewed; renew keeps its fence | durable intake | beta |
work.lease.ended |
WorkEventFact |
a lease was released, expired or revoked (including holder death) and its old generation invalidated | durable intake | beta |
work.binding.reserved |
ProtocolBindingEvent |
a protocol binding and fenced WorkItem authority were reserved before transmission | durable intake | beta |
work.binding.observed |
ProtocolBindingEvent |
a protocol observation produced a CLEAN or BROKEN outcome | durable intake | beta |
work.binding.ambiguous |
ProtocolBindingEvent |
a protocol observation remained explicitly UNKNOWN | durable intake | beta |
work.binding.cancel_requested |
ProtocolBindingEvent |
a cancellation intent was durably claimed before the remote side effect | durable intake | beta |
audit.recorded |
AuditRecord |
a sealed audit-ledger record forwarded to a SIEM — never on the bus (see below) | durable intake | stable |
Payloads
Section titled “Payloads”EdgeObservation — edge.observed
Section titled “EdgeObservation — edge.observed”Minimal-data: identifiers and the access classification only.
| Field | Type | Notes |
|---|---|---|
OriginKind |
enum | agent | identity | session |
OriginRef |
string | the connector’s natural reference for the origin |
ResourceKind |
string | e.g. postgres.table, s3.bucket, http.api |
ResourceRef |
string | e.g. public.customers, arn:aws:s3:::bucket |
Mode |
enum | unknown | read | write | readwrite |
Source |
enum | otel | mcp_annotation | pg_audit | cloudtrail | ebpf | policy | a2a |
Confidence |
enum | attributed | approximate |
ToolRef |
string | optional tool/operation that performed the access |
ObservedAt |
timestamp | the natural-key timestamp consumers de-duplicate on |
mcp_annotation is treated as untrusted (corroborated, never trusted alone);
unknown mode and approximate confidence are explicit, so the product never
fabricates certainty.
CostSample — cost.sampled
Section titled “CostSample — cost.sampled”Money is integer micro-USD (millionths of a dollar). The fields below the first
seven are an additive, provider-neutral extension aligned to OpenTelemetry gen_ai.*
and FOCUS; zero/empty means “not reported”, never “zero”.
| Field | Type | Notes |
|---|---|---|
ProviderRef, ModelRef |
string | natural provider/model references |
SessionRef |
string | optional session tie |
InputTokens |
int64 | TOTAL input (the cache split below is a breakdown of this) |
OutputTokens |
int64 | output count |
CostMicroUSD |
int64 | cost in micro-USD |
OccurredAt |
timestamp | when the usage happened |
CacheReadTokens |
int64 | cache-hit input tokens |
CacheCreation1hTokens, CacheCreation5mTokens |
int64 | cache-write tokens by TTL |
WorkspaceRef |
string | billing workspace/project |
APIKeyRef |
string | masked key/service-account reference, never the secret |
Actor |
string | the principal that incurred the cost (chargeback “who”) |
ServiceTier, ContextWindow, InferenceGeo |
string | provider vocabulary (tier / context band / residency) |
Gateway |
enum | direct | bedrock-mantle | bedrock-legacy | vertex | foundry | claude-platform-aws (open string) |
Provenance |
enum | estimated | billed — empty treated as estimated |
CostType |
string | non-token server-tool charge class (empty = ordinary token cost) |
FindingReport — finding.reported
Section titled “FindingReport — finding.reported”| Field | Type | Notes |
|---|---|---|
Kind |
string | e.g. guardrail, redteam, forensic |
Severity |
enum | info | low | medium | high | critical |
SubjectKind, SubjectRef |
string | what the finding is about |
Title |
string | short, non-sensitive summary safe to display |
DetailHash |
string | hex SHA-256 of the redacted detail; the raw detail is never transmitted or stored |
OccurredAt |
timestamp | when the finding was produced |
OWASPLLM, OWASPASI, ATLAS |
string[] | framework references (OWASP LLM Top 10, OWASP Agentic Top 10, MITRE ATLAS); a finding may map to several at once |
ObservedText — guardrail.observed
Section titled “ObservedText — guardrail.observed”A bounded, already-redacted excerpt of observed agent text. The producer must redact secrets/PII before emitting; the consumer clamps it again defensively.
| Field | Type | Notes |
|---|---|---|
Surface |
enum | input | output | tool_args |
Text |
string | the redacted, bounded excerpt the detectors inspect |
AgentRef, SessionRef, ResourceRef |
string | non-sensitive context references (any may be empty) |
ApprovalRequest — approval.requested
Section titled “ApprovalRequest — approval.requested”Minimal-data: identifiers and the approval’s decision parameters only. It
deliberately carries neither the requester’s free-text reason nor the
subject reference; a consumer authorized for governance:approval:read fetches
the full approval by ApprovalID.
| Field | Type | Notes |
|---|---|---|
ApprovalID |
string | the approval’s id — the reference to fetch, decide or watch the request |
Action |
string | the requested action (a bounded short identifier) |
SubjectKind |
string | the kind of subject the action targets (the subject’s reference is deliberately not carried) |
RiskTier |
string | the risk classification the request was opened under (e.g. critical); determines the dual-control floor |
RequiredApprovals |
int64 | the number of distinct approvers needed |
PolicyRef |
string | the approval policy that matched; empty when the request used caller-supplied parameters |
ExpiresAt |
timestamp | when the pending request lapses (absent = never expires) |
EscalateAt |
timestamp | when an undecided request escalates (absent = never) |
MetricSample — metric.sampled
Section titled “MetricSample — metric.sampled”A usage/productivity measure. The subject may be a developer reference (the org-internal email or key name the ROI subject needs), which is why receiving it is gated on the privileged drill-down permission rather than the viewer-tier aggregate.
| Field | Type | Notes |
|---|---|---|
Name |
string | the metric’s natural name (e.g. claude_code.lines_of_code.count) |
Value |
int64 | the measure in its natural integer unit; integer keeps measure/money arithmetic exact |
Additive |
bool | true = a delta to SUM; false = a level/snapshot to keep as latest |
Unit |
string | lines | commits | sessions | tokens | ms | 1 | … ; empty = dimensionless |
SubjectKind, SubjectRef |
string | who/what the measure is about — developer | team | session | account | org | agent and its reference |
OccurredAt |
timestamp | the datapoint’s instant (delta) or bucket day (snapshot); also the producer-controlled idempotency key |
Dimensions |
map | the metric’s own breakdown axes; structural labels, never payload/PII — they JOIN the natural key |
Labels |
map | operator-supplied attribution tags (team/project/cost centre); they never join the natural key |
ApprovalResolution — approval.resolved
Section titled “ApprovalResolution — approval.resolved”The terminal counterpart of approval.requested, with the same minimal-data
posture: identifiers and decision parameters only, never the subject reference
or a free-text reason.
| Field | Type | Notes |
|---|---|---|
ApprovalID |
string | the resolved approval’s id — the reference to fetch the full record |
Action |
string | the requested action (a bounded short identifier) |
SubjectKind |
string | the kind of subject the action targeted |
RiskTier |
string | the live-derived risk classification at resolution time |
Outcome |
string | approved | rejected | canceled | expired — open on the wire; tolerate values you do not know |
RequiredApprovals |
int64 | distinct approvers needed at resolution time |
ApproveCount, RejectCount |
int64 | recorded decisions of each kind |
PolicyRef |
string | the approval policy that matched; empty when caller-supplied parameters were used |
DecidedAt |
timestamp | when the terminal outcome was reached |
WorkflowSignal — workflow.signal
Section titled “WorkflowSignal — workflow.signal”Published by the orchestration module when a governed DAG workflow reaches an
eventing-emit step. The type is fixed by the module, never taken from step
configuration, so a workflow author can never forge a first-party event into
another module’s ingestion; the step’s config contributes only the bounded
label.
| Field | Type | Notes |
|---|---|---|
WorkflowRef |
string | the workflow whose run emitted the signal |
RunRef |
string | the run — pair it with StepRef to locate the moment in the run timeline |
StepRef |
string | the emitting step’s ref within the graph |
Label |
string | the operator-supplied label from the step’s config, bounded and non-sensitive |
WorkEventFact — K1/K2 work.*
Section titled “WorkEventFact — K1/K2 work.*”The eight K1/K2 work channels expose the same bounded payload_json projection of
an append-only WorkEvent. The event type carries the semantic class; this
payload identifies the command, result and resulting aggregate state. It never
contains WorkItem brief text, acceptance statements, decision statements,
rationale or owner-authored free text. Holder fields are stable identity
references, not display names. Consumers must tolerate additive fields while the
channels are beta.
| Field | Type | Notes |
|---|---|---|
command |
string | closed durable-work mutation name that produced the fact |
result_kind |
string | kind of entity returned by the mutation |
result_id |
UUID | returned entity reference |
workspace_id |
UUID | governed workspace reference |
work_item_id |
UUID | WorkItem reference |
status |
string | resulting WorkItem state |
owner_epoch |
int64 | resulting monotonic ownership epoch |
event_seq |
int64 | resulting monotonic sequence within the WorkItem |
lease_id |
UUID | K2 lease event only: stable WorkLease row reference |
lease_state |
string | K2 lease event only: resulting lease state |
holder_sid |
string | K2 lease event only: canonical holder SID |
holder_run_ref, holder_agent_ref |
string | K2 lease event only: bounded execution/agent references when present |
fence |
int64 | K2 lease event only: resulting monotonic fencing generation |
expires_at |
timestamp | K2 lease event only: database-clock expiry while active |
end_reason_code |
string | K2 ended event only: server-defined reason class, never operator-authored text |
end_reason_hash |
string | K2 ended event only: SHA-256 hex of the stored reason for non-disclosing correlation |
forced |
boolean | K2 force-takeover only: always true, marking an override of live lease authority |
severity |
string | K2 force-takeover only: fixed to high |
decision_id |
UUID | K2 force-takeover only: effective governance Decision that authorized the override |
takeover_reason_hash |
string | K2 force-takeover only: SHA-256 hex for correlation; the operator-authored reason is never published |
The four force-takeover fields are an optional projection on
work.lease.acquired: ordinary acquire, renew and non-force takeover events do
not carry them. A consumer that needs the restricted operator-authored reason
must follow the Decision/audit references through an authorized surface; it
cannot recover that text from this event.
DirectNoticeAvailableV1 — work.message.available
Section titled “DirectNoticeAvailableV1 — work.message.available”The immutable v1 fact written by the DirectNotice source transaction into its
WorkEvent and WorkOutbox. The Message is the subject: message_id and
result_id are the same UUID, and result_kind is fixed to
sessions.message. Recipient identity and message content are deliberately
absent; an authorized consumer follows the Message reference through the
governed read surface.
| Field | Type | Notes |
|---|---|---|
schema_version |
int64 | fixed to 1; a later writer adds a new schema instead of relabelling retained v1 facts |
command |
string | fixed to message.publish.direct |
result_kind |
string | fixed to sessions.message |
result_id, message_id |
UUID | identical Message subject references |
channel_id |
UUID | governed Channel reference |
message_kind |
string | fixed to notice for this first K3 write vertical |
state |
string | fixed to published at availability |
version |
int64 | 2, after the atomic draft→published transition |
event_sequence |
int64 | 1, the first append-only event of the Message aggregate |
delivery_count |
int64 | 1, because DirectNotice resolves one initial Delivery |
required_count, ack_quorum |
int64 | initial acknowledgement requirement, each 0 or 1 |
fulfillment |
object | initial not_required or pending projection with required/acknowledged/viable/unmet/quorum counts |
audience_hash |
SHA-256 hex | binds the audience graph without disclosing the recipient |
payload_digest |
SHA-256 hex | binds canonical message content without carrying it |
plan_hash |
SHA-256 hex | binds the authorized publish plan |
The WorkOutbox supplies the envelope ID; retries after ambiguous settlement use
that same ID and byte-identical payload, so Eventing intake treats them as one
event. A different type, source, occurrence time, payload or Message subject under
that ID is rejected. Webhook consumers de-duplicate on X-Olivares-Event; an
operator replay creates a new X-Olivares-Delivery but keeps the event ID.
K3/K4 communication lifecycle facts
Section titled “K3/K4 communication lifecycle facts”The remaining communication WorkEvents use closed, minimal-data projections. They carry IDs, states, monotonic versions/fences and plan or protected-value digests; they never carry Message content, DecisionResponse content or Handoff payload/reason text. Full field constraints are published in the AsyncAPI schemas.
| Schema | Channels | Subject fields |
|---|---|---|
DirectNoticeAcknowledgedV1 |
work.message.acknowledged |
Ack, Delivery and Message IDs; Delivery version/state; late flag; fulfillment; plan hash |
WorkflowMessageCarrierV1 |
workflow form of work.message.available; work.handoff.carrier.available; work.protocol.reply.available; work.protocol.message.received |
WorkItem, Message and Delivery IDs; kind/state/version; event sequence; plan hash; no remote content or artifact bytes |
MessageLifecycleV1 |
work.message.retracted, work.message.expired, work.message.overdue |
Message/optional WorkItem and linked aggregate IDs; state/version; affected Delivery count; optional fulfillment; plan hash |
MessageDerivedV1 |
work.message.rerouted, work.message.escalated |
source/new Message IDs, bounded recipient reference, automation depth and plan hash |
DecisionRequestEvent |
work.decision.request.responded, work.decision.request.expired |
request/response/WorkItem IDs, transition/state and response digest |
HandoffEventV1 |
work.handoff.offered, work.handoff.accepted, work.handoff.rejected, work.handoff.withdrawn, work.handoff.expired |
Handoff/Message/Delivery/WorkItem IDs, state, owner epoch, lease fence and plan hash |
ProtocolBindingEvent — K5 work.binding.*
Section titled “ProtocolBindingEvent — K5 work.binding.*”ProtocolBinding writes one bounded projection into the WorkItem event stream
when it reserves an outbound or inbound binding, reconciles an observation, or
claims a cancellation intent. The four channels share the same exact schema;
the event type supplies the mutation class. These are ordinary WorkItem
aggregate facts and receiving them is gated by sessions:work:read.
| Field | Type | Notes |
|---|---|---|
binding_id |
UUID | durable ProtocolBinding reference |
binding_spec_id |
UUID | immutable ProtocolBindingSpec pinned by the binding |
binding_spec_generation |
int64 | pinned spec generation, at least 1 |
binding_generation |
int64 | exact external-resource generation represented by the binding |
protocol |
enum | a2a | mcp |
workspace_id, work_item_id |
UUID | governed workspace and WorkItem aggregate references |
work_status |
enum | resulting active | review | blocked | canceled WorkItem state |
lease_fence |
int64 | fencing generation assigned to the binding’s synthetic session |
verdict |
enum | CLEAN | BROKEN | UNKNOWN; UNKNOWN is never treated as success |
code |
string | bounded system reason code (maximum 128 bytes), never free text |
terminal |
boolean | whether the observation proves a terminal remote outcome |
event_seq |
int64 | monotonic sequence within the WorkItem aggregate |
external_id_hash |
SHA-256 hex | optional one-way correlation of a bound remote ID; the ID itself is absent |
The payload deliberately excludes the remote resource reference and state, request/tool arguments, task or message results, message content, observation detail and operator-authored cancellation reason. Those values remain behind their governed stores; the event exposes only the minimal reconciliation fact.
AuditRecord — audit.recorded
Section titled “AuditRecord — audit.recorded”A sealed record of the tamper-evident audit ledger, forwarded to a SIEM control tower. It does not ride the bus (see the note above): the ledger forwarder walks the chain from a per-tenant cursor and hands each record to a durable intake, so the integrity fields ride through untouched and a control tower can verify the chain itself.
| Field | Type | Notes |
|---|---|---|
EventID |
string | the audit event’s id — the stable idempotency key a consumer dedups on |
Seq |
int64 | the per-tenant ledger sequence — the natural key; gaps are detectable |
OccurredAt |
timestamp | when the audited action happened |
Source |
string | the emitting component |
Payload |
bytes | the already-encoded minimal-data record, carrying the chain fields (sequence, previous hash, hash, signature) verbatim |
PolicyChange — policy.changed
Section titled “PolicyChange — policy.changed”Mirrors what the policy mutation’s audit record keeps — kind and enabled — plus
the id and the operation. It never carries the operator-supplied policy name
or the policy spec; a consumer authorized for governance:policy:read fetches
the policy by PolicyID.
| Field | Type | Notes |
|---|---|---|
PolicyID |
string | the changed policy’s id |
Kind |
enum | abac | approval |
Op |
enum | created | updated | deleted — open on the wire; tolerate values you do not know |
Enabled |
bool | the enabled flag after the change; false for a deletion |
External subscriptions (eventing platform)
Section titled “External subscriptions (eventing platform)”The eventing module forwards the catalogued event types to external HTTPS
endpoints as signed webhooks. Subscriptions are managed at
/v1/m/eventing/subscriptions — a module route, deliberately outside the
REST OpenAPI contract — while the event types it delivers carry the
per-type stability tiers above.
The delivery
Section titled “The delivery”Each delivery is an HTTPS POST whose body is the JSON envelope plus
Seq — the same field names as the envelope above (the SDK is the contract),
with one additive field: Seq, the per-tenant cursor a replay starts from. The
typed payload rides under Payload.
{ "ID": "0197a2b4-6e1d-7c3a-9f4e-2d8b5c1a0e7f", "Type": "cost.sampled", "Tenant": "…", "Source": "…", "Time": "2026-06-11T12:00:00Z", "Seq": 42, "Payload": { "ProviderRef": "…" }}| Header | Meaning |
|---|---|
X-Olivares-Timestamp |
the Unix-seconds timestamp the signature covers |
X-Olivares-Signature |
t=<ts>,v1=<hexsig> — HMAC-SHA256 over <ts>.<body> with the subscription secret; verify with connectors/webhook.VerifyWithin |
X-Olivares-Event |
the stable event id — your idempotency key, identical across every retry and replay of one event |
X-Olivares-Event-Type |
the event type (the channel address) |
X-Olivares-Delivery |
the delivery id — a replay is a new delivery of the same event |
- At-least-once. The same event may arrive more than once; de-duplicate on
X-Olivares-Event. - Retries. A
408,425,429, any5xxor a network failure is retried on an exponential backoff ladder — 30s, 2m, 10m, 30m, 1h, 2h, 4h, 8h (±20% jitter) — then the delivery dead-letters (the DLQ). Any other non-2xx response is terminal. - Replay. A subscription can be replayed from a
Seqcursor; a replay keeps the event’sX-Olivares-Eventid under a freshX-Olivares-Delivery. - Redirects are never followed — a redirect would re-route the signed body.
- Secret rotation is immediate. The platform holds exactly one signing
secret per subscription: after
POST …/rotate-secret, every later attempt — including retries of already-queued deliveries — signs with the new secret. Update your verifier first, then rotate. - Narrowing
event_typesis not a recall. Deliveries already captured for the subscription stay queued and are delivered (the per-type permission still applies); the narrowed filter governs what is captured from then on.
Per-type receive permission
Section titled “Per-type receive permission”A subscription names a role; before every delivery attempt that role is evaluated against the event type’s permission, through the full RBAC+ABAC pipeline (deny-closed). The mapping mirrors each type’s read surface in the product API:
| Event type | Permission | Stability |
|---|---|---|
edge.observed |
accessgraph:read (privileged: editor+) |
stable |
cost.sampled |
finops:spend:read |
stable |
finding.reported |
security:finding:read |
stable |
guardrail.observed |
security:observed:read (privileged: editor+) |
beta |
approval.requested |
governance:approval:read |
beta |
policy.changed |
governance:policy:read |
beta |
metric.sampled |
adoption:developer:read (privileged: editor+) |
beta |
approval.resolved |
governance:approval:read |
beta |
workflow.signal |
orchestration:workflow:read |
beta |
work.item.created |
sessions:work:read |
beta |
work.item.transitioned |
sessions:work:read |
beta |
work.owner.changed |
sessions:work:read |
beta |
work.dependency.changed |
sessions:work:read |
beta |
work.acceptance.changed |
sessions:work:read |
beta |
work.message.available |
sessions:message:read |
beta |
work.message.acknowledged |
sessions:message:read |
beta |
work.message.retracted |
sessions:message:read |
beta |
work.message.expired |
sessions:message:read |
beta |
work.message.overdue |
sessions:message:read |
beta |
work.message.rerouted |
sessions:message:read |
beta |
work.message.escalated |
sessions:message:read |
beta |
work.protocol.reply.available |
sessions:message:read |
beta |
work.protocol.message.received |
sessions:message:read |
beta |
work.handoff.carrier.available |
sessions:message:read |
beta |
work.decision.recorded |
sessions:decision:read |
beta |
work.decision.request.responded |
sessions:decision-request:read |
beta |
work.decision.request.expired |
sessions:decision-request:read |
beta |
work.handoff.offered |
sessions:handoff:read |
beta |
work.handoff.accepted |
sessions:handoff:read |
beta |
work.handoff.rejected |
sessions:handoff:read |
beta |
work.handoff.withdrawn |
sessions:handoff:read |
beta |
work.handoff.expired |
sessions:handoff:read |
beta |
work.lease.acquired |
sessions:lease:read |
beta |
work.lease.ended |
sessions:lease:read |
beta |
work.binding.reserved |
sessions:work:read |
beta |
work.binding.observed |
sessions:work:read |
beta |
work.binding.ambiguous |
sessions:work:read |
beta |
work.binding.cancel_requested |
sessions:work:read |
beta |
audit.recorded |
audit:read |
stable |
See also
Section titled “See also”- REST API reference — the synchronous contract (OpenAPI 3.1).
- API stability — the windows behind the per-type stability tiers.
- Architecture overview — how observations become edges and reach the access map.
- The raw spec:
/asyncapi/asyncapi.yaml.