- blank on the dashboard, filled in the file
- the file arrived after the sync
- the newest day is often a day behind — check again tomorrow
Every morning an agent I built works through a live product the way a careful user would: every number against its source, every screen for what misleads. I write it up for the developers, with a working mock-up of the fix when words aren't enough.
This is one real engagement, with the names and numbers changed. A production dashboard, fed by spreadsheets people export by hand, used by a team every day. I check it the way a careful user would — every number against its source, every screen for anything that confuses or misleads — and each morning an agent I built does the first pass. What we find goes to the developers as a numbered note with the evidence attached, and when a fix is easier to show than describe, I build a working mock-up of the screen I'd want instead. These are the folders.
names changednumbers illustrativestill runningThe spreadsheet and the dashboard are supposed to say the same thing. So every morning the agent reads one, opens the other, and compares them cell for cell. Where they agree, it moves on. Where they don't, it starts asking questions.
| Date | Ref | Rate | Yield % | Ratio | Var | Loss % | Load % | |
|---|---|---|---|---|---|---|---|---|
| 2 | 09 Jun | 10412 | 62.48✓ | 4.12✓ | 2.31✓ | 0.081✓ | 3.95✓ | 8.20✓ |
| 3 | 10 Jun | 10418 | 61.90✓ | 4.40✓ | 2.28✓ | 0.079✓ | 4.02✓ | 8.61✓ |
| 4 | 11 Jun | 10425 | 62.77✓ | 3.98✓ | 2.35✓ | 0.083✓ | 3.88✓ | 7.94✓ |
| 5 | 12 Jun | 10431 | 62.05✓ | 4.21✓ | 2.40✓ | 0.080✓ | 4.11✓ | 8.35✓ |
| 6 | 13 Jun | 10437 | 61.66✓ | 4.55✓ | 2.26✓ | 0.077✓ | 4.20✓ | 8.90✓ |
| 7 | 14 Jun | 10444 | 62.31✓ | 4.09✓ | 2.33✓ | 0.082✓ | 3.97✓ | 8.12✓ |
| 8 | 15 Jun | 10450 | 62.84✓ | 3.90✓ | 2.29✓ | 0.084✓ | 3.81✓ | 7.70✓ |
| Date | Ref | Rate | Yield % | Ratio | Var | Loss % | Load % |
|---|---|---|---|---|---|---|---|
| 09 Jun | 10412 | 62.48✓ | 4.12✓ | 2.31✓ | 0.092✓ | 3.95✓ | 8.20✓ |
| 10 Jun | 10418 | 61.90✓ | 4.40✓ | 2.28✓ | 0.079✓ | 4.02✓ | 8.61✓ |
| 11 Jun | 10425 | 62.77✓ | 3.98✓ | 2.35✓ | 0.083✓ | 3.88✓ | 7.94✓ |
| 12 Jun | 10431 | 62.05✓ | 4.21✓ | 2.40✓ | 0.080✓ | 4.11✓ | 8.35✓ |
| 13 Jun | 10437 | 61.66✓ | 4.55✓ | 2.26✓ | 0.077✓ | 4.20✓ | 8.90✓ |
| 14 Jun | 10444 | 62.31✓ | 4.09✓ | 2.33✓ | 0.082✓ | 3.97✓ | 8.12✓ |
| 15 Jun | 10450 | 62.84✓ | —✓ | 2.29✓ | 0.084✓ | 3.81✓ | 7.70✓ |
Most of the differences it finds have an innocent explanation: a file that arrived late, a column that was never meant to be imported, a period that got restated. It works those out itself and writes them down. When it can't explain something, it hands it to a person with everything they need already attached.
Every one of these looked perfectly normal on screen. Nothing was red, nothing errored. Some were numbers that had quietly gone wrong on the way from the file. Some were screens that told the person using them the wrong thing.
Someone moved a record to the day before. The dashboard moved it too — but left its numbers behind, so the row showed the next record's values.
dozens of cells wrong| Date | Ref | Rate | Yield % |
|---|---|---|---|
| 12 Jun | 10431 | 61.66 | 4.55 |
| 13 Jun | 10437 | 61.66 | 4.55 |
| Date | Ref | Rate | Yield % |
|---|---|---|---|
| 12 Jun | 10431 | 62.05 | 4.21 |
| 13 Jun | 10437 | 61.66 | 4.55 |
A row of 7.00s appeared out of nowhere. Someone's test data had made it into production and was showing as real.
| Date | Rate | Yield % | Loss % | Load % |
|---|---|---|---|---|
| 30 Jun | 62.31 | 4.09 | 3.97 | 8.12 |
| 01 Jul | 7.00 | 7.00 | 7.00 | 7.00 |
| Date | Rate | Yield % | Loss % | Load % |
|---|---|---|---|---|
| 30 Jun | 62.31 | 4.09 | 3.97 | 8.12 |
The import just stopped. No error, no alert — the 'last synced' time simply stopped moving.
caught the same day| last synced |
|---|
| 4 days ago |
| last synced |
|---|
| this morning |
The dashboard remembers where each column group was the first time it saw it. The spreadsheet moves columns around. Short date ranges look fine; long ones come out scrambled.
short range fine · long range wrong| Group order — long range |
|---|
| GROUP D · GROUP A · GROUP C · GROUP B |
| Group order — short range |
|---|
| GROUP A · GROUP B · GROUP C · GROUP D |
Proven by rebuilding a dozen old versions of the spreadsheet — and by predicting what the next one would do before it arrived.
Three different column groups had the same name. The dashboard told them apart by name, so it merged all three into one — in the wrong place.
same name, three groups| Block | Slot | Rows |
|---|---|---|
| TOTAL ×3 | first (empty) | all merged |
| Block | Slot | Rows |
|---|---|---|
| TOTAL (1) | own slot | 2 |
| TOTAL (2) | own slot | 3 |
| TOTAL (3) | own slot | 2 |
Every new draft was stamped with the day before it was created. The numbers underneath were fine; the label on them wasn't — and people were reading the wrong day.
a screen, not a number| Created on | Shown as |
|---|---|
| 09 Jun | 08 Jun |
| Created on | Shown as |
|---|---|
| 09 Jun | 09 Jun |
Save stayed enabled on an empty form. One click created a blank record, which then turned up in every list and every total.
a screen, not a number| Required fields filled | Save button |
|---|---|
| 0 of 3 | enabled |
| Required fields filled | Save button |
|---|---|
| 0 of 3 | disabled |
Each morning's run is a line here: how many cells it checked, what it explained, what it flagged. A clean run still leaves a count behind.
For the first stretch, every value matched and every run was clean. Then a check of the headers turned up a column sitting under the wrong heading. In the spreadsheet it fell outside every merged header, and the importer tucked it in with the group to its left. The numbers were right and the label was wrong, and comparing numbers can never catch that. So now the agent checks the headers too.
A finding is only useful once someone can act on it. So each one goes to the developers as a numbered line with the evidence attached — the record, both values, a screenshot. And when a fix is easier to show than to describe, I build a working mock-up of the screen I'd want instead, in the product's own stack.
| Date | Actual |
|---|---|
| 09 Jun | 62.48 |
| 10 Jun | 61.90 |
| 11 Jun | 62.77 |
| 12 Jun | 62.05 |
| 13 Jun | 61.66 |
| Date | Actual | Target | Δ |
|---|---|---|---|
| 09 Jun | 62.48 | 62.00 | +0.48 |
| 10 Jun | 61.90 | 62.00 | −0.10 |
| 11 Jun | 62.77 | 62.00 | +0.77 |
| 12 Jun | 62.05 | 62.00 | +0.05 |
| 13 Jun | 61.66 | 62.00 | −0.34 |
Every round is written back into a knowledge vault the agent reads before the next one — the patterns it learned, the bugs it found, the fixes it checked. So each morning starts with everything from the morning before. And anything in there can be asked for in plain language, over chat, from the same brain.
Get in touch ↗