Repository navigation
Conversation
…ismatch certify-data refuses a regional release that neither was built with nor claims the pinned policyengine-uk. The only Microcosm local-area cut is on 2.132.6, a new one takes 2-13 hours plus a two-build sign-off, and area receipts are uncertified anyway (the certificate covers the national dataset only, #685). So each national re-cut on a newer policyengine-uk had to drop area regions or wait for a dense rebuild. --accept-regional-model-mismatch REASON (UK only) keeps the regional release routed and records regional_certification in the bundle: basis accepted_model_mismatch, both model versions, the reason and area_receipts: uncertified. It refuses an empty reason, a regional release that already covers the version, and a run without a regional release; the core must still be covered. The national certificate is unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
My ruling on the accepted mismatch: keep the evidence, and fix what counts as dropped. I like requiring evidence for this exception, and producing it is cheap. I dry-ran this PR's own
The port dropped the baseline that PolicyEngine/microcosm#1348's comparison keeps: "Columns neither model defines, and inputs absent under both, are not changes." Please:
With those changes the evidence takes about a minute to produce and can be scripted, which is fine for Budget day. Until the new national and dense pair on 2.151.0 lands, we accept the mismatch only to test the machinery. |
scripts/bundle.py reports a ValueError from a subcommand through parser.error, so the certifier's "needs a reason" refusal reaches the caller as SystemExit(2) with that refusal as its context. The test now expects that, and still checks that the empty reason was forwarded, nothing was printed to stdout and the bundle is unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The input-surface audit counted every stored column the target model does not define as dropped, so it refused every Microcosm dense cut on its own columns (area codes, build and source ids, clone indices, SPI donor fields), even against the model the cut was built with. It now compares the stored columns with the build model the regional manifest records as well as the target, as Microcosm #1348's comparison does: - dropped: stored columns the build model defines and the target does not. These still refuse, with no override. - never modelled: stored columns neither model defines, recorded only. - defaulted: target inputs the file does not store, after the target's aliases, that were not inputs of the build model. The build model's variables and inputs come from a throwaway `uv run --no-project --with policyengine-uk==V --with policyengine-core==C` environment, through an injectable runner, without the caller's uv project settings. The probe reports the versions it imported, and any other resolution refuses, as does a manifest that records no build model or core. The evidence moves to schema version 2, so version 1 files refuse. It adds the build model and core versions, the build model's full variable and input lists, and the never-modelled columns, so certification can recompute all three lists exactly. Certification binds both build versions to the regional manifest, recomputes the lists, refuses drops, records never_modelled_columns in regional_certification and names their count in its warning. It matches the .h5 suffix case-insensitively, as the audit does. The execution receipt schema is regenerated. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The data-certification skill now defines dropped, never-modelled and defaulted names relative to the regional build model, notes that the audit needs uv and PyPI to read that model, and replaces the note that the dense cut was never audited with the audit's results for microcosm-uk-2024-25-dense-20261019T000432Z-ee5c2dbe (built with policyengine-uk 2.132.6): 83 never-modelled columns, no dropped column under 2.147.2 or 2.151.0, 16 new defaults under 2.147.2 and 37 under 2.151.0, with 123 inputs already defaulted under 2.132.6. It says which 2.151.0 defaults belong in the limitations. The changelog fragments describe the build-relative comparison. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Replying to the ruling: your four requests are pushed, with main merged in first (331fec1).
The docs carry your measurements (f14690e). Re-running the audit on the 19 Oct dense cut reproduces them: no drops and 83 never-modelled columns under 2.147.2 and 2.151.0, with 16 and 37 new defaults. |
|
@juaristi22 @MaxGhenis round 1, at Verdict: the four requested changes are in and the national certificate does not widen, but the evidence is checked for consistency, not for truth, so an edited file can still hide a drop. No must-fix findings; three shoulds. The four requests
Invariants
Findings
What I ran
🤖 Generated with Claude Code |
Review of #699 (Vahid Ahmadi, findings 1 and 4). Certification recomputed the dropped, never-modelled and defaulted lists from the surfaces declared in the evidence, so editing the file could hide a drop: leaving a stored column out of build_model_variables, adding it to model_variables, or adding the new defaults to build_model_inputs were all accepted. verify_model_surfaces now reads the target model in process, which certifying an accepted mismatch therefore needs installed at the evidence's model_version, and the build model again through the uv probe, and refuses any list or input alias that differs. Only the stored columns rest on the auditor's word, bound to each H5's SHA-256. The probe resolves reproducibly: uv run --no-config --default-index https://pypi.org/simple, with --exclude-newer set to the regional manifest's build.built_at in UTC, rounded up to the second, and without any UV_* setting except the cache, Python-install and connection ones. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Review of #699 (Vahid Ahmadi, finding 2). The inputs area runs default reached regional_certification.defaulted_inputs, TRACE, receipts and the certify warning, but not the limitations unless the operator typed them. Certification now appends one generated limitation naming them, as it appends the VAT one, unless the audit already carries the same text, and none when nothing defaults. The warning gives the count and joins the limitations with semicolons. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… only Review of #699 (Vahid Ahmadi, finding 3). Every UK receipt carried the whole regional_certification record, evidence included: both models' full variable and input lists, roughly 86 KB on 2.132.6 alone, and all of it in execution_identity_sha256. A certified national receipt gains nothing from that, since certificate_sha256 already digests the data_releases.uk record that holds it. Now only an area run, a receipt whose data is the artifact the accepted exception covers, carries regional_certification, as a RegionalCertificationIdentity: the record's model versions, reason, audited lists and limitations, and record_sha256, the RFC 8785 digest of the whole record, evidence included. A certified receipt cannot carry one. verify_regional_certification checks an area receipt's summary and data identity against the manifest the run used, as verify_certificate does for a certificate; verify_certificate no longer compares a regional record. The published schema and its rules say so. The field is new in this pull request, so this does not change a released v1 field. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Review of #699 (Vahid Ahmadi, findings 5 and 6). A reason made only of a zero-width space passed certification, because str.strip() keeps it. A \S pattern keeps it too, as it keeps U+FEFF, U+2060 and soft hyphens, so the mismatch reason, the auditor and every limitation now need one printable character that is not whitespace, in the audit and in certification. RegionalCertification.accepted_reason also takes the \S pattern audited_by has, so a hand-edited bundle with a blank reason does not validate. schema_version is now required, so evidence without it refuses rather than reading as version 2. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ation The data-certification skill says certification re-reads both models (the target installed in process, the build model with uv) and that only the stored columns rest on the auditor's word; gives the probe's pinned resolution; says certification names the defaulted inputs in the limitations; and describes the area receipt's summary and record digest. docs/receipts.md documents regional_certification and verify_regional_certification. The audit script's docstring and the changelog fragments follow. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Thanks, @vahid-ahmadi. All six are addressed in commits up to f0870aa:
The docs and changelog are in f0870aa. |
The test asserted that UV_CACHE_DIR was the only uv setting the build-model probe kept, but CI's setup-uv also sets UV_PYTHON_INSTALL_DIR, which the probe keeps on purpose, so Test (3.14) failed. The test now removes every UV_* variable before setting its own. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Brings in #720, the Microcosm UK pair on policyengine-uk 2.151.0, so CI runs this branch on that pin before it merges. No file changed on both sides. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
@juaristi22 @MaxGhenis round 2, at Verdict: all six round 1 items are in. Certification now rejects every edit we made to the model lists. One part is still taken on the auditor's word: the list of stored columns. That is documented and bound to the H5's sha256, and I think it is fine for this PR. No musts. There are two shoulds and two nits below. Round 1 items
Injection through the probe pins. None found. The command is an argv list with no shell. Both build versions pass Findings
What I ran
🤖 Generated with Claude Code |
Review of #699, round 2 (Vahid Ahmadi). - The probe runs uv run --isolated. Without it, uv reused an environment that already met both pins, such as a .venv in the working directory, so neither the PyPI index nor the --exclude-newer cutoff applied and the second read was not independent of the operator's environment. - A regional manifest without build.built_at now refuses, as one without build versions does, instead of reading the build model unpinned. - regional_certification records stored_columns: auditor_attested, and the area receipt's summary carries it: certification re-reads both models but not the H5s, so a reader of the bundle sees the basis of the stored-column lists without opening the docs. - The comment on the lazy policyengine_uk import no longer says certification keeps the model out. Tests and the receipt schema follow. Not run locally; CI runs them. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… basis Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Thanks, @vahid-ahmadi. Round 2 is addressed at 517396a:
The docs and changelog are in 517396a. These changes weren't run locally, because a long build is running on my machine; this PR's CI runs them on the head. |
Require audited evidence for a UK regional release served on an accepted model mismatch.
Invariants:
--drop-regional-releaseremoves the exception, regional manifest digest, area routes and dense artifact without changing the national certificate.The audit is relative to the regional build model, as María ruled.
scripts/audit_regional_input_surface.pycompares the entity-table columns the H5 stores, in each period, with the build model and core the regional manifest records and with the installed target model, keeping the baseline of PolicyEngine/microcosm#1348's comparison:The build model's surface is read in a throwaway
uv run --isolated --no-project --no-config --default-index https://pypi.org/simple --exclude-newer <build.built_at> --python 3.13 --with policyengine-uk==<build> --with policyengine-core==<core>environment, without the caller'sUV_*settings other than cache, Python-install and connection ones, so the audit needsuvand PyPI.--isolatedkeeps uv from reusing an environment that already meets both pins, such as a.venvin the working directory. The probe reports the versions it imported; any other resolution refuses, as does a manifest that records no build model, core orbuild.built_at. The evidence moves to schema version 2 (version 1, or no version, refuses) and carries both models' full variable and input lists.Certification does not trust those lists (from Vahid's review). It reads the target model in process, so
certify-datamust run where the target policyengine-uk is installed, as the audit does, and reads the build model again withuv. Only the stored columns rest on the auditor's word, bound to each H5's SHA-256, and the record says so:stored_columns: auditor_attested. It then recomputes all three lists, recordsnever_modelled_columnsinregional_certification, names the defaulted inputs in a generated limitation, and gives their counts in its warning.verify_regional_certificationchecks an area receipt's summary against the manifest the run used.Required downstream refresh: update the dashboard's vendored
tests/fixtures/w4/execution_receipt.v1.schema.jsonfrom this repository's regenerated schema.Validation:
4931d18f(1,056 passed, 3 skipped) and the realverify_model_surfaceson 2.151.0. The round-2 changes (--isolated, the required build time,stored_columns) were not run locally while a long build ran on the producer's machine; this PR's CI runs them.test_measure_regional_inputs.py,test_regional_input_evidence.py,test_certify_data_release.py,test_execution_receipt.py): 1,056 passed and 3 skipped. One skip is the rdflib JSON-LD case, which passed when run with rdflib. The build-model probe and the re-read surfaces are faked in tests, so CI installs nothing from PyPI; one test runs the real probe script against the installed model.scripts/generate_receipt_schemas.py --check,ruff format --checkandruff check(latest ruff, as CI) pass. Mypy reports nothing in the changed code.microcosm-uk-2024-25-dense-20261019T000432Z-ee5c2dbe(built with policyengine-uk 2.132.6, core 3.33.3), reading column names only: 0 dropped and 83 never-modelled under each target; 0 new defaults against 2.132.6 itself, 16 against 2.147.2 (the 16 the docs list) and 37 against 2.151.0. These match María's figures, including the 123 inputs already defaulted under 2.132.6. With the pinned probe, the 2.147.2 audit is identical and took 24 s after the download.certify_data_releaseon a scratch copy of the bundle, with the 2.147.2 national cutmicrocosm-uk-2024-25-national-20261023T075039Z-a133f37a, the dense cut and its 2.147.2 evidence, in an environment with 2.147.2 installed, re-read both real models and recordedaccepted_model_mismatchwith no dropped columns, 83 never-modelled columns and 16 defaulted inputs, named in a generated limitation, in about 11 s. The same evidence with a stored build-model variable claimed as never modelled was refused. The area-receipt summary of that record is about 4 KB; the full record is about 110 KB.🤖 Generated with Claude Code