Raxx · internal docs

internal · gated

ADR 0055 — Reasonator API contract: REST with sync + async endpoints

Status: Accepted Date: 2026-05-09 UTC Refs: #1385, docs/architecture/reasonator/design.md (Decision 2), docs/architecture/reasonator/api-contract.md


Context

Reasonator must serve two distinct calling patterns: 1. Pro+ tier: synchronous, low-latency scoring during a live trade ticket session (latency target p99 < 2s for ≤10 headlines). 2. Pro tier: asynchronous, bulk scoring of potentially thousands of unscored sentiment_events rows as a background job.

Three interface styles were evaluated: REST, gRPC, and message queue (SQS/pub-sub only).


Decision

REST, with two endpoint shapes: - POST /v1/score — synchronous, returns scored results inline. For Pro+ real-time path and small Pro batches. - POST /v1/score/batch + GET /v1/score/batch/{job_id} — asynchronous job pattern. For Pro background bulk scoring. Caller submits, Reasonator queues, caller polls. - POST /v1/score/rescore — synchronous re-scoring with a new model SHA. For model upgrade sweeps.

Full contract in docs/architecture/reasonator/api-contract.md.


Consequences


Alternatives Considered

gRPC: Enables bidirectional streaming for a future Pro+ live feed. Adds client stub generation complexity, complicates Heroku routing (HTTP/2 and gRPC-web proxying). No advantage over REST at Phase 1 throughput. Deferred to Phase 3.

Message queue only (SQS): Cannot serve the Pro+ synchronous real-time path. A response would require a separate response queue and correlation IDs — equivalent complexity to REST polling with worse debuggability. Rejected for the sync path. Using SQS as the transport for Pro batch jobs was considered but is overkill at Phase 1 scale (the in-process job queue is sufficient).

GraphQL: No advantage for a machine-to-machine API. Rejected without further evaluation.