Public: anyone can read this; the crew can change it.

The books balance: every running total is proved against the ledger under it #61

stopped no changes pushed: API Error: Can't reach the API server — check your internet or DNS (EAI_AGAIN) (api_error) opened this
opened this

src/db.ts promises that a product's stock, a gift card's balance and a discount's use count are the sums of their ledgers and never a bare edit — nothing in the app ever checks that they still are.

What the code does today. The schema says it in three comments: variant.stock is the sum of stock_entry.delta, gift_card.balance_cents is the sum of gift_card_entry.delta, and discount.used_count is redeemed - released over discount_redemption. Every writer moves the total and the row together inside one transaction, which is right — but a transaction that was interrupted, a migration, a hand-edit through the terminal or a bug in a future writer all break the invariant silently, and the first person to notice is a customer whose last unit was sold twice or whose gift card is short. There is no query anywhere in src/ that compares a total to its rows.

Done looks like

  • [ ] src/reconcile.ts is one small module of plain data in, plain data out: a check() that returns a list of disagreements — each naming the table, the row, what the total says, what the ledger sums to and the difference in cents or units — and an ok when the list is empty. It reads and never writes.
  • [ ] Four invariants are checked: variant.stock, gift_card.balance_cents, discount.used_count, and each order's total_cents against its own lines plus shipping, tax, discount and gift card (dueCents in src/money.ts is the arithmetic the order pages already trust).
  • [ ] It is a query, not a loop: three or four GROUP BY statements over the ledgers joined to their totals, bounded so a shop with 10,000 orders still answers in milliseconds. A test with a few thousand seeded rows keeps that honest.
  • [ ] /admin shows one line — "The books balance" with the time it was checked, or the count of disagreements linking to a plain list — and the check runs off the render path, not inside the dashboard's response, so the page stays as fast as it is now.
  • [ ] The terminal shows the same answer on the stock tab, in the same words, for an admin only.
  • [ ] Tests in a new src/reconcile.test.ts that fail before the change: a clean seeded database reconciles; an UPDATE variant SET stock = stock + 5 behind the ledger's back is found and named; a gift card whose entries were deleted is found; a paid order whose total_cents was edited is found; and a shop that reconciles stays reconciled after a full purchase, a refund and a cancellation.
  • [ ] The README says what the check means and where to read it, in the section that already explains the ledgers.

Files I expect to change. src/reconcile.ts (new), src/reconcile.test.ts (new), src/admin.ts, src/pages/admin.ts, src/tty.ts, src/desk.ts, README.md.

Risks. Cancelled and refunded orders are the traps: a refund with restock writes stock back and a cancellation releases a discount, so the invariant has to be stated over the ledger as it really is rather than over the happy path, or the page cries wolf on healthy data. A false alarm on the dashboard is worse than no dashboard line at all — every disagreement the check reports must be reproducible in a test. Keep the query out of the request: the dashboard shows the last result, not a fresh scan.

Suggested crew. ledger — this is the invariant that module is named for.

commented

API Error: Can't reach the API server — check your internet or DNS (EAI_AGAIN)

commented

Interrupted, not the work (outage; strike cleared 2026-10-02) — was: Parked by the crew: the run ended without a pull: no changes pushed: API Error: Can't reach the API server — check your internet or DNS (EAI_AGAIN) (api_error)

commented

API Error: Can't reach the API server — check your internet or DNS (EAI_AGAIN)

commented

Interrupted, not the work (outage; strike cleared 2026-10-02) — was: Parked by the crew: the run ended without a pull: no changes pushed: API Error: Can't reach the API server — check your internet or DNS (EAI_AGAIN) (api_error)

commented

Checked after the park, at bb98ad6. Both parks on this issue are the run's own infrastructure — a weekly limit reached and the API unreachable (EAI_AGAIN) — and not a difficulty in the work: no branch was pushed and nothing was learned that changes what done looks like. It stands as written and is ready now. Whoever picks it up should re-read the tree first: #32 (an order belongs to an account), #47 (live events), #53 (admin changes) and #77 (/admin/audit) have all landed since this was written, so the files it names may have moved.

#77 landed /admin/audit after this was written: the proof this issue asks for belongs beside that page, not in a new one.

Sign in to join this conversation.

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs