London DataTrading systems technology

Nexus engineering · Deep dives

API & integration.
Design for the lost reply.

Every boundary in Nexus answers three questions before it carries any data: who owns the state, what each value means, and what the caller does when the reply never arrives. The answers decide whether code is shared as a library, owned by a service or wrapped in an adapter.

Ownership before transportMeaning in the typesA defined unhappy pathCompatible change

Source reviewed 2 November 2026 and rechecked 3 November. Each design below is marked Built or Proposed.

01 · Choose the boundary

Ownership first. Transport second.

Putting everything behind HTTP would add failure modes without settling who owns a decision. Nexus picks the kind of boundary from what is being shared, then accepts that kind's cost and controls it.

Shared library · in processBuilt

Target engine

Research and trading must build targets from the same code, so both import it rather than call it. There is no network hop, and no reply to lose.

Cost: every consumer is tied to a version. Control: research and trading each pin the engine as a git submodule, and trading's CI fails unless both pin the same commit.

Service APIBuilt

Market data

The data service owns prices and the rulings on their quality. Consumers read through its API rather than recreating its rules against its tables.

Cost: a read can time out or be refused. Control: each read has a bounded timeout, and a refused series arrives as a named error.

Service APIBuilt

Hermes messages

Hermes owns acceptance and delivery, so a caller hands over a message and moves on. It never waits on Slack.

Cost: accepted and delivered become two states the caller must not confuse. Control: status and delivery routes report each one.

AdapterContract proposed

Broker

A broker brings its own identities, units and failure modes. The adapter is the one edge where they are translated into Nexus's terms.

Today: IG runs behind an existing abstraction, with some IG detail still crossing it; the IB adapter is a stub. Proposed: a portable typed contract that every adapter must pass a shared conformance suite to join.

Three of the four cross a network. Each of those needs an answer, decided in advance, for the reply that never arrives.

02 · Design the unhappy path

One timeout. Three right answers.

A timeout says only that no reply arrived in time. What the caller should do next depends on what sits behind the boundary, so each boundary defines it before it is needed.

Price read · data APIBuilt

Stop, and raise the error.

The data service owns quality. A series ruled misderived or corrupt is refused with a 409, which the client turns into a named SuppressedSeriesError; a series under review is served with its quality status attached. A price read has a bounded timeout, and any other failure propagates to the caller.

So the calculation stops rather than quietly switching to another source or yesterday's value. Asking again does not help: the ruling comes back with every read until it is lifted, and lifting it is an audited operation. Some reference lookups, such as instrument names and sectors, return an empty result on failure; their callers treat empty as unknown.

Message · HermesBuilt

Retry with the same key.

If Hermes committed the message but its reply was lost, resending with the same tenant, client and idempotency key returns the original record, not a second message. Two submissions with the same key, racing each other, take the same path.

The key belongs to one intent: Hermes does not compare a resent payload, so a changed message needs a new key. A 202 confirms acceptance, not delivery; the status and delivery routes say whether the post to Slack succeeded.

Order · brokerProposed contract

Reconcile before resending.

A timeout after an order is sent does not mean the broker rejected it. Sending it again blind can double the exposure.

The proposed broker contract records that order as outcome_unknown and blocks any retry that would change exposure until order queries and reconciliation establish what happened. If the broker cannot say, the intent is quarantined for an explicit decision. The contract is a design dated 26 October 2026; today's IG path is judged on its own recovery behaviour.

The identity rule tightens as the stakes rise. Hermes returns the original record for a repeated key whatever the payload. The proposed broker contract refuses a repeated intent ID whose payload has changed.

03 · The message answer, in detail

Accepted means durably recorded.

  1. 1

    Submit

    The caller sends a typed message with its idempotency key.

  2. 2

    Commit

    The message, one delivery record per recipient, the acceptance event and the outbox rows commit in one transaction.

  3. 3

    Acknowledge

    Hermes moves the outbox rows onto its internal delivery queue and answers 202, with the message ID and links to its status and deliveries.

  4. 4

    Deliver

    A separate worker posts to Slack. Each delivery has its own state and attempts, which the caller can read later.

A transactional outbox closes the gap between saving and sending.

If Hermes stops after the commit but before it answers, the work waits in the outbox, and a resend with the same key returns the original record. If it stops before the commit, nothing was stored and the resend creates the message. Either way an accepted message is neither lost nor accepted twice. The outbox does not make delivery to Slack exactly-once.

The Hermes alert path follows one failure alert through these steps.

04 · Meaning in the types

Validate the economics as well as the JSON.

Schema validation proves that a field is a number. It does not say whether the number is contracts, lots, currency per point or a fraction of NAV, or whether a timestamp marks observation, availability, execution or receipt. Each boundary names those meanings in its types.

What each boundary's types must say, and where each stands
BoundaryWhat the types must sayWhere it stands
Model → engineUniverse, forecast time, availability, horizon and scale, and whether the model sends a forecast or a target weight. Nexus applies sizing and limits after the boundary.Built Shared contract types and validation. The outside-model routes are gated; see Models.
Data → calculationInstrument, provider and feed, the completed-bar boundary and the quality ruling. A missing series must not quietly become another source.Built A suppressed series arrives as a named error, and price reads have explicit timeouts.
Caller → HermesTenant, client, idempotency key, recipients and payload, and the difference between an accepted message and a completed delivery.Built Typed submission and response models, a durable store, and status and delivery routes.
Nexus → brokerAccount and environment, exact instrument, quantity and its unit, order identity, timestamps, and the difference between a receipt and a fill.Proposed IG runs behind an existing abstraction with some IG detail crossing it. The full typed contract is proposed; the IB adapter is a stub.

05 · Change without breaking

Compatibility is an operating responsibility.

Version the meaning

The API standard versions new routes and gives a breaking response change a new path; Hermes's /v1/messages is one. Older unversioned routes are grandfathered, so the standard governs new work rather than every existing route.

Test at the boundary

A useful consumer check exercises the real response shape and its units. The proposed broker conformance suite adds partial fills, corrections, stale quotes, reconnects and unknown outcomes; matching a Python interface is not enough.

Carry identity through

Model version, book configuration, request or message ID, and source and receipt times make a fault traceable from one service to the next. Authentication and credential custody are a separate design; see Security architecture.