App country dimension: surface the UK end-to-end - #50
Conversation
|
Dual-gate review: HOLD on the UK feed-architecture adjudication (#48 vs #32), by design — |
Review — App country dimension (UK end-to-end)No backward-compat/data-loss bug — the load-bearing contract holds: Should address
Suggestion
Reviewed with Claude Code assistance. |
|
All three should-address items fixed in c5c17e7:
Suite: python 129 passed / 4 skipped (was 127); The lanes.json drift suggestion is left as-is for now (pre-existing, as you noted — The #57-adjudication HOLD stands — these fixes just clear the re-gate queue for whenever the ingest architecture lands. |
Re-review — all addressed ✅
Only cosmetic TS-typing nits left (a |
DTrim99
left a comment
There was a problem hiding this comment.
Re-reviewed — all findings addressed (AttributionPanel gated by country, LANE_FEED raises on missing country, types.test.ts added). Approving; the remaining TS-typing/lanes.json-dup items are cosmetic/pre-existing.
|
Heads-up: the UK foundation landed on main today, so this branch's data surfaces have moved under it. What changed that touches this PR:
Suggested sequence: once #72 merges (imminent), rebase onto main — export_populations.py, ingest_harvest.py, and both lanes.json copies will conflict, and main's versions carry gate-hardened behavior (the exporter's per-result annotations/baseline labels, sync_lane_feed's 🤖 Generated with Claude Code |
Adds an explicit country field to data/lanes.json (US for existing lanes, UK for the six DWP/HBAI/HMRC/OBR/UKMOD lanes) and threads a Country type through the app's data contracts: lanes, comparison rows and population rows, with a missing country always read as US so historical exports never drop. The header gains a US/UK toggle that scopes the coverage spine, scorecard, divergences and gaps views; UK renders as a pipeline status panel listing each lane's stage while no UK rows exist, mission control shows the UK lanes with their stage transitions, and the reform-validation tab states its US-only scope explicitly until claims from a second country land (then it grows a country filter). Status taxonomy is untouched — pe_gap and concept_mismatch render identically for any country. Closes #42 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…pended lane entries, countryOf tests - AttributionPanel takes the selected country and renders nothing outside US: exhibits.json is a US-only feed (SPM poverty, state geographies), so the UK view no longer shows US attribution unconditionally. Threaded via DivergenceBoard from filters.country. - sync_lane_feed refuses to append a feed entry whose meta lacks 'country' (countryOf() would silently render it as US); every LANE_FEED entry and the populace-reform-validation caller now carry country explicitly. Both pinned by tests. - App unit tests: countryOf() default/explicit/scoping contract under `bun test src` (test files excluded from the tsc -b build graph). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Rebase completion (the branch forked before the whole UK arc — #43-#48, #52, #71, #72 all landed under it): - uk-deductions-frr (merged today, unknown to this branch) was the one committed lane without a country tag -> UK. - The UK ingests' appended lane metas now carry country explicitly (ingest_uk_externals' five lanes + ingest_uk_deductions' one), so a fresh-feed append passes the new sync_lane_feed guard and never files a UK lane under the app's missing-key US default. - app/public/data copies refreshed from data/ (they had drifted to a 270-row populations.json vs 284) and pinned: new test asserts the committed copies byte-match data/, and a second asserts every committed lane carries US|UK — the two drift classes this rebase surfaced. Suite: 241 python + 3 bun; oxlint + vite build clean; committed DB byte-stable. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
c5c17e7 to
cedd1b5
Compare
|
Rebased onto main in place (your two commits intact, one completion commit on top) — the foundation had moved four merges under this branch since it forked, so I did the mechanical part rather than leaving it to go stale:
Suite: 241 python + your 3 bun tests; oxlint + vite build clean; CI green. Dual gate (sol pass) running next — merges on MERGE-SAFE per the standing sequence. Shout if anything in the completion commit doesn't match your intent. 🤖 Generated with Claude Code |
Sol's three blockers on the rebased head, each fixed and verified in the running app: 1. The populations exporter never emitted country, so all 284 rows — including the 14 UK reckoner claims cedd1b5 shipped into the app copy — classified as US under countryOf()'s missing-key default. Rows now carry country from the claim's own conditions (US: 270, UK: 14, pinned in the export integration test); regenerated feed + app copy. 2. fmtV prefixed every non-share value with $: currency now follows value_kind (gbp* -> £, usd* -> $, counts unsymboled; percent and index kinds render properly). uk_hmrc and the other UK source slugs get display labels. 3. The header toggle now owns the country dimension everywhere: MissionControl takes country — lanes/backlog scope to it, and the US-feed-derived held-out record and freshest divergences render only under US, with truthful UK cards in their place (the first UK results are on the validation tab, held-out relationship on a constructed basis; a UK record lands when UK comparisons join the comparison feed). ReformValidationView takes country and scopes rows, source/status counts, and its summary prose to it — its internal country select is gone (one owner). Coverage: CI now runs the bun tests (they existed but never ran). Verified in the built app: US view unchanged; UK view shows the 7-lane pipeline, honest cards, and 14 HMRC rows at £ values with constructed statuses. Suite: 241 python + 3 bun; oxlint + vite build clean. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Sol's three round-2 findings:
1. HIGH — source/status filter state carried across country toggles,
so a US filter (e.g. Source=JCT) emptied the UK table and vice
versa. ReformValidationView is now keyed by country in App.tsx:
the toggle remounts it, so no internal state can survive a country
switch — the failure class is gone by construction, both
directions. Verified in the running app on sol's exact repro
(US -> validation -> JCT -> UK => selects reset, 14 rows render).
2. MEDIUM — MissionControl was US-gated, not country-scoped: its
record/divergences read ALL comparison rows under US and were
forced empty under UK, so future UK comparison rows would have
inflated the US cards while staying hidden under UK. Both now
compute from countryOf-scoped rows; the explainer cards render on
emptiness (with the UK-specific prose conditional on UK), numbers
render whenever a country's rows exist.
3. MEDIUM — the freshest-divergences UK copy repeated the corrected
false claim ("first UK held-out results"); it now says "when UK
rows join the comparison feed".
Also per the round's scope note: the provenance stamp is labeled
"external (US comparison)" and the Method tab opens with an explicit
US-scope line (the country toggle does not change either).
Suite unchanged (241 python + 3 bun); oxlint + vite build clean.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…alification
Sol's round-3 blocker: the cards said "No {country} rows in the
comparison feed" whenever heldOut/freshest were empty — but a feed
slice of consumed-target or valueless rows would make that copy lie.
Both cards are now three-state: numbers when qualifiers exist;
feed-absence copy only when countryRows is actually empty; and honest
"rows exist but none qualify" / "no material national divergences"
states between.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Sol's three findings: 1. CI now runs `git diff --exit-code` after the determinism builds AND after pytest — the builds rewrite tracked feeds (lanes, ledger, uk_resolved) as ingest side effects, so the tree must equal HEAD or a committed artifact has gone stale relative to the code that regenerates it. (App copies are tracked, so the same gate covers data/ vs app/public/data drift.) 2. Fresh-clone workflow: tests/conftest.py session fixture builds the DB when absent (plain pytest works from a clean clone; no-op in CI); scorecard_db/README documents build_db as the canonical flow, the from-scratch refusal, and the empty-DB-from-ScorecardDB() trap. 3. pipeline/build_comparison.py now reads the vendored interchange and fails loudly when it is missing (it used to silently build empty). Plus sol's low-risk hardening: build_db refuses any duplicate (claim_id, computed_at) in pe_results — the exporters use the autoincrement id as an ORDER BY tie-breaker, so a tie would let physical insert order leak into populations.json (zero ties today). Rebased onto post-#50 main (the app-copy refresh commit was superseded by the merge and dropped). Hash unchanged: 0c63dff1.... Suite: 247; tree verified clean through build + suite locally. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Closes #42.
What was done
Data contract (
data/lanes.json+ committed copyapp/public/data/lanes.json, kept identical)"country"field —"US"for existing lanes,"UK"fordwp-takeup,hbai-poverty,hmrc-personal-tax,obr-welfare,ukmod-stats,ukmod-cases— documented in the_schemablock. The diff adds onlycountrylines (plus the writer-canonical trailing newline); stage/note/updated untouched.sync_lane_feedmerges by key, so pipeline rewrites preserve the field.App types (
app/src/types.ts)Countrytype ("US" | "UK"),COUNTRY_LABELS, and a singlecountryOf()helper: a missingcountrykey always means US, so US-era comparison/populations exports never drop a row.Lane,Row, andPopulationRowgain the optionalcountryfield.Scoreboard views (
App.tsx)ComparisonTable/DivergenceBoard/MissionControlgeneralize the hardcoded"US"national-geography checks to the row's country code, so UK national rows land in the right buckets when they arrive.bucketOf,SPINE_META, and the status chips are country-blind, sope_gapandconcept_mismatchUK cells will render exactly like US ones and stay on the page.Reform-validation tab
countryOf.What remains
build_comparison/export_populations) still need to emitcountryon rows when UK claims land (other branches carry"country": "UK"externals).Verification
bun install --frozen-lockfile && bun run lint && bun run buildinapp/: lint clean (no warnings),tsc -b && vite buildpass.PYTHONPATH=. uv run --with pytest pytest tests/ -qfrom repo root: 127 passed, 4 skipped.data/lanes.jsonandapp/public/data/lanes.jsonverified byte-identical.🤖 Generated with Claude Code