Agents and AutomationLesson 24 of 72

Contents

Agents and Automation

Lesson 24 of 72. Sign in to keep your place.

Module 3 · The data underneath: sources, documents, records

The boring bugs that eat automations

9 min read

Money is not a float

0.1 + 0.2 is 0.30000000000000004 in Python, JavaScript, Java and every other language using binary floating point, because a decimal fraction like 0.1 has no exact binary representation, the same way a third has no exact decimal one. The error is tiny and it accumulates.

Over ten thousand invoice lines your total drifts from the accounting system’s by a few pence, reconciliation fails, and somebody spends two days looking for a missing transaction that does not exist.

Store money as an integer number of minor units (paise, cents, pence) or as a decimal type:

Python
from decimal import Decimal
total = Decimal("48200.00") + Decimal("0.10")   # exact

Parse from the string, never through a float on the way. Decimal(0.1) inherits the error that Decimal("0.1") avoids. And keep the currency next to the amount in the same object, because an amount without a currency is a number waiting to be added to the wrong thing.

A date is not a date without a locale

03/04/2026 is the third of April in Mumbai and London, and the fourth of March in Chicago. The string parses successfully under both readings, which is what makes it dangerous: there is no error to catch, only a value that is wrong by a month.

Rules that work:

  • Internally, one format only: ISO 8601, 2026-04-03. Unambiguous and sorts correctly as text.
  • When a source is ambiguous, you must know the locale by other means. If you do not, refuse rather than guess, and route it to a person. Guessing here is the definition of an invisible error.
  • Store timestamps in UTC and keep the original offset alongside. “Which day did this happen on” has a different answer in Auckland and Los Angeles for the same instant.
  • Daily jobs and clock changes: a job scheduled at 02:30 local time does not run at all on the spring-forward day in countries that observe daylight saving, and runs twice in autumn. Schedule in UTC, or pick a time that does not exist in the danger window, and make the job idempotent so a double run is harmless.

Number formats differ by more than currency symbols

1.234,56 is one thousand two hundred and thirty-four in most of Europe and something else entirely if parsed as English. Indian grouping puts 12,34,567 where an English reader expects 1,234,567. Neither breaks a naive comma-strip, but abbreviations do: 12L, 1.2 Cr, ₹4.5k all appear in real business documents and none of them parse.

Detect and normalise explicitly, keep the raw string, and reject what you cannot parse rather than defaulting to zero. Silent zeros are how a report shows a department spending nothing.

Names do not have parts

There is no reliable split into first and last. Order varies by culture, many people have one name, many have four, particles like van der attach in ways that regex does not capture, and transliteration produces Mohammed, Muhammad, Mohd and Md for the same person.

So: store the name as given, in one field, exactly as the person wrote it. If you need a matching key, compute one (lowercased, unaccented, whitespace-collapsed) and store it beside the original, never over it. A normalised key is a tool for your code. The name is the person’s, and an automation that corrects somebody’s name to fit a schema is doing damage that is visible to them and invisible to you.

Encoding, and the CSV that starts with a ghost

A UTF-8 file saved by Excel often begins with a byte-order mark. Read it without accounting for that and your first column is named \ufeffinvoice_id instead of invoice_id, every lookup on that column returns nothing, and the header looks completely normal in every editor you inspect it with. In Python, open CSVs with encoding="utf-8-sig" and the problem disappears.

The related symptom is mojibake (’ where an apostrophe should be) which is UTF-8 bytes being read as Windows-1252. Fix it at the read, never with a find-and-replace downstream, because you will only ever patch the characters you happened to notice.

Units, and the general rule

Kilograms and pounds, metres and feet, per-item and per-case pricing. Put the unit in the column name or in a companion column, and refuse arithmetic between different units at the type level if your language lets you.

Underneath all of these is one rule: parse at the edge, normalise once, and keep the raw value. The moment you have both the printed string and your parsed value stored side by side, every one of the bugs above becomes a query you can run rather than an archaeology project.

Every lesson here is open. Your progress is recorded once you pass the Context Engineering exam.

Check your understanding

An automation stores invoice totals as floating-point numbers. After some months, its monthly total differs from the accounting system’s by a few pence and the difference is never the same twice. What is happening?

Pick the one you would defend. Your answer stays private.

Next lesson · 9 minThe same customer, three times

Stuck on something?Ask Mai, your AI tutor

How to cite: Addaly (2026) ‘The boring bugs that eat automations’, in Agents and Automation. Edited by M. Mun. Addaly. Available at: https://addaly.com/learn/agents-and-automation/dates-names-and-numbers (Accessed: 13 October 2026).