ADR 0004. Async-First Ingestion (Control Plane vs. Data Plane)
Status
Accepted.
Tightened by spec §34 and ADR 0015: gameplay
must not call PlayerPal at all. Ingestion remains async-first. ACK after durable
acceptance (202). See docs/ingestion-and-availability.md.
Context
The naive design validates, queries, calculates campaigns, updates points, updates analytics, then responds. That puts a large amount of synchronous work in the request path of every single activity event. At scale this is both slow and expensive, and couples ingestion availability to the reward engine's availability.
Decision
Split the system into:
- Control plane (low frequency, session establishment, identity resolution, token issuance, campaign/integration config): may touch DB/cache directly.
- Data plane (high frequency, bets, rounds, transactions, telemetry): the ingestion request does auth + minimal envelope validation + durable append only, then responds 202. Everything else (normalization, rule evaluation, ledger updates, analytics) happens asynchronously off a durable event log.
Real-time and batch ingestion both normalize into one shared event model feeding one reward engine, never two parallel engines.
Consequences
- A reward-engine outage does not block activity acceptance.
- Ingestion API is stateless and trivially horizontally scalable.
- Requires idempotent processing downstream (see ADR 0008) since durability here is at-least-once, not exactly-once.
- Requires an explicit choice on ACK timing (broker-confirmed vs. local-append-then-forward). See the architecture brief §4.8 for the trade-off; not a separate ADR since it's phase-dependent, not fixed.