Companion to #1 (payments hardening). Same source: the origin app's pre-launch consolidation + adversarial review. These are the OPERATIONS invariants — what keeps a multi-terminal, local-first shop's books truthful when devices sync every few seconds. Every item below corresponds to a bug that actually happened (or was proven reachable) in production. They belong in the engine's kernel-invariants list (MODULE-LIBRARY.md already has the seed) and in whatever sync layer customPOS ships.
The #1 lesson: field edits must WIN the merge
In a last-write-wins sync, any mutation that doesn't stamp its record's modified-time can be silently reverted by the next pull while related array-adds (payments, log entries) survive. This ONE mechanism produced, in production or verified-reachable form: delivered orders snapping back to Ready with money already taken (handed out twice / re-charged), racked garments "lost" (on the shelf, screen says Assembled), un-racked garments handed out with the stain still on them, queue approvals reverting to pending and being approved twice, a paid-out refund lock reverting (double payout), settled collections re-raising as collectible, and store credit spendable twice. Recommendation: the engine should stamp centrally on mutation (or ship a one-liner touch(record) convention enforced by tests), and the docs should name this failure class. Idempotency flags (billed-once guards, consumed-once flags, already-decided guards) belong NEXT to the stamp — a reverted flag re-arms the action.
Money-recording invariants (kernel, not per-trade)
- Ledger and drawer move together. Every real payment is BOTH a ledger entry and a drawer-visible payment row; the origin app fixed "collected money invisible to the drawer/daily report" twice before consolidating. One
recordPayment unit, not per-flow copies.
- Every payment row carries where it was TAKEN (station/location) separate from which location's books it belongs to — otherwise cash reconciliation goes over/short across locations.
- Cents-round at every mutation. Four of six hand-rolled balance updates in the origin app drifted unrounded.
- Bill-once guard: a re-run flow (re-delivery, retry) must never double-bill an order or duplicate its collections record — check the ledger net before charging.
- Debt leaves the books only as a payment or by the OWNER's hand — write-offs/A-R removal are owner-only, logged, and voiding an order must clear its receivable (the origin app's approval-queue void skipped that until audited).
Authority + audit invariants
- One non-overridable owner predicate. Owner-only money actions must NOT route through the general permission system (a perms edit must never grant refunds). One
isOwner() definition — the origin app had 54 scattered role compares before the sweep.
- PIN lookups: one helper — always trim, always enforce active!==false (a fired employee's PIN authorized things in one code path), and LOG rejected PINs at money gates: wrong-PIN guessing at the unpaid-release/void-approval screens was invisible to the theft log until audited.
- Fresh PIN for irreversible approvals (voids AND refunds): an unattended logged-in owner session must not be enough to pay out cash.
- Denials get logged. The gates guarding money actions were exactly the ones showing a toast with no audit event.
Truthfulness invariants (operator trust)
- Notification claims must reflect the attempt decision, not config toggles: return {sent, reason} synchronously from one notify gate and have modals/logs read it. The origin app told staff "Text sent ✓" for opted-out customers, so nobody called them.
- A bad auth key must never render as an empty inbox. Server: fail-closed key check + a 401 body that says WHICH side to fix (server env vs device key) on every endpoint. Client: inbox loaders surface that error instead of "No new messages."
- A deploy gate harness: load the real single-file app in a Node vm and assert the money math (totals/tax, merge behavior, guards). The origin app's harness (196 assertions) caught regressions in every wave; it is the single highest-leverage practice to ship as a template alongside the engine.
Own-your-data (fits the project's core pitch)
One-click full JSON export (restorable) + CSV exports (customers/orders/payments/ledger) in-app, a one-click verified backup script, and a documented rebuild-from-nothing playbook. The honest-exit story — tokens can't move (by design), everything else can — is a trust feature worth advertising.
Source: origin-app consolidation pass, 2026-07 (multi-agent adversarial review, all findings regression-tested). No proprietary data included.
Companion to #1 (payments hardening). Same source: the origin app's pre-launch consolidation + adversarial review. These are the OPERATIONS invariants — what keeps a multi-terminal, local-first shop's books truthful when devices sync every few seconds. Every item below corresponds to a bug that actually happened (or was proven reachable) in production. They belong in the engine's kernel-invariants list (MODULE-LIBRARY.md already has the seed) and in whatever sync layer customPOS ships.
The #1 lesson: field edits must WIN the merge
In a last-write-wins sync, any mutation that doesn't stamp its record's modified-time can be silently reverted by the next pull while related array-adds (payments, log entries) survive. This ONE mechanism produced, in production or verified-reachable form: delivered orders snapping back to Ready with money already taken (handed out twice / re-charged), racked garments "lost" (on the shelf, screen says Assembled), un-racked garments handed out with the stain still on them, queue approvals reverting to pending and being approved twice, a paid-out refund lock reverting (double payout), settled collections re-raising as collectible, and store credit spendable twice. Recommendation: the engine should stamp centrally on mutation (or ship a one-liner
touch(record)convention enforced by tests), and the docs should name this failure class. Idempotency flags (billed-once guards, consumed-once flags, already-decided guards) belong NEXT to the stamp — a reverted flag re-arms the action.Money-recording invariants (kernel, not per-trade)
recordPaymentunit, not per-flow copies.Authority + audit invariants
isOwner()definition — the origin app had 54 scattered role compares before the sweep.Truthfulness invariants (operator trust)
Own-your-data (fits the project's core pitch)
One-click full JSON export (restorable) + CSV exports (customers/orders/payments/ledger) in-app, a one-click verified backup script, and a documented rebuild-from-nothing playbook. The honest-exit story — tokens can't move (by design), everything else can — is a trust feature worth advertising.
Source: origin-app consolidation pass, 2026-07 (multi-agent adversarial review, all findings regression-tested). No proprietary data included.