Skip to content

Keep same-named UK constituencies and local authorities apart in the calibration views - #237

Merged
anth-volk merged 3 commits into
mainfrom
uk-calibration-views
Oct 20, 2026
Merged

anth-volk merged 3 commits into
mainfrom
uk-calibration-views

Conversation

@anth-volk

@anth-volk anth-volk commented Oct 19, 2026 •

Copy link
Copy Markdown
Contributor

Fixes #236

Summary

Stacked on #220, which is stacked on #223, in GitHub stack #230; #239 sits on top. Base: calibration-tree-package. After #220's review fix (ca4edf5), gh stack rebase --no-trunk replayed this branch onto #220 without conflicts; the first commit is now 6931416. Two review fixes follow it (commits 2 and 3 below).

This PR checks the UK calibration views that #223 doesn't change, using the shapes UK data has today:

  • tagged builds of microcosm-uk-2024-25-national;
  • the dense release, which exists only as a tag;
  • local-area staged diagnostics named <dataset>.diagnostics.json;
  • the geography levels of UK targets.

One view was still wrong, and this PR fixes it. A UK constituency and a local authority with the same name were merged into one geography.

The fix

The dashboard groups, filters and lists targets by the geography's label. UK local-area builds calibrate constituencies and local authorities side by side, and 115 labels belong to one of each. As a result:

  • the calibration fit map's geography view showed one "Ashfield" tile, holding 18 constituency and 26 local-authority targets;
  • its Geography filter, /microcosm/targets and the Staging comparison maps selected both areas at once.

buildCalibration now gives any label that more than one level uses its level as well, for example "Ashfield (constituency)" and "Ashfield (local authority)" (new module geography-labels, exported as @policyengine/calibration-tree/geography-labels). Two kinds of label are left as published:

  • A label used at only one level.
  • The country's own national label. A target whose geography can't be resolved falls back to it at the national level, and it still means the whole country. The existing test "legacy UK geography metadata resolves GSS identifiers across target-name formats" caught a first version that split "United Kingdom" into country and national entries.

Every view reads its rows from buildCalibration: the explorer and its published trees, the targets page, the live Staging trees and comparisons, and the treemap route. So they all change together. Target matching between builds uses target names and identities, not geography labels, so comparisons are unaffected.

What changes in published output: I checked the filter index of all 45 trees published today (28 US, 2 Belgian, 15 UK). Only the three UK local candidates from September have labels at more than one level, 115 labels each. Every US, Belgian and UK national tree has none, so the new function returns its input unchanged for them. The golden record still reproduces byte for byte.

Before merging: trees already published keep merged labels

A tree's build ID comes from its inputs, not from the builder's code, and published trees are never rebuilt. So:

  • The three September UK local-candidate trees keep their merged tiles. They are staging builds. If one ever needs a repair (a stored part has gone missing), the rebuilt index differs from the digest the manifest records, and the publisher refuses it with "Rebuilt staging index differs from immutable manifest entry".
    • Correction: an earlier version of this description gave the release message, "Rebuilt calibration index differs …", and didn't say what the refusal did next.
    • Before commit 2, reconcileStagingBuilds threw at that run, so every UK staging run after it would have stayed unpublished on every later run of the publisher.
    • Since commit 2, the refusal is recorded as that run's failed outcome, the remaining runs are still reconciled, and the publisher then exits with an error naming the failed run.
  • The same applies to anything Publish Microcosm UK release cuts, open the UK page on the national line, and show local candidates on Staging #223's rollout publishes before this PR deploys. That includes the dense release and the October local candidates. A refused repair of a release build, such as the dense release, still stops release reconciliation, which commit 2 doesn't change. To publish those with separate areas, keep tree publishing paused until this PR is deployed. Publishing is paused now: CALIBRATION_TREE_BUILD_ENABLED=FALSE was set on 2026-10-19 at 20:58 UTC, and it pauses every country. The plan keeps it paused until Keep same-named UK constituencies and local authorities apart in the calibration views #237 and Compare UK local-area Staging candidates with the local-area release #239 are deployed.

Commits

  1. Keep same-named UK areas at different geography levels apart (6931416; earlier ffd5b9e, then 6e65097)
    • Red: 3 of 4 new tests in shared-geography-labels.test.ts failed, each with both areas under "Ashfield":

      • the row labels;
      • the targets page's Geography list and filter;
      • the explorer's geography tiles (one tile with 2 targets) and its filter options.

      The fourth test, which checks that UK national labels are unchanged, passed, as intended.

    • Green: 4 of 4 passed. Rerun after the commit across 5 files, 113 passed and 0 failed: the new tests, the package boundary test (now including the new export), latest-artifact.test.ts (84), and both golden suites (16, unchanged record).

    • bun run lint (dashboard and package typecheck): clean.

  2. Record a staging build that cannot be reconciled and keep going (19699ac, from review)
    • Why: see "Before merging" above. Any error for one finalized run (a refused repair, a declared diagnostics file that is missing or has the wrong digest, a size limit) stopped staging reconciliation at that run, so every run after it stayed unpublished until someone intervened.
    • Choice: record and continue, rather than leave the throw. The refusal itself is unchanged, so immutable data is still never overwritten. The workflow still fails, so the failure stays visible, but one bad run no longer blocks the others. Errors before the per-run loop (an unavailable repository, incompatible runs) still stop reconciliation. Release reconciliation is unchanged: it still stops at the first release it can't publish or repair.
    • Change:
      • each run's error becomes that run's failed outcome, with the error as reason, and the loop continues;
      • after printing the report, runPublisher throws "N of M staging sources failed to reconcile: .", so the command exits with status 1;
      • reconcileStagingBuilds is exported and takes the CalibrationManifestStore that release reconciliation already takes, and runPublisher accepts that store, so both can be tested without Vercel Blob. The Blob store is the default, and it makes the same calls as before.
    • Docs: docs/calibration-tree-artifacts.md lists the failed outcome and when it occurs.
    • Red: 2 of 2 new tests in publish-calibration-tree-golden.test.ts failed. For this run, the store parameter had already been added (no behavior change), so the file loaded.
      • "a refused staging repair is recorded as that run's failure, and the runs after it are still published": the call rejected with "Rebuilt staging index differs from immutable manifest entry aaaa…".
      • "the publisher prints every staging outcome, then exits with an error naming the failed run": runPublisher ignored the store and stopped at "Vercel Blob: Invalid token". No request was sent.
    • Green: 2 of 2. Rerun at the commit: 44 passed across 5 files (both publisher suites, the builder golden suite, the harness test and the boundary test); bun run lint clean.
    • The test serves a UK staging repository with two finalized runs, using the harness's recorded UK version 2 run under each run ID (new harness helper ukStagingRepositoryFiles). The newer run has a manifest entry with a missing index and a stale digest. The golden record is unchanged.
  3. Document level-qualified geography labels (0820b3f, from review; documentation only, so no red step)
    • docs/calibration-map-hierarchy.md no longer says the dashboard doesn't construct labels for schema 8. A new section, "Geography labels shared by several levels", gives the rule:
      • which labels get their level;
      • how the level is written;
      • that the national label is never qualified (the release manifest's country.geography_label, or else the registration's geography);
      • that rows without a level keep their label;
      • that labels and levels are compared after trimming whitespace.
    • docs/calibration-tree-artifacts.md ("Filtering indices") says geography postings use those labels, and that a tree published before the rule keeps one merged label, so a repair of it is refused.

What I checked in the other UK views

Data used

  • Real data, read without credentials: the production dashboard's public API. It runs main, without Publish Microcosm UK release cuts, open the UK page on the national line, and show local candidates on Staging #223, so it reads only the national release folder, not the tagged builds. I read its UK release list, target diagnostics, tree manifest, tree indexes and filter indexes, and one staging comparison.
  • Real data, read with the locally configured Hugging Face login: the UK staging repository's run manifests and staged-file receipts. Nothing was printed or stored except the downloaded JSON.
  • Not readable locally: the UK release repository (policyengine/populace-uk-private). The local login gets 404 there, so the tagged builds and the local-area diagnostics themselves were checked only through the shapes above and the tests.

Findings

Tests run

  • Locally, at commit 1: only this branch's new and changed test files and the golden suites that prove outputs didn't change (113 tests, 5 files), plus bun run lint.
  • Locally, at the head after the restack (0820b3f): every test file this branch adds or changes, plus both golden suites, the boundary test and the harness test. That is 132 passed and 0 failed across 7 files: shared-geography-labels, latest-artifact, package-boundary, calibration-tree-golden, publish-calibration-tree-golden, publish-calibration-tree and test-support/calibration-tree-golden-cases. bun run lint was clean.
  • Not run locally: the full suites and next build, because the machine is shared. CI runs them.

Environment variables

This PR changes no workflow, deploy script or configuration, and the code reads no new variables. Commit 2 changes how the publisher run by publish-calibration-tree.yml ends: the command exits with an error after a failed staging run, instead of stopping at it. So here is the publish job's wiring, which is unchanged:

Variable Read by Provider and wiring Verified
CALIBRATION_TREE_BUILD_ENABLED publish job if: Repository variable, FALSE since 2026-10-19 at 20:58 UTC, so the job is skipped Value read with gh variable list
BLOB_READ_WRITE_TOKEN runPublisher Repository secret, mapped in the publish job's env: and inherited by bun run publish:calibration-tree Name listed by gh secret list
HF_TOKEN Hugging Face reads of the release repository Repository secret, publish job env: Name listed
POPULACE_UK_STAGING_HF_TOKEN UK staging reads (the registration's token_env) Repository secret, publish job env: Name listed
HUGGINGFACE_TOKEN, CALIBRATION_TREE_MAX_RAW_BYTES, CALIBRATION_TREE_MAX_GZIP_BYTES, repository overrides publisher Optional; not set in the workflow, so defaults apply Not applicable

Unverified: the secret values. Only their names are visible, and this PR doesn't change them.

🤖 Generated with Claude Code

@vercel

vercel Bot commented Oct 19, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
calibration-diagnostics Ready Ready Preview Oct 20, 2026 2:55pm UTC

Request Review

@anth-volk
anth-volk added this pull request to stack #230 October 19, 2026 20:51
@anth-volk
anth-volk force-pushed the uk-calibration-views branch from ffd5b9e to 6e65097 Compare October 19, 2026 21:09
@anth-volk
anth-volk force-pushed the uk-calibration-views branch from 6e65097 to 6931416 Compare October 20, 2026 12:44
anth-volk added a commit that referenced this pull request Oct 20, 2026
Brings in the rewritten 1A stack (#220 ca4edf5, #237 0820b3f, #239 753fb5c).
The publisher's build-folder layout now travels in runPublisher's
dependencies (releaseLayout) beside #239's manifest store.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@anth-volk
anth-volk force-pushed the uk-calibration-views branch from 0820b3f to fdb77ff Compare October 20, 2026 13:15
@anth-volk
anth-volk force-pushed the uk-calibration-views branch from fdb77ff to a3b3d70 Compare October 20, 2026 14:13
Base automatically changed from calibration-tree-package to main October 20, 2026 14:54
anth-volk and others added 3 commits October 20, 2026 18:54
The dashboard groups, filters and lists calibration targets by the
geography's label. Microcosm's UK local-area builds calibrate
parliamentary constituencies and local authorities side by side, and
115 labels belong to one of each. In the published tree of the
19 Sep local candidate, the explorer's geography map therefore shows
one "Ashfield" tile holding 18 constituency and 26 local-authority
targets, and its Geography filter, the targets page and the comparison
maps select both areas at once. The hierarchy validator already keys a
geography by its level and code; only the label merged them.

A label that more than one level uses now carries its level, for
example "Ashfield (constituency)" and "Ashfield (local authority)".
Labels used at one level stay as published, and so does the country's
own national label, because a target with no resolvable geography falls
back to it at the national level and still means the whole country.
Of the 45 trees published today, only the three UK local candidates
have such labels, so US, Belgian and UK national outputs are unchanged;
the golden record still reproduces byte for byte.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Staging reconciliation threw at the first finalized run it could not
publish or repair, such as a repair whose rebuilt index differs from
the digest the manifest records. Every run after it then stayed
unpublished on every later invocation. The September UK local-area
trees are staging builds, and the level-qualified geography labels
change what the builder writes for them, so repairing one would stop
UK staging publication.

Each run's error is now recorded as that run's "failed" outcome, with
the error as its reason, and the remaining runs are still reconciled.
After printing the report, the publisher exits with an error naming
every failed run, so the workflow still fails. Errors before the
per-run loop (an unavailable repository, incompatible runs) still stop
reconciliation.

reconcileStagingBuilds now takes the manifest store that release
reconciliation already takes, and runPublisher accepts that store, so
both can be tested without Vercel Blob.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The calibration map hierarchy document still said the dashboard does
not construct labels for schema 8. buildCalibration now qualifies a
geography label that more than one level uses in a build, so the
document describes that rule and its exceptions, and the tree artifact
document notes that published trees keep the labels they were built
with.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
anth-volk added a commit that referenced this pull request Oct 21, 2026
Release reconciliation throws at the first release it cannot publish or
repair, so it prints no report, never reaches the releases after it, and
never updates the latest-release selection. These tests describe the
behaviour staging reconciliation has had since #237:

- a release the schema 8 reader refuses is reported as `failed` with the
  error, and the releases after it are still published;
- a release whose uploaded build fails its audit gets no manifest entry;
  the audit now comes before the manifest write;
- when the release the line pointer names fails, the latest-release
  selection is left as it was and the report says why;
- the publisher prints the whole report, then exits with an error that
  names every failed release;
- a dry run records the failure and writes nothing;
- the recorded-digest repair test now expects a `failed` outcome instead
  of a rejected call.

The in-memory store in publish-calibration-tree.test.ts now records the
order of uploads, listings, audits and manifest writes.

Tests only. All six fail on the current publisher, which throws at the
failing release.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
anth-volk added a commit that referenced this pull request Oct 21, 2026
Release reconciliation threw at the first release it could not publish
or repair. It printed no report, left every release after it
unreconciled and never updated the latest-release selection, on every
later invocation. Since 2026-10-02 one US release has blocked every later
US release this way.

Each release's error is now recorded as that release's `failed` outcome,
with the error as its reason, and the remaining releases are still
reconciled, as staging reconciliation has done since #237. After
printing the report, the publisher exits with an error naming every
failed release, so the workflow still fails. Errors before the
per-release loop (reading the manifest, listing releases or tags) still
stop reconciliation.

A failed release leaves no manifest entry and is never selected as the
latest release:

- The uploaded build is now listed and audited before its manifest
  entry is written, not after, so an incomplete upload is never
  registered. The audit reads the build's own index and the Blob
  listing, not the manifest. Successful publications upload and write
  the same bytes as before.
- The latest-release selection skips a release that failed in the same
  run, keeping the build it named before. When the selection cannot be
  read or updated, the report's new `latestReleaseFailure` field says
  why, and the publisher exits with an error after printing the report
  (it used to throw without a report).

The failure message reads "N of M releases failed to reconcile" for
releases; the staging message is unchanged. The docs describe the new
behaviour and the order of a release's writes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

This branch was successfully deployed

1 active deployment
Preview — 780d6d48 Deployed Oct 20, 2026 by vercel[bot]
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.

UK constituencies and local authorities with the same name are merged in the calibration views

1 participant