Moving a hospital group's entire reporting suite to a new front end — and discovering that the hard part was never the move.
A hospital group's finance and marketing reporting — receivables, profit and loss, sales, footfall, balance sheet — all of it running through Power BI, all of it read by people who make real decisions on it.
The job was to move the whole presentation layer to a JSON-driven front end. Mechanically, that's a conversion exercise. In practice, the moment things started moving, figures on the new screens stopped matching figures on the old ones.
A dashboard that shows a slightly wrong number is worse than one that shows nothing. Nobody knows to stop trusting it.
And in a hospital group, "slightly wrong" lands on a receivables position or a monthly P&L that someone is about to act on.
Find the number that's wrong on the dashboard and correct it there. Fast, visible, and it makes the complaint go away this afternoon.
Walk backwards through every layer until you find the first place the value diverges from its source — then correct the logic at that layer, where it will stay corrected.
The obvious temptation on a migration is to modernise everything at once while you have permission to change things. I kept SQL exactly as it was and rebuilt only the layer above it — which meant that when numbers disagreed, the cause was in a much smaller haystack.
One layer changed, one layer deliberately frozen. If a figure came out wrong, it could only have gone wrong in the part I'd just rebuilt — which turns a needle-in-a-haystack into a short list.
For every mismatch, I took the same walk: read the value at each stage and compare it to the one before. The first stage where it changes is the only place worth opening the code.
Illustrative figures, real method. Patching the number on the screen fixes one report and leaves every other report built on the same logic quietly wrong.
Converting a full dashboard suite into JSON by hand is weeks of exacting, repetitive work. I used GPT to write the conversion code and translate the definitions, which turned weeks into days.
Dashboard definitions and the code to translate them. Fast, repetitive, well-suited to a model — and low risk, because the output was structure rather than judgement.
Every converted figure still had to survive the layer-by-layer check. The model sped up the work; it never decided whether the work was right.
A model doing the mechanical part, a deterministic check confirming the numbers, and a person accountable for the result. This is where that habit started.
"It looks the same" is not a test. Before anything was signed off, every migrated report had to reproduce the old system's output over the same period, to the rupee.
Exact match on the reported figure across a fixed set of historical periods. Not a sample, not a spot check — the same set every time, so one run was comparable to the last.
Zero. On a financial report, a discrepancy small enough to round away is still a discrepancy somebody will eventually have to explain to an auditor.
A mismatch wasn't a failure, it was a starting point. Walk the number backwards through each join until it stops agreeing. The last place it agreed is the defect.
₹4,72,100 matched at three stages and became ₹4,68,900 at the fourth. The gap wasn't the bug — it was the address of the bug. Years later I built the same method into generated text: check every figure against the record it came from, and when they disagree, don't argue with the output, go and find where it diverged.
I started moving things before I fully understood where every number came from. The mismatches weren't bad luck — they were the bill for mapping the lineage as I went instead of before I began.
On the next migration I'd spend the first fortnight drawing where every figure originates and what touches it on the way up, and treat that map as a deliverable rather than something I carry in my head. It would have looked like a delay to everyone watching, and it would have been faster.