# My Data Pipeline Caught an AI Fabricating a Source. Here's What 19 Years of Safaricom's Financial Data Taught Me About Trust.

> Source: <https://dev.to/derrickryangiggs/my-data-pipeline-caught-an-ai-fabricating-a-source-heres-what-19-years-of-safaricoms-financial-2ebe>
> Published: 2026-08-18 16:50:03+00:00

Partway through building a data pipeline on Safaricom's public financial disclosures, one of my own extraction passes handed me two numbers for Ethiopia's EBIT loss, and a citation to back them up. The citation credited the quote to Reuters and CNBC Africa.

Neither outlet had ever said it.

The numbers were wrong, and something along the way had generated a source to make the wrong numbers look confirmed. That single moment taught me more about data engineering than the rest of the project combined, and it's the reason this post exists.

Safaricom PLC, Kenya's largest telecom operator and the company behind M-PESA, publishes some of the most detailed segment-level financial disclosures of any company in East Africa. The problem is that all of it lives in disconnected PDFs. Results booklets, narrative press releases, full annual reports, each with its own structure, spanning nearly two decades of inconsistent reporting formats. Want to know how M-PESA's share of total revenue has changed since its 2007 launch, or how Ethiopia's losses compare to Kenya's own early years? That means opening a dozen-plus documents and transcribing numbers by hand, every single time.

I built Safaricom Intelligence to turn 19 years of that history, FY2008 through FY2026, into a versioned, queryable BigQuery dataset that refreshes automatically every week, with a dbt transformation layer and a public Looker Studio dashboard sitting on top.

The stack, for anyone curious about the plumbing:

Worth being upfront about that second item: the actual cadence here doesn't need a scheduler this heavy, a cron job would do. Safaricom only publishes results twice a year, so the scraper DAG spends 50-plus of its 52 weekly runs short-circuiting to nothing. Airflow's used here deliberately, to demonstrate DAG design, custom Docker images, and orchestration patterns that would matter at higher pipeline volume, not because this specific workload needs a scheduler at all.

That's the pipeline. The more interesting part is what happened once real, messy, human-written financial disclosures met an actual test suite.

Building the pipeline was the easy part. Trusting it wasn't. Several numbers that looked completely fine sitting on their own turned out to be wrong once I checked them against a primary source, and a few of the failure modes are worth naming specifically, because none of them would show up if you only glanced at the data.

One early seed file had three fields for the earliest year that were byte-for-byte identical to the most recent year's figures. One of those fields tracked Fuliza, the overdraft product, which did not exist yet in that earliest year. The tell wasn't a broken pipeline. It was a number that was too clean, sitting somewhere it had no business being.

A BigQuery table had two columns silently appended to the end of its schema instead of sitting in their intended positions, because BigQuery only allows adding columns to the end of an existing table, never inserting them in the middle, and the load job wasn't passing an explicit schema. Every load after that point quietly mapped values into the wrong column. Nothing crashed. Every load technically succeeded. The pipeline was fully green and fully wrong at the same time, which is a much scarier failure mode than an error message.

And then there's the fabricated citation. A later re-extraction attempt produced a different pair of Ethiopia loss figures, backed by a quote credited to Reuters and CNBC Africa. Checking that citation against the actual wire coverage, both of those outlets, plus two other independent financial sources, all quoting the same earnings call, confirmed a completely different pair of numbers. The fabricated version got rejected. The wire-confirmed one stayed.

That last one is really the point of this whole post. A wrong number is a bug. A wrong number wearing a real news outlet's name as a source is a trap, because it looks more trustworthy than an honest gap, not less. The only reason it got caught is that the project ran on a standing rule: verify against primary sources in order of reliability, press release first, then the results booklet, then the annual report's actual segment note, and never accept a number just because it arrived with a citation already attached to it.

Once the pipeline was trustworthy, the numbers told a genuinely good story.

M-PESA launched generating roughly KES 0.37 billion in its first partial year. By FY2026 it's a business worth over KES 180 billion, and M-PESA revenue alone now makes up roughly 45.6 percent of Safaricom Kenya's entire service revenue. That's not a side product anymore. That's most of the company.

M-PESA revenue trend from FY2008 to FY2026, climbing from near zero to over KES 180 billion, with the steepest acceleration visible from FY2022 onward

Voice revenue tells the opposite story, and it's not a gradual one. It actually declined in absolute shilling terms during FY2020 and FY2021, a real, Safaricom-confirmed effect of COVID cutting call volumes at exactly the moment data usage was spiking. The pivot toward data and M-PESA wasn't a slow drift. It got accelerated by a specific two-year shock, and it's visible directly in the numbers: watch the blue voice-revenue line dip right as the M-PESA and mobile-data bars keep climbing.

Revenue mix by segment from FY2008 to FY2026: voice revenue (blue line) dips during FY2020–21 while M-PESA (green) and mobile data (purple) bars keep growing, with M-PESA overtaking voice as the dominant segment

Ethiopia is the most interesting chart on the whole dashboard, because the shape matters more than any single figure. Safaricom's Ethiopian unit didn't lose money at a steady, improving rate. It got worse before it got better. A loss of 5.1 billion shillings, then 30.7 billion, then 59.6 billion, then a trough of 61.1 billion, before nearly halving to 30.1 billion in the most recent year. That's a textbook market-entry J-curve, and most casual commentary on whether the Ethiopia bet is working doesn't wait long enough in the data to actually see the turn.

Ethiopia's path to profitability: EBIT loss widening from -5.1bn in FY22 to a -61.1bn trough in FY24, then narrowing to -30.1bn in FY26

The capex trend backs up the same story from a different angle. Ethiopia's capital spend peaked well above Kenya's in the early build-out years and has been pulling back steadily since, right alongside the narrowing losses, while Kenya's own capex has kept climbing:

Capital expenditure, Kenya vs Ethiopia, FY22 to FY26: Ethiopia's capex peaks early and tapers off while Kenya's climbs steadily higher

A few practices did most of the work, and none of them are complicated.

Every growth and margin figure in the dashboard is computed independently in SQL, using window functions on the raw disclosed numbers, rather than copying the percentages Safaricom prints in its own booklets. That single decision is what made automated reconciliation possible at all. Two dbt tests specifically check that different tables' overlapping figures actually agree with each other, and both of them caught real, confirmed errors during development, not false positives.

For the earliest, hardest-to-source years, every figure went through two fully independent extraction passes, diffed against each other before being trusted. Disagreements got resolved by going back to the literal printed label next to a number in the source PDF, not by picking whichever value looked more plausible.

And a decent chunk of the known limitations in this project are deliberate blanks. A calculated connectivity total is left blank for years where its components are incomplete, rather than summed anyway and silently understated. An honest gap in a dataset is a feature. A confident, wrong number is the actual risk.

Airflow, dbt, Terraform, BigQuery, none of that is the interesting part anymore. Plenty of tutorials will teach you the wiring. What's harder to teach, and what actually separates a real data engineer from someone who can follow a setup guide, is the instinct to distrust a number that looks too clean, to check a citation instead of accepting it, and to build tests that catch exactly the kind of quiet, well-formatted failure that a schema drift or a fabricated source produces.

That instinct matters more now than it did a few years ago, not less. The easier it gets to generate a plausible-looking number with a plausible-looking source attached, the more valuable it is to be the person who checks anyway.

The live dashboard and the full repository, including the complete data quality log documenting every one of these fixes, are linked below.

**Live dashboard:** [https://datastudio.google.com/reporting/d1679099-7abb-4d6e-bc15-aa8beb9dfa6c](https://datastudio.google.com/reporting/d1679099-7abb-4d6e-bc15-aa8beb9dfa6c)

**Repository:** [https://github.com/Derrick-Ryan-Giggs/safaricom-intelligence](https://github.com/Derrick-Ryan-Giggs/safaricom-intelligence)

If you build data pipelines on messy public disclosures too, I'd love to hear what's broken on you in a way that looked fine at first glance.
