Delivery

AEP Delivery Semantics

> Status: draft. Part of the AEP 0.1 protocol specification.

Purpose

Define the event delivery contract between producer and consumer across all transports, including acknowledgement, sequence tracking, and replay.

Delivery Modes

ModeDeliveryDuplicatesReplayUse Case
best_effortAt most onceNoNoTransient UI updates, heartbeat
at_least_onceAlways deliveredPossibleNoTask results, memory facts
replayableAlways deliveredPossibleYes (cursor)Late-joining consumers, audit

Delivery mode is declared in the subscription filter as delivery_mode and carried on each event under delivery.mode.

Event Identity

Every event has a globally unique id. Consumers use the id for idempotent processing:

Acknowledgement Protocol

AEP-level Acknowledgement

When a consumer has successfully processed an event, it sends:

{
  "type": "event.acknowledged",
  "causation_id": "evt_01JZ0000000000000000000000",
  "payload": {
    "acknowledged_event_id": "evt_01JZ0000000000000000000000",
    "cursor": "stream_01:42"
  }
}

Rejection

When a consumer cannot process an event:

{
  "type": "event.rejected",
  "causation_id": "evt_01JZ0000000000000000000000",
  "payload": {
    "acknowledged_event_id": "evt_01JZ0000000000000000000000",
    "error": {
      "code": "protocol_error",
      "message": "unexpected event type for current state"
    }
  }
}

Ack Expectations

Sequence Tracking

Each event in a delivery stream carries a sequence number:

{
  "delivery": {
    "mode": "at_least_once",
    "sequence": 42,
    "cursor": "stream_01:42"
  }
}

The cursor format is transport-specific and opaque to consumers. Common formats:

TransportCursor Format
stdioNot applicable (no replay)
WebSocket<stream_id>:<sequence>
HTTP SSEEvent id from SSE protocol
NATS/KafkaNative offset or timestamp

Replay

A consumer replays events by subscribing with from_cursor:

{
  "types": ["task.*"],
  "from_cursor": "stream_01:42",
  "delivery_mode": "replayable"
}

The producer: 1. Finds the stream position matching the cursor. 2. Delivers all events from that position forward (including the event at the cursor position if from_cursor is inclusive). 3. Transitions to live delivery once caught up.

When replay is complete and the stream is caught up, the producer may send:

{
  "type": "event.replayed",
  "payload": {
    "from_cursor": "stream_01:42",
    "to_cursor": "stream_01:99",
    "events_replayed": 57
  }
}

Redelivery

When a consumer disconnects before acknowledging events, the producer may redeliver unacknowledged events on reconnect. Redelivered events carry:

{
  "type": "event.redelivered",
  "payload": {
    "original_event_id": "evt_01JZ0000000000000000000000",
    "attempt": 2
  }
}

The attempt field counts 1-indexed delivery attempts for the same event.

Implementation Notes