Summary
search-charts returns three record types, and roughly a third to all of the hits for a given query are not plain charts. explorerView and multiDimView hits carry a queryParams field that selects which indicator the view shows. fetch-chart-data documents only the plain case ($CHARTURL.metadata.json / $CHARTURL.csv), so an agent that drops or mishandles those params gets a different indicator back, with HTTP 200 and no error of any kind.
For a data skill this is the worst failure class: plausible-looking numbers, silently wrong, no signal.
Evidence
Non-chart share of search hits (hitsPerPage=100, measured 2026-08-18):
| Query |
Composition |
life expectancy |
chart=58, explorerView=30, multiDimView=12 |
poverty |
chart=64, explorerView=36 |
co2 emissions |
chart=86, explorerView=14 |
energy mix |
multiDimView=100 — not a single plain chart |
An explorer view, with and without its queryParams:
E="https://ourworldindata.org/explorers/population-and-demography"
# without params — what you get if they are stripped
curl -s "$E.csv?csvType=filtered&country=USA&time=2015"
# Entity,Code,Year,all years
# United States,USA,2015,326126496 <- population
# with the params the search result actually returned
curl -s "$E.csv?indicator=Life+expectancy&Sex=Both+sexes&Age=At+birth&Projection+scenario=None&csvType=filtered&country=USA&time=2015"
# Entity,Code,Year,Life expectancy at birth
# United States,USA,2015,78.722 <- life expectancy
Population versus life expectancy from the same URL. Both HTTP 200.
Same for a multi-dim chart — the column changes from Both genders to Primary education:
M="https://ourworldindata.org/grapher/years-of-schooling"
curl -s "$M.csv?csvType=filtered&time=2015" | head -1
# Entity,Code,Year,Both genders,Both genders (Original Year)
curl -s "$M.csv?level=primary&metric_type=expected_years_schooling&sex=both&csvType=filtered&time=2015" | head -1
# Entity,Code,Year,Primary education,Primary education (Original Year)
Why the skills allow it
search-charts is right, and says so (SKILL.md:112):
To fetch the data behind a chart, use the url property as is verbatim, including all query params.
But fetch-chart-data (SKILL.md:10) only describes:
Once you have identified a chart url like https://ourworldindata.org/grapher/literate-and-illiterate-world-population … The urls for both are $CHARTURL.metadata.json and $CHARTURL.csv respectively.
Two problems follow:
- The mechanics are undocumented. When the URL already has a query string, the
.csv suffix goes before the ?, and the view's params must be merged with csvType=filtered etc. Naively appending .csv to a URL ending in &sex=both does not produce a valid data URL. Nothing says this.
explorers/ URLs are never mentioned. The skill only ever shows grapher/ paths, so there is no signal that ourworldindata.org/explorers/<slug> is even a fetchable thing.
Why the existing test layers miss it
- Layer 1 (contract tests) cannot catch it as written: both URL forms return HTTP 200 with a well-formed CSV. The bug is that they return different data, which no current check compares.
- Layer 3 (output evals) would catch it, but no case exercises an explorer or multi-dim hit. All 12 cases use plain grapher charts.
Proposed fix
fetch-chart-data: document the three record types, that queryParams selects the indicator and must be carried through, that .csv/.metadata.json is inserted before the query string, and that explorers/<slug> works the same way as grapher/<slug>.
- Contract test: assert the two URL forms return different column names for a known multi-dim chart and a known explorer. That converts an invisible failure into a red test, and guards against regression if OWID changes the defaults.
- Layer 3 case: a prompt that starts from a search result which happens to be an explorer view, asserting the returned indicator matches the one requested.
- Layer 2 case: no trigger set currently mentions explorers or multi-dim views; worth one positive so routing is exercised for that phrasing too.
Secondary observation
In the multi-dim example, passing country=USA without the dimension params returned Afghanistan rather than the USA, so entity filtering may also behave differently for these views. Not investigated — worth checking while fixing the above, and possibly its own test.
Found while building the eval layers (#17–#20). Layer 1 and layer 2 are working; this is the first defect that needs layer 3 to catch it, which is a useful argument for building that runner.
Summary
search-chartsreturns three record types, and roughly a third to all of the hits for a given query are not plain charts.explorerViewandmultiDimViewhits carry aqueryParamsfield that selects which indicator the view shows.fetch-chart-datadocuments only the plain case ($CHARTURL.metadata.json/$CHARTURL.csv), so an agent that drops or mishandles those params gets a different indicator back, with HTTP 200 and no error of any kind.For a data skill this is the worst failure class: plausible-looking numbers, silently wrong, no signal.
Evidence
Non-chart share of search hits (
hitsPerPage=100, measured 2026-08-18):life expectancypovertyco2 emissionsenergy mixAn explorer view, with and without its
queryParams:Population versus life expectancy from the same URL. Both HTTP 200.
Same for a multi-dim chart — the column changes from
Both genderstoPrimary education:Why the skills allow it
search-chartsis right, and says so (SKILL.md:112):But
fetch-chart-data(SKILL.md:10) only describes:Two problems follow:
.csvsuffix goes before the?, and the view's params must be merged withcsvType=filteredetc. Naively appending.csvto a URL ending in&sex=bothdoes not produce a valid data URL. Nothing says this.explorers/URLs are never mentioned. The skill only ever showsgrapher/paths, so there is no signal thatourworldindata.org/explorers/<slug>is even a fetchable thing.Why the existing test layers miss it
Proposed fix
fetch-chart-data: document the three record types, thatqueryParamsselects the indicator and must be carried through, that.csv/.metadata.jsonis inserted before the query string, and thatexplorers/<slug>works the same way asgrapher/<slug>.Secondary observation
In the multi-dim example, passing
country=USAwithout the dimension params returned Afghanistan rather than the USA, so entity filtering may also behave differently for these views. Not investigated — worth checking while fixing the above, and possibly its own test.Found while building the eval layers (#17–#20). Layer 1 and layer 2 are working; this is the first defect that needs layer 3 to catch it, which is a useful argument for building that runner.