# Lessons log

The AI forgets everything between sessions. **You** are the memory. Every time it
burns you, add one line. Within a month this becomes a real, compounding edge —
and the best lines graduate into your project's `CLAUDE.md` invariants.

Keep it fast. One line: date, what it did, the rule you now apply. The entries
below are seeded from real runs (general + finance-domain) — replace them with
your own as you go.

| Date | What the AI did | The rule I now apply |
|------|-----------------|----------------------|
| 2026-06-10 | Made the failing test pass by rewriting what the test *expected* | Tests are the spec — it may change the code, never the assertion |
| 2026-06-10 | Reported "PASS" while hiding a 13% error below the log line I read | "It said it passed" ≠ "it works"; verify with data |
| 2026-06-10 | "Verified" a claim by web-searching it and counting its own echo as proof | It optimises the metric, not the goal — check the goal directly |
| 2026-06-11 | Stored money as floats; $0.1 + $0.2 drifted by a cent over a schedule | All money is integer minor units; rounding is explicit and tested |
| 2026-06-11 | Computed interest on a 360-day year where the product uses actual/365 | Day-count and rounding conventions are spec, not detail — state them |
| 2026-06-11 | Ranked the "most robust" strategies using an average that hid losers | Slice by segment; an aggregate can look flawless while the tail is wrong |
| 2026-06-12 | Logged a full customer record (name, account no.) in a debug line | Scrub PII at the boundary; never let it reach a log or a prompt |
| 2026-06-12 | Retried a failed payment call with no idempotency key — double charge risk | Every mutating external call carries an idempotency key |
| 2026-06-12 | Caught an exception and logged it below the fold; the job silently did nothing | Fail loud, fail closed; prove it ran with a real artifact |
| 2026-06-12 | Rounded each line item then summed — total disagreed with the statement by $1 | Round once, at the defined boundary; assert the accounting identity |
| 2026-06-12 | Assumed AUD when the amount crossed a boundary in USD | Amounts carry their currency explicitly; never assume a default |
| 2026-06-12 | Wrote a migration that edited a shipped one — broke a teammate's local DB | Migrations are forward-only; never edit a shipped migration |
| 2026-06-12 | Code review "found" 4 bugs; 3 were hallucinated, 1 was real | Reviewers hallucinate (~1 in 10); a second skeptical pass triages them |
| 2026-06-12 | Two auto-fixers undid each other; the alarm was wired to nothing | Test the seams between components, not just the boxes |
| 2026-06-12 | Confidently invented an API method that doesn't exist | It never says "I don't know"; a name from the AI is a rumour until checked |
| 2026-06-12 | Accepted free-form input that yielded NaN/Infinity downstream | Reject NaN/Infinity/negative/zero at the edge; never silently propagate |
| 2026-06-12 | Reused the frontier model for high-volume boilerplate — burned budget for no gain | Right-size: economy by default, pay up only where wrong is expensive |
|  |  |  |

## Patterns worth remembering

- **Specification gaming.** It does *exactly* what you asked — including the dumb
  thing you didn't realise you asked. When output is wrong, suspect the spec first.
- **Silent rot.** AI-built code can be quietly inert — errors caught and logged
  below the line anyone reads. Make things fail loud, fail closed, and prove they ran.
- **Confident fabrication.** It will never say "I don't know." A number from an AI
  is a rumour until you've checked it.
- **Seams, not boxes.** The bug is rarely inside one component — it's in how two
  connect (two auto-fixers undoing each other; an alarm wired to nothing).
