Abuse & fraud prevention · interactive lab
Refund authorization, replay, and ledger-race lab
Compare approval binding, expiry, tenant ownership, idempotency, and atomic reservations using a synthetic 100-unit refund ledger.
Synthetic data · no model or payment API callsExperiment inputs
Complete-run results
Decision trace
The invariant under test
Every run starts with 100 synthetic refundable units. The experiment shows why several controls are needed together: tenant ownership establishes access, approval binding protects the exact proposal, freshness rejects stale decisions, idempotency deduplicates one operation, and atomic reservation protects the shared balance across different operations. None of these controls is a substitute for all the others.
No money moves and no payment provider is contacted. The amounts are unitless teaching values. A real service must handle currency-specific minor units, processor contracts, durable state, authenticated evidence, and reconciliation of uncertain outcomes.
Run the race and replay comparisons
The default race uses two distinct approved requests of 70 units each. With atomic reservation enabled, one commits and the second sees only 30 remaining, so it is blocked. Turn atomic reservation off: both workers use the same stale 100-unit snapshot and the final balance becomes negative 40. The ordering of the winning request is not the point; the aggregate invariant is.
Choose the replay fixture to submit the same 50-unit operation twice. With idempotency enabled, the second request returns the prior result without another effect. Turn it off and observe two effects. This does not necessarily overspend the 100-unit balance, but it still violates the intended one-operation contract.
Test approval and identity failures
The changed-amount fixture approves 50 and requests 80. Exact binding blocks it unless you disable that control. The expired-approval and wrong-tenant fixtures similarly isolate freshness and ownership. The valid fixture confirms that the controls can permit a legitimate 50-unit operation. Controls that do not apply to the selected fixture should not change its outcome; that is useful evidence about their scope.
Use Start trace and Next step to inspect each attempted operation, or Show all to see the complete result. The slider changes trace visibility only. Complete-run metrics report committed units, remaining balance, duplicate effects, invalid approvals used, and overspend. Reset restores all controls and the race fixture. Export JSON saves the assumptions and decision trace locally.
Translate the lesson into backend tests
The model assumes approvals and identities are represented by trusted fixture flags. It does not implement cryptographic approval records, database locks, external processor idempotency, or network timeouts. In production, those mechanisms must be real and independently tested. A language-model callback cannot make a non-atomic database update atomic.
Build a concurrency test with two workers synchronized before reservation. Assert committed plus reserved never exceeds eligibility. Add a processor fake that accepts an operation and then times out; verify that recovery reconciles the same operation instead of issuing another payment. Test changed destinations and currencies as well as amounts. The goal is an action service that remains correct even when the assistant proposes the wrong thing.