This recipe exposes owned operations through HTTP, a resumable stream, and a message queue without turning routes, status codes, frames, or broker acknowledgement into domain meaning.
The .one syntax below is illustrative end-product syntax.
1. Start with operations
semantic parcelhub.tracking
domain one.contracts@1
fault TrackingFault@1
not_found
operation Tracking.GetShipment@1
accepts GetShipmentRequest
returns Shipment
faults TrackingFault
effect read
operation Tracking.WatchShipment@1
accepts WatchShipmentRequest
returns stream<ShipmentEvent>
delivery resumable cursor: ShipmentCursor
ordering per_shipment
backpressure bounded(256)Neither operation implies a network boundary.
2. Add an HTTP projection
semantic parcelhub.tracking_http
domain one.communication.http@1
interface TrackingHttp@1
operation parcelhub.tracking#Tracking.GetShipment@1
request GET "/shipments/{shipment_id}"
parameter shipment_id from input.shipment_id
result 200 json(output)
fault TrackingFault.not_found -> 404 json(fault)
operation parcelhub.tracking#Tracking.WatchShipment@1
request GET "/shipments/{shipment_id}/events"
result server_sent_events(output)
resume header("Last-Event-ID") from input.cursorThe profile validates path collisions, encoding, headers, status mappings, identity, deadlines, cancellation, disclosure, and semantic loss.
3. Consume the stream with explicit flow control
let mut events = client
.watch_shipment(WatchShipmentRequest { shipment_id, cursor })
.await?;
while let Some(event) = events.next().await? {
apply(event.value)?;
events.ack(event.cursor).await?;
}A gap, expired cursor, slow reader, revocation, transport loss, and domain end remain different dispositions. Reconnect resumes from an accepted cursor; it does not replay a mutation.
4. Test the claimed boundary
one test --root TrackingHttp --scenario canonical-paths
one test --root TrackingHttp --scenario stream-gap-and-resnapshot
one test --root TrackingHttp --scenario slow-reader-backpressureSee communication.
5. Project commands and events to messaging
The same semantic edges project to a queue. Broker acknowledgement is delivery evidence, not the domain result:
operation Orders.Place@1
accepts PlaceOrderRequest
returns PlaceOrderResponse
faults OrdersPlaceFault
effect irreversible
idempotency operation(window: 24h)
event OrderPlaced@1
payload OrderPlacedEvent
ordering customer
retention 7dinterface OrdersMessaging@1
command parcelhub.orders#Orders.Place@1
channel "orders.place"
key input.customer_id
delivery at_least_once
acknowledgement accepted_for_delivery
event parcelhub.orders#OrderPlaced@1
channel "orders.placed"
key payload.customer_id
cursor broker_offsetThe profile owns envelope, key, acknowledgement, retry, dead-letter, deduplication, ordering, cursor, and fault mappings. The consumer preserves the distinction between an applied effect, a domain rejection, an unknown outcome, and a retryable cause:
match delivery.handle().await {
Applied(receipt) => delivery.ack(receipt).await?,
Rejected(fault) => delivery.reject(fault).await?,
OutcomeUnknown(effect) => delivery.suspend(effect).await?,
Retryable(cause) => delivery.retry_within_budget(cause).await?,
}See handle failures.