feat: reconcile a URDB record against the cited parse - #67
Merged
Conversation
OpenEI's Utility Rate Database is the dataset most tools use for California tariffs, and its records carry no citation to a page. `reconcile` audits a record the user downloaded themselves against a parse of the document it claims to describe, and reports per field: confirms (with the citation), contradicts (with both values and the page), no statement, or not comparable (with the reason). There is no state meaning "checked out fine". A parse that emitted no charges reports every priced field as "no statement" — never confirmed, never contradicted. What it refuses to do is the substance. It does not align URDB's index-numbered rate periods with the names a document prints, because neither record states the correspondence; values are compared by membership in a unit family instead, and the report says so. A tier carrying a non-zero adjustment is not compared, because rate + adj is what a customer pays and the printed price is what this model records. A credit is not matched against a rate. And a record whose start date no charge carries widens the comparison to every charge rather than narrowing it to an empty set, so silence can never be printed where there is a disagreement. Every key in the record is reported, including the unmapped ones, each with its reason — the report is complete over the record rather than quietly partial.
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.
Issue #51 asked for a
reconcileverb that audits a URDB rate record the user supplies against the cited parse, field by field. This is that verb.What was wrong
OpenEI's Utility Rate Database is the dataset most tools reach for when they need a California tariff, and its records carry no citation to a page. Anyone who wants to know whether a URDB number is what the utility actually published has to open the PDF. This repository already holds cited parses of seven documents and had no way to answer that question.
What changed
ca-tariff-parse reconcile parsed.json urdb-record.jsonreads a record the user downloaded themselves — nothing is fetched — and reports per field:confirmscontradictsno statementnot comparableExits 0 when nothing contradicts, 3 when something does, 2 when the record cannot be read at all.
--jsonwrites aca-tariff-parse/reconcile/v1payload.There is deliberately no state meaning "checked out fine."
smud-ssrprices nothing (ADR 0011), so every priced field of any record reconciled against it comes backno statement. Reporting "nothing to disagree with" as agreement would be the same error as printing a suppressed cell as zero.Every key in the record is reported, including the ones the mapping does not cover, each with its reason — so the report is complete over the record rather than quietly partial.
Four refusals, which are the substance
reconcilediagnoses neither.adjis not compared. What a customer pays israte + adj; what this model records is the price the page prints. Comparing the bare rate would confirm a number nobody is billed.startdatematches an effective date in the parse, priced fields are compared only against charges effective on that date. When it matches none, they are compared against every charge and the report says why. Narrowing to nothing would have printed silence where there is a disagreement — the failure this repository exists to avoid.Numbers are decoded with
Decimal, notfloat, so a rate printed0.1724is compared as0.1724rather than as the nearest binary approximation of it.One deviation from the issue, stated plainly
The issue lists "TOU schedule matrices" among the fields with a counterpart. They are reported
not comparablehere, with that reason written into the output. A 12×24 matrix of period indices cannot be aligned toTouWindowrecords identified by the period names the document prints without inventing the correspondence, and several of this project's windows are residual — defined by exclusion, with no hours to align at all (ADR 0002). Doing it anyway is the one thing in this feature that would have manufactured a value out of an absence. If you want the matrices compared, the correspondence has to come from somewhere both records state, and I did not find it. That part of #51 is not delivered; everything else is.minchargeis likewisenot comparable: this model records priced line items, and nothing in aChargestates the role "the minimum a bill must reach". Selecting one by reading its label text would be a guess.How it was verified
make verify— install, ruff, ruff format, mypy strict, pytest. 677 passed, 2 skipped (the two skips are therealdoctests, which needmake fetch). Total coverage 94.56%;reconcile.pyat 94%.The issue's three acceptance criteria each have a test:
test_a_matching_record_confirms_every_mapped_field_with_a_citation— and asserts every confirmation carries a locatortest_one_altered_price_is_exactly_one_contradiction— asserts the count is 1, both values appear, and the locator issynthetic p.2 sheet SYN-1-2 II.A L11test_a_parse_with_no_charges_states_nothing_rather_than_agreeing— run against the committeddata/parsed/smud-ssr.json, not a synthetic stand-inThree negative controls. Each sabotage was asserted present in the file before the run, and the file was restored from a byte copy afterwards (
shasumequal,cmpclean, suite green again):confirmsinstead ofno statementsmud-ssrone and the credit onefamily()testskwbeforekwh, so an energy price reads as a demand pricetest_a_date_no_charge_carries_widens_rather_than_silencingThe fixture record
tests/fixtures/SYNTHETIC-urdb-record.jsonis written in URDB's shape and describes no real utility and no real price.What this does not touch
No schema change, no baseline regeneration, no new dependency, no network.
tests/golden/anddata/parsed/are byte for byte unchanged.Part of #51; the schedule-matrix comparison described above is the remainder.
Prepared with AI assistance; reviewed before submission.