---
name: store-understood-checks
description: 16 rules from the Noesa course "Store, understood". For developers, integrators and product people who will build, operate or answer for a store, and who keep finding that the interesting bugs live between the parts rather than inside them.
---

# Store, understood — the rules

Use with: Claude Code or Claude (save as a skill), Cursor (save under .cursor/rules as .mdc), ChatGPT or any other assistant (paste the text below into custom instructions or a project's instructions).

16 rules, taken from the course at https://noesa.leafsoft.online/c/store-understood

Each heading is one thing the course teaches. Most are checks to run on your own output before presenting it as done; a few are background you are expected to have. 16 also name a mistake models make by default, under "Watch for".

Apply these to the thing you are producing — the type, the schema, the query, the copy — not only to how you explain it. Where a rule names a field, a format or an identifier, that name belongs in the output.

## Build the smallest store that breaks

Create `store.db` with products, prices and one order, and show that the order remembers a price the catalogue has forgotten.

**Watch for:** If you asked an AI to design the tables for a store's orders, what would it most likely leave out?

The copy of the price. The shortest schema that looks correct stores a product reference and a quantity, and reads the amount from the price list when the order is displayed. It is fewer columns, and it passes every test written on a catalogue that never changes. Nothing fails until a price moves, and then it fails backwards through your whole order history at once. Keep the charged amount on the line, and treat any figure the order was built from as something to store rather than to look up later.

## Separate what you sell from what you charge

Explain why a product, its code and its price are three separate things, and query a catalogue where one product carries two prices.

**Watch for:** If you asked an AI to add a second currency to a product catalogue, what shortcut would cost you later?

Putting the price on the product row and adding a second column for the second currency. It is the smallest change that makes the feature work, and it reads well right up to the third currency, the regional price, or the two-week sale. At that point the schema needs a new column for every new way of asking for money. Every one of them has to be added to every query. The shape to insist on is a separate price row per code and currency, so a new way to price is new data rather than new columns.

## Treat availability as a promise

Explain why a stock count is not an answer to "can I sell this", and hold stock for an order without overselling.

**Watch for:** If you asked an AI to stop a shop overselling its last item, what would it be likely to produce?

A check before the write — fetch the stock, compare it in application code, then decrement — because that mirrors how the request reads in plain language and it passes any test that runs one shopper at a time. It fails only when two requests interleave, which is exactly the condition worth protecting against and the hardest one to notice in review. Ask instead for a single statement that decides and writes together, and confirm the code checks whether it actually changed a row rather than assuming it did.

## Own the cart as state

Keep a cart in rows per shopper, add an item twice without duplicating it, and say what a cart is not.

**Watch for:** If you asked an AI to build a shopping cart for a web store, where would it put the cart?

In the session or in browser storage, because that is the shortest thing that works for one visitor on one device in one visit, and it demos perfectly. What it cannot know is that the cart is one of your most valuable records: it is the only evidence of what people nearly bought, and the thing a returning shopper expects to still be there. Ask for the cart as rows keyed to a shopper, and treat the browser as a cache of it rather than the home for it.

## Show a price you can honour

Serve a catalogue from a cache and re-check the price at the moment of acceptance, and explain why those are two different reads.

**Watch for:** If you asked an AI to make a slow product page fast, what would it not think to ask you?

How old a price is allowed to be. It will reach for a cache with a time limit, because that is the standard and correct fix for a slow read, and the number it picks will be about speed. What it cannot know is that one of the values on that page is an offer, so staleness there is not a small inaccuracy but a promise you may have to honour or withdraw. Say which fields may be cached and which must be re-read at the moment money is taken.

## Freeze the order at the moment of acceptance

Write the checkout step that turns a cart into an order, and name every value it must copy rather than reference.

**Watch for:** If you asked an AI to turn a shopping cart into an order, what would it forget to write down?

Everything that is not obviously part of the transaction: which version of the terms was accepted, which tax basis was used, and what the shopper was shown before they clicked. It will copy the items, the quantities and usually the price, because those are visibly the order. The rest looks like configuration rather than data, and configuration is exactly what will have changed by the time anyone asks. Name the values that must be frozen, and treat any of them still reachable only by a live lookup as unrecorded.

## Ask for tax, do not invent it

List the facts a store must supply for tax, and store the resulting tax on the order as its own line.

**Watch for:** If you asked an AI to add tax to a store's checkout, what would it produce with complete confidence?

A single percentage applied to the cart total, because that is what the request sounds like and what most examples show. It cannot know where you are registered, where the buyer is, whether the buyer is a business, or which of those facts changes the answer. Nor will it tell you it is missing them, because the arithmetic it produced is correct arithmetic. Treat any tax figure it writes as a placeholder until the five facts are named and stored, and keep the collected amount as its own column.

## Separate authorised money from captured money

Model a payment through authorised, captured and settled, and explain why an order may be paid and unfunded at the same time.

**Watch for:** If you asked an AI to take a card payment at checkout, which distinction would it collapse?

Authorised and paid. A single successful response reads as success, so the natural code marks the order paid and moves on — and for the majority of orders that eventually becomes true, which is what makes the bug survive review. It cannot know your capture policy, your shipping trigger, or that money is only yours after settlement. Insist that the payment has a state, that shipping keys off capture rather than authorisation, and that something looks for authorisations that were never claimed.

## Give the order one state machine

Express an order's life as a small set of named states with legal transitions, and reject an illegal one in the database.

**Watch for:** If you asked an AI to add order statuses to a store, what would it hand you?

A text column and a list of strings used in the code, because that is flexible, quick, and correct on the first day. What it cannot see is that a status is a shared vocabulary across the warehouse, finance and support, and the cost of an ungoverned one arrives months later as reports that disagree. Ask for the permitted values to be enforced by the schema, and for the illegal transitions to be named as explicitly as the legal ones.

## Deliver the thing you promised

Separate what the buyer is owed from what they were billed, and record fulfilment as its own fact.

**Watch for:** If you asked an AI to mark an order as delivered, what would it be likely to build?

A status change on the order — one column, one value, done. It matches the request exactly, and for a store that always ships everything in one parcel it is even correct. What it cannot know is that partial shipments, backorders and per-item returns are normal, and that once "delivered" is a single flag there is nowhere to record which items actually went. Ask for fulfilment as its own rows with quantities, and keep the order's status as a summary of them rather than a substitute.

## Reconcile the store against the money

Produce the three-way comparison between orders, payments and fulfilments, and name what each kind of mismatch means.

**Watch for:** If you asked an AI to check that a store's payments match its orders, what would it be likely to compare?

Two totals for a period, because it is a natural reading of "match" and it produces a satisfying single number. What that hides is every offsetting pair: an order overcharged and another undercharged net to zero and the report says the books agree. It also cannot know which of your payment states counts as money, so it will usually pick the earliest. Ask for the comparison per order, with the payment state named and the age of each gap shown, so that in-flight and broken stop looking identical.

## Weigh a fraud rule against the customers it blocks

Compute the good orders a fraud rule blocks per fraud caught, and why a highly accurate rule can still be bad.

**Watch for:** If you asked an AI to write a rule that catches fraudulent orders, what would it not weigh?

The honest orders the rule refuses. Asked to catch fraud, it optimises for catching fraud, and the signals it reaches for — a mismatched country, a new account, an unusual amount — describe ordinary customers too. It has no way of knowing how rare fraud is in your store, and rarity is what decides whether a sensible-looking rule blocks five good orders per thief or fifty. Give it the base rate and the cost of a wrongly refused customer, and judge any rule on both columns rather than its hit count. A second habit belongs here: do not paste customer records into an AI to ask whether an order looks fraudulent. That is exactly the boundary Data safety with AI, Day 3 draws.

## Return the goods and the money together

Record a partial return that reverses the right amount of tax, and explain why a refund is not a negative sale.

**Watch for:** If you asked an AI to add refunds to a store, what would it get subtly wrong about tax?

It will apply the current tax rate to the refund amount, because that is how tax is calculated everywhere else in the code and it produces a plausible number. What it cannot know is that a refund reverses a specific past transaction, so the tax owed back is a share of what was actually collected then — a figure that only exists because the order stored it. Refund tax proportionally from the recorded amount, and treat any refund computed from today's configuration as suspect.

## Refuse the price the client sends you

Demonstrate a price-tampering attempt and block it by deriving every money figure on the server.

**Watch for:** If you asked an AI to build a checkout endpoint, which field would it accept without question?

The amount. A checkout request that carries a total is the shape most examples use, it makes the endpoint easy to test, and the code that reads it looks entirely reasonable. What is missing is the recognition that money is the one field the buyer must never supply, because a tampered price produces a valid order rather than an error — nothing fails, and the store simply sells at the attacker's number. Ask for every monetary value to be looked up server-side from the identifiers, and treat any money field in a request body as the vulnerability itself.

## Report conversion without flattering it

State the denominator behind a conversion rate and show how two defensible definitions produce different numbers.

**Watch for:** If you asked an AI for your store's conversion rate, what would it not tell you?

Which denominator it chose. It will pick a reasonable one — carts, sessions or visitors — compute correctly, and report a single confident percentage, because that is the shape of the answer requested. It cannot know which population your decision depends on, and it has no reason to mention that another defensible choice would have produced a materially different number. Ask for the numerator and denominator as separate columns, and treat any rate published without its denominator as unreadable rather than merely imprecise.

## Follow one order across six disciplines

Trace one order through catalogue, checkout, tax, payment, fulfilment and reporting, naming which discipline owns each step and what breaks between them.

**Watch for:** If you asked an AI to build a report showing how each order is doing, what would it produce that reads well and cannot be trusted?

A single joined query with one row per order and one status column, because that is what a report looks like and it will render beautifully. Collapsing six independent facts into one status is precisely the move that hides paid-and-undelivered orders, authorisations counted as revenue, and returns that never reached the ledger — each of them appears as an ordinary-looking row. Ask for the facts kept separate and side by side, with the age of every disagreement, and treat any single order-health column as a summary you must be able to decompose.
