← Back to the StreamLD module index
1. Introduction
StreamLD defines an append-only, per-stream event log. Each event is assigned a *sequence number* by the server at write time: a strictly increasing, per-stream integer starting at 1. Sequence numbers are the sole ordering primitive — StreamLD defines no timestamp-based ordering.
2. The Event Envelope
Every StreamLD event is a `streamld:EventEnvelope`. Its normative field list is defined by the SHACL shape at `streamld/model/envelope.ttl` and summarized below.
streamld/model/envelope.ttl by
generator/generate_streamld_docs.py. Do not edit it by hand — edit
the SHACL shape and regenerate.
2.1. EventEnvelope
| Field | Type | Required |
|---|---|---|
isSnapshot
| boolean | Yes |
payload
| (node) | Yes |
sequence
| integer | Yes |
streamId
| string | Yes |
2.2. ReplicationFrame
| Field | Type | Required |
|---|---|---|
cursor
| integer | Yes |
event
| (node) | Yes |
2.3. SubscriptionRequest
| Field | Type | Required |
|---|---|---|
after
| integer | No |
stream
| (node) | Yes |
2.4. GapSignal
| Field | Type | Required |
|---|---|---|
oldestAvailable
| integer | No |
3. The Cursor
A StreamLD *cursor* is a sequence number: the position of the last event a subscriber has already received. A subscription request of the form "everything after cursor C" MUST be interpreted as "all events with sequence number greater than C, in ascending sequence order."
3.1. Gap handling
If a server can no longer satisfy a subscription request because the requested cursor has aged out of the stream’s retention window, it MUST respond with a `streamld:GapSignal` rather than silently resuming from an incorrect position. A client that receives a `streamld:GapSignal` MUST perform a full historical read of the stream before re-subscribing live.
4. Conformance
A StreamLD-conformant server MUST:
-
Assign sequence numbers as a strictly increasing, per-stream integer sequence starting at 1, with no gaps in the sequence for events actually appended.
-
Reject a subscription request whose `streamld:after` cursor is not resolvable against the stream’s current retention window by responding with a `streamld:GapSignal`, never by silently omitting events.