All posts
dispatchevent logsAPI designoperations

Keep read progress separate from dispatch acknowledgement

A reader position helps someone resume a log. An acknowledgement records who has accepted the work

An operator opens the event history for a dispatch, reads until they understand why delivery stopped, and moves to another case. An hour later they return. New events have arrived. If the screen simply shows a longer list, they must reconstruct where their earlier reading ended before they can tell what changed.

The log has two distinct questions to answer. Where did this reader stop? Who has accepted responsibility for the unresolved work? A reading position helps with the first. An acknowledgement answers the second. Treating them as one action can hide a failure from the next shift merely because someone opened the page.

Give each event a durable position

Timestamps are useful for human orientation, but they are a poor sole reading position. Two events can share a timestamp, clocks can differ, and late-arriving records can carry an earlier event time. If a client resumes with everything after the last timestamp, it may skip one event or repeat another.

A per-dispatch sequence number or another stable total order is easier to reason about. Each event gets a position that does not change when its display text is corrected or when later events arrive. The API can return the highest position included in a response. A client can ask for events after that position and know which boundary it is crossing.

The contract still needs to say what happens when events are redacted or access changes. A missing position must not cause the caller to invent an event or assume the list is complete. A response can preserve the ordering boundary while explaining that some positions are unavailable to this reader. Authorisation is checked on every request, including a resumed one.

Separate seen from acknowledged

Read through position 42 is an observation about a reader, not an approval of the dispatch. A person may read a failure and leave it unresolved. A monitoring process may consume an event without accepting responsibility for recovery. Conflating seen with handled turns a progress marker into an unsafe workflow action.

For an operator interface, the reading position can remain local to that user until they choose to save it. For a shared team view, an acknowledged position needs an actor and a time. The system should not silently move a team cursor because one person opened the page. Otherwise the next shift may arrive to a clean looking inbox even though nobody decided what to do.

The same distinction applies to API consumers. A client may request a page and crash before it processes every event. The server cannot infer consumption from the response alone. Let the client store its own checkpoint or explicitly acknowledge a position under a separate contract. Repeated delivery after a crash is usually safer than an invisible gap.

Make resumption testable

A useful test begins with an incomplete history. Fetch the first page, record its last position, append several events, then resume. The next response should contain every event after the saved boundary exactly once under the documented order. Repeat with two events bearing the same event time and with an event whose source time predates the first page.

Test permissions as well. If the reader loses access, resumption should fail clearly rather than returning an empty page that looks like the end of the log. If an event is removed from view, the client should still be able to advance past the unavailable position without guessing its content. These cases reveal whether the cursor represents order or merely a timestamp-shaped convenience.

The response can be compact: events, next position, and whether more are currently available. A separate status field can say whether the dispatch itself is pending, completed, or blocked. Keeping list traversal separate from dispatch state prevents a reader from treating the end of the current page as proof that the operation has ended.

Stack Dispatch deals with histories that keep changing after a request returns. A stable reader position gives operators and clients a modest, precise promise: they can resume from a known boundary and examine what arrived next. It does not decide whether an event was understood or a failure was resolved. Those decisions deserve their own explicit record.

0 comments

Join the conversation

Get the next dispatch

New writing on software architecture, AI systems, and shipping production software, sent by email. Unsubscribe anytime.