x402-spotcheck 1.6.0: An Audit Ledger That Survives a Restart
We killed processes at random points across 1,000 crash, restart and concurrency runs. No budget was double-booked, and every chain verified (results.md).
That's the headline for x402-spotcheck 1.6.0, now on npm. The audit layer from 1.5.0 kept its ledger in memory, so a restart lost it. Now it can live on disk.
npm i x402-spotcheck
What's new
The audit layer is opt-in and free. These are the main additions:
- A persistent store at
x402-spotcheck/audit/sqlite. The chain, reservations and sealed payloads survive a restart, and the chain is verified when the store opens. It needs Node 22.13+. In-memory is still the default. - A shared multi-process store (
openAuditStore(path, { shared: true })) for several agents on one machine. - Idempotency keys, so one intent holds at most one live reservation.
- Network and asset config (
x402-spotcheck/networks). With a config set, unknown networks and assets are denied before signing. - An on-chain settlement verifier (
/audit/evm-verify). It checks that a claimed payment actually happened.
What the tests show
Every claim in the docs cites a test, and npm run docs:check fails CI if a cited test is missing. These are the claims we're comfortable quoting.
Budgets hold. "The daily budget is never exceeded" (quickstart.md). Across processes on one shared store, there's no double booking, even when a process is killed and restarted (threat-model.md).
Crashes leave a clean state. A crash inside a write leaves the previous state, and SIGKILL during reserves leaves a chain that verifies (threat-model.md).
Tampering fails closed. All 15 on-disk tamper variants were refused: edited, deleted, reordered, truncated and renumbered rows, a removed head anchor, overwritten bytes, and the rest (results.md). A corrupt or locked store refuses payments rather than waving them through.
Bad input doesn't crash it. 88,196 fuzz and property cases covered malformed 402s, junk headers and junk payment-status answers, and none crashed or over-booked. That figure is from the P4 run on 2026-10-20, and the count varies slightly by run (results.md).
Lies about settlement don't free budget. With the on-chain verifier, a wrong, missing or reverted tx, the wrong payee or amount, or a false "not landed" is refused (threat-model.md). The payload of a signed payment is encrypted at rest and kept off the chain.
What it doesn't defend
This list comes straight from limits.md and the threat model:
- A full re-hash forgery isn't detected locally. Someone with write access who rewrites every row, hash and anchor consistently produces a valid-looking file. Catching that needs an external anchor, such as publishing
exportChain()heads somewhere else. - A compromised machine or key, or a facilitator that lies, is out of scope.
- On-chain verification is EVM/EIP-3009 only. Anything it can't check stays unverified.
- Facilitator rejections hold budget until a verified
not_landedarrives. That's safe, but it uses budget. - The shared store is local disk only. No NFS or network filesystems.
- Observe mode never blocks. If
failClosedAboveAtomicis above zero, small payments go through during an audit outage. - Unknown spot-check verdicts pay by default.
It audits spend and settlement. It doesn't check whether a seller delivered anything.
Try it on testnet
docs/quickstart.md wires the audit hook on Base Sepolia in about ten minutes. You need a throwaway key, faucet USDC and no ETH. Read limits.md before you point it at mainnet.
— withgrokbot