Repository navigation
Conversation
Every UK verifier trusted whichever key was in the environment, so any 32-byte key that signed a report also verified it. Register the keys that may sign (one per builder: HMAC means the verifier needs the signer's secret, so a cut is signed, certified and published by one key holder), and check the registry at every UK signer and verifier: - the publisher's schema-4 checks (battery, certification, dense report) accept only active or retired keys; - the gate battery, the certifier and the scoped re-signer sign only with an active key; - the national role refuses an unusable key before loading inputs, not after the solve (runbook F8); - the local release-candidate preflight names an unregistered key. The registry starts with the key that signed every UK cut on record (66bf0e29...). Tests keep their throwaway keys through a root-conftest admission; tests marked committed_gate_key_registry see the real one. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The national role now checks its key before loading inputs, so the tests that drive a national build through stubs need one, as the others do. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
tools/run_uk_cut.py runs fetch -> preflight -> spine -> national (dry run first) -> score (only when the in-build evaluation did not pass) -> certify -> stage-1 comparison (diagnostic) -> assemble -> inspection publish, from a clean checkout of main. Each step has a done-check over its real outputs, so `all` resumes where it stopped and never rebuilds over a spine, overwrites a calibration run or re-assembles a release. Publication is opt-in (--publish) and always --no-latest --tag-only, so main's files and the latest-*.json pointers never move (runbook Q12/F14). Inputs come from tools/uk_cut_inputs.json, which says only where each input lives; every digest is read from the pins the build itself checks (source_stages.json, frs_release.json, chronicle_feed.json, gates.json). FRS, SPI, WAS and ETB come byte-exact from the gated UKDS zips already in policyengine-uk-data-private; NTS 2002-2024 and LCFS 2024-25 are declared there pending a one-time upload. The Chronicle artifact and the input-mass reference come from the new private dataset policyengine/microcosm-uk-build-inputs. tools/modal_rebuild_uk_chronicle_artifact.py rebuilds the Chronicle UK artifact from the public repo on Modal and uploads it only if its digests reproduce the pin. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Does what policyengine.py#685 did by hand, from one command, on a fresh branch from policyengine.py's main: one-writer check, regional-route pre-check (refuses a dense cut on another policyengine-uk before anything is written, naming the routes), certify-data at the cut's own model and core, uv lock + release_lock, generate --include-tros, policyengine.py's own certified-constant rewrite plus the local-area tag, snapshot refresh, check --published-spm --include-tros --strict-tros, the UC floor and the tests. It commits; it pushes and opens a draft only when asked, and never merges or releases. The PR body lists the judgment calls (UC floor acceptance, dropped overlays, warnings, failing tests) as a checklist. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
docs/uk-cut-anyone.md: the one command, what it never does, where every input lives and how each missing one gets hosted (NTS/LCFS upload, the Chronicle rebuild, the mass-reference recipe), the signing-key registry with rotation and revocation, the policyengine.py handoff, and the four regional routes. CLAUDE.md points at it from the release boundary. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
tools/uk_cut_inputs.json names policyengine-uk-data-private, which hosts the licensed UKDS archives and the sha-pinned incumbent, for the reason uk/frs_release.json already does: a download location checked against committed pins, never an import. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
When the certification handoff accepts a local-area cut built on another policyengine-uk, it now lists the regional file's input columns the newer model no longer defines (ignored on load; refused unless --allow-dropped-columns) and the newer model's inputs the file cannot carry (defaulted), and puts both in the pull request. A built input that became a formula is in neither: its stored values still load. Property tests pin the set algebra. Measured for the 2.132.6 dense cut under 2.146.4: nothing dropped; 13 inputs defaulted, among them salary_sacrifice_returned_to_income and local_bus_uncapped_single_fare. The doc records this and the regional recommendation. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The repo's addopts already pass -q, so the summary line can be absent and the check printed pytest's footer instead of a result. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The schema-3 terminal-report check (exact-K release ids) verified under whatever key POPULACE_UK_TERMINAL_GATE_SIGNING_KEY held. No schema-3 report is published (every UK terminal report on the Hub is schema 4, signed by 66bf0e29...), so binding it to the registry breaks nothing and leaves no UK verifier that trusts an unregistered key. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Hosted files are downloaded beside their destination and moved in after verification instead of copied out of the Hub cache, so the 7.4 GB Chronicle artifact does not occupy the disk twice. - The national dry run is skipped only when it finished, not whenever the state file mentions it. - The free-disk check walks up to an existing ancestor of the work dir. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
tools/modal_uk_cut.py clones a pushed commit on main, syncs its lock with the uk extra and runs tools/run_uk_cut.py all with the work directory on a Modal volume, passing HF_TOKEN and the signing key to that run only. Plan-only by default; processing UKDS data there needs the data owners' OK first (the doc says so). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Rebuilt on Modal from public Chronicle at abf0921: both the facts (2b64fecf...) and manifest (b90fb1b8...) digests reproduce the committed feed pin byte for byte, so the rebuild is deterministic across machines and needs no R2 credentials. Hosted in policyengine/microcosm-uk-build-inputs at d4c8b191; the bundle took 2h24m and peaked at 35.5 GB. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The UK hub's rehearsal patches (the 13 commits above) were validated under a different Ruff configuration: sort one import block and bind the resume-validation fake's loop variables as defaults (B023). Their load and disk refusal thresholds were the shared build host's constants; they are now defaults the operator can change (--max-load1, --min-free-gb), so the tool also runs on a builder's laptop. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Review finding: the check compared two models' input lists, but Microcosm stores formula variables too (is_uc_claimant, is_claimant_or_partner...), so a newer model removing a stored formula variable went unreported, and a stored formula-to-input variable was wrongly listed as defaulted. The handoff now downloads the regional cut's microdata at its manifest pin, checks its sha256, and reads only the column names (pandas table-format entity tables, or the flat per-variable layout; anything else refused). dropped = stored columns the build model defined and the certified model does not; defaulted = certified inputs the file does not store that were not build-model inputs. Measured on the 2.132.6 dense cut under 2.147.2: nothing dropped, 16 defaulted, matching the UK hub's independent probe. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…he cache Answers the Sol review of #1348: - A retried spine never reruns over an attempt: the builder deletes its sidecars (a gate-blocked attempt's signed report included) on start, so --retry-spine moves the whole attempt aside first. Retried scores, certifications and stage-1 comparisons keep the earlier file as <name>.superseded-<time>. - --work-dir and --previous-h5 are made absolute at parse time; assembly and publication run from the release directory. - The stage-1 done-check binds the candidate and previous files by the sha256 the comparison recorded, so a new candidate or a new previous cut redoes it. - The verification cache keys on inode, size, mtime and ctime: an equal-length replacement with its mtime restored is re-hashed. - The doc says the mass reference carries a byte pin, and gives the regional loss as measured on the dense file itself (16 inputs under 2.147.2). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
NTS and LCFS are on the Hub. I've checked the licensing, and both inputs are now in
Could you pin both here rather than in a follow-up PR? In
The doc's inputs table can then mark both as fetched, and its LCFS row can say the zip is a repack. Regions (Q13). Yes, a new national and dense pair on policyengine-uk 2.151.0 will be in Microcosm soon. In the meantime, we can accept the mismatch (PolicyEngine/policyengine.py#699) if we need it to test the machinery. CI. The last run on |
juaristi22
left a comment
There was a problem hiding this comment.
Review at 300ce55. The key registry and the verifier changes look right: every UK signer now needs an active registered key, and every verifier a registered one. The CI re-run on this head has passed engine-uk, integration-uk, lint and wheels; engine-free and engine-us were still running when I posted this.
Findings, most important first:
- The accepted-mismatch route can't certify (
tools/certify_uk_cut_in_policyengine_py.py:1011). It passes only--accept-regional-model-mismatch <reason>, but PolicyEngine/policyengine.py#699 also requires--regional-input-surface-evidence, socertify-datarefuses after the worktree, sync and column audit have run. Following my ruling there: once that PR measures drops against the build model, generate the evidence with itsscripts/audit_regional_input_surface.pyand pass the file. This tool already downloads the regional H5 and reads its columns, so that replacesinput_surface_changerather than adding a step. - A resumed cut isn't bound to the key that signed it (
tools/run_uk_cut.py:1482and preflight'ssigning_key_check). With two active keys, a second key holder resumingallgets an HMAC failure at certify that preflight never warned about, andcut_receipt.jsonrecords the resumer's key rather than the signer's. Check the environment key against the fingerprint in the cut's signed reports, and take the receipt's fingerprint from those reports. - The one-writer check misses suffixed branches (
tools/certify_uk_cut_in_policyengine_py.py:496). It looks only forcertify-uk-<id>, while the hub's branch for a133f37a iscertify-uk-a133f37a-national. Match any branch that starts withcertify-uk-<id>. allhasn't run end to end on a real cut. Spine through assembly and publication has only run against a fake executor; the hub rehearsal ran the policyengine.py handoff on my 23 Oct cut. The done-checks rely on fixture formats, such as taking the assembly summary from the last JSON object in an append-mode log. Before the team relies on it for a Budget re-cut, please run one full cut that doesn't matter.- The signing-key variable name is copied (
tools/run_uk_cut.py:59,tools/modal_uk_cut.py:45) although this PR exportsUK_GATE_SIGNING_KEY_ENV.docs/agent-guide.mdasks us to import shared static data "instead of copying it". - Defaults specific to one machine: the reservation tool path (
tools/run_uk_cut.py:66), the certifier's load limit of 110 (tools/certify_uk_cut_in_policyengine_py.py:173) and the doc's pointer to a runbook on your machine. On other machines, the reservation check is silently skipped and the load guard never trips. - Every certification commit credits Claude (
tools/certify_uk_cut_in_policyengine_py.py:1180), whoever runs the tool. - A UC-floor receipt without
passedcrashes with a KeyError (tools/certify_uk_cut_in_policyengine_py.py:1126anduc_floor_summary) instead of the intended "failed operationally" refusal.
Lets any team member or agent session build, sign and assemble a Microcosm UK national cut, and open its policyengine.py certification, without the one machine that held the key and some of the inputs. Every input is fetched by the pins the build already enforces. Draft until the independent review agrees.
What's in it
microcosm.data.gate_signing_keys).MICROCOSM_UK_TERMINAL_GATE_SIGNING_KEY.66bf0e29…. The team keydd31e325…is registered separately in Register a team UK gate signing key (hold: needs María's agreement) #1350, held for María's agreement.python -m microcosm.data.gate_signing_keys {check,list,generate}.tools/run_uk_cut.py: one resumable command.fetch→preflight→ spine → national (dry run first) → score (only if the in-build evaluation did not pass) → certify → stage-1 (diagnostic) → assemble → publish preflight → publish (opt-in).--retry-national) or re-assembles a release.--publishis always--no-latest --tag-only, so main's files andlatest-*.jsonnever move (runbook Q12, F14).origin/main, unless--allow-off-main "<who agreed>".tools/uk_cut_inputs.jsonsays only where each input lives. Digests come fromsource_stages.json,frs_release.json,chronicle_feed.json,gates.jsonand the mass-reference pin.policyengine-uk-data-private(all 18 tabs match their pins).policyengine/microcosm-uk-build-inputs. It was reproduced byte-for-byte tofd41cb5f…at microcosm0eac9bbbdwith policyengine-uk 2.89.0; today's engine emits 2 more columns, and the shared 131 totals are identical.tools/modal_rebuild_uk_chronicle_artifact.pyrebuilds the pinned Chronicle UK artifact from the public repo, which needs no R2 credentials. It hosts the artifact privately only if both digests reproduce; otherwise it uploads diagnostics.tools/certify_uk_cut_in_policyengine_py.py: the policyengine.py certification handoff, as Net-new UK stages: UC deduction attributes, bus fares, WAS debt #685 did it by hand.docs/uk-cut-anyone.mddocuments all of this, plus key rotation and revocation and the regional routes, with a recommendation.Since the first review (2026-10-23)
tools/certify_uk_cut_in_policyengine_py.pyend to end on María's cuta133f37a(pe-uk 2.147.2), in 97 min and mechanically clean. Its 13 commits are here under their own authorship:--base-refand--pr-base, to stack on policyengine.py#704;--max-load1and--min-free-gb) and per-step timings;-vv, durations and stall tracebacks;--resume-worktreewith allowlisted staging.--retry-spinemoves it aside, keeping a gate-blocked attempt's signed report);.superseded-<time>;--work-diris made absolute;Regions (runbook Q13, María's call)
salary_sacrifice_returned_to_income,local_bus_uncapped_single_fareanddirectly_held_shares;Invariants (tested)
allruns nothing.--helpdeclares.chronicle_feed.json,frs_release.json,gates.jsonandsource_stages.json).@main.Local results
frs_release.jsondoes.ukextra.axiom: n/a: build infrastructure (no policy encoding)
🤖 Generated with Claude Code