Chapter 1 — a customer places an order and knows it was taken
An order that is silently dropped and an order that is quietly duplicated look identical to whoever placed it: nothing arrives, or two things do, and in both cases the shop knew and the customer did not. This chapter is about the moment between those two.
mermaid source for this flow
flowchart TD
START([<b>START</b> · somebody with a basket<br/>and a card]):::terminal
TAKE[<b>ch1-1</b> · take the order —<br/>what was asked for, and by whom]:::process
STOCK{<b>ch1-2</b><br/>is every line<br/>actually available?}:::decision
SHORT([<b>refused</b> · said before the card is charged]):::bad
CHARGE[<b>ch1-3</b> · charge once, and only<br/>after the order is committed]:::process
TELL[<b>ch1-4</b> · tell the customer,<br/>with a reference they can quote]:::process
DONE([<b>END</b> · an order the shop can act on]):::good
START --> TAKE --> STOCK
STOCK -->|no| SHORT
STOCK -->|yes| CHARGE --> TELL --> DONE
U1>"<b>ch1-U1</b> what happens to a basket<br/>abandoned mid-charge"]:::unknown
CHARGE -.exposes.-> U1
subgraph LEGEND["legend — shape carries the role"]
direction LR
LT([start / end]):::terminal
LA[action]:::process
LD{decision}:::decision
LG([reached]):::good
LB([refused]):::bad
LU>open unknown]:::unknown
end
classDef terminal fill:#eef0ee,stroke:#52514e,color:#0b0b0b;
classDef process fill:#e9eef5,stroke:#2a78d6,color:#0b0b0b;
classDef decision fill:#e9eef5,stroke:#2a78d6,color:#0b0b0b;
classDef good fill:#e2f2e2,stroke:#0ca30c,color:#0b0b0b;
classDef bad fill:#f7e1e1,stroke:#d03b3b,color:#0b0b0b;
classDef unknown fill:#f4f4f2,stroke:#898781,color:#0b0b0b,stroke-dasharray:2 2;Story → test trace
| Story | What it proves |
|---|---|
ch1-1 |
An order records what was asked for and who asked, and neither is inferred later — a basket is a customer's intent at one moment, and a shop that reconstructs it from stock levels and prices at dispatch time is answering a different question than the one the customer asked |
ch1-2 |
Availability is checked before the card, never after — the cost of getting this backwards is not symmetric. Refusing an order that could have been filled loses a sale; charging for an order that cannot be filled takes money for nothing and spends the refund, the apology and the trust to put it back. A reservation is held between the check and the charge, and how long it is held is a real question nobody here has measured: too short and a slow card releases stock somebody has already been promised; too long and a browsing customer holds stock nobody can sell |
ch1-3 |
A card is charged exactly once per order, and a retry cannot charge twice — the network between a shop and a payment processor drops responses as readily as requests, so the charge succeeded and the charge is unknown are the same evidence. Idempotency is what makes the retry safe, and a retry always happens eventually. Note also that the processor's reconciliation window closes at 02:00, which is not ours to negotiate, so a charge submitted near it may settle on either side of the boundary and nothing here may assume same-day settlement |
ch1-4 |
The customer is told, with a reference they can quote back — a confirmation that carries no handle is a courtesy rather than a record: it cannot be searched for, cited in a complaint, or used by the shop to find the order it refers to |
Input → process → output
Input
- a basket — the lines a customer chose, with the quantity of each (
ch1-1) - the customer placing it, identified well enough to charge and to tell (
ch1-1)
Process
- [P1] take the order — record the basket and the customer as one thing (
ch1-1) - [P2] check availability — every line, before anything is charged (
ch1-2) - [P3] charge the card once — keyed so a retry of the same order is the same charge (
ch1-3) - [P4] confirm to the customer — carrying the reference (
ch1-4)
Output
- an order the shop can act on, or a refusal naming the line that was short (
ch1-2) - a confirmation the customer can quote (
ch1-4)
Data definitions
| Element | Type | Card. | Domain | Enforced | Provenance |
|---|---|---|---|---|---|
basket |
list<line> | 1 | at least one line | yes | authored |
line |
record | 1..n per basket | — | — | authored |
line.quantity |
integer | 1 per line | 1 or more | yes | authored |
customer |
record | 1 | — | — | authored |
order |
record | 0..1 | — | — | derived |
order.reference |
string | 1 per order | unique across all orders | yes | generated |
reservation |
record | 0..1 per order | — | — | derived |
charge |
record | 0..1 per order | — | — | observed |
refusal |
record | 0..1 | names one short line | no | derived |
confirmation |
record | 0..1 per order | — | — | derived |
What each step takes and leaves
| Step | Consumes | Produces |
|---|---|---|
[P1] take the order (ch1-1) |
basket, line, line.quantity, customer |
order, order.reference |
[P2] check availability (ch1-2) |
order, line, line.quantity |
reservation, order, or refusal |
[P3] charge the card once (ch1-3) |
order, order.reference, customer |
charge |
[P4] confirm to the customer (ch1-4) |
order.reference, customer |
confirmation |
Open unknowns
- ch1-U1 — what happens to a basket abandoned mid-charge. The card was submitted and no response came back. The order is neither placed nor refused, and the customer has closed the tab.
Glossary
| Term | Meaning |
|---|---|
| Basket | What a customer chose, before it is an order |
| Order | A basket the shop has accepted responsibility for |
| Short | A line the shop cannot fill in the quantity asked for |