Skip to content

fix(solana): recover a payment from the durable ledger fetchPaid used (agent 2.12.3) - #152

Merged
enot3615 merged 1 commit into
mainfrom
fix/solana-recovery-file-ledger
Nov 2, 2026
Merged

enot3615 merged 1 commit into
mainfrom
fix/solana-recovery-file-ledger

Conversation

@enot3615

@enot3615 enot3615 commented Nov 2, 2026

Copy link
Copy Markdown
Collaborator

Problem

A Solana fetchPaid checks the signature status once, right after sending. A transaction that is not finalized yet ends in SOLANA_V14_PENDING with a recovery object, and the documented next step is recoverPaidPayment.

On the devnet E2E (2026-11-02) every such recovery failed with "Recovery disagrees with the original spending reservation". Without a daily cap, this.ledger is a MemorySpendLedger. fetchPaid opens FileSpendLedger.forAgent(...) for Solana and reserves the purchase there. A new process, or any agent instance other than the one that paid, then recovered against the empty in-memory ledger. As a result no receipt was ever issued for a pending Solana payment.

Change

node/src/unifiedAgent.ts: recoverPaidPayment for a Solana recovery opens the same file ledger that fetchPaid uses, unless a spendLedger override was given. The fix is one line.

Python is not affected: it reads the ledger from the journal path it is given.

Tests

  • New: "a new agent without a daily cap recovers a %s payment from the durable ledger fetchPaid used" (SOL and USDC). It pays with no spendLedger override and no daily cap, then recovers from a freshly constructed agent. Without the fix it fails with exactly the devnet error.
  • tsc --noEmit passes, vitest 876/876, MCP cohort test passes, version gate passes.
  • Live devnet, with this commit packed into the E2E harness: recovered rcpt_aa90ab7c… for the second payment and rcpt_91b347c4… for the first. The local AIFP-1 gate answered 200 with the recovered receipt.

Agent 2.12.3; the MCP cohort pin moves to match.

Linked surfaces

  • Python SDK: not affected. Recovery takes an explicit journal path.
  • MCP: picks this up once it pins agent 2.12.3.
  • Backend / dashboard / docs: not affected. This is a client-side ledger selection only.

… (agent 2.12.3)

Without a daily cap the agent's ledger is in memory, but fetchPaid opens the
file ledger for Solana and reserves the purchase there. recoverPaidPayment in
a new process read the empty in-memory ledger and failed with "Recovery
disagrees with the original spending reservation", so no receipt was ever
issued after SOLANA_V14_PENDING. Recovery now opens the same file ledger.
@enot3615
enot3615 merged commit 01ca290 into main Nov 2, 2026
44 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant