Five bugs a data audit caught before anyone made a decision on them

Leads counted twice, spend never recorded, the best leads hidden by default. What an independent audit of AHA’s marketing data found, and the rules that keep it fixed.

27 Oct 2026 2 min readCase study · AI growth agent

The problem

Dashboards looked plausible, but leads, spend and channels were each off.

The solution

Recompute every number by a second route before trusting it.

2.00× → 1.00×Meta lead count
20%of a month’s spend was unrecorded
+11%hidden leads restored

The most dangerous dashboard isn’t the broken one. It’s the one that looks plausible. When I rebuilt AHA’s marketing data, I started with a single question: is any of this true?

The method: two routes to every number

For every headline figure (leads, spend, demos, wins), I wrote a second way of getting it that shared no code with the first. That meant different tables, a different API endpoint, or the platform’s own export. If the two routes agreed, the number was trusted. If they didn’t, the gap had to be explained before anything else shipped. Snapshots of every page were taken before and after each change, so any “fix” that moved a number we hadn’t meant to move showed up straight away.

Bug 1: every Meta lead counted twice

Meta lead counts were exactly 2.00× the real figure. Not roughly double; exactly. That precision was the clue. The old puller summed the generic lead action and its two components, so each lead was counted once for itself and once for its parts.

Fix: count only the lead action, and have the reporting views recount from stored actions so the rule can’t drift. The ratio is now 1.00 across 13 weeks.

Bug 2: spend that was never stored

Google spend for one month read 20% low. Performance Max campaigns, and any cost without a location attached, were silently dropped by the old pull.

Fix: pull spend at campaign level and re-read the entire history on every run, so late-arriving conversions land too. Stored spend now matches the platform to within a few rupees over five months.

Bug 3: the CRM hides your best leads by default

One test week showed about 10% fewer leads than really arrived. Zoho’s default read leaves out leads that have already converted into deals, so the ones that disappeared were exactly the successful ones.

Fix: every read explicitly asks for converted and unconverted leads. It’s one parameter, and it was invisible until the audit compared two routes.

Bug 4: WhatsApp leads in the wrong bucket

Leads that came in through WhatsApp click-to-chat ads were landing in “other” instead of the paid channel that bought them. That made the paid channel look worse than it was.

Fix: a classifier rule for the WhatsApp source, applied in the clean layer. One month’s paid-search lead count rose by more than half once they were bucketed correctly.

Bug 5: a “complete” day that wasn’t

The dashboard showed data “up to” yesterday, but one morning yesterday was missing some spend and two demos. One source had finished copying and another hadn’t.

Fix: the “data to” date only moves forward once every source has copied that day. The audit caught this one the same morning.

The rules that came out of it

  1. Copy sources faithfully, then clean in a separate layer. Raw stays raw.
  2. Every number has a second route. If you can’t verify it independently, label it as unverified.
  3. Exact ratios are clues. 2.00× is a bug, not a coincidence.
  4. Freshness is a property of the slowest source, not the fastest.

The fixes made the numbers slightly less flattering in places and far more useful everywhere. That’s the trade you want.

More problems, more solutions.

All posts

Non-brand clicks are the SEO number that matters

+183% non-brand clicks

A path-traced showroom in a TV browser

22 renders, path-traced offline in about 2 hours