Make sense of a messy table
Inspect a messy synthetic spreadsheet, spot missing rows and unit traps, and check whether the summary matches the numbers.
1. Scenario
Pick a work role starter with synthetic material, or switch to Bring your own.
Monthly bookings sheet with credit notes mixed in
Sales · Synthetic materialYou are preparing the October regional bookings total and notice credit notes are sitting in the same table as new orders.
entry_id,account,type,amount_usd,rep INV-901,Oak Clinic,new_order,4200,Dana INV-902,Pine Dental,new_order,3600,Dana CN-903,Oak Clinic,credit_note,1200,Dana INV-904,River Vet,new_order,5000,Sam CN-905,River Vet,credit_note,800,Sam
2. Work area
Edit the briefs or setup below before you run.
Only the header row, inferred column types, and at most 20 sample rows leave your device. The analysis function runs in your browser on all rows.
Answer and chart
Example. No model ran.Across all regions, 91000 GBP sits in accounts marked at-risk. South leads total renewal value at 146000 GBP.
- 1. Sum value_gbp by region and count how many accounts in each region are marked at-risk.
- 2. Calculate the total GBP value across all at-risk renewals.
- 3. Show the at-risk rows so the account lead can check the sum by hand.
Inspect the analyze(rows) code that ran in your browser
function analyze(rows) {
const byRegion = {};
let atRiskValue = 0;
for (const row of rows) {
const region = String(row.region || "Other");
const val = Number(row.value_gbp) || 0;
if (!byRegion[region]) {
byRegion[region] = { region, accounts: 0, totalGbp: 0, atRiskGbp: 0 };
}
byRegion[region].accounts += 1;
byRegion[region].totalGbp += val;
if (String(row.stage) === "at-risk") {
byRegion[region].atRiskGbp += val;
atRiskValue += val;
}
}
const table = Object.values(byRegion).sort((a, b) => b.totalGbp - a.totalGbp);
const chart = table.map((item) => ({ label: item.region, value: item.totalGbp }));
return {
answer: "Across all regions, " + atRiskValue + " GBP sits in accounts marked at-risk. " + (table[0] ? table[0].region : "South") + " leads total renewal value at " + (table[0] ? table[0].totalGbp : 0) + " GBP.",
table,
chart,
checkOne: {
label: "Total GBP in at-risk accounts",
figure: atRiskValue,
column: "stage",
equals: "at-risk",
mode: "sum",
sumColumn: "value_gbp"
}
};
}Check one number by hand
Reported: 91000 · Rows found: 91000Total GBP in at-risk accounts: Filter where stage equals at-risk. Below are all 5 matching rows from the 24-row spreadsheet so you can count or sum them yourself.
3. Run
Nothing leaves your browser until you press Run.
Sends only the column header and at most twenty sample rows when you press run. to job data_code (claude-sonnet-5-5, effort medium). Raw text is processed in memory and not stored.
4. Inspect
See what left the browser, which model ran, and the receipt.
Nothing sent yet. When you run, only headers and at most 20 sample rows leave this device.
All 24 rows stay in your browser and run inside the sandboxed Web Worker.
data_code · claude-sonnet-5-5 (effort medium, max 1600 tokens). Haiku reads the schema and sample rows to propose checks you can verify against the full table.
0 runs used · source: offline · Example. No model ran.
5. Judge
Did the total subtract CN-903 ($1,200) and CN-905 ($800) instead of adding them as positive revenue?
50 is a coin flip. 99 is certain. Honest confidence scores best.
6. Debrief and Keep
What to check next time, the matching lesson, and keeping this setup as a recipe.
What to check next time
Many accounting exports store credit notes as positive numbers with a `type` column of `credit_note`. Summing the amount column blindly adds refunds to revenue.
Keep as a recipe
Save the stronger brief and scenario setup to your device so you can reuse or adapt it in Keep.