Event-Bus-Referenz (AsyncAPI 3.0)
Connectors heben normalisierte Beobachtungen auf den internen Event-Bus der Engine als Events; Module und Output-Connectors abonnieren nach Event-Typ und reagieren — ohne dass eines von ihnen ein anderes importiert. Diese Seite ist dieser Contract, ausgedrückt als AsyncAPI 3.0 — das asynchrone Gegenstück zur REST-API-Referenz.
Das Bus-Modell
Abschnitt betitelt „Das Bus-Modell“- Transport. Der v1-Standard ist ein In-Process-Go-Channel-Bus innerhalb des einzelnen
olivares-Binarys. DasBus-Interface exponiert keinen Channel, sodass eine verteilte Implementierung (NATS) für Multi-Host-Deployments eingeschoben werden kann, ohne einen einzigen Subscriber zu ändern. NATS ist das geplante verteilte Binding, nicht erforderlich für den Standard. - Subscription. Ein Subscriber registriert einen Handler, gefiltert nach einem Set von Event- Typen; ein leeres Set bedeutet jedes Event. Der Bus besitzt die Goroutine, die den Handler ausführt.
- Delivery. Asynchron und at-least-once: jeder Subscriber hat seine eigene gepufferte Queue, geleert von einer dedizierten Goroutine; ein langsamer Subscriber wendet Backpressure an; ein Handler-Panic wird isoliert. Consumer deduplizieren über den Natural-Key-Timestamp nach einem Connector-Neustart.
- Minimal-Data. Jedes Event trägt den Fakt, niemals rohe Payloads, Secrets
oder PII. Eine Kante ist
(origin → resource, R/RW); ein Finding trägt einen Hash des geschwärzten Details, niemals das Detail. - Durable Intake.
audit.recordedund die dauerhaftenwork.*-Typen laufen niemals über den prozesslokalen Bus. Ihre Source-Outbox liefert eine stabile ID und bestätigt erst, nachdem Eventing das Event persistiert hat. Ein identisches Replay ist ein No-op; die Wiederverwendung derselben ID für einen anderen Typ, eine andere Source, Zeit oder Payload wird abgelehnt.
Der Envelope
Abschnitt betitelt „Der Envelope“Jedes Event teilt sich den immutablen Event-Envelope; die Beobachtung reitet in
Payload.
| Feld | Typ | Bedeutung |
|---|---|---|
| ID | string | Eindeutige Event-ID, für Bus-Traffic von der Engine vergeben und bei einer dauerhaften Source vor dem Intake erforderlich. |
| Type | string | Der Diskriminator — eine der unten aufgeführten Channel-Adressen. |
| Tenant | string | Der ursprüngliche Tenant als String-Referenz; die Engine löst ihn intern auf. |
| Source | string | Name der Komponente (Connector/Modul), die es emittierte. |
| Time | timestamp | Wann der zugrunde liegende Fakt eintrat, in der Uhr des Connectors. |
| Payload | object | Der Fakt — eines der Payload-Schemas unten. |
Channels
Abschnitt betitelt „Channels“Der Katalog kombiniert versiegelte First-Party-Observations, moduldefinierte Live-Bus- Events und die unten aufgeführten Channels, die ausschließlich über Durable Intake laufen. Jeder Typ trägt seine eigene Stabilitätsstufe, getrieben aus dem In-Code-Katalog (siehe API-Stabilität: stable = 24-monatiges Deprecation→Sunset-Fenster, beta = 12-monatig, bindend ab GA; ein Beta-Payload kann weiterhin Felder gewinnen, niemals stillschweigend verlieren).
| Channel (Type) | Payload | Zweck | Transport | Stabilität |
|---|---|---|---|---|
| edge.observed | EdgeObservation | ein Origin berührte eine Resource (R/RW) — das Rückgrat der Access Map | typed gRPC oneof | stable |
| cost.sampled | CostSample | ein Modell-/Provider-Usage-Kostenfakt | typed gRPC oneof | stable |
| finding.reported | FindingReport | ein Guardrail-/Red-Team-/Forensik-Finding | typed gRPC oneof | stable |
| guardrail.observed | ObservedText | ein geschwärzter Auszug beobachteten Agent-Texts (Detective-Input) | JSON-Fallback | beta |
| approval.requested | ApprovalRequest | eine ausstehende Approval wurde eröffnet und wartet auf Entscheidung | JSON-Fallback | beta |
| policy.changed | PolicyChange | eine Governance-Policy wurde erstellt, aktualisiert oder gelöscht | JSON-Fallback | beta |
| metric.sampled | MetricSample | Nutzungs-/Produktivitätsmetrik; das Subject kann eine Entwicklerreferenz sein | typed gRPC oneof | beta |
| approval.resolved | ApprovalResolution | eine ausstehende Approval erreichte ein terminales Ergebnis | JSON-Fallback | beta |
| workflow.signal | WorkflowSignal | ein eventing-emit-Schritt eines DAG-Workflows lief | JSON-Fallback | beta |
| work.item.created | WorkEventFact | Durable-WorkItem-Erstellungsfakt | Durable Intake | beta |
| work.item.transitioned | WorkEventFact | Durable-WorkItem-Update, -Archivierung oder governed Zustandsübergang | Durable Intake | beta |
| work.owner.changed | WorkEventFact | kanonischer Owner oder Ownership-Epoch wurde geändert | Durable Intake | beta |
| work.dependency.changed | WorkEventFact | Dependency wurde hinzugefügt, reaktiviert oder tombstoned | Durable Intake | beta |
| work.acceptance.changed | WorkEventFact | Akzeptanzkriterium wurde erstellt, aktualisiert, bewertet oder erlassen | Durable Intake | beta |
| work.message.available | DirectNoticeAvailableV1 oder WorkflowMessageCarrierV1 | DirectNotice- oder Workflow-Work-Task-Message-Carrier wurde verfügbar | Durable Intake | beta |
| work.message.acknowledged | DirectNoticeAcknowledgedV1 | eine Delivery erhielt einen expliziten Ack, pünktlich oder verspätet | Durable Intake | beta |
| work.message.retracted | MessageLifecycleV1 | eine Message wurde zurückgezogen | Durable Intake | beta |
| work.message.expired | MessageLifecycleV1 | eine Message erreichte ihre Ablaufgrenze | Durable Intake | beta |
| work.message.overdue | MessageLifecycleV1 | eine Message überschritt ihre Bestätigungsfrist | Durable Intake | beta |
| work.message.rerouted | MessageDerivedV1 | ein governed Reroute leitete einen neuen Message-Carrier ab | Durable Intake | beta |
| work.message.escalated | MessageDerivedV1 | eine überfällige Message erzeugte eine begrenzte Eskalation | Durable Intake | beta |
| work.protocol.reply.available | WorkflowMessageCarrierV1 | eine authentifizierte Protokollantwort wurde zu einem begrenzten lokalen Message-Carrier | Durable Intake | beta |
| work.protocol.message.received | WorkflowMessageCarrierV1 | eine authentifizierte eingehende Protokoll-Message wurde zu einem begrenzten lokalen Message-Carrier | Durable Intake | beta |
| work.handoff.carrier.available | WorkflowMessageCarrierV1 | ein Workflow erstellte den Message-/Delivery-Carrier für einen künftigen Handoff | Durable Intake | beta |
| work.decision.recorded | WorkEventFact | Append-only-Decision und aktuelle Head-Projektion wurden aufgezeichnet | Durable Intake | beta |
| work.decision.request.responded | DecisionRequestEvent | eine DecisionRequest erhielt eine explizite governed Antwort | Durable Intake | beta |
| work.decision.request.expired | DecisionRequestEvent | eine DecisionRequest überschritt ihre Frist | Durable Intake | beta |
| work.handoff.offered | HandoffEventV1 | ein governed Handoff wurde angeboten | Durable Intake | beta |
| work.handoff.accepted | HandoffEventV1 | das Handoff-Ziel nahm das Angebot an | Durable Intake | beta |
| work.handoff.rejected | HandoffEventV1 | das Handoff-Ziel lehnte das Angebot ab | Durable Intake | beta |
| work.handoff.withdrawn | HandoffEventV1 | der Handoff-Owner zog das Angebot zurück | Durable Intake | beta |
| work.handoff.expired | HandoffEventV1 | ein Handoff überschritt seine Bestätigungsfrist | Durable Intake | beta |
| work.lease.acquired | WorkEventFact | Lease wurde erworben, übernommen oder erneuert; Renew behält seinen Fence | Durable Intake | beta |
| work.lease.ended | WorkEventFact | Lease wurde freigegeben, lief ab oder wurde widerrufen; alte Generation invalidiert | Durable Intake | beta |
| work.binding.reserved | ProtocolBindingEvent | Protokollbindung und gefencete WorkItem-Autorität vor Übertragung reserviert | Durable Intake | beta |
| work.binding.observed | ProtocolBindingEvent | Protokoll-Observation erzeugte CLEAN oder BROKEN | Durable Intake | beta |
| work.binding.ambiguous | ProtocolBindingEvent | Protokoll-Observation blieb ausdrücklich UNKNOWN | Durable Intake | beta |
| work.binding.cancel_requested | ProtocolBindingEvent | Abbruchabsicht wurde vor dem Remote-Side-Effect dauerhaft beansprucht | Durable Intake | beta |
| audit.recorded | AuditRecord | versiegelter Audit-Ledger-Datensatz an ein SIEM — niemals auf dem Bus | Durable Intake | stable |
Payloads
Abschnitt betitelt „Payloads“EdgeObservation — edge.observed
Abschnitt betitelt „EdgeObservation — edge.observed“Minimal-Data: nur Identifikatoren und die Zugriffsklassifizierung.
| Feld | Typ | Hinweise |
|---|---|---|
| OriginKind | enum | agent | identity | session |
| OriginRef | string | die natürliche Referenz des Connectors für das Origin |
| ResourceKind | string | z. B. postgres.table, s3.bucket, http.api |
| ResourceRef | string | z. B. 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 | optionales Tool/Operation, das den Zugriff durchführte |
| ObservedAt | timestamp | der Natural-Key-Timestamp, über den Consumer deduplizieren |
mcp_annotation wird als untrusted behandelt (bestätigt, niemals allein vertraut);
unknown-Modus und approximate-Konfidenz sind explizit, sodass das Produkt niemals
Gewissheit fabriziert.
CostSample — cost.sampled
Abschnitt betitelt „CostSample — cost.sampled“Geld ist Integer-Micro-USD (Millionstel eines Dollars). Die Felder unterhalb der ersten
sieben sind eine additive, provider-neutrale Erweiterung, ausgerichtet an OpenTelemetry gen_ai.*
und FOCUS; Null/leer bedeutet „nicht gemeldet“, niemals „null“.
| Feld | Typ | Hinweise |
|---|---|---|
| ProviderRef, ModelRef | string | natürliche Provider-/Modell-Referenzen |
| SessionRef | string | optionale Session-Anbindung |
| InputTokens | int64 | GESAMT-Input (der Cache-Split unten ist eine Aufschlüsselung davon) |
| OutputTokens | int64 | Output-Anzahl |
| CostMicroUSD | int64 | Kosten in Micro-USD |
| OccurredAt | timestamp | wann die Usage eintrat |
| CacheReadTokens | int64 | Cache-Hit-Input-Tokens |
| CacheCreation1hTokens, CacheCreation5mTokens | int64 | Cache-Write-Tokens nach TTL |
| WorkspaceRef | string | Billing-Workspace/-Projekt |
| APIKeyRef | string | maskierte Key-/Service-Account-Referenz, niemals das Secret |
| Actor | string | der Principal, der die Kosten verursachte (Chargeback-„wer“) |
| ServiceTier, ContextWindow, InferenceGeo | string | Provider-Vokabular (Tier / Context-Band / Residency) |
| Gateway | enum | direct | bedrock-mantle | bedrock-legacy | vertex | foundry | claude-platform-aws (offener String) |
| Provenance | enum | estimated | billed — leer wird als estimated behandelt |
| CostType | string | Non-Token-Server-Tool-Charge-Klasse (leer = gewöhnliche Token-Kosten) |
FindingReport — finding.reported
Abschnitt betitelt „FindingReport — finding.reported“| Feld | Typ | Hinweise |
|---|---|---|
| Kind | string | z. B. guardrail, redteam, forensic |
| Severity | enum | info | low | medium | high | critical |
| SubjectKind, SubjectRef | string | worüber das Finding ist |
| Title | string | kurze, nicht-sensible Zusammenfassung, sicher anzeigbar |
| DetailHash | string | Hex-SHA-256 des geschwärzten Details; das rohe Detail wird niemals übertragen oder gespeichert |
| OccurredAt | timestamp | wann das Finding erzeugt wurde |
| OWASPLLM, OWASPASI, ATLAS | string[] | Framework-Referenzen (OWASP LLM Top 10, OWASP Agentic Top 10, MITRE ATLAS); ein Finding kann mehreren gleichzeitig zugeordnet sein |
ObservedText — guardrail.observed
Abschnitt betitelt „ObservedText — guardrail.observed“Ein begrenzter, bereits geschwärzter Auszug beobachteten Agent-Texts. Der Producer muss Secrets/PII vor dem Emittieren schwärzen; der Consumer klemmt ihn defensiv erneut.
| Feld | Typ | Hinweise |
|---|---|---|
| Surface | enum | input | output | tool_args |
| Text | string | der geschwärzte, begrenzte Auszug, den die Detektoren inspizieren |
| AgentRef, SessionRef, ResourceRef | string | nicht-sensible Kontext-Referenzen (jede kann leer sein) |
ApprovalRequest — approval.requested
Abschnitt betitelt „ApprovalRequest — approval.requested“Minimal-Data: nur Identifikatoren und die Entscheidungsparameter der Approval. Es
trägt bewusst weder den Freitext-Grund des Anfordernden noch die
Subject-Referenz; ein für governance:approval:read autorisierter Consumer holt
die vollständige Approval über ApprovalID.
| Feld | Typ | Hinweise |
|---|---|---|
| ApprovalID | string | die ID der Approval — die Referenz zum Holen, Entscheiden oder Beobachten der Anfrage |
| Action | string | die angeforderte Action (ein begrenzter Kurz-Identifikator) |
| SubjectKind | string | die Art des Subjects, das die Action zum Ziel hat (die Referenz des Subjects wird bewusst nicht getragen) |
| RiskTier | string | die Risikoklassifizierung, unter der die Anfrage eröffnet wurde (z. B. critical); bestimmt das Dual-Control-Floor |
| RequiredApprovals | int64 | die Anzahl der benötigten verschiedenen Approver |
| PolicyRef | string | die Approval-Policy, die matchte; leer, wenn die Anfrage caller-supplied Parameter verwendete |
| ExpiresAt | timestamp | wann die ausstehende Anfrage verfällt (fehlend = läuft nie ab) |
| EscalateAt | timestamp | wann eine unentschiedene Anfrage eskaliert (fehlend = nie) |
MetricSample — metric.sampled
Abschnitt betitelt „MetricSample — metric.sampled“Ein Nutzungs-/Produktivitätsmaß. Das Subject kann eine Entwicklerreferenz sein (interne E-Mail oder Key-Name), daher ist der Empfang an die privilegierte Drill-down- Permission und nicht an das Viewer-Tier-Aggregat gebunden.
| Feld | Typ | Hinweise |
|---|---|---|
| Name | string | natürlicher Name der Metrik, z. B. claude_code.lines_of_code.count |
| Value | int64 | Maß in seiner natürlichen Integer-Einheit; Integer hält Maß-/Geld-Arithmetik exakt |
| Additive | bool | true = Delta für SUM; false = Level/Snapshot, von dem das neueste bleibt |
| Unit | string | lines | commits | sessions | tokens | ms | 1 | …; leer = dimensionslos |
| SubjectKind, SubjectRef | string | worüber das Maß ist: developer | team | session | account | org | agent samt Referenz |
| OccurredAt | timestamp | Zeitpunkt des Datenpunkts bzw. Bucket-Tag; auch producer-gesteuerter Idempotency-Key |
| Dimensions | map | eigene Aufschlüsselungsachsen; strukturelle Labels, nie Payload/PII — sie gehören zum Natural Key |
| Labels | map | Betreiber-Tags für Zuordnung; sie gehören nie zum Natural Key |
ApprovalResolution — approval.resolved
Abschnitt betitelt „ApprovalResolution — approval.resolved“Terminales Gegenstück zu approval.requested mit derselben Minimal-Data-Haltung:
nur Identifikatoren und Entscheidungsparameter, niemals Subject-Referenz oder Freitextgrund.
| Feld | Typ | Hinweise |
|---|---|---|
| ApprovalID | string | ID der entschiedenen Approval — Referenz zum Holen des vollständigen Records |
| Action | string | angeforderte Action (begrenzter Kurz-Identifikator) |
| SubjectKind | string | Art des Ziel-Subjects |
| RiskTier | string | live abgeleitete Risikoklassifizierung zum Entscheidungszeitpunkt |
| Outcome | string | approved | rejected | canceled | expired — offen auf dem Wire; unbekannte Werte tolerieren |
| RequiredApprovals | int64 | bei der Entscheidung erforderliche verschiedene Approver |
| ApproveCount, RejectCount | int64 | aufgezeichnete Entscheidungen jeder Art |
| PolicyRef | string | matchende Approval-Policy; leer bei caller-supplied Parametern |
| DecidedAt | timestamp | Zeitpunkt des terminalen Ergebnisses |
WorkflowSignal — workflow.signal
Abschnitt betitelt „WorkflowSignal — workflow.signal“Vom Orchestration-Modul publiziert, wenn ein governed DAG-Workflow einen
eventing-emit-Schritt erreicht. Der Typ wird vom Modul festgelegt, niemals aus der
Step-Konfiguration gelesen; ein Workflow-Autor kann daher kein First-Party-Event in das
Ingest eines anderen Moduls fälschen. Die Konfiguration liefert nur das begrenzte Label.
| Feld | Typ | Hinweise |
|---|---|---|
| WorkflowRef | string | Workflow, dessen Run das Signal emittierte |
| RunRef | string | Run; zusammen mit StepRef lokalisiert er den Moment in der Timeline |
| StepRef | string | Referenz des emittierenden Steps im Graphen |
| Label | string | vom Operator geliefertes, begrenztes, nicht-sensibles Label |
WorkEventFact — K1/K2 work.*
Abschnitt betitelt „WorkEventFact — K1/K2 work.*“Die acht K1/K2-Work-Channels exponieren dieselbe begrenzte payload_json-Projektion
eines append-only WorkEvent. Der Typ trägt die semantische Klasse; das Payload benennt
Command, Result und resultierenden Aggregatzustand. Es enthält niemals Brief-Text,
Acceptance-/Decision-Aussagen, Begründungen oder Owner-Freitext. Holder-Felder sind stabile
Identity-Referenzen, keine Anzeigenamen. Während beta müssen Consumer additive Felder tolerieren.
| Feld | Typ | Hinweise |
|---|---|---|
| command | string | geschlossener Name der Durable-Work-Mutation |
| result_kind | string | Art der zurückgegebenen Entität |
| result_id | UUID | Referenz der zurückgegebenen Entität |
| workspace_id | UUID | governed Workspace-Referenz |
| work_item_id | UUID | WorkItem-Referenz |
| status | string | resultierender WorkItem-Zustand |
| owner_epoch | int64 | resultierende monotone Ownership-Epoch |
| event_seq | int64 | resultierende monotone Sequenz im WorkItem |
| lease_id | UUID | nur K2-Lease-Event: stabile WorkLease-Zeilenreferenz |
| lease_state | string | nur K2-Lease-Event: resultierender Lease-Zustand |
| holder_sid | string | nur K2-Lease-Event: kanonische Holder-SID |
| holder_run_ref, holder_agent_ref | string | nur K2: begrenzte Run-/Agent-Referenzen, falls vorhanden |
| fence | int64 | nur K2: resultierende monotone Fencing-Generation |
| expires_at | timestamp | nur K2: Ablaufzeit nach DB-Uhr, solange aktiv |
| end_reason_code | string | nur beendetes K2-Event: serverdefinierte Reason-Klasse, nie Operator-Freitext |
| end_reason_hash | string | nur beendetes K2-Event: SHA-256-Hex des gespeicherten Grunds |
| forced | boolean | nur Force-Takeover: immer true, markiert Override der Live-Lease-Autorität |
| severity | string | nur Force-Takeover: fest high |
| decision_id | UUID | nur Force-Takeover: effektive Governance-Decision, die den Override autorisierte |
| takeover_reason_hash | string | nur Force-Takeover: SHA-256-Hex; Operator-Grund wird nie publiziert |
Die vier Force-Takeover-Felder sind eine optionale Projektion auf work.lease.acquired;
normales Acquire, Renew und nicht erzwungenes Takeover tragen sie nicht. Den geschützten
Operator-Grund kann ein Consumer nur autorisiert über Decision-/Audit-Referenzen holen,
nicht aus diesem Event rekonstruieren.
DirectNoticeAvailableV1 — work.message.available
Abschnitt betitelt „DirectNoticeAvailableV1 — work.message.available“Der unveränderliche v1-Fakt, den die DirectNotice-Source-Transaktion in WorkEvent und
WorkOutbox schreibt. Die Message ist das Subject: message_id und result_id sind
dieselbe UUID; result_kind ist fest sessions.message. Empfängeridentität und Inhalt
fehlen bewusst; ein autorisierter Consumer folgt der Message-Referenz.
| Feld | Typ | Hinweise |
|---|---|---|
| schema_version | int64 | fest 1; ein späterer Writer fügt ein Schema hinzu, statt v1-Fakten umzubenennen |
| command | string | fest message.publish.direct |
| result_kind | string | fest sessions.message |
| result_id, message_id | UUID | identische Message-Subject-Referenzen |
| channel_id | UUID | governed Channel-Referenz |
| message_kind | string | fest notice für diese erste K3-Write-Vertikale |
| state | string | bei Verfügbarkeit fest published |
| version | int64 | 2, nach atomarem draft→published-Übergang |
| event_sequence | int64 | 1, erstes append-only Event des Message-Aggregats |
| delivery_count | int64 | 1, da DirectNotice eine initiale Delivery auflöst |
| required_count, ack_quorum | int64 | initiale Ack-Anforderung, jeweils 0 oder 1 |
| fulfillment | object | initiale not_required- oder pending-Projektion samt Counts |
| audience_hash | SHA-256 hex | bindet den Audience-Graphen, ohne Empfänger offenzulegen |
| payload_digest | SHA-256 hex | bindet kanonischen Message-Inhalt, ohne ihn zu tragen |
| plan_hash | SHA-256 hex | bindet den autorisierten Publish-Plan |
Die WorkOutbox liefert die Envelope-ID; Retries nach unklarer Abwicklung verwenden
dieselbe ID und byte-identisches Payload, sodass Eventing sie als ein Event behandelt.
Abweichender Typ, Source, Zeitpunkt, Payload oder Message-Subject unter derselben ID wird
abgelehnt. Webhook-Consumer deduplizieren auf X-Olivares-Event; ein Operator-Replay
erzeugt ein neues X-Olivares-Delivery, behält aber die Event-ID.
K3/K4-Kommunikations-Lifecycle-Fakten
Abschnitt betitelt „K3/K4-Kommunikations-Lifecycle-Fakten“Die übrigen Kommunikations-WorkEvents verwenden geschlossene Minimal-Data-Projektionen. Sie tragen IDs, Zustände, monotone Versionen/Fences und Digests, niemals Message- Inhalt, DecisionResponse-Inhalt oder Handoff-Payload/-Grund. Vollständige Feldgrenzen stehen in den AsyncAPI-Schemas.
| Schema | Channels | Subject-Felder |
|---|---|---|
| DirectNoticeAcknowledgedV1 | work.message.acknowledged | Ack-, Delivery- und Message-IDs; Version/Zustand; Late-Flag; Fulfillment; Plan-Hash |
| WorkflowMessageCarrierV1 | Workflow-Form von work.message.available; work.handoff.carrier.available; work.protocol.reply.available; work.protocol.message.received | WorkItem-, Message-, Delivery-IDs; Kind/State/Version; Sequenz; Plan-Hash; kein Remote-Inhalt |
| MessageLifecycleV1 | work.message.retracted, work.message.expired, work.message.overdue | Message-/optionale WorkItem-/Aggregate-IDs; State/Version; Delivery-Count; Fulfillment; Plan-Hash |
| MessageDerivedV1 | work.message.rerouted, work.message.escalated | Quell-/neue Message-ID, begrenzte Empfängerreferenz, Automationstiefe, Plan-Hash |
| DecisionRequestEvent | work.decision.request.responded, work.decision.request.expired | Request-/Response-/WorkItem-IDs, Transition/State, 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, Plan-Hash |
ProtocolBindingEvent — K5 work.binding.*
Abschnitt betitelt „ProtocolBindingEvent — K5 work.binding.*“ProtocolBinding schreibt eine begrenzte Projektion in den WorkItem-Eventstream, wenn es
eine aus-/eingehende Bindung reserviert, eine Observation reconciliert oder eine
Abbruchabsicht beansprucht. Vier Channels teilen dasselbe Schema; der Typ bestimmt die
Mutation. Empfang ist durch sessions:work:read geschützt.
| Feld | Typ | Hinweise |
|---|---|---|
| binding_id | UUID | durable ProtocolBinding-Referenz |
| binding_spec_id | UUID | immutable, von der Bindung gepinnte ProtocolBindingSpec |
| binding_spec_generation | int64 | gepinnte Spec-Generation, mindestens 1 |
| binding_generation | int64 | genaue repräsentierte Generation der externen Ressource |
| protocol | enum | a2a | mcp |
| workspace_id, work_item_id | UUID | governed Workspace-/WorkItem-Referenzen |
| work_status | enum | resultierender active | review | blocked | canceled-Zustand |
| lease_fence | int64 | Fencing-Generation der synthetischen Session |
| verdict | enum | CLEAN | BROKEN | UNKNOWN; UNKNOWN gilt niemals als Erfolg |
| code | string | begrenzter System-Reason-Code (maximal 128 Byte), nie Freitext |
| terminal | boolean | ob die Observation ein terminales Remote-Ergebnis beweist |
| event_seq | int64 | monotone Sequenz im WorkItem-Aggregat |
| external_id_hash | SHA-256 hex | optionale Einwegkorrelation einer Remote-ID; die ID selbst fehlt |
Das Payload schließt Remote-Ressourcenreferenz/-zustand, Request-/Tool-Argumente, Task-/Message-Ergebnisse, Message-Inhalt, Observation-Detail und Operator-Abbruchgrund bewusst aus. Diese Werte bleiben hinter governed Stores; das Event exponiert nur den minimalen Reconciliation-Fakt.
AuditRecord — audit.recorded
Abschnitt betitelt „AuditRecord — audit.recorded“Ein versiegelter Datensatz des manipulationsnachweisenden Audit-Ledgers, an ein SIEM weitergeleitet. Er läuft nicht über den Bus: Der Forwarder geht die Chain ab einem Tenant-Cursor entlang und übergibt jeden Record an Durable Intake; Integrity-Felder bleiben unverändert, sodass ein Control Tower die Chain selbst verifizieren kann.
| Feld | Typ | Hinweise |
|---|---|---|
| EventID | string | stabile Idempotency-ID, auf der Consumer deduplizieren |
| Seq | int64 | Tenant-Ledger-Sequenz und Natural Key; Lücken sind erkennbar |
| OccurredAt | timestamp | Zeitpunkt der auditierten Action |
| Source | string | emittierende Komponente |
| Payload | bytes | bereits encodierter Minimal-Data-Record mit Chain-Feldern (Sequenz, Previous Hash, Hash, Signatur) |
PolicyChange — policy.changed
Abschnitt betitelt „PolicyChange — policy.changed“Spiegelt, was der Audit-Record der Policy-Mutation behält — Kind und Enabled — plus
die ID und die Operation. Es trägt niemals den vom Operator gelieferten Policy-Namen
oder die Policy-Spec; ein für governance:policy:read autorisierter Consumer holt
die Policy über PolicyID.
| Feld | Typ | Hinweise |
|---|---|---|
| PolicyID | string | die ID der geänderten Policy |
| Kind | enum | abac | approval |
| Op | enum | created | updated | deleted — offen auf dem Wire; toleriere Werte, die du nicht kennst |
| Enabled | bool | das Enabled-Flag nach der Änderung; false bei einer Löschung |
Externe Subscriptions (Eventing-Plattform)
Abschnitt betitelt „Externe Subscriptions (Eventing-Plattform)“Das Eventing-Modul leitet die katalogisierten Event-Typen an externe HTTPS-
Endpoints als signierte Webhooks weiter. Subscriptions werden unter
/v1/m/eventing/subscriptions verwaltet — eine Modul-Route, bewusst außerhalb des
REST-OpenAPI-Contracts — während die Event-Typen, die es ausliefert, die
Per-Typ-Stabilitätsstufen oben tragen.
Die Delivery
Abschnitt betitelt „Die Delivery“Jede Delivery ist ein HTTPS-POST, dessen Body der JSON-Envelope plus
Seq ist — dieselben Feldnamen wie der Envelope oben (das SDK ist der Contract),
mit einem additiven Feld: Seq, der Per-Tenant-Cursor, von dem ein Replay startet. Der
typed Payload reitet unter Payload.
{ "ID": "0197a2b4-6e1d-7c3a-9f4e-2d8b5c1a0e7f", "Type": "cost.sampled", "Tenant": "…", "Source": "…", "Time": "2026-06-11T12:00:00Z", "Seq": 42, "Payload": { "ProviderRef": "…" }}| Header | Bedeutung |
|---|---|
| X-Olivares-Timestamp | der Unix-Sekunden-Timestamp, den die Signatur abdeckt |
| X-Olivares-Signature | t=<ts>,v1=<hexsig> — HMAC-SHA256 über <ts>.<body> mit dem Subscription-Secret; verifiziere mit connectors/webhook.VerifyWithin |
| X-Olivares-Event | die stabile Event-ID — dein Idempotenz-Key, identisch über jeden Retry und Replay eines Events |
| X-Olivares-Event-Type | der Event-Typ (die Channel-Adresse) |
| X-Olivares-Delivery | die Delivery-ID — ein Replay ist eine neue Delivery des gleichen Events |
- At-least-once. Dasselbe Event kann mehr als einmal ankommen; dedupliziere über
X-Olivares-Event. - Retries. Ein
408,425,429, jedes5xxoder ein Netzwerkfehler wird auf einer exponentiellen Backoff-Leiter wiederholt — 30s, 2m, 10m, 30m, 1h, 2h, 4h, 8h (±20% Jitter) — dann dead-lettert die Delivery (die DLQ). Jede andere Non-2xx- Response ist terminal. - Replay. Eine Subscription kann ab einem
Seq-Cursor wiederholt werden; ein Replay behält dieX-Olivares-Event-ID des Events unter einer frischenX-Olivares-Delivery. - Redirects werden niemals gefolgt — ein Redirect würde den signierten Body umleiten.
- Secret-Rotation ist sofortig. Die Plattform hält genau ein Signing-
Secret pro Subscription: nach
POST …/rotate-secretsigniert jeder spätere Versuch — einschließlich Retries bereits gequeuter Deliveries — mit dem neuen Secret. Aktualisiere zuerst deinen Verifier, dann rotiere. - Das Verengen von
event_typesist kein Recall. Bereits für die Subscription erfasste Deliveries bleiben gequeut und werden ausgeliefert (die Per-Typ-Permission gilt weiterhin); der verengte Filter bestimmt, was von da an erfasst wird.
Per-Typ-Receive-Permission
Abschnitt betitelt „Per-Typ-Receive-Permission“Eine Subscription benennt eine Rolle; vor jedem Delivery-Versuch wird diese Rolle gegen die Permission des Event-Typs evaluiert, durch die volle RBAC+ABAC- Pipeline (deny-closed). Das Mapping spiegelt die Read-Oberfläche jedes Typs in der Produkt-API:
| Event-Typ | Permission | Stabilität |
|---|---|---|
| edge.observed | accessgraph:read (privilegiert: editor+) | stable |
| cost.sampled | finops:spend:read | stable |
| finding.reported | security:finding:read | stable |
| guardrail.observed | security:observed:read (privilegiert: editor+) | beta |
| approval.requested | governance:approval:read | beta |
| policy.changed | governance:policy:read | beta |
| metric.sampled | adoption:developer:read (privilegiert: 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 |
Siehe auch
Abschnitt betitelt „Siehe auch“- REST-API-Referenz — der synchrone Contract (OpenAPI 3.1).
- API-Stabilität — die Fenster hinter den Per-Typ- Stabilitätsstufen.
- Architektur-Überblick — wie Beobachtungen zu Kanten werden und die Access Map erreichen.
- Die rohe Spezifikation:
/asyncapi/asyncapi.yaml.