Repository navigation
Publish Microcosm UK release cuts, open the UK page on the national line, and show local candidates on Staging - #223
Merged
Conversation
Microcosm publishes a release line (microcosm#823) under a constant release id: the line's files stay in releases/<release id>/ and each cut is an immutable tag, <release id>-<YYYYMMDDTHHMMSSZ>-<attempt>. The publisher treated a release id as one commit, looked for a tag's files under releases/<tag>/, and took the UK default from latest.json, which stays on the June 2023 build. The UK national cuts after 4 Oct and the tag-only dense local-area release therefore never reached the Calibration fit page, and UK release reconciliation stops with "Released dataset ... changed". - A cut tag is its own release build. Its manifest entry carries the tag as releaseId and the line folder as the new optional releaseDirectory; readers fetch releases/<releaseDirectory>/ at the entry's commit. A tag counts as a cut only when that folder's release_manifest.json names it as build.cut_tag. - A line folder on main is not published again once its cuts are; a build already published from it stays pinned at its own commit. - The country registration gains pointer_path (UK: latest-national.json). Its revision names the cut that becomes the latest release. - The release picker adds every published cut beside the folders on main, labels it by line and attempt, and hides a line folder unless the latest release still points at it. Local-area cuts keep the existing flag. - US and Belgium have no cut tags and no pointer_path, so their inventory, picker and latest selection are unchanged. bun test: 615 pass; tsc --noEmit clean; next build passes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
The Staging candidates page reads an unreleased candidate's per-target fit from its staged bundle, but only from calibration_diagnostics.json. Microcosm's UK local lane stages its outputs under the dataset's own stem, so its diagnostics arrive as microcosm_uk_2024_25_local.diagnostics.json and every local candidate since early October showed "has not uploaded calibration diagnostics yet"; staging reconciliation reported them ineligible. The staged diagnostics file is now calibration_diagnostics.json when the receipt records it, or else the one <dataset>.diagnostics.json the receipt records. A receipt recording several stem files, or a name with a path, has no target view, so nothing is guessed and no recorded name can leave the staged prefix. The digest check is unchanged. Checked against the 19 Oct local candidate, the 19 Sep local candidate and the 19 Oct national attempt: all three now load, the latter two from the same files as before. bun test: 617 pass; tsc --noEmit clean; next build passes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
juaristi22
marked this pull request as ready for review
October 19, 2026 12:15
Brings in main's backend/requirements.lock, which pins a published policyengine-us release and fixes this branch's failing hosted Python dependency check. Conflict resolved: frontend/lib/microcosm/latest-artifact.test.ts. Both sides added a name to the same import list (this branch added mergeReleaseInventory; main added MAPPED_MEASURE_CONCEPT_VARIABLES). Kept both, in the list's existing alphabetical order. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
anth-volk
added a commit
that referenced
this pull request
Oct 19, 2026
The tree builder is about to move out of the dashboard into its own package. Its outputs are byte-exact contracts: the index records every part's raw-JSON SHA-256 and gzip size, build ids derive from the inputs, and a repair refuses any change to the index digest. So the move has to be proved to change no byte. This records, from the builder as it is today, what it writes for representative inputs built from the fixtures the module tests already use. The inputs cover US and UK, releases and staging runs (version 1, version 2, and a staged dataset bundle), Belgium, and a UK release with reported loss attribution. For each, the record holds every part's path, raw JSON digest and size, gzip size and deflate-stream digest, plus the build id. It also records release-to-staging comparison bundles built through the comparison reader, the explorer's root responses read back from the stored bytes, and the manifest serialization. The gzip header's operating-system byte varies by platform, so the header is asserted separately and the digest covers the stream after it. A second test drives the publisher's dry-run repair of the recorded US, UK and Belgium releases against a stubbed Hugging Face repository. The publisher refuses a rebuilt index whose digest differs, so a successful repair proves its own reads and hashing reproduce the recorded index. The stubbed repository serves each country's release pointer at the path the publisher reads it from: `latest.json`, or `latest-national.json` for the UK since #223. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
anth-volk
added a commit
that referenced
this pull request
Oct 19, 2026
The tree builder and the schema 6 code the dashboard shares with it are moving to the collector as a Bun worker, and its types and readers will be published as a package the dashboard imports. That needs the builder to be one self-contained unit with explicit dependencies and its own tests. Inside frontend/lib nothing stopped a dashboard-only import from reaching it. The package, @policyengine/calibration-tree in frontend/packages/, is the builder's import closure: the schema 6 types, parsers, serializers and bundle builder, the comparison builder, Blob I/O behind the existing injectable client, and the release and staging readers the builder reads from, including the country registry. Its 30 modules move unchanged apart from ten import lines that used the dashboard's path alias. Their tests and fixtures move with them. Next.js routes, the HTTP helpers and the client hooks stay in the dashboard and import the package through its subpath exports. One of the 30 is release-cut.ts, added by #223. It parses the Hugging Face tag names Microcosm gives each build of a UK release, and latest-artifact.ts and calibration-tree-manifest.ts import it, so it moves with them and is exported as release-cut. The dashboard's shared formatter and the publisher now import it through that export. Two other additions since this branch began are adjusted to fit. #223's releases route and its test import the moved modules through the package. #229's check that the mapped measure concept table matches integrations/microcosm_policyengine_us/mappings.yaml moves out of the package's latest-artifact tests into lib/microcosm/mapped-measure-concept-variables.test.ts, because it reads a file of this repository that will not move with the package. A boundary test requires package modules to import only each other, Node built-ins and declared dependencies (@vercel/blob), and requires every module to be exported. The package has its own typecheck, chained into the frontend lint script, so CI runs it without a workflow change. The readers pass Next.js's fetch cache hint, which Bun ignores; a declaration seen only by the package's typecheck mirrors Next's. The golden tests now import the builder through the package and reproduce the record taken before the move, which moved unchanged. The workspace sits inside frontend/ because Vercel, CI and the publisher workflow all install from there. bunfig keeps Bun's hoisted linker so node_modules keeps its current layout. The former countries path stays as a re-export for code not yet switched to the package path. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This was referenced Oct 19, 2026
Closed
Reconciliation publishes a Microcosm tag only when the release manifest in its folder at that tag names the tag in build.cut_tag. The --latest mode skipped that check: given a latest-national.json whose revision is a tag whose manifest names another build, it published the tag's files under that tag and promoted it (found by the Codex review of this PR). readUpstreamLatest now applies the same check to the tag the pointer names, before any mode publishes or promotes from it, and requires the tag's files to sit in the folder the pointer's release_id names. Reconciliation passes its manifest, so a tag already pinned there at the same commit is not probed again on every run. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
readUpstreamLatest checked latest-national.json's schema_version, line
and tag only when the file had a revision. A file without one, for
example {"schema_version":99,"line":"dense","release_id":...}, was read
as a folder release, published at the repository's current commit and
promoted (found by the Codex review of this PR).
A country whose registration names its own pointer file (the UK's
pointer_path) now always gets those checks, and a file without a
revision is refused. Countries on latest.json keep reading release_id
alone. The reconciliation metadata test used a UK pointer without a
revision; it now names a published tag of the same folder.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
publishRelease copied the diagnostics' release_id into the bundle's comparison metadata. Microcosm's diagnostics name the folder, so a build published as microcosm-uk-2024-25-national-20261019T083323Z-... recorded index.build.releaseId as the tag but index.targetComparison.releaseId as microcosm-uk-2024-25-national, and a comparison between two builds of that release labelled both sides the same (found by the Codex review of this PR). A tag published from its folder now records the tag in both places, as the release reader already does when it loads one. A folder release keeps the id its diagnostics carry, so its comparison metadata is unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
stagedBundleDiagnosticsFile dropped stem names that are not one path segment before counting them. A receipt recording both microcosm_uk_2024_25_local.diagnostics.json and nested/dense.diagnostics.json therefore returned the first file, though this PR's rule is that a receipt recording several stem files, or a name containing a path, has no target view (found by the Codex review of this PR). The count now includes every stem name, and the one stem file must also be a single path segment. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
anth-volk
added a commit
that referenced
this pull request
Oct 19, 2026
The tree builder is about to move out of the dashboard into its own package. Its outputs are byte-exact contracts: the index records every part's raw-JSON SHA-256 and gzip size, build ids derive from the inputs, and a repair refuses any change to the index digest. So the move has to be proved to change no byte. This records, from the builder as it is today, what it writes for representative inputs built from the fixtures the module tests already use. The inputs cover US and UK, releases and staging runs (version 1, version 2, and a staged dataset bundle), Belgium, and a UK release with reported loss attribution. For each, the record holds every part's path, raw JSON digest and size, gzip size and deflate-stream digest, plus the build id. It also records release-to-staging comparison bundles built through the comparison reader, the explorer's root responses read back from the stored bytes, and the manifest serialization. The gzip header's operating-system byte varies by platform, so the header is asserted separately and the digest covers the stream after it. A second test drives the publisher's dry-run repair of the recorded US, UK and Belgium releases against a stubbed Hugging Face repository. The publisher refuses a rebuilt index whose digest differs, so a successful repair proves its own reads and hashing reproduce the recorded index. The stubbed repository serves each country's release pointer at the path the publisher reads it from: `latest.json`, or `latest-national.json` for the UK since #223. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
anth-volk
added a commit
that referenced
this pull request
Oct 19, 2026
The tree builder and the schema 6 code the dashboard shares with it are moving to the collector as a Bun worker, and its types and readers will be published as a package the dashboard imports. That needs the builder to be one self-contained unit with explicit dependencies and its own tests. Inside frontend/lib nothing stopped a dashboard-only import from reaching it. The package, @policyengine/calibration-tree in frontend/packages/, is the builder's import closure: the schema 6 types, parsers, serializers and bundle builder, the comparison builder, Blob I/O behind the existing injectable client, and the release and staging readers the builder reads from, including the country registry. Its 30 modules move unchanged apart from ten import lines that used the dashboard's path alias. Their tests and fixtures move with them. Next.js routes, the HTTP helpers and the client hooks stay in the dashboard and import the package through its subpath exports. One of the 30 is release-cut.ts, added by #223. It parses the Hugging Face tag names Microcosm gives each build of a UK release, and latest-artifact.ts and calibration-tree-manifest.ts import it, so it moves with them and is exported as release-cut. The dashboard's shared formatter and the publisher now import it through that export. Two other additions since this branch began are adjusted to fit. #223's releases route and its test import the moved modules through the package. #229's check that the mapped measure concept table matches integrations/microcosm_policyengine_us/mappings.yaml moves out of the package's latest-artifact tests into lib/microcosm/mapped-measure-concept-variables.test.ts, because it reads a file of this repository that will not move with the package. A boundary test requires package modules to import only each other, Node built-ins and declared dependencies (@vercel/blob), and requires every module to be exported. The package has its own typecheck, chained into the frontend lint script, so CI runs it without a workflow change. The readers pass Next.js's fetch cache hint, which Bun ignores; a declaration seen only by the package's typecheck mirrors Next's. The golden tests now import the builder through the package and reproduce the record taken before the move, which moved unchanged. The workspace sits inside frontend/ because Vercel, CI and the publisher workflow all install from there. bunfig keeps Bun's hoisted linker so node_modules keeps its current layout. The former countries path stays as a re-export for code not yet switched to the package path. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
anth-volk
added a commit
that referenced
this pull request
Oct 19, 2026
#223 now checks the UK's latest-national.json whenever the registration names it: the file must carry schema_version 1, the matching line and a revision, and the tag it names must be the build its release manifest names. The golden repair harness served only {release_id}, so the UK dry-run repair stopped at "latest-national.json has unsupported schema_version undefined." For a country registered with its own pointer file, the stubbed repository now serves a pointer naming a tag of the recorded release at another commit, with that tag's folder listing and a release manifest naming the tag. The tag is not among the repository's refs, so the reconciliation the test checks is unchanged. Countries on latest.json keep the old pointer. The golden record is unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
anth-volk
added a commit
that referenced
this pull request
Oct 20, 2026
The tree builder is about to move out of the dashboard into its own package. Its outputs are byte-exact contracts: the index records every part's raw-JSON SHA-256 and gzip size, build ids derive from the inputs, and a repair refuses any change to the index digest. So the move has to be proved to change no byte. This records, from the builder as it is today, what it writes for representative inputs built from the fixtures the module tests already use. The inputs cover US and UK, releases and staging runs (version 1, version 2, and a staged dataset bundle), Belgium, and a UK release with reported loss attribution. For each, the record holds every part's path, raw JSON digest and size, gzip size and deflate-stream digest, plus the build id. It also records release-to-staging comparison bundles built through the comparison reader, the explorer's root responses read back from the stored bytes, and the manifest serialization. The gzip header's operating-system byte varies by platform, so the header is asserted separately and the digest covers the stream after it. A second test drives the publisher's dry-run repair of the recorded US, UK and Belgium releases against a stubbed Hugging Face repository. The publisher refuses a rebuilt index whose digest differs, so a successful repair proves its own reads and hashing reproduce the recorded index. The stubbed repository serves each country's release pointer at the path the publisher reads it from: `latest.json`, or `latest-national.json` for the UK since #223. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
anth-volk
added a commit
that referenced
this pull request
Oct 20, 2026
The tree builder and the schema 6 code the dashboard shares with it are moving to the collector as a Bun worker, and its types and readers will be published as a package the dashboard imports. That needs the builder to be one self-contained unit with explicit dependencies and its own tests. Inside frontend/lib nothing stopped a dashboard-only import from reaching it. The package, @policyengine/calibration-tree in frontend/packages/, is the builder's import closure: the schema 6 types, parsers, serializers and bundle builder, the comparison builder, Blob I/O behind the existing injectable client, and the release and staging readers the builder reads from, including the country registry. Its 30 modules move unchanged apart from ten import lines that used the dashboard's path alias. Their tests and fixtures move with them. Next.js routes, the HTTP helpers and the client hooks stay in the dashboard and import the package through its subpath exports. One of the 30 is release-cut.ts, added by #223. It parses the Hugging Face tag names Microcosm gives each build of a UK release, and latest-artifact.ts and calibration-tree-manifest.ts import it, so it moves with them and is exported as release-cut. The dashboard's shared formatter and the publisher now import it through that export. Two other additions since this branch began are adjusted to fit. #223's releases route and its test import the moved modules through the package. #229's check that the mapped measure concept table matches integrations/microcosm_policyengine_us/mappings.yaml moves out of the package's latest-artifact tests into lib/microcosm/mapped-measure-concept-variables.test.ts, because it reads a file of this repository that will not move with the package. A boundary test requires package modules to import only each other, Node built-ins and declared dependencies (@vercel/blob), and requires every module to be exported. The package has its own typecheck, chained into the frontend lint script, so CI runs it without a workflow change. The readers pass Next.js's fetch cache hint, which Bun ignores; a declaration seen only by the package's typecheck mirrors Next's. The golden tests now import the builder through the package and reproduce the record taken before the move, which moved unchanged. The workspace sits inside frontend/ because Vercel, CI and the publisher workflow all install from there. bunfig keeps Bun's hoisted linker so node_modules keeps its current layout. The former countries path stays as a re-export for code not yet switched to the package path. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
anth-volk
added a commit
that referenced
this pull request
Oct 20, 2026
#223 now checks the UK's latest-national.json whenever the registration names it: the file must carry schema_version 1, the matching line and a revision, and the tag it names must be the build its release manifest names. The golden repair harness served only {release_id}, so the UK dry-run repair stopped at "latest-national.json has unsupported schema_version undefined." For a country registered with its own pointer file, the stubbed repository now serves a pointer naming a tag of the recorded release at another commit, with that tag's folder listing and a release manifest naming the tag. The tag is not among the repository's refs, so the reconciliation the test checks is unchanged. Countries on latest.json keep the old pointer. The golden record is unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This branch was successfully deployed
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.
Microcosm UK publishes each dataset as a release line (PolicyEngine/microcosm#823). This PR lets the Calibration fit page show every published cut of a line, including the local-area dense release. It also makes the UK page open on the current national cut instead of the June 2023 Populace build. Finally, it lets the Staging candidates page show the per-target fit of UK local-area candidates again.
Problem
A Microcosm line keeps one release id and one folder,
releases/<release id>/. Each cut is an immutable Hugging Face tag,<release id>-<YYYYMMDDTHHMMSSZ>-<attempt>. The national line's current cut is named bylatest-national.json. The repository-widelatest.jsonstays on the June 2023 build.The publisher assumed that a release id has one commit and that a tag's files sit under
releases/<tag>/. It also read onlylatest.json. As a result:microcosm-uk-2024-25-nationalis still stored as the 4 Oct cut. Each later cut changed the folder's commit, so UK release reconciliation now stops with "Released dataset … changed".microcosm-uk-2024-25-dense-20261019T000432Z-ee5c2dbe, which exists only as a tag.Changes
releaseIdand source ID. A new optional field,releaseDirectory, records the line folder. Readers fetchreleases/<releaseDirectory>/at the entry's commit. Entries without the field readreleases/<releaseId>/as before.releases/<release id>/release_manifest.jsonat that tag names it inbuild.cut_tag. Any other cut-shaped tag is reported ineligible with a reason, and the run continues.mainis not published again once its cuts are. A build already published from the folder stays pinned at its own commit, so it still audits and repairs. Tags that the manifest already pins at the same commit are not probed again.pointer_path, which islatest-national.jsonfor the UK. The publisher reads it and checks it:schema_version1, alinethat matches the file name, and arevisionthat is a cut ofrelease_id. That revision becomes the latest release./api/microcosm/releasesadds every published cut beside the folders onmain. It labels each cut by line and attempt, for example2026-10-19 08:33Z · 2024-25-national · 6cba5d71. It hides a line folder unless the latest release still points at it. Each cut's role comes from its own release manifest at its commit, so the dense release keeps the existing "local area · experimental" flag.publishReleasetakes an options object, and the manifest store can inject the bundle upload, so the reconciliation test runs without a dry run.calibration_diagnostics.json. Microcosm's UK local lane stages its outputs under the dataset's own stem, so its diagnostics arrive asmicrocosm_uk_2024_25_local.diagnostics.json. Every local candidate since early October therefore showed "has not uploaded calibration diagnostics yet", and staging reconciliation reported them ineligible. The reader now usescalibration_diagnostics.jsonwhen the receipt records it. Otherwise it uses the one<dataset>.diagnostics.jsonthat the receipt records. If the receipt records several stem files, or a name that contains a path, the run has no target view. The digest check is unchanged.US and Belgium have no cut tags and no
pointer_path. Their inventory, picker, labels and latest selection are unchanged by construction, and tests check this. The manifest change is one optional entry field. The current reader already accepts and keeps unknown optional fields.Rollout
The old frontend would read a cut entry from
releases/<tag>/and get a 404. Publishing therefore pauses until the new frontend is deployed:CALIBRATION_TREE_BUILD_ENABLED=FALSE.CALIBRATION_TREE_BUILD_ENABLED.manual, dry run. Expect:published;microcosm-uk-2024-25-nationalfolder buildcomplete;latest-national.jsonnames.manual, real run.staging, to catch up on webhooks skipped while publishing was paused.manualdry runs, expecting every buildcomplete.The first UK run builds the dense bundle. Locally, from the published files, it took about 2.5 minutes and produced 42 files. The largest file is 16.2 MB raw, against the 100 MB limit. Building the summary for that release took 0.3 seconds.
Related
migrate-timestampsrun from Supply and qualify private release credentials before deployment #211 corrected it on 19 Oct, so it now shows 4 Oct 2026. New cut entries are dated from their tag's commit.frontend/packages/calibration-tree/src/. Whichever PR merges second will need a rebase; git follows the renames.Validation
cd frontend && bun test: 617 pass. New tests:bun run lint(tsc --noEmit) is clean.bun run buildpasses.backend/requirements.lockpinspolicyengine-us==1.764.6, which has been deleted; Pin .py 6.4.1 instead of the deleted policyengine-us 1.764.6 #222 replaces the pin. This PR changes no Python.Review fixes (added by @anth-volk, with Claude Code)
Merged
maininto this branch (649a299, one import-list conflict inlatest-artifact.test.ts: both sides kept). That fixes the hosted Python check.Four fixes for bugs a Codex review of this PR found, one commit each. Each red count is from the new test(s) before the fix; each green count is the whole test file afterwards, rerun after the commit.
--latestchecks the pointer's tag against its release manifest (8a01c06). Reconciliation publishes a tag only whenreleases/<release id>/release_manifest.jsonat that tag names it inbuild.cut_tag.--latestskipped that check: given alatest-national.jsonwhoserevisionis a tag whose manifest names another build, it published that tag and promoted it.readUpstreamLatestnow applies the same check before any mode publishes or promotes from the pointer, and requires the tag's files to be under the folder named by the pointer'srelease_id. Reconciliation passes its manifest, so a tag already pinned there at the same commit is not probed again.readUpstreamLatestandrunPublisher({ country: "uk", mode: "latest" })accepted the tag.5fea679). A country whose registration names its own pointer file (the UK'spointer_path) now always gets theschema_version,lineand tag checks, and a file withoutrevisionis refused. Countries that uselatest.jsonstill readrelease_idalone. The reconciliation metadata test used a UK pointer without a revision, so it now names a published tag of the same folder.{"schema_version":99,"line":"dense",...}and a pointer with no revision were both accepted).3614ca7).publishReleasecopied the diagnostics'release_id, which is the folder name, intoindex.targetComparison.releaseId, so two builds of one release compared as the same release. A tag published from its folder now records the tag there, asindex.build.releaseIdalready did. A folder release keeps the id its diagnostics carry, so its bytes are unchanged.microcosm-uk-2024-25-nationalandmicrocosm-uk-2024-25-dense).1079fa9).stagedBundleDiagnosticsFiledropped such names before counting, so{local.diagnostics.json, nested/dense.diagnostics.json}returned the first file. The count now includes every stem name, and the single stem file must also be one path segment.Typecheck (
tsc --noEmit) is clean after each commit. Only the changed test files were run locally; CI runs the rest.Tree publishing is paused (
CALIBRATION_TREE_BUILD_ENABLED=FALSE, set 2026-10-19) until this stack is deployed, so rollout step 1 is already done.🤖 Generated with Claude Code