Commodity TradingField engagement

Every step of the trade already existed in isolation, so the deliverable was a state machine over a record that settlement and reporting both trust.

Architecture and delivery lead.
The approach, in four words
model the trade, not the screensidempotent acceptanceappend-only recordprojections, not copies
01Quotedprice issued
›
02Acceptedidempotent, binding
›
03Rules passor rejected
›
04Executedonce, exactly
›
05Recordedappend-only
settlement and reporting are projections of this record, never separate copies of it
What was at stake

The operator does not introduce buyers to sellers and take a fee. It buys in its own name. So when a supplier accepts a quote, the operator has made a purchase, and the trade has to travel from quote to acceptance to a record carrying everything settlement and reporting need. No step can silently drop and no step can fire twice. A trade that exists in one system and is missing from another is not a reporting inconvenience. It is material the operator owns, or money it owes, that nobody is tracking.

How this works

When the platform is the buyer, every accepted quote is a contract it has signed.

There are two ways to stand in the middle of a trade. A marketplace introduces a buyer to a seller. They agree terms with each other, the platform takes a fee, and if the deal goes wrong the dispute is between the two of them. A principal counterparty works differently. It buys from the seller in its own name and later sells to a buyer in its own name. For the time in between it owns the goods, carries the risk that the price moves, and is the party everyone else has a contract with.

That difference changes what a quote is. On a marketplace a quote is information. From a principal, a quote is an offer made with the principal's own money, and acceptance turns it into a contract. Trading firms call the moment a deal enters their books trade capture. Everything that follows reads from the captured record: settlement, which is the actual exchange of material and money, and reporting, which tells the business what it holds, what it owes and what it is owed.

Two engineering ideas carry this kind of system. The first is a state machine, a list of the states a trade can be in and the only moves allowed between them. The second is idempotency, the property of an operation that has the same effect whether it runs once or several times. Networks redeliver messages and people tap buttons twice. A binding action that is not idempotent will, sooner or later, happen twice, and for a principal that means buying the same material twice.

Marketplace
Introduces buyer and seller
they contract with each other
Earns a fee
never owns the material
A broken trade is theirs
the platform's exposure is mostly reputational
Principal counterparty
Buys in its own name
the supplier's contract is with the operator
Holds the material
and the price risk until it sells on
A broken trade is its loss
a duplicate booking is a real purchase
Same screens, different liability
This engagement sits on the right-hand side, which is why the record had to be exact.
FigureThe same accepted quote means two different things depending on where the platform stands. A marketplace connects two parties and earns a fee. A principal counterparty is one of the parties, so a booking error on its platform is a loss on its own books.
The constraint

Every step was already there somewhere: a quote, an acceptance, a set of checks, an execution, a record. What was missing was the connection between them. That makes the platform's job a reliable state machine over an auditable trade record, and the screens are the smallest part of it. Acceptance is binding, so the transition that records it has to be correct the first time and harmless every time after, including the second tap from a supplier on a slow phone connection.

Where it usually breaks

Trading systems lose trades in the gaps between steps that each work.

Each step in a trade usually works when tested alone. A quote screen shows a price. An acceptance endpoint records a yes. A settlement job pays what it finds. The failures live between them: a crash after the acceptance is saved and before the trade is, a message delivered twice, a job that reads a row while another process is halfway through changing it. Testing each screen in turn never exercises any of those.

The second pattern is duplication of truth. Settlement keeps its own table because it needs different fields. Reporting keeps another because it needs them summarised. Each copy is updated by its own code, and the copies drift. When they disagree there is no way to say which is right, because neither one was ever the original.

01

The double execution

A supplier taps accept twice on a slow connection, or the app retries a request that had in fact succeeded. Without a key identifying the acceptance, the server sees two orders and books two trades.

02

The half-written trade

The acceptance is saved, then the process stops before the trade record is written. The supplier believes there is a deal and the operator's books do not show one.

03

The accepted stale quote

A quote is accepted after it should have expired. If validity is a display detail and not a check at the transition, the operator is bound to a price it would no longer offer.

04

Two copies that disagree

Settlement and reporting each keep their own version of the trade. A correction reaches one and not the other, and month-end becomes an argument with no referee.

05

The rule nobody wrote down

The trader always declined a certain kind of trade without thinking about it. The platform was never told, so it accepts one.

Supplier taps accept
the connection is slow and nothing seems to happen
Supplier taps again
a perfectly reasonable response
Server receives two requests
nothing marks them as the same acceptance
Two executions recorded
both pass every check, because each one is valid
The failure point
One decision, two purchases
the operator now owns material it meant to buy once
An acceptance key turns the second request into a lookup of the first result.
Retries by the app and redelivery by the network produce the same failure without any tap at all.
Any binding action a user can trigger will eventually be triggered twice.
FigureHow one supplier decision becomes two trades. Neither request is wrong on its own, and the phone cannot be relied on to send exactly once. The only place to stop the duplicate is the server, by recognising that the second request is the first one again.
The fork

The reflex, and the fix.

Road not taken

Screens calling services as needed

Pull

It matches how the work looks from the outside, and each screen is simple on its own.

Why not

Nothing in that design makes a transition atomic or repeatable. Acceptance and the trade record can drift apart, and a double tap on a phone can execute the same trade twice.

Road taken

A trade state machine with idempotent transitions

Accepted

Explicit states and transitions to design up front, and an append-only record in place of a row that gets edited.

Bought

A trade that is in exactly one state at a time, an acceptance that can be retried safely, and a single record that settlement and reporting both read from.

Decision

Model the trade, because its states are what the business is accountable for. The screens are ways of looking at those states.

How it was built
01Quoted
›
02Accepted
›
03Rules pass
›
04Executed
›
05Recorded
01

Named states with defined moves

Quoted, accepted, executed, recorded and rejected are states, and the transitions between them are listed. A trade cannot be both accepted and rejected because no transition leads there. An impossible combination is unrepresentable, which is a stronger guarantee than unlikely.

02

Idempotent acceptance

Each acceptance carries a key. A retry, a double tap or a request the network delivers twice arrives with the same key and reaches the same single execution.

03

An append-only trade record

Each event is written once and never edited. That is what lets the record serve as evidence of what happened. A row that gets edited only says what somebody last typed.

04

Settlement and reporting as projections

Both views are computed from the same record and keep no copies of their own. They cannot disagree about what happened, because there is only one account of it.

05

A missing rule stops the trade

When a trade reaches a situation that no written rule covers, it halts and goes to a person. The platform does not improvise a policy at the moment a binding decision is being made.

Inside the key decisions

What each choice cost, and what it bought.

AModelling the trade before the screens

The brief read like a set of screens, and screens are what a client can see progress on. Starting from the states a trade can be in, and the allowed moves between them, delayed the visible part of the work. It bought something the screens could never provide on their own: a trade that cannot be in two states at once, and a single place where every move is checked. The screens then became thin, because the decisions they used to make now live in the transitions.

BPutting the duplicate check at the server

It is tempting to stop double execution in the interface, by greying out the button after the first tap. That helps the person and does nothing about network retries, redelivered messages or a second device. Giving each acceptance a key and having the server treat a repeated key as a request for the existing result costs a little design up front. It makes acceptance safe to retry from anywhere, which is the only kind of safe that holds on a phone.

CAppending to the record and never editing it

An editable trade row is simpler to build and quicker to query. It also destroys the evidence of how a trade reached its present state, which is the first thing anyone asks for when a settlement is disputed. An append-only record costs more storage and a little more work to read the current state. In exchange, every question about the past can be answered from the record itself, and settlement and reporting can be computed from it without keeping copies.

DStopping on the case no rule covers

When the platform meets a situation that the written rules do not address, it can guess or it can stop. Guessing keeps trades flowing and quietly commits the operator to decisions nobody made. Stopping sends the trade to a person and makes the missing rule visible, so it can be written down. That is slower on the day and it is how the rule set grew to match what the trader actually did.

Settlement and reporting viewscomputed from the record, holding no copies
Supplier and trader screensways of looking at state, with no authority over it
Trade state machinethe only path from one state to the next
Idempotency key on acceptancea repeated acceptance returns the original result
Append-only trade recordwritten once per event, never edited
If a fact is not in the bottom layer, nothing above it can know it.
FigureHow the platform is layered, from the views people use down to the record everything rests on. Authority runs upward from the bottom. The screens and the downstream views hold no state of their own, so they cannot disagree with the record or with each other.
How it was measured

A single headline number hides where a system fails. This work was scored on the dimensions that actually decide whether it holds in production, measured on real, held-out cases rather than the demo path.

Double-execution under retry and double submissionCompleteness of the record for settlementCorrectness of state transitions under failureAgreement between settlement and reporting views
  1. Accept, then retry
    the same key must return the same single trade
  2. Double submit from a phone
    two taps must produce one execution
  3. Fail between transitions
    a trade must land in a defined state, never half of one
  4. Check the record for settlement
    everything settlement needs must already be in it
  5. Compare the two views
    settlement and reporting must agree because they share a source
Outcomes are described qualitatively. No figures are claimed.
FigureWhat the platform was tested against. No measured figures are published for this engagement, so each check is described by the property it proves. Every one of them targets a gap between steps, because that is where trades go missing.
figures

No measured figures are published for this engagement. Outcomes are described qualitatively.

What it produces
Without this discipline

Screens that mostly work, an acceptance that occasionally executes twice, and a settlement view that disagrees with the reporting view with nobody able to say which one is right.

This system

A trade state machine with idempotent transitions over an append-only record. Settlement and reporting are two readings of the same history, so the question of which copy is right never arises.

model the trade, not the screensidempotent acceptanceappend-only recordprojections, not copies
The operating envelope

What it owns, and what it hands to a person.

Handled with confidence
Quote to acceptance to recorded trade
Retried or duplicated acceptance
Settlement and reporting from one record
Flagged for review
A case no stated rule covers, which stops rather than guesses
Out of scope by design
Trades agreed outside the platform
Rules that have not been elicited and written down
The honest limit

The record is only as complete as the rules feeding it. A rule the trader held in their head and never said aloud is a gap in the platform until somebody writes it down. Finding those rules was part of the work, and could not be finished before the work started. Trades agreed outside the platform are outside it entirely, and no amount of internal correctness brings them in.

What it generalizes to

Any flow where acceptance is binding, from quote to accept to settle, wants the same four things: an explicit state machine, idempotent transitions, a record that is appended to and never edited, and downstream views computed from it. Insurance binding, purchase orders and reservations all share this shape.

What to take from this

A principal counterparty buys and sells in its own name, so every accepted quote on its platform is a contract it is bound by, and a software defect becomes its own financial exposure.

Any binding action a user can trigger twice will eventually be triggered twice. Make it idempotent with a key the server checks, because no client can promise to send exactly once.

Name the states a record can be in and the moves allowed between them. A combination no transition reaches cannot occur, which beats detecting it afterwards.

Keep one record of what happened and compute every other view from it. Two copies of the truth will drift, and nothing can say which one is right.

When a process is automated, the rules people applied without noticing are the ones that go missing. Treat finding and writing them down as part of the build.

How we engage

You have a system like this one.
Tell us where it stands.

Whether it is failing, not yet built, or about to meet a scale it has never seen, we can tell you what we see.

Start a conversation
mostafa@opulion.dev · Response within 24 hours · By inquiry