Payment Failure Lab
Prove what the application persisted after payment failures and retries. HTTP success alone is insufficient. The full ZIP contains an adapter-driven runner, a synthetic SQLite example and a scenario matrix. Python 3.10+ is enough for the example; testing your app requires a local/sandbox deployment and an app-specific adapter.
Establish the contract
Identify the payment provider, SDK/version, event schemas, signature verifier, entitlement store, financial ledger, payout/outbox records and queue settlement mechanism. Read adapter and provider integration. Follow existing repository permissions; the lab does not authorize live purchases, refunds, transfers or ledger edits.
Define expected state from product rules before running a handler. Use integer minor units with explicit currency. Include every durable effect relevant to the case: order status, entitlement count, credited amount, refund balance, event dedupe count, payout/outbox status. A subset that omits credits cannot establish absence of duplicate credits.
Wire the lab
Use a fresh disposable environment. Implement an argv-based adapter accepting one JSON request on stdin and returning one JSON object. It must invoke the actual local/sandbox webhook endpoint or handler, and independently query application storage. Do not compute snapshots from the incoming event or expected scenario. Do not connect this runner to production.
python3 scripts/run-lab.py templates/sequence.json --adapter python3 scripts/example-adapter.py /path/to/new-demo.sqlite
This command tests the bundled synthetic model only. For your application, replace the adapter and fixture payloads. snapshot must report a real queue barrier with settled: true; a timer by itself does not prove settlement. The runner rejects unsettled state and adapter timeouts.
Exercise failures
Start with success → duplicate → refund → duplicate refund → delayed success; the last event must follow the application's documented refund precedence. Add invalid-signature and stale-signature cases, payment failure with no access, interrupted checkout with no event, and out-of-order delivery. Use the scenario matrix to record coverage. Add concurrent deliveries in the app's integration suite; this sequential runner cannot establish race safety.
A failure means inspect persisted effects and repair the narrow cause. Create a new disposable test state before rerunning; never delete live dedupe rows to make a test pass.
Deliver
Return reproducible scenarios, adapter, sanitized pass/fail output, a map from state fields to actual storage queries, and uncovered cases. A synthetic pass is a helper self-test, not payment-provider certification. Report provider sandbox and concurrency testing separately.