Compute
Start work from an event
Verify where an event came from, freeze the input it points at, and give the run one occurrence identity so duplicate, late or reordered events cannot charge you twice.
Before you start
You need a scoped automation identity, one workflow that already runs correctly by hand, and a source of events you control.
You also need a rule for which events matter. Event triggers fire on your data changing, and data changes far more often than work needs to run.
Verify where the event came from
Treat every inbound event as a claim until you have checked it. An event that arrives at your endpoint is not evidence that your system sent it.
Check the sender, the signature and the time before you act. Then check that the event refers to something your automation is actually allowed to read.
An event you cannot attribute is not a trigger. Drop it, record that you dropped it, and do not start paid work on it.
Freeze the input before you run
An event tells you something changed. It does not tell you what the data looks like now, and it will keep changing while you decide.
So pin the input before admission. The snapshot carries a version_id and a content_sha256, and the run reads those exact bytes for its whole life.
That pair is what makes the run explainable later. If someone asks which data produced a result, you answer with the snapshot, not with a timestamp. See how an immutable snapshot is pinned if the two values ever disagree.
Give the run one occurrence identity
Every occurrence has a stable identity derived from the schedule, its version and the occurrence you intended:
occurrence_key = H(schedule_id || version || intended_occurrence)
Derive that identity from the event, not from the moment you happened to process it. Two deliveries of the same event must produce the same identity.
That is the whole defense against double-charging. An exact replay of the same identity and the same payload digest returns the prior result rather than starting new work.
Handle duplicate, late and reordered events
Assume all three will happen, because at-least-once delivery is normal and ordering is not promised.
- Duplicate. The same identity with the same digest returns the earlier result. Nothing new is admitted and nothing new is charged.
- Equivocation. The same identity with a different digest is refused. That is a real signal: two different requests are claiming to be the same occurrence.
- Late. A stale attempt cannot advance state. An event that arrives after its occurrence resolved is recorded, not replayed into it.
- Reordered. Compare versions rather than arrival order. A lower version never overwrites a higher one.
If you see equivocation, do not retry. Find out which of the two payloads is the one you meant, and send that as a deliberately new occurrence.
Confirm success
Fire one real event and follow it end to end. You should see one occurrence, one fresh quote, one admitted job and one result.
Then fire the same event again on purpose. A correct integration produces the same occurrence identity and no second charge.
Keep the receipt reference from the first run. It is what you quote to support if the two runs ever look different.