Menu ▾ ▴

#15 [Tracking] Transaction recovery and operator reconciliation

open
nobody
2026-09-20
2026-09-17
Anonymous
No

Originally created by: SergeevDmitry

Depends on: the bug "Settlement is recorded as failed when the facilitator returns no tx hash".

Context & Rationale

After a crash an operator has to piece together what happened from three places: payment attempts, receipts and events, and the separate AP2 replay store. None of them represents the purchase as a whole. safePersist() in src/core/execution/pipeline.ts also lets execution continue when a settlement update or receipt write fails, so the local record can silently lag the real world.

Tracking issue: each box is a separate PR, ticked as it lands. Anything that grows its own discussion gets promoted to an issue.

Proposed Changes

  • [ ] Add a per-purchase transaction journal
  • A durable record per purchase linking request, payment attempts, authorization reference, backend execution and receipt, with a stable transaction ID and an input/config digest written before the first irreversible action.
  • [ ] Define purchase lifecycle states, separate from persistence state
  • At least: payment failed, payment uncertain, settled/undelivered, delivery started, delivery unknown, delivered, in remediation. Keep "what the external system did" separate from "what we managed to persist".
  • [ ] Add an authenticated view of unresolved transactions
  • Paginated, with age and related records.
  • [ ] Reconcile x402 settlement and AP2 holds against external evidence
  • Resolve settlement against on-chain or facilitator evidence and align holds with the confirmed outcome. Idempotent, with the resolving actor recorded.
  • [ ] Report safePersist() failures and only hand out committed receipt references
  • The caller learns when persistence failed; a receipt reference given to a buyer always points at a committed row. Migrations preserve existing receipts and replay history.

Non-goals / Invariants Preserved

  • Reconciliation alone never charges, retries delivery or refunds: that is the later remediation work.
  • No raw payment proofs, mandates or merchant payloads in the journal; references and digests only.
  • PostgreSQL and multi-instance atomicity are out of scope.

Impact & Value

Done when, after a crash, restart or partial failure, the gateway can answer from durable state whether payment happened, whether the merchant backend ran, and whether an operator step is needed, with every purchase held as one transaction rather than as scattered protocol-specific records.

Open questions

  • Is the journal a new SQLite table alongside receipts, or do we fold payment attempts into it and migrate? The former is safer, the latter avoids a fourth source of truth.
  • Does the AP2 replay store move into the same database now, or stay separate with a foreign reference?
Test plan (across the list) Crash or store failure injected before settlement, after settlement dispatch, after backend dispatch, after backend success, and before receipt commit. For each: restart, run reconciliation, check state and the idempotency of a second run. Plus unauthorized access to the operator view and redaction of its output.

Discussion


Log in to post a comment.