Fix the seven documentation drifts the contract tests found - #18
Merged
Conversation
lucasrodes
force-pushed
the
fix-skill-doc-drift
branch
from
August 18, 2026 11:36
964fbec to
f430830
Compare
lucasrodes
force-pushed
the
fix-skill-doc-drift
branch
2 times, most recently
from
August 18, 2026 13:31
0b7b773 to
87097bb
Compare
lucasrodes
force-pushed
the
fix-skill-doc-drift
branch
3 times, most recently
from
August 18, 2026 14:11
561a571 to
bf3e618
Compare
Every change here is backed by a check that now passes. Where a check asserted "the API sends what SKILL.md documents" and the doc was the wrong side of that comparison, the check is inverted to assert the corrected behaviour rather than deleted, so a field cannot creep back into the docs without the API sending it. search-charts: - Drop `objectID` from BaseSearchChartHit (returned on 0 of 200 hits) and the now-unused ExplorerType enum along with `explorerType`. - Drop `chartConfigId` from SearchMultiDimViewHit, same reason. - Document `publishedAt` / `updatedAt` (always present) and `containerTitle` (on both non-chart record types). - Add StackedDiscreteBar and Dumbbell to the tab -> URL parameter table, with the values taken from GRAPHER_TAB_CONFIG_OPTIONS in owid-grapher, and add Dumbbell to the GrapherTabName union. fetch-chart-data: - descriptionKey is a markdown bulleted string, not string[]. - Note that useColumnShortNames=true lowercases the first three CSV headers, so the recommended base parameters return `entity,code,year`. owid-catalog: - search() takes no sort_by argument; the documented example raised TypeError. Replace it with ResponseSet.sort_by(), and name the fields it can sort on. - Name each dependent indicator check once, so the skip path and the run path cannot drift apart as checks are added or renamed. The previous hardcoded skip list had already gone stale against the renamed sort_by check. Contract tests: 119 checks, 0 failures. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
lucasrodes
force-pushed
the
fix-skill-doc-drift
branch
from
August 18, 2026 14:29
bf3e618 to
96d73f7
Compare
This was referenced Aug 18, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Stacked on #17 — base is
evaluate-skills, notmain, so the diff shows only the fixes. Merge #17 first and this retargets tomainautomatically.#17 landed the contract tests with seven checks failing on purpose, so the first run would report the drift rather than freeze it in. This fixes all seven. Contract tests go from 104/7 to 120 passed, 0 failed.
Every change is backed by a check that passes. Where a check asserted "the API sends what
SKILL.mddocuments" and the doc turned out to be the wrong side of the comparison, I inverted the check to assert the corrected behaviour rather than deleting it — so a field can't creep back into the docs without the API actually sending it.The fixes
search-chartsobjectIDfromBaseSearchChartHitexplorerTypefromSearchExplorerViewHit, and the now-unusedExplorerTypeenumchartConfigIdfromSearchMultiDimViewHitpublishedAt/updatedAtcontainerTitleto both non-chart typesStackedDiscreteBar→stacked-discrete-barandDumbbell→dumbbellto the tab table; addedDumbbelltoGrapherTabNameGRAPHER_TAB_CONFIG_OPTIONSinowid-grapher, not guessedNet effect on the skill's token cost is slightly negative — the five-line
ExplorerTypeenum was dead weight onceexplorerTypewent.fetch-chart-datadescriptionKeyis typedstring[]but is a single markdown bulleted string (-per line). Fixed the type and said so, since the skill tells agents to surface this field to users.useColumnShortNames=true— which the skill recommends — lowercases the first three headers toentity,code,year, and to match column names case-insensitively. The documentedEntity,Code,Yearwas only true for calls that skip the recommended parameter.owid-catalogsearch(..., sort_by="relevance")raisedTypeError:search()in owid-catalog 1.1.0 has nosort_byparameter. Replaced withResponseSet.sort_by(), which does exist, and named the fields it can actually sort on (score,popularity,n_charts) — verified by inspecting the installed signature and result fields.One thing I added beyond the six
chartConfigIdonSearchMultiDimViewHitis a seventh drift, same defect class asobjectIDandexplorerType(schema declares a required field the API never sends). I only found it because the search index shifted mid-session — see below — which finally gave me multiDimView hits to inspect. Fixing it alongside the other two seemed more coherent than leaving one instance of the same bug behind, but say the word and I'll split it out.A real finding about eval fragility
The query
energy mixreturned 47 chart / 53 explorerView hits at the start of this work and 100 multiDimView hits about an hour later — same query, same parameters. The index composition is not stable.That broke my own assertion ("this query returns at least one explorerView hit"), not the skill. So the non-chart hit-shape checks now:
skip()loudly when it doesn't,q=life expectancy, which currently returns all three types (chart=58, explorerView=30, multiDimView=12).Worth knowing for layer 2 as well: assertions pinned to live-index composition will flake. Assert shapes, not populations.
Verification
Run it yourself with
./evals/run-contract-tests.sh.Still not fixed (deliberately)
These were in #17's description as observations rather than failing checks, and each needs a judgement call rather than a mechanical fix:
joining-datatells agents to read$.columns.[0].timespan—columnsis an object keyed by column name, so that path is not valid jq. It matters most forpopulation-with-un-projections, where the first column is estimates (1950–2023) and the projection to 2100 is a second column; reading one column's timespan gives the wrong answer for exactly the recent/future-year case the skill recommends that chart for. Needs a decision on what to tell agents instead (union across columns? name the two columns explicitly?).search-chartssays "If you don't get any results, try slightly different terms", butnbHits == 0essentially never happens. The guidance needs rewriting around low relevance rather than zero results — a prose change with real behavioural consequences, so probably yours to make.csvType=filteredalso applies the chart's own default entity selection.population.csv?csvType=filtered&time=2020returns 7 rows — continents and World, no countries. Bothfetch-chart-dataandjoining-dataimply country rows are present.owid-catalogsays indicator results are "ranked by popularity". They're actually ordered by semantic similarity (score) descending, with popularity breaking ties. I left the prose alone since it's adjacent to but not part of thesort_byfix.Happy to do all four in a follow-up.
🤖 Generated with Claude Code