| Exchange process crashes or is killed |
Health check; Compose restarts it |
Orders in flight get no answer; nothing acknowledged is lost (answers only after fsync) |
Recovery loads the newest snapshot, replays the input after it, verifies every replayed event against the event log, repairs a missing event-log tail |
JournalRecoveryTest, SnapshotTest, ExchangeApiTest restarts; make e2e restart from snapshot |
| Crash mid-write: half a journal record |
CRC32C / length check on open |
That record was never fsynced, so no client was told about it |
Cut off as a torn tail (ADR 0007) |
FileJournalTest, JournalTailerTest |
| A journal segment damaged in the middle |
CRC check during recovery |
Exchange refuses to start |
Restore the disk; the journal is the source of truth |
FileJournalTest.damageInAnEarlierSegmentIsCorruptionNotATornWrite |
Replay does not reproduce the event log (rule changed without SetRules, non-determinism) |
Recovery's byte-for-byte comparison; make e2e replay check |
Exchange refuses to start rather than trade on a different book |
Fix the code, or rebuild the derived event log from the input journal (runbook 7) |
JournalRecoveryTest doctored log; ADR 0014 incident |
| Snapshot file damaged |
CRC check on load |
None: an older snapshot or a full replay is used |
Automatic fallback |
SnapshotTest damaged newest falls back |
| Snapshot differs from what replay reaches |
ReplayCheck compares every snapshot |
Would make recovery wrong; caught before use in CI/e2e |
Delete the snapshot; fix the bug |
Replay.checkSnapshots, make e2e |
| Ring full (a slow stage) |
prayog_ring_remaining; self-test "ring has room" |
New orders refused with 503 busy; nothing queues without bound |
Clients retry; the slow stage catches up |
ExchangePipelineTest.trySubmitRefusesWhenTheRingIsFull |
| Client floods orders |
Token bucket per account and tier |
That account gets 429; others unaffected |
Automatic refill |
ExchangeApiTest rate-limit tests (ADR 0020) |
| Client retries after a timeout |
Duplicate client order id check (rules v2) |
Retry rejected DUPLICATE_CLIENT_ORDER_ID; no second order |
None needed |
ExchangeRulesTest, Cucumber scenario, API test |
| Slow market-data subscriber |
Per-subscriber buffer overflow |
That subscriber is disconnected; nobody else slows down |
Client reconnects and gets a fresh snapshot |
SDK reconnect; market_check feed integrity |
| A gap in a market-data feed |
Per-symbol sequence numbers |
Client's book would be wrong |
SDK and web detect the gap and resync from a snapshot |
test_book.py, market_check |
| Admin halts or closes the market by mistake |
Session state on every page |
Halt: cancels only; close: open orders expire |
Ops page: Open |
ExchangeRulesTest sessions; Cucumber |