Implementation guides, worked examples, and interactive labs
Agent command gateway: stale reads, conflicts and duplicate credits
Send credit proposals from an agent through an event-sourced aggregate and see which checks stop stale reads, retries and cap breaches.
Synthetic fixtures · deterministic model · nothing is called over the networkExperiment inputs
Complete-run results
Decision trace
What this experiment demonstrates
A support agent reads an account summary from a read model and proposes service credits for three synthetic complaints. The proposals go through an account aggregate that owns three rules: an idempotency check, an optimistic concurrency check on the stream version, and a 30-day credit cap with an approval threshold. The account starts at version 41 with 120 credited. Just after the agent reads the account for the first complaint, a colleague issues a 30 credit by hand, so the agent's view is already out of date when its command arrives.
Nothing here calls a language model. The agent is a fixed policy: it proposes the requested amount, reduced to whatever room it believes is left under the cap. That keeps every difference traceable to one control instead of to model randomness.
Run controlled comparisons
Start with the defaults and read the trace. Each complaint first conflicts because the read model lags by one event, the aggregate returns the current state, and the agent re-plans. The first proposal is above the approval threshold, so it becomes a pending request instead of a credit. After the second complaint the tool call times out and the agent retries; the retry carries the same intent-derived key, so the aggregate appends nothing.
Now change the idempotency key to a new key per attempt. The retry conflicts, the agent re-plans because it cannot tell that its first attempt succeeded, and a second credit is appended. The version check alone does not save you. Set the key back, switch the version check off, and move the cap check into the agent prompt with a cap of 200 and a threshold of 100: the agent's stale view lets the account pass the cap. Move the cap check back into the aggregate and the same run is safe. Finally set re-plans to zero to see every conflicted complaint escalate to a human.
Notice what does not change. With the version check on and the cap in the aggregate, raising the read-model lag from one to three events only adds conflicts, and moving the cap into the prompt changes nothing because the aggregate never needed to reject. Lag and prompt-only rules become dangerous exactly when the deterministic checks are switched off.
Inspect the trace and keep evidence
The event table lists every event appended after the starting version, including the colleague's credit, with the actor that caused it. Metrics count conflicts, blocked duplicates, pending approvals, escalations, duplicate credits and states above the cap; the last two are the invariant violations and are highlighted when non-zero. Start trace hides the steps, Next step reveals them one by one, and Show all or the slider returns to the full sequence. Reset restores the defaults, and Export JSON downloads the inputs, events and trace so two runs can be compared side by side.
Limits and production translation
The window is a single counter rather than credits that expire by date, the human acts once at a fixed moment, and the transport never reorders messages. Real systems also need authorization of the person the agent acts for, which this page leaves out. The point that carries over is structural: the checks that must always hold live in the aggregate, keys come from intent rather than attempts, and conflicts lead to a bounded re-plan or a human, never to a silent overwrite.