| pollster | enddate | samplesize | remain | leave | undecided |
|---|---|---|---|---|---|
| YouGov | 2016-06-23 | 4772 | 0.52 | 0.48 | 0.00 |
| Populus | 2016-06-22 | 4700 | 0.55 | 0.45 | 0.00 |
| YouGov | 2016-06-22 | 3766 | 0.51 | 0.49 | 0.00 |
| Ipsos MORI | 2016-06-22 | 1592 | 0.49 | 0.46 | 0.01 |
| Opinium | 2016-06-22 | 3011 | 0.44 | 0.45 | 0.09 |
13 October, 2026
Today’s habit, again
The agent will happily write a query that runs without error and returns a plausible number. Running without error is not the same as being right.
import duckdb (Python), library(duckdb) (R), or the duckdb CLI binary.R
All three point at the same file — no import/export, no separate database to keep in sync.
data/brexit.csv: 127 opinion polls conducted between January and June 2016, ahead of the UK’s “Brexit” referendum.pollster, poll_type, startdate/enddate, samplesize, remain, leave, undecided, spread.| pollster | enddate | samplesize | remain | leave | undecided |
|---|---|---|---|---|---|
| YouGov | 2016-06-23 | 4772 | 0.52 | 0.48 | 0.00 |
| Populus | 2016-06-22 | 4700 | 0.55 | 0.45 | 0.00 |
| YouGov | 2016-06-22 | 3766 | 0.51 | 0.49 | 0.00 |
| Ipsos MORI | 2016-06-22 | 1592 | 0.49 | 0.46 | 0.01 |
| Opinium | 2016-06-22 | 3011 | 0.44 | 0.45 | 0.09 |
Prompt given to the agent (OpenCode):
“Write a DuckDB SQL query against
data/brexit.csvthat estimates the referendum outcome — the percentage voting Leave and the percentage voting Remain.”
The agent’s first draft — plausible, runs without error:
| leave_pct | remain_pct |
|---|---|
| 42.23 | 44.24 |
leave_pct = 42.23, remain_pct = 44.24. Looks like a plausible pair of vote shares. Do not trust it yet.
The cheapest check costs one extra line: do the shares add up to 100%?
| leave_pct | remain_pct | undecided_pct | total_pct |
|---|---|---|---|
| 42.23 | 44.24 | 12.65 | 99.11 |
They do (≈100%, modulo rounding) — but the query silently dropped undecided respondents from the two numbers it reported. leave_pct + remain_pct alone is only 86.5%, not 100%. The agent answered the wrong question: “average raw share” instead of “share of those who expressed a preference.”
leave and remain shares out of all respondents (including undecided), not as shares of decided voters — the quantity we actually asked for.AVG() treats a poll of 500 people the same as a poll of 5,000 — every poll gets an equal vote, regardless of samplesize.None of these threw an error. All three are silent, plausible-looking mistakes — exactly the kind unit tests and invariant checks (S7–S8) are built to catch.
| leave_pct | remain_pct | n_polls |
|---|---|---|
| 48.61 | 51.39 | 15 |
Re-normalized (excludes undecided from the denominator), sample-size weighted, restricted to the final week.
# Source: SQL [?? x 3]
# Database: DuckDB 1.4.2 [floswald@Darwin 24.6.0:R 4.5.1/:memory:]
leave_pct remain_pct n_polls
<dbl> <dbl> <dbl>
1 48.6 51.4 15
tbl(con, ...) on a DuckDB connection means these dplyr verbs are translated to SQL and run inside DuckDB — dplyr::show_query(weighted_r) prints the generated SQL, useful for checking the agent’s dplyr code actually does what you think.
leave_pct remain_pct n_polls
0 48.61 51.39 15
Same numbers as the SQL and the dplyr version — three languages, one DuckDB query plan.
The query is now correct. The prediction is still wrong.
Fixing the SQL bug (undecided handling, weighting, date window) got us a defensible number — but it’s still on the wrong side of the actual outcome. 2016 UK polls famously under-counted Leave support (non-response bias, “shy” Leave voters, herding among pollsters).
This is the distinction to keep: verification catches query bugs (wrong denominator, wrong weights, wrong date range — things you can check against an invariant). It does not catch measurement error in the data itself — that needs domain knowledge, not a better query. Keep this distinction for S9 (cost/quality tradeoffs) and S11 (cataloguing failure modes).
Working with the same brexit.csv (or a dataset of your choice with a known, checkable answer):
Ideas to try: split by pollster or poll_type (phone vs. online — did they differ systematically?), compute a rolling weekly average, or compare spread in the data to leave - remain you compute yourself (does the pollster’s number match your recomputation?).
For the session outcome, write down one concrete case where the agent’s first answer was wrong, in this format:
Template
This is not a hypothetical exercise — use whatever actually happened when you ran your own prompt. If your agent got it right first try, push it further (harder aggregation, trickier date logic, a join) until it doesn’t.