Skip to content

feat: reconcile a URDB record against the cited parse - #67

Merged
ChelseaKR merged 1 commit into
mainfrom
feat/reconcile-a-urdb-record-against-the-parse
Sep 7, 2026
Merged

feat: reconcile a URDB record against the cited parse#67
ChelseaKR merged 1 commit into
mainfrom
feat/reconcile-a-urdb-record-against-the-parse

Conversation

@ChelseaKR

Copy link
Copy Markdown
Owner

Issue #51 asked for a reconcile verb 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.json reads a record the user downloaded themselves — nothing is fetched — and reports per field:

state means
confirms the parse states this value, in a comparable unit, and here is the citation
contradicts the parse states values of this kind and none of them is this one
no statement the parse read no value of this kind at all
not comparable this model cannot express the field, and the reason is named

Exits 0 when nothing contradicts, 3 when something does, 2 when the record cannot be read at all. --json writes a ca-tariff-parse/reconcile/v1 payload.

There is deliberately no state meaning "checked out fine." smud-ssr prices nothing (ADR 0011), so every priced field of any record reconciled against it comes back no 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

  • URDB's rate periods are not aligned with the document's. URDB names its periods by index; the document names them in the words it prints. Neither record states the correspondence, so aligning them would be a guess. Values are compared by membership in a unit family instead, and the report says so in its own preamble. A contradiction therefore means the two records disagree about what the schedule prices — either a URDB entry error or a gap in this parser, and reconcile diagnoses neither.
  • A tier carrying a non-zero adj is not compared. What a customer pays is rate + adj; what this model records is the price the page prints. Comparing the bare rate would confirm a number nobody is billed.
  • A credit is not matched against a rate. Credits are excluded from every family.
  • A start date no charge carries widens the comparison rather than emptying it. When the record's startdate matches 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, not float, so a rate printed 0.1724 is compared as 0.1724 rather 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 comparable here, with that reason written into the output. A 12×24 matrix of period indices cannot be aligned to TouWindow records 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.

mincharge is likewise not comparable: this model records priced line items, and nothing in a Charge states 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 the realdoc tests, which need make fetch). Total coverage 94.56%; reconcile.py at 94%.

The issue's three acceptance criteria each have a test:

criterion test
a matching record reports every mapped field confirmed with a citation test_a_matching_record_confirms_every_mapped_field_with_a_citation — and asserts every confirmation carries a locator
the same record with one price altered reports exactly one contradiction naming both values and the page test_one_altered_price_is_exactly_one_contradiction — asserts the count is 1, both values appear, and the locator is synthetic p.2 sheet SYN-1-2 II.A L11
a parse that emitted zero charges reports every price field as no statement, never contradicted test_a_parse_with_no_charges_states_nothing_rather_than_agreeing — run against the committed data/parsed/smud-ssr.json, not a synthetic stand-in

Three negative controls. Each sabotage was asserted present in the file before the run, and the file was restored from a byte copy afterwards (shasum equal, cmp clean, suite green again):

sabotage result
an empty comparison pool returns confirms instead of no statement red — 3 tests, including the smud-ssr one and the credit one
family() tests kw before kwh, so an energy price reads as a demand price red — 6 tests, including the CLI exit-3 test
a start date no charge carries narrows the selection to nothing red — test_a_date_no_charge_carries_widens_rather_than_silencing

The fixture record tests/fixtures/SYNTHETIC-urdb-record.json is 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/ and data/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.

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.
@ChelseaKR
ChelseaKR merged commit 5b18b19 into main Sep 7, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant