Description
The scheduled settlement sync job calls service.reconcilePendingSettlements() (src/services/settlementStatusSyncJob.ts:28) and five unit tests in src/__tests__/revenueSettlementService.test.ts:266,295,324,367,400 assert its behavior, yet RevenueSettlementService (src/services/revenueSettlementService.ts:29-207) does not define that method — only runBatch, runBatchOnce, recordFailedSettlement, and getErrorMessage exist, and there is a dangling unused reconcileTail field at src/services/revenueSettlementService.ts:31. Separately, runBatchOnce silently drops orphaned events whose API has no registry entry (src/services/revenueSettlementService.ts:80-83 simply continues), so they never settle and never surface. This issue implements reconciliation and adds dead-letter handling for orphaned events.
Requirements and context
- Implement
reconcilePendingSettlements() on RevenueSettlementService returning { checked, completed, failed, errors }, exactly as the existing tests expect (src/__tests__/revenueSettlementService.test.ts:268,297).
- It must read pending settlements (the
SettlementStore exposes getPendingSettlements() — see src/services/settlementStore.ts), query Horizon for each tx_hash using the horizonUrl/fetchImpl options already on RevenueSettlementOptions (src/services/revenueSettlementService.ts:18-19), and transition settlements to completed when successful: true, to failed when successful: false, and treat a 404/missing transaction as failed (per the test at src/__tests__/revenueSettlementService.test.ts:305).
- Serialize reconciliation runs using the existing
reconcileTail promise field, mirroring how runBatch serializes via batchTail (src/services/revenueSettlementService.ts:49-61).
- Replace the silent
continue for orphaned events (src/services/revenueSettlementService.ts:80-83) with explicit dead-letter handling: record/log the orphan with its usageEventId and apiId so operators can act, instead of dropping it.
- Non-functional: use the bounded
withRetry/transient-error helpers from src/lib/retry.js (already imported) for Horizon calls; never mark events settled on a failed payout (current behavior at src/services/revenueSettlementService.ts:161-165 must be preserved).
Acceptance criteria
Suggested execution
1. Fork the repo and create a branch
git checkout -b feature/settlement-reconciliation-deadletter
2. Implement changes — add the method and dead-letter handling in src/services/revenueSettlementService.ts.
3. Write/extend tests — extend src/__tests__/revenueSettlementService.test.ts.
4. Test and commit
npm run lint
npm run typecheck
npm test -- revenueSettlementService --runInBand
Example commit message
fix(settlement): implement reconcilePendingSettlements and dead-letter orphans
Guidelines
Maintain the repo's 90%+ coverage target (README.md). Add JSDoc to reconcilePendingSettlements documenting the return shape and Horizon semantics, and align SETTLEMENT_STORE_DOCUMENTATION.md. Timeframe: 96 hours.
Description
The scheduled settlement sync job calls
service.reconcilePendingSettlements()(src/services/settlementStatusSyncJob.ts:28) and five unit tests insrc/__tests__/revenueSettlementService.test.ts:266,295,324,367,400assert its behavior, yetRevenueSettlementService(src/services/revenueSettlementService.ts:29-207) does not define that method — onlyrunBatch,runBatchOnce,recordFailedSettlement, andgetErrorMessageexist, and there is a dangling unusedreconcileTailfield atsrc/services/revenueSettlementService.ts:31. Separately,runBatchOncesilently drops orphaned events whose API has no registry entry (src/services/revenueSettlementService.ts:80-83simplycontinues), so they never settle and never surface. This issue implements reconciliation and adds dead-letter handling for orphaned events.Requirements and context
reconcilePendingSettlements()onRevenueSettlementServicereturning{ checked, completed, failed, errors }, exactly as the existing tests expect (src/__tests__/revenueSettlementService.test.ts:268,297).SettlementStoreexposesgetPendingSettlements()— seesrc/services/settlementStore.ts), query Horizon for eachtx_hashusing thehorizonUrl/fetchImploptions already onRevenueSettlementOptions(src/services/revenueSettlementService.ts:18-19), and transition settlements tocompletedwhensuccessful: true, tofailedwhensuccessful: false, and treat a404/missing transaction asfailed(per the test atsrc/__tests__/revenueSettlementService.test.ts:305).reconcileTailpromise field, mirroring howrunBatchserializes viabatchTail(src/services/revenueSettlementService.ts:49-61).continuefor orphaned events (src/services/revenueSettlementService.ts:80-83) with explicit dead-letter handling: record/log the orphan with itsusageEventIdandapiIdso operators can act, instead of dropping it.withRetry/transient-error helpers fromsrc/lib/retry.js(already imported) for Horizon calls; never mark events settled on a failed payout (current behavior atsrc/services/revenueSettlementService.ts:161-165must be preserved).Acceptance criteria
reconcilePendingSettlements()exists and the five existing reconciliation tests pass without modification.completed/failedbased on Horizonsuccessful, and missing transactions are treated asfailed.reconcileTail.npm run typecheckpasses (the file currently references an undefined method).Suggested execution
1. Fork the repo and create a branch
2. Implement changes — add the method and dead-letter handling in
src/services/revenueSettlementService.ts.3. Write/extend tests — extend
src/__tests__/revenueSettlementService.test.ts.4. Test and commit
npm run lint npm run typecheck npm test -- revenueSettlementService --runInBandExample commit message
Guidelines
Maintain the repo's 90%+ coverage target (
README.md). Add JSDoc toreconcilePendingSettlementsdocumenting the return shape and Horizon semantics, and alignSETTLEMENT_STORE_DOCUMENTATION.md. Timeframe: 96 hours.