Owner: whoever owns event-ingestion/disputes (unassigned) · Priority: Low-medium, can be split into per-store PRs — does not block rollout of the Redis approach elsewhere, except EventProcessorService/LedgerCursorService's reorg-safety semantics should be explicitly re-verified as part of their migration.
Description
Beyond the services named in the original persistence spike (#181), the inventory in backend/PERSISTENT_STORAGE_SPIKE.md (§1) found several more process-local Map stores backing background workers, sagas, and run-history tracking:
DisputeSagaService (src/dispute/dispute-saga.service.ts) — Map<sagaId, DisputeSaga> + Map<escrowId, sagaId> index. Losing state mid-saga on restart leaves a dispute stuck between steps.
EventProcessorService (src/event-ingestion/event-processor.service.ts) — Map<eventId, ProcessedEvent>, the reorg-safety dedup log gating whether a Soroban event has already been processed. Losing it on restart risks double-processing events ingested just before the restart.
LedgerCursorService (src/event-ingestion/ledger-cursor.service.ts) — Map<contractId, LedgerCheckpoint>. Already prefixes its Map keys with ledger_cursor:, i.e. it's already shaped like a Redis key — looks like an unfinished migration.
ReputationScoreStore (src/reputation/reputation-score.store.ts) — Map<address, ReputationScoreRecord>. Simple KV shape, lowest risk of the group.
EscrowReconciliationStateStore (src/escrow-reconciliation/escrow-reconciliation-state.store.ts) — Map<runId, ReconciliationRun>, sorted by start time for listing.
MigrationStateStore (src/migration/migration-state.store.ts) — Map<runId, MigrationRun> + Map<migrationName, activeRunId>. Notably, the framework that runs schema migrations currently has no persistent record of having run one.
All six are simple KV/small-index shapes with no unusual query needs — same recommendation as the rest of the spike: Redis, following the pattern GigService's prototype in #181 establishes (entity as SET/GET, indices as sets/sorted sets, transaction-result verification, fallback metric, production fail-fast, graceful fallback to memory otherwise on Redis errors logged at error level).
Tasks
Acceptance Criteria
Estimated Time
3-4 days (spans six stores; may be split into smaller PRs)
Owner: whoever owns event-ingestion/disputes (unassigned) · Priority: Low-medium, can be split into per-store PRs — does not block rollout of the Redis approach elsewhere, except
EventProcessorService/LedgerCursorService's reorg-safety semantics should be explicitly re-verified as part of their migration.Description
Beyond the services named in the original persistence spike (#181), the inventory in
backend/PERSISTENT_STORAGE_SPIKE.md(§1) found several more process-localMapstores backing background workers, sagas, and run-history tracking:DisputeSagaService(src/dispute/dispute-saga.service.ts) —Map<sagaId, DisputeSaga>+Map<escrowId, sagaId>index. Losing state mid-saga on restart leaves a dispute stuck between steps.EventProcessorService(src/event-ingestion/event-processor.service.ts) —Map<eventId, ProcessedEvent>, the reorg-safety dedup log gating whether a Soroban event has already been processed. Losing it on restart risks double-processing events ingested just before the restart.LedgerCursorService(src/event-ingestion/ledger-cursor.service.ts) —Map<contractId, LedgerCheckpoint>. Already prefixes its Map keys withledger_cursor:, i.e. it's already shaped like a Redis key — looks like an unfinished migration.ReputationScoreStore(src/reputation/reputation-score.store.ts) —Map<address, ReputationScoreRecord>. Simple KV shape, lowest risk of the group.EscrowReconciliationStateStore(src/escrow-reconciliation/escrow-reconciliation-state.store.ts) —Map<runId, ReconciliationRun>, sorted by start time for listing.MigrationStateStore(src/migration/migration-state.store.ts) —Map<runId, MigrationRun>+Map<migrationName, activeRunId>. Notably, the framework that runs schema migrations currently has no persistent record of having run one.All six are simple KV/small-index shapes with no unusual query needs — same recommendation as the rest of the spike: Redis, following the pattern
GigService's prototype in #181 establishes (entity asSET/GET, indices as sets/sorted sets, transaction-result verification, fallback metric, production fail-fast, graceful fallback to memory otherwise on Redis errors logged aterrorlevel).Tasks
GigServicepattern (can land as separate PRs per store, or grouped — whichever keeps each PR reviewable)EventProcessorServiceandLedgerCursorServicespecifically: verify the migration preserves reorg-safety semantics (no gap where an event could be double-processed or a cursor lost between the old and new store)Acceptance Criteria
event-processor/ledger-cursormigration is explicitly verified not to weaken reorg-safety guaranteesEstimated Time
3-4 days (spans six stores; may be split into smaller PRs)