They’re independent. Start with whichever fits. Lint is a five-line change; replay takes an afternoon the first time, then catches the bugs lint can’t see.
Lint
- Reusable workflow
- Composite action
- Plain go run
The least setup. It installs Go from your
go.mod, runs the linter, and annotates findings inline on the PR..github/workflows/istravex.yml
Replay
The linter reads code. Replay checks behavior: feed your indexer the corpus’s real ledgers, then ask it what it stored.1. Point your indexer at the mock RPC
The mock RPC serves the corpus’s canonical ledgers through the samegetLedgers interface as Stellar RPC, so your indexer runs unmodified. Only the URL and passphrase change:
Most indexers are configured for one network at a time. Start with
pubnet, which covers the two patterns with the most real-world bugs (fee-bumps and muxed accounts), and add the others as separate runs.
Only the fixture ledgers exist, so the range is sparse: mainnet has ledger 65,474,279 and 65,474,309 and nothing in between. If your ingestion insists on contiguous ledgers, request each fixture’s ledger on its own (
startLedger = the fixture’s ledger, limit = 1). That’s exactly what the wallet-backend pilot does. See the ledger range is sparse.2. Write down what you stored
After ingestion, look up each fixture’s transaction in your store and write what you find toobserved.json, using the same keys as the fixture’s expected_indexed:
observed.json
null, or leave the key out, when your indexer stored nothing for a fixture. This is the only part that’s specific to your codebase, usually a short query or a call into your repository layer. For a complete real example, see the wallet-backend adapter: it runs wallet-backend’s own ProcessLedger against the mock RPC and prints what it produced.
3. Score it
Save this next to your adapter. It fetches each fixture’s expectations, compares field by field, prints a verdict per fixture and exits non-zero unless every one is correct.istravex-score.mjs
source argument to the JSON.parse reviver). A failing run looks like this:
4. Wire it into CI
.github/workflows/istravex.yml
npm ci, and start npm run rpc -- --network pubnet --port 8000 in the background, then point RPC_URL at http://localhost:8000.
When replay fails
Every fixture maps to a rule in the hardening guide that explains the mechanism and the fix:
If you believe the fixture is wrong rather than your indexer, open an issue. Expectations come from independent sources, but that doesn’t make them infallible.