Repository navigation
The claims gate could not see the preprint, and EUR reconciled as USD - #31
Merged
Merged
Conversation
`check_claims.py` printed "paper ok" while checking none of the 53 percentages in paper/main.tex. `strip_markup` unescaped `\%` -- but only AFTER stripping TeX comments with a bare `%.*`, which treats the `%` in `45.7\%` as a comment start and deletes the rest of the line. Every figure after the first percentage in a table row, and the tail of the abstract, vanished before `claims_in` ever saw them. Strip only an unescaped `%`. The gate's docstring claims it checks "the published study pages, the preprint and the dataset card". Three further gaps sat under that claim: - README.md carries the same headline tables as FINDINGS.md and was not a surface at all. Added as `repo-readme`. - `--offline` silently drops the four live guide pages, then printed the unqualified "every published number". It now names what it skipped and says to run online before publishing a number. - "43% first-named" and "93% of answers name one of those three" had no figure behind them; they passed only by rounding to the same integer as an unrelated figure. Both now come from aeo/results.json -- `named_first_pct`, and `aeo.top3.named_in` as a union over answers. A seed value (`seed 20260910`) is an identifier, not a claim. Coverage: 64 -> 139 claims offline, 249 -> 285 online. Both modes green, `figures.py --check-fresh` green, and the two allowlist entries added are the only kind that belongs there -- a person's hand adjudication, which no script can produce. verify/test_claims_gate.py pins all of it, and goes red on the old ordering: the table-row test returns [] instead of three percentages. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NRueWxopDXHoWY2dPvsmLG
Every entry in units.CURRENCY carries a scale of 1.0, because the benchmark holds no exchange rates -- an FX rate is a price on a date, not a unit conversion. That made EUR, GBP and USD interchangeable, so a model answering "85.00 EUR per tonne CO2e" scored 85 against a USD/tCO2e truth, wrong by whatever the rate happened to be and counted as an answer rather than an unscoreable one. `sek: None` was already refusing this way by having no scale at all; the rest were reconciling by accident. parse_unit now records WHICH currency a numerator is, and reconcile refuses a mismatched pair with a reason. Same currency, either spelling, is unaffected. This is the same bug class as #23 (a currency the extractor drops), found while reviewing #30: the guard proposed there only covered a currency written BEFORE the number, and all three live hits are written after it. Three answers were being scored, all gemini-3.6-flash, all carbon_pricing.*: EU ETS 85.00, Spain 15.00, Netherlands 51.00 EUR/tCO2e against a USD truth. One of the three was being counted correct. Published figures brought back into line with the scorer: scoreable 315 -> 312 within_10pct 41.9% -> 42.0% unscoreable 85 -> 88 within_50pct 78.1% -> 77.9% correct 132 -> 131 conf. wrong 21.9% -> 22.1% pct of all 467 28.3% -> 28.1% in FINDINGS.md, README.md, paper/main.tex (the abstract's range and the results table) and the page/ snapshots. No other model moves, and paired.json is untouched. results/absolute.json fed the `pct_of_all` column with no script behind it, so a scorer change moved it silently and --check-fresh could not see it. absolute.py now generates it -- it reproduced the committed file exactly on the old scorer before this change, model order and all -- and check_fresh reruns it. Also corrected while verifying: the by-category page said 867 pooled scored answers. The true figure was 886 before this change and is 883 after; 867 is from an earlier scorer version. CLAIM_RE only matches counts with a thousands separator, so the gate never saw it. verify/test_currency_mismatch.py covers it, including the three answers as the models actually wrote them, and goes red without the fix. NOT DONE, needs server access: the live pages still show the old gemini figures. `check_claims.py` (online) fails on guide:accuracy with 41.9% and 28.3%, which is the correct signal. Live post ids are 9316 (accuracy) and 9327 (by-category) -- note 9327, not the page/9322-body.html snapshot. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NRueWxopDXHoWY2dPvsmLG
This was referenced Sep 20, 2026
FINDINGS.md's scorer section opens "It was wrong six times, and each is recorded because on a benchmark the corrections matter more than the headline." The EUR-as-USD fix in the previous commit is a seventh, and leaving it out fails that document's own standard — so it is now entry 7, and README.md and the paper abstract say seven. Two details worth being straight about rather than smoothing over: - Six of the seven were found BEFORE the number was published. This one was not; it was found after, while reviewing a contributor's fix for the related extraction bug. The paragraph now says so instead of keeping the tidier claim. - The same section ended "mostly currency (a SEK answer against a USD truth)", which implied currency mismatches were handled. Only SEK was, and only by accident -- it is the one entry in CURRENCY with no scale. EUR and GBP were converted at 1.0. Reworded to say what the scorer now does. The bug-log entry quotes 41.9%, which no script produces any more. That is the one shape an allowlist entry is for, and it goes in `findings` next to the existing 46.7% for the same reason -- a historical figure in a narrated correction, with the current value named in the reason. Also: nothing ran verify/test_*.py. Three test files existed across this branch and #30 and CI executed none of them, which is worse than having no tests because it reads as cover. claims.yml now has a scorer-tests job that discovers them by glob and fails if the glob matches nothing -- a listed filename would have gone stale the first time one was renamed. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NRueWxopDXHoWY2dPvsmLG
This was referenced Sep 20, 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.
Two fixes found while reviewing #30, plus the published figures they move.
1. The claims gate could not see the preprint
check_claims.pyprintedpaper okwhile checking none of the 53 percentages inpaper/main.tex.strip_markupunescapes\%— but only after stripping TeX comments with a bare%.*, which treats the%in45.7\%as a comment start and deletes the rest of the line. Every figure after the first percentage in a table row, and the tail of the abstract, vanished beforeclaims_inever saw them.Two more gaps sat under the same docstring claim of checking "the published study pages, the preprint and the dataset card":
README.mdcarries the same headline tables asFINDINGS.mdand was not a surface at all.--offlinesilently drops the four live guide pages, then printed the unqualified "every published number". It now names what it skipped.43%first-named and93%of answers naming one of the top three had no figure behind them — they were passing only by rounding to the same integer as an unrelated figure. Both now come fromaeo/results.json.Coverage: 64 → 139 claims offline, 249 → 285 online.
2. Two different currencies must never reconcile
Every entry in
units.CURRENCYcarries a scale of1.0, because the benchmark holds no exchange rates — an FX rate is a price on a date, not a unit conversion. That made EUR, GBP and USD interchangeable, so a model answering85.00 EUR per tonne CO2escored 85 against aUSD/tCO2etruth and counted as an answer rather than an unscoreable one.sek: Nonewas already refusing this way by having no scale at all; the rest were reconciling by accident.parse_unitnow records which currency a numerator is, andreconcilerefuses a mismatched pair with a reason. Same currency, either spelling, is unaffected.Three answers were being scored this way, all
gemini-3.6-flash, allcarbon_pricing.*— EU ETS 85.00, Spain 15.00, Netherlands 51.00 EUR/tCO2e against a USD truth. One of the three was being counted correct.This is the same bug class as #23. The guard proposed in #30 only covers a currency written before the number, and all three live instances are written after it.
Published figures brought back into line
Updated in
FINDINGS.md,README.md,paper/main.tex(the abstract's range and the results table) and thepage/snapshots. No other model moves andpaired.jsonis untouched.results/absolute.jsonfed thepct_of_allcolumn with no script behind it, so a scorer change moved it silently and--check-freshcould not see it.absolute.pynow generates it — it reproduced the committed file exactly on the old scorer, model order and all — andcheck_freshreruns it.Also corrected while verifying: the by-category page said 867 pooled scored answers. The true figure was 886 before this change and is 883 after.
CLAIM_REonly matches counts with a thousands separator, so the gate never saw it.Verification
From a clean clone at the branch tip:
verify/test_claims_gate.pyverify/test_currency_mismatch.pyverify/figures.py --check-freshverify/dataset.pyverify/licences.pyverify/check_claims.py --offlinecompare.py/paired.py/absolute.pyrerunBoth new tests go red without their fix — the gate test returns
[]instead of three percentages on the old comment ordering.check_claims.pyonline fails onguide:accuracy(41.9%, 28.3%), and that is the correct signal: the live pages still carry the old figures. Live post ids are 9316 (accuracy) and 9327 (by-category) — note 9327, not thepage/9322-body.htmlsnapshot, which is superseded. That deploy is not in this PR.Not in scope
Opening separately: unenumerated dollar codes (
A$,C$,R$,S$) collapsing to USD, andreconcilenot comparing numerator dimensions (USD 5 per kWhagainst akg CO2e/kWhtruth). Neither has a live hit today.🤖 Generated with Claude Code
https://claude.ai/code/session_01NRueWxopDXHoWY2dPvsmLG