← Mostly Postgres

Correctness Is Not a Knob

transactions, or overselling

⚠ warning: slop currently. Work in progress — not final.
In one line
Postgres is correct by default — ACID transactions and referential integrity — and the famous trade of correctness for speed, eventual consistency, was a mistake even Google walked back. Overselling is a narrow business decision, not a performance knob you casually turn.

Referential integrity, defined by the man who built it

Stonebraker likes a small example. A department has employees. You fire the last one. Now what? Do you delete the department, or do you leave a department with nobody in it — a ghost that every later query has to step around? There is no right answer in the abstract. There is only your answer, and the question is where you write it down.

You can write it in hope: a comment in the codebase, a convention everyone is supposed to follow, a cleanup script someone runs on Fridays. Or you write it in the database, as a constraint, where it cannot be forgotten and cannot be skipped by the one code path that didn't get the memo. Referential integrity is just that decision, encoded once, enforced on every write.

-- the rule lives in the schema, not in a Friday cleanup script
CREATE TABLE department (
    id    int PRIMARY KEY,
    name  text NOT NULL
);

CREATE TABLE employee (
    id    int PRIMARY KEY,
    dept  int NOT NULL REFERENCES department(id) ON DELETE RESTRICT
);
-- ON DELETE RESTRICT: you cannot drop a department that still has staff.
-- swap for ON DELETE CASCADE if your answer is "delete the department too."
-- either way the answer is in one place, and the database keeps it.
Cautionary one-liner
Oracle once shipped a manual page that defined referential integrity and ended the entry with: "not yet implemented." The feature you describe but do not enforce is the feature you do not have.

The eventual-consistency mistake

For a stretch Google preached eventual consistency as the way to do concurrency control at scale. Don't coordinate on every write; let each site act locally and reconcile later. Walk the warehouse. You stock widgets. There's a site on the east coast and a site on the west coast.

One widget is left. East coast sells it: decrement the local count, send an async message west, "eventually" the two coasts agree. West coast sells the same last widget at the same moment: decrement locally, send its own async message east. Both sales succeeded. Both messages arrive. Now the counts merge.

Mike Stonebraker
"the state of the warehouse will be minus one and somebody won't get their widget"

The integrity constraint you wanted — stock > -1 — is exactly the thing eventual consistency cannot hold. It can only notice the violation after it has already shipped a widget that does not exist. There is no widget. Somebody is getting a refund and an apology.

Mike Stonebraker
"eventual consistency just doesn't work"

The retreat

This is not a contrarian take that lost. Google figured it out. Jeff Dean and the team that had pushed eventual consistency hardest reversed course; Spanner went back to a conventional transactional system — real distributed transactions, real consistency, the boring guarantees a relational database always offered.

Mike Stonebraker
"Google completely abandoned eventual consistency"

When the company with the most servers on earth, the one that invented the eventual-consistency pitch, walks all the way back to transactions, the question stops being "can I afford correctness?" The default is correctness. You do the work to leave it, and you'd better have a reason.

When you're actually allowed to oversell

There is a reason, and it's worth naming because it's narrow. You may oversell when the business can absorb it. Amazon "usually ships in 24 hours" — if the warehouse comes up one short, they buy more, or they wait a day, and the customer was promised "usually" anyway. The slack is in the business model, not the database.

Correct by default (most enterprises)
A transaction holds the count. The last widget is sold once. The constraint stock > -1 never fails because it can't.
A little coordination cost on every write. Almost always invisible.
Eventually consistent (rare special case)
Sites act locally, no cross-coast coordination, only viable when the business can eat the occasional minus-one.
Somebody doesn't get their widget. Only acceptable when "usually ships in 24 hours" is a real promise.

Most enterprises cannot make that promise. So correctness is the default and eventual consistency is the exception you reach for in a specific business that can carry the cost — not a knob you turn because a benchmark looked slow.

Proverb
A guarantee you weaken to go faster is a bug you scheduled for later.

The agentic turn

This is about to matter more, not less. Read-only AI hides the problem: ask a model a question, it answers, nothing changes. Read-write AI brings it all back. Move $100 between two accounts with two agents — one debits, one credits. That is a distributed transaction again. It has to be atomic.

Mike Stonebraker
on atomic workflows: "it all happens or it looks like it never happened"
-- one transaction, both legs, all-or-nothing
BEGIN;
  UPDATE account SET balance = balance - 100 WHERE id = 'A';
  UPDATE account SET balance = balance + 100 WHERE id = 'B';
COMMIT;
-- if anything between BEGIN and COMMIT fails, both updates vanish.
-- the $100 is never half-moved. it all happens, or it never happened.

What it removes

Correctness-by-default removes a whole class of bug you would otherwise debug in production at 3am: the half-moved dollar, the negative stock, the order that references a customer who was deleted. What it removes: the reconciliation job, the apology email, the spreadsheet someone keeps to catch the cases the system let through.

This is the data-tier throughline again. Remove to accelerate. Fewer datastores, fewer failure modes — and within the one you keep, fewer guarantees you've quietly weakened. Part 2 said the engine grows to fit the problem. This part says the engine stays honest while it does. The transaction is not the slow path you optimize away. It is the thing that lets you sleep.

Part 2: The Extensible Core · Mostly Postgres · Part 4: The Sprawl Tax