Payment committed. Confirmation lost.

AIKUS lab engagement

A mock charge committed, but its confirmation was withheld. The caller retried the tool. This lab checks the ledger, tool report and status lookup under five conditions.

Seeded flaws disclosed

The first version is deliberately built to create a new provider idempotency key for every charge attempt instead of forwarding the caller's stable key. It also deliberately reports failed when the provider response is lost, to show that the challenge detects a misleading status. These are seeded flaws, not discovered customer bugs. Because provider keys differ from caller keys, lookup by caller key cannot locate seeded charges. The fixed version forwards the caller key and reports outcome_unknown on a lost response. Both versions use the same provider, proxy and challenge harness.

Claim

Under these tested conditions, repeating a charge with the same key and payload creates one ledger charge; changed inputs conflict; loss before commit permits a legitimate retry; a lost response is reported as an unknown outcome and can be checked by caller key.

Challenge — asserted conditions

Condition Seeded expectation Fixed expectation
1. One call, no fault One charge One charge
2. Charge commits, confirmation lost, identical retry Two charges One charge; original result returned
3. Request dropped before commit, identical retry No charge before retry; one after No charge before retry; one after
4. Charge commits, confirmation lost, amount changes under same key Second charge at changed amount Conflict; original charge unchanged
5. Charge commits, confirmation lost, inspect status and lookup Incorrect `failed`; lookup by caller key misses the charge `outcome_unknown`; lookup returns committed charge

Each case starts fresh provider, proxy and tool processes with an empty ledger. The original amount is USD 10.00 (1000 minor units); the changed amount is USD 15.00 (1500). Both versions have exactly the same challenges. The caller supplies caller-1 for all calls in each case; the schema requires the key. Calls are sequential from the caller's perspective. The retry is sent after the caller's timeout, while the proxy is still holding the first connection; overlapping charge calls from the caller were not tested.

The tool HTTP response timeout is 250 ms. For injected loss the proxy holds for 500 ms before closing the connection without a response. Before-commit loss means the proxy never forwards the request; after-commit loss means it receives and records the committed provider result, then withholds it. The caller therefore times out before the proxy closes. The hold and actual observed call durations are separate quantities. The final state is captured after the proxy handler finishes. This wait is not payment recovery.

get_payment_status is a separate MCP tool and queries the same provider directly by caller key. Its timeout is 2 seconds. This controlled lookup path is available even when the charge-response path is faulty; that availability is an assumption, not a general recovery guarantee.

Evidence

evidence/trace.jsonl contains every harness MCP request, notification and response, fault configuration, provider ledger and events after every response, proxy events, and final state. Responses include actual elapsed milliseconds and UTC timestamps. The ledger is the oracle for charges; a tool status alone is not evidence that no charge occurred. evidence/findings.json records ten observed version/condition results. evidence/sha256.json covers this README, the executed source, review page, trace and findings. The manifest does not hash itself.

Observed findings

The packaged run matched the expected outcomes encoded as assertions in lab.py. Its timestamps and timing are recorded in the trace.

Condition Seeded observed charges Fixed observed charges Fixed outcome
1. Baseline 1 at USD 10 1 at USD 10 Held
2. Lost after commit, identical retry 2 at USD 10 each 1 at USD 10 Original charge C1 returned
3. Lost before commit, retry 0 before retry, 1 after 0 before retry, 1 after Legitimate retry charged
4. Lost after commit, changed amount USD 10 plus USD 15 USD 10 only IDEMPOTENCY_CONFLICT; ledger unchanged
5. Lost after commit, report and lookup 1; reported failed; caller-key lookup not_found 1; reported outcome_unknown; lookup returned C1 Held

In condition 3, the seeded tool reports failed and no charge exists at that point, so its status happens to be correct. This does not establish that failed is a reliable interpretation of a timeout.

Seeded claims held in conditions 1 and 3 and failed in 2, 4 and 5. Fixed claims held in all five. A not_found lookup in the seeded case is not evidence of no charge: the ledger contains it under the deliberately changed provider key.

The harness asserts the encoded expectations and verifies the empty ledger after before-commit loss. These checks validate the intentionally disclosed seeded failures as well as the fixed outcomes. No recording is provided for this lab; the trace is the evidence.

Boundary

One AIKUS-built charge_payment MCP tool plus get_payment_status, a fault proxy and one mock provider with an in-memory idempotency map and ledger, on loopback HTTP. No real payment network or customer systems. Calls are sequential from the caller's perspective: the retry is sent after the caller's timeout, while the proxy is still holding the first connection. Overlapping charge calls from the caller were not tested. Fresh processes and ledger per case; USD mock charges only. No settlement, refunds or reconciliation jobs.

Assumes the caller supplies a stable idempotency key; whether a given agent does is not tested. The provider supports idempotency and changed-payload conflicts. Idempotency here depends on forwarding that key to that provider. The lab does not implement or certify the Agentic Commerce Protocol, does not establish payment-network readiness and does not extend Delivery Check's agreed API scope.

Not tested

Concurrent or overlapping charge calls; persistent idempotency across provider restart; crashes between commit and key storage; multiple instances; key expiration or reuse after expiration; authentication, authorization, tenant isolation or hostile key contents; malformed-input coverage; failed/declined-charge caching policies; caller retries with a different key; long-running or delayed provider commit; unavailable or stale status lookup; different providers; settlement, refunds, reconciliation; production or model behaviour. The before-commit case drops a request rather than exercising a provider transaction rollback. The fixed tool reports unknown even when the proxy secretly knows the request was never forwarded; the tool cannot infer that from a timeout.

Public evidence downloads

Get trace.jsonl, findings.json, sha256.json and boundary.txt below. These files are public; no email request is needed. The ZIP includes all four. Filenames in the manifest use the full-pack paths, such as evidence/trace.jsonl; the public ZIP places these same files at its root.

Download the one-page evidence note (.pdf)

The complete trace is primary evidence. Download it with the boundary, findings and manifest:

Download public evidence with boundary (.zip)

The manifest also covers the source and review pack documents. Request the source or full pack to compare their hashes with this public record.

Request source and full pack

Back to lab evidence