chore(tests): add chokepoint-baselines fixture + parity guard (§L #8)#3379
Conversation
Closes gap #8 from docs/internal/energy-atlas-registry-expansion.md §L — the last missing V5-7 golden fixture. Adds `tests/fixtures/chokepoint-baselines-sample.json` as a snapshot of the expected buildPayload output shape (7 EIA chokepoints, top-level source/referenceYear/chokepoints). Extends the existing `tests/chokepoint-baselines-seed.test.mjs` with a 3-test fixture-parity describe block that catches any silent drift in: - Top-level key set (source, referenceYear, chokepoints array length) - Position-by-position chokepoint entries (id, relayId, mbd) - updatedAt ISO-parseability (format only — value is volatile) Doesn't snapshot updatedAt byte-for-byte because it's a per-run timestamp; parity is scoped to the schema-stable fields downstream consumers depend on (CountryDeepDivePanel transit-chokepoint scoring, shock RPC CHOKEPOINT_EXPOSURE lookup, chokepoint-flows calibration). If a future change adds/removes an entry or renames a field, this suite fails until the fixture is updated alongside — making schema drift a deliberate reviewed action rather than a silent shift. Test plan: - [x] `npx tsx --test tests/chokepoint-baselines-seed.test.mjs` — 17/17 pass - [x] `npm run typecheck` — clean - [x] `npm run test:data` — 6697/6697 pass (+3 new fixture-parity cases)
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Greptile SummaryThis PR adds a golden fixture (
Confidence Score: 4/5Safe to merge after adding lat/lon assertions to the parity test. One P1 gap: lat/lon are stated as part of the guarded regression surface in the PR description but are absent from the position-by-position test. The fixture carries correct values so the fix is a one-line addition, but the guard as written doesn't fulfill its stated purpose. tests/chokepoint-baselines-seed.test.mjs — position-by-position test needs lat/lon assertions. Important Files Changed
Sequence DiagramsequenceDiagram
participant T as Test Runner
participant S as seed-chokepoint-baselines.mjs
participant F as fixtures/chokepoint-baselines-sample.json
T->>S: import CHOKEPOINTS, buildPayload()
T->>F: readFileSync (fixture)
T->>S: buildPayload() → payload
T->>T: assert fixture.source == payload.source
T->>T: assert fixture.referenceYear == payload.referenceYear
T->>T: assert fixture.chokepoints.length == payload.chokepoints.length
loop for each CHOKEPOINT[i]
T->>T: assert fix.id == seed.id
T->>T: assert fix.relayId == seed.relayId
T->>T: assert fix.mbd == seed.mbd
note over T: ⚠ lat / lon NOT asserted
end
T->>T: assert Date.parse(fixture.updatedAt) is finite
Reviews (1): Last reviewed commit: "chore(tests): add chokepoint-baselines f..." | Re-trigger Greptile |
| assert.ok(Array.isArray(fixture.chokepoints)); | ||
| assert.equal(fixture.chokepoints.length, payload.chokepoints.length); | ||
| }); | ||
|
|
||
| it('fixture chokepoints match seeded CHOKEPOINTS position-by-position (id, relayId, mbd)', () => { | ||
| for (let i = 0; i < CHOKEPOINTS.length; i++) { | ||
| const seed = CHOKEPOINTS[i]; | ||
| const fix = fixture.chokepoints[i]; | ||
| assert.equal(fix.id, seed.id, `position ${i}: id drift (seed=${seed.id} fixture=${fix.id})`); |
There was a problem hiding this comment.
lat/lon omitted from parity guard despite stated regression surface
The PR description explicitly lists lat and lon among the stable fields the guard is meant to protect ("chokepoint-flows calibration all depend on the stable fields (id / relayId / mbd / lat / lon)"), but the position-by-position test only asserts id, relayId, and mbd. A silent drift in either coordinate would go undetected by this suite, even though the fixture already carries the correct values.
| assert.ok(Array.isArray(fixture.chokepoints)); | |
| assert.equal(fixture.chokepoints.length, payload.chokepoints.length); | |
| }); | |
| it('fixture chokepoints match seeded CHOKEPOINTS position-by-position (id, relayId, mbd)', () => { | |
| for (let i = 0; i < CHOKEPOINTS.length; i++) { | |
| const seed = CHOKEPOINTS[i]; | |
| const fix = fixture.chokepoints[i]; | |
| assert.equal(fix.id, seed.id, `position ${i}: id drift (seed=${seed.id} fixture=${fix.id})`); | |
| it('fixture chokepoints match seeded CHOKEPOINTS position-by-position (id, relayId, mbd, lat, lon)', () => { | |
| for (let i = 0; i < CHOKEPOINTS.length; i++) { | |
| const seed = CHOKEPOINTS[i]; | |
| const fix = fixture.chokepoints[i]; | |
| assert.equal(fix.id, seed.id, `position ${i}: id drift (seed=${seed.id} fixture=${fix.id})`); | |
| assert.equal(fix.relayId, seed.relayId, `${seed.id}: relayId drift`); | |
| assert.equal(fix.mbd, seed.mbd, `${seed.id}: mbd drift (seed=${seed.mbd} fixture=${fix.mbd})`); | |
| assert.equal(fix.lat, seed.lat, `${seed.id}: lat drift (seed=${seed.lat} fixture=${fix.lat})`); | |
| assert.equal(fix.lon, seed.lon, `${seed.id}: lon drift (seed=${seed.lon} fixture=${fix.lon})`); | |
| } | |
| }); |
… (review P2) Codex P2: the parity check validated entries against the CHOKEPOINTS constant, not buildPayload().chokepoints — so it guarded the source array rather than the seeded wire contract the fixture claims to snapshot. If buildPayload ever transforms entries (coerce, reorder, normalize), the check would miss it. Also P2: the fixture contained richer fields (name, lat, lon) but the old assert only checked id/relayId/mbd — most of the fixture realism was unused and produced false confidence. Fix: - Parity loop now iterates payload.chokepoints (seeded output, not the raw source array) and asserts id, relayId, name, mbd, lat, lon per entry. - Added an entry-key-set assertion that catches added/removed fields between seed and fixture — forces deliberate evolution rather than silent drift. 18 tests pass (was 17), typecheck clean.
Summary
Closes gap #8 from `docs/internal/energy-atlas-registry-expansion.md` §L — the last missing V5-7 golden fixture. Brings parity with the other seed fixtures already under `tests/fixtures/` (`ember-monthly-sample.csv`, `portwatch-arcgis-sample.json`, …).
Changes
The existing 14 tests on main are untouched.
Why schema-stable fields only (no byte-match on updatedAt)
`updatedAt` is a per-run timestamp. Asserting an exact value would break every run. Parity is scoped to the downstream-consumer contract instead: `CountryDeepDivePanel` transit-chokepoint scoring, the shock RPC `CHOKEPOINT_EXPOSURE` lookup, and chokepoint-flows calibration all depend on the stable fields (id / relayId / mbd / lat / lon) — those are the regression surface this guard protects.
If a future change adds/removes an entry or renames a field, the suite now fails until the fixture is updated alongside.
Test plan
Context
This was the only remaining item in the plan's §L gap list. With this merged, the plan doc's §N announcement gate is substantively complete except for product decisions that were already resolved (§S=A subdomain-deferred path keeps #9/10/11/12 out of scope).