Agents write plausible money code. Plausible is the problem: it passes a demo, passes a code review by someone skimming, and fails at scale in a way that costs real money and takes two days to trace.

These are the ones I see most often, and the three rules I put in every project memory file now.

Bug 1: floats for money

const total = price * qty where price is 19.99. Then a discount, then a percentage, then a sum of a hundred lines. 0.1 + 0.2 !== 0.3 is not a curiosity when it is a ledger.

Rule: money is an integer in minor units. Currency is explicit on every amount. No parseFloat, no toFixed, no division that produces a float, anywhere near a price.

Bug 2: side effects inside a transaction

The agent wraps "create order → charge card → send email" in one transaction because that reads as atomic. It is not: the card charge commits immediately in someone else's database. When your transaction rolls back, the customer has paid for nothing.

Rule: the transaction wraps database writes only. External calls happen outside it, with a compensation path or an outbox.

Bug 3: no idempotency

Webhook handlers, retry logic, double clicks, queue redelivery. The agent writes handlers as if each event arrives exactly once, because that is how it reads in the prompt.

Rule: any write that can be retried carries an idempotency key with a uniqueness constraint, and the key appears in the diff.

Bug 4: timezone off by hours

new Date('2026-10-28') is UTC midnight. Your server is UTC. Your user is in UTC+8. A subscription "ending on the 28th" ends eight hours into the wrong day, and your support queue fills with people who are technically correct.

Rule: store UTC, convert at the display boundary, and never parse a date string without an explicit timezone.

Bug 5: rounding in the wrong direction

Fees rounded up on a small amount look like nothing in testing and like an overcharge across ten thousand orders.

Rule: state the rounding direction for each money operation in the memory file. "Round half up on the customer's favour" is a decision someone has to make explicitly.

Why the agent does this

Not malice, and not a model that "does not understand money". It is pattern completion over a corpus where money is usually a float, transactions are usually atomic in the tutorial, and webhooks are usually called once. Your repo is the only place that says otherwise.

The three rules that carry most of the weight

  1. Money is integer minor units; currency explicit.
  2. Transactions wrap DB writes only; external calls outside.
  3. Retry-safe writes carry a visible idempotency key.

Put them in the project memory file, and put the money section into the pre-merge checklist so a diff that violates them gets flagged before merge rather than after the refund requests.

I keep these as a checklist with the file-and-line evidence requirement, plus the memory-file template: AI Agent Engineering Kit — free starter included.