Agentic testing · a case study

QA testing,
with an upgrade.

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.

RUNNING EVERY WEEKDAY · NUMBERS, SCREENS, WRITE-UPS · NOTHING LEFT UNEXPLAINED
01The Round

One morning,
three exhibits.

The 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.

Exhibits A–C · one morning · one screen
Exhibit A · the spreadsheetsent after the sync
DateRefRateYield %RatioVarLoss %Load %
209 Jun1041262.484.122.310.0813.958.20
310 Jun1041861.904.402.280.0794.028.61
411 Jun1042562.773.982.350.0833.887.94
512 Jun1043162.054.212.400.0804.118.35
613 Jun1043761.664.552.260.0774.208.90
714 Jun1044462.314.092.330.0823.978.12
815 Jun1045062.843.902.290.0843.817.70
Exhibit B · the dashboardsynced this morning
DateRefRateYield %RatioVarLoss %Load %
09 Jun1041262.484.122.310.0923.958.20
10 Jun1041861.904.402.280.0794.028.61
11 Jun1042562.773.982.350.0833.887.94
12 Jun1043162.054.212.400.0804.118.35
13 Jun1043761.664.552.260.0774.208.90
14 Jun1044462.314.092.330.0823.978.12
15 Jun1045062.842.290.0843.817.70
Exhibit C · the agent's notesa few minutes later
$ read the spreadsheets
several files · a dozen screens · thousands of values
$ open the dashboard
every screen captured · synced this morning
$ compare
checking…
Screen 5 · 15 Jun · Yield % — blank on the dashboard. The file arrived after the sync. It'll be there tomorrow.
Screen 1 · 09 Jun · Var — 0.081 in the file, 0.092 on screen. Nothing explains that. Flagging it.
✔ every cell checked · a few explained · one flagged · notes written
$
matchesexplained · nothing wronghanded to a person
Flagged
02VerdictsNext Verdicts
02Verdicts

Not every mismatch
is a bug.

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.

01
difference 1 · this morningexplained
Screen 5 — 15 Jun · Yield %
in the file3.90on screen
  1. blank on the dashboard, filled in the file
  2. the file arrived after the sync
  3. the newest day is often a day behind — check again tomorrow
Explained
02
difference 2 · this morningexplained
Screen 2 — whole column · Extras
in the filea full columnon screen
  1. the whole column is missing from the dashboard
  2. it's on the list of columns left out on purpose
  3. not a bug, and never will be
Explained
03
difference 3 · this morningexplained
Screen 3 — 11 Jun · Loss %
in the file###on screen3.88
  1. the cell in the file can't be read
  2. the dashboard shows a sensible value from a corrected file
  3. skip it — it clears on the next sync
Explained
04
difference 4 · this morningexplained
Screen 4 — 02 Jun · full row
in the filere-datedon screenold date
  1. an old period was sent again, re-dated and renumbered
  2. the new version arrived after the sync, so the dashboard is behind
  3. check again once it's imported — anything still wrong is a bug
Explained
05
difference 5 · this morningneeds a person
Screen 1 — 09 Jun · Var
in the file0.081on screen0.092
  1. a settled date, two different values, and the gap is too big
  2. nothing I've seen explains a changed value on a settled date
  3. flagging it with the record, both values and the timestamps
Flagged
What happens to each oneidle
  1. found
  2. explained
  3. flagged
  4. fixed
  5. checked again
Most stop at explained. The flagged ones go all the way round, and get checked again the next morning.
03Case FilesNext Case Files
03Case Files

The bugs nobody
could see.

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.

Fixed
AT-01 · an early round

The shifted record

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
on screen · beforean early round
DateRefRateYield %
12 Jun1043161.664.55
13 Jun1043761.664.55
after the fixchecked again ✓
DateRefRateYield %
12 Jun1043162.054.21
13 Jun1043761.664.55
Fixed
AT-02 · a middle round

The phantom row

A row of 7.00s appeared out of nowhere. Someone's test data had made it into production and was showing as real.

on screen · beforea middle round
DateRateYield %Loss %Load %
30 Jun62.314.093.978.12
01 Jul7.007.007.007.00
after the fixchecked again ✓
DateRateYield %Loss %Load %
30 Jun62.314.093.978.12
Fixed
AT-03 · an early round

The silent stall

The import just stopped. No error, no alert — the 'last synced' time simply stopped moving.

caught the same day
on screen · beforean early round
last synced
4 days ago
after the fixchecked again ✓
last synced
this morning
Watching
AT-04 · later rounds

The frozen order

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
on screen · beforelater rounds
Group order — long range
GROUP D · GROUP A · GROUP C · GROUP B
what the spreadsheet sayswatching
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.

Watching
AT-05 · the latest round

The merged twins

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
on screen · beforethe latest round
BlockSlotRows
TOTAL ×3first (empty)all merged
what the spreadsheet sayswatching
BlockSlotRows
TOTAL (1)own slot2
TOTAL (2)own slot3
TOTAL (3)own slot2
Fixed
AT-06 · a later round

The date that lied

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
on screen · beforea later round
Created onShown as
09 Jun08 Jun
after the fixchecked again ✓
Created onShown as
09 Jun09 Jun
Watching
AT-07 · a later round

The save that shouldn't

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
on screen · beforea later round
Required fields filledSave button
0 of 3enabled
what the spreadsheet sayswatching
Required fields filledSave button
0 of 3disabled
04The LedgerNext The Ledger
04The Ledger

Every round,
on the record.

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.

Ledger · cells checked each morning · red = a bug flagged
0rounds so far
0cells checked
0left unexplained
01~1.3kfirst full map
02~1.7kfile vs screen
03~3.3kpass
04import stalled — caught same day
05~4.4koverwrite confirmed
06~5.9kshifted record found
07~6.2kshift fixed ✓
08~5.9kphantom row found
09~6kpass
10~6.1kphantom gone ✓
11~6.2kheader check added
12~6.2kfrozen order proven

The one the numbers
couldn't show.

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.

GROUP A?GROUP B
RateYield %Loss %Load %RefRateYield %Load %
in the spreadsheet
GROUP AGROUP B
on the dashboard · the stray column pulled left
05The Write-upNext The Write-up
05The Write-up

What the developers
get from me.

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.

Exhibit D · the feedback note · one round
Feedback · for the developers4 items
  1. 1
    screen
    Drafts are stamped with the day before they were created.
    entered 09 Jun · shown 08 Jun · every draft
  2. 2
    number
    Row 09 Jun, Var reads 0.092. The file says 0.081.
    ref 10412 · expected 0.081 · got 0.092
  3. 3
    screen
    Column groups change order when the date range is widened.
    1 month: A · B · C · D — 3 months: D · A · C · B
  4. 4
    screen
    Save is enabled on an empty form; one click makes a blank record.
    required fields: 3 · filled: 0 · save: enabled
Sent
Exhibit E · the mock-up · a working page, not a picture
as builttoday
DateActual
09 Jun62.48
10 Jun61.90
11 Jun62.77
12 Jun62.05
13 Jun61.66
proposedtarget + difference
DateActualTargetΔ
09 Jun62.4862.00+0.48
10 Jun61.9062.00−0.10
11 Jun62.7762.00+0.77
12 Jun62.0562.00+0.05
13 Jun61.6662.00−0.34
Proposed
The team asked "how far off target are we?" and had to work it out by hand. The proposed screen answers it in the table itself — built as a page they could drop in, so the conversation is about the answer, not the idea.
Close the file
Where it all goes

It gets smarter
every morning.

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 ↗