Skip to content

Bind the d2011 pair: UK 2.151.0 and Microcosm a6299504 (policyengine.py 6.11.1) - #39

Merged
MaxGhenis merged 16 commits into
mainfrom
d2011-bind-2151-pair
Oct 27, 2026
Merged

MaxGhenis merged 16 commits into
mainfrom
d2011-bind-2151-pair

Conversation

@MaxGhenis

@MaxGhenis MaxGhenis commented Oct 25, 2026 •

Copy link
Copy Markdown
Contributor

Max ruled d2011 = A on 25 October: the triple lock's binding primary follows the certified 2.151.0 national and local-area pair built at PolicyEngine/microcosm#1396. This PR moves every binding identity to that pair. policyengine.py 6.11.1 released the pair on 27 October, certified by policyengine.py#720, and the last commit (c48aa2a) fills its identities from the tag. The fallback was not taken. #38 and #40 have merged, and this branch merges main. The final head, 61363c1, is approved (round 9) and ready; it merges on gates.

What changes

  • Pins. policyengine-uk==2.151.0 in pyproject.toml, requirements-lock.txt (only that line) and CI's comment. Core 3.33.3 is unchanged. The base carrier was the preparatory 6.10.1 (datasets.PREPARATORY_CARRIER) until the fill commit set it to the release, 6.11.1.

  • datasets.py.

    • CERTIFIED_BUNDLE is d2011's: model 2.151.0, wheel 5722f55a… with the d2011 attestation (Review policyengine-uk 2.151.0 as an exact Budget wheel beside 2.147.2 #38), and core 3.33.3's existing attestation.
    • New microcosm_uk_2024_25@a6299504: SHA-256 b96a8cd6…, the staged attempt uk-frs-calibration-attempt-20261025T091414Z-a6299504 (342,348,841 bytes, built at 67ee2ddf3, clean); microcosm-data 0.1.0. The tag microcosm-uk-2024-25-national-20261025T091414Z-a6299504 now exists on the Hub with those bytes.
    • #715's a133f37a entry stays as the fallback, with its own BUNDLE_715 and pending FALLBACK_* bundle identities.
  • The local-area cut is identified, not just named (88550bf). Every cut publishes microcosm_uk_2024_25_dense.h5, so a file name alone let a6299504 certify with any dense cut. datasets.local_area_cut pins a cut's:

    • file, tag and SHA-256;
    • release manifest URIs and digest;
    • build model;
    • routing basis.

    The installed-bundle check calls _local_area_routed. It requires exactly one bundle datasets entry for the cut's file with that tag, SHA-256 and repository, regional_release_kind local_area, both regional manifest URIs, and the digest wherever the bundle records one.

    • Binding: the 2.151.0 cut c9df4b86 (cb3712f2…, manifest 30be4754…), filled from the release in BINDING_LOCAL_AREA_{PATH,REVISION,SHA256,MANIFEST_SHA256}. Its basis is built_with 2.151.0, so a regional_certification block refuses: both halves are on 2.151.0.
    • Fallback: the 19 October cut is pinned now (ee5c2dbe, 8e10e130…, manifest b9dc7cae…, built on 2.132.6). The bundle must carry #699's regional_certification for exactly that accepted mismatch: certified 2.147.2, built 2.132.6, the cut's manifest URI and digest, area receipts uncertified. It must also carry regional_source_manifest_sha256.
  • Region routing. National goes to the national file; constituency and local_authority go to the cut's file (datasets.area_routed; policyengine.py LOCAL_AREA_REGION_TYPES["uk"]). The release's routing must equal this exactly.

  • Core coverage. datasets.certified_core applies policyengine.py's rule, made stricter:

    • Under core_binding certified, it takes the named certified_for_core_version, which must equal the bundle's core pin.
    • Under bundle_pin (6.11.0's form), or with no binding, it takes the pin; a named core must equal it.
    • Anything else certifies nothing.
  • Certifying pull request. A released-manifest certificate needs its certifying pull request and commit in provenance too, not only in the preflight.

  • config.PRIMARY_DATASET is now microcosm_uk_2024_25@a6299504.

  • certified_bundle_preflight admits only datasets.D2011_PAIRS and checks the bundle of whichever pair PRIMARY_DATASET names, so a fallback commit moves only the primary.

  • data/binding-bridge.pending.json. The model step goes to UK 2.151.0 and the data step to Microcosm a6299504; pending_release is unset. data/binding-bridge.json is its ready copy for 6.11.1.

  • scripts/fill_release_identities.py (new). With --release TAG it:

    • reads the UK bundle manifest at the tag (not the merge: the release workflow's version commit rewrites it) and checks every pinned identity;

    • reads the local-area cut's own release manifest at the cut's tag on the Hub (or --regional-manifest FILE). That manifest's cut_tag, build model and core, dataset_role and microdata artifact must match;

    • requires the certifying pull request to be merged and its merge commit to be in the tag (compare: ahead or identical). The tag's manifest bytes must equal as_released(merge manifest, tag version), a replay of the release workflow at policyengine.py 6.11.0:

      • .github/bump_version.py sync_bundle_versions sets the carrier version fields and each country's bundle id;
      • scripts/generate_bundle_artifacts.py normalized_manifest sets each package's install requirement and the citation, and drops source.

      Nothing else may differ (aac81df). Against the real upstream manifests, the replay writes 6.11.0 from #704's merge and 6.2.6 from #555's byte for byte;

    • prints the eight binding values only the release supplies (four for the fallback). With --apply (only with --release) it builds and checks every file before writing any. It then writes them, the carrier pin in both dependency files and the ready bridge config.

    A rerun with --manifest on the installed wheel's manifest also checks every filled identity.

  • Wording.

    • pipeline.method_limitations and its docstring, and engine.py's notes.
    • METHOD.md, outside the frozen C2 section, whose bytes are unchanged.
    • REBUILD.md, including the lock re-resolution and the full list of fallback moves.
    • The d2011 audit.
    • Version-neutral pyproject, lock and CI comments.

Filled from the release: policyengine.py 6.11.1 (c48aa2a)

policyengine.py 6.11.1 (tag b14ee554, 27 October 01:30Z; PyPI wheel 9ada4083…) carries the pair. It is certified by #720, whose merge 610ebc42 is of reviewed head 99a3e48b, ahead of d2011's 18:00Z deadline. scripts/fill_release_identities.py --pr 720 --release 6.11.1 --apply passed all 32 checks at the tag and wrote:

Identity Value
BINDING_BUNDLE_VERSION 6.11.1
BINDING_BUNDLE_MANIFEST_SHA256 ab60903b390e7a765ea6558ec5e2d8fa5aede06b6f735fbf4e4c96109ffd1617 (the tag's src/policyengine/data/bundle/manifest.json, and the wheel's)
BINDING_CERTIFICATION_URL / _COMMIT #720 / 610ebc42586b7358c41afe4fabec7c67adf17205
BINDING_LOCAL_AREA_PATH / _REVISION microcosm_uk_2024_25_dense.h5 / microcosm-uk-2024-25-dense-20261026T105309Z-c9df4b86
BINDING_LOCAL_AREA_SHA256 / _MANIFEST_SHA256 cb3712f25b76109ad27b7b0cdf5dee78c55d3b7f55ce7bf207ef1a191da2ae9a / 30be47545efd2aa320e30f8d04240cf345aec105fa1d788334770bc4e17c583e

It also wrote policyengine==6.11.1 in pyproject.toml and the lock, and data/binding-bridge.json, the ready copy of the pending config: the carrier in the three new endpoints, pending_release filled, status ready.

  • The tag's manifest is byte for byte the release workflow's rewrite of the merge's. The versioning commit changed only version strings, 6.11.0 to 6.11.1. The workflow files (.github, scripts, Makefile) are unchanged from 6.11.0 to 6.11.1, so the replay's basis holds.
  • The lock. It was re-resolved with --upgrade-package policyengine, which moved only policyengine, 6.10.1 to 6.11.1. 6.11.1's [uk] extra pins UK 2.151.0 and core 3.33.3, and the lock still installs the base carrier.
  • Hand-written wording. Where text said the release was pending, it now describes the release:
    • the lock's first comment and CI's install comment;
    • datasets.py's docstring, the PREPARATORY_CARRIER comment and the UNCERTIFIED reason, which tests/test_results.py matches only by its uncertified prefix;
    • README, which still named the superseded d1727 release;
    • METHOD.md outside the frozen C2 section, whose bytes are unchanged;
    • REBUILD.md.

Fallback (not taken)

The pair shipped in 6.11.1 before d2011's deadline, so this stays unused; the FALLBACK_* identities stay pending. d2011's fallback was a133f37a "with policyengine.py #699's area routing": a133f37a's national file, with areas routed to the 19 October dense cut on an accepted model mismatch (#699's Budget route). #715's candidate head e02d41bc routes national only. The cut is pinned now; the four FALLBACK_* bundle identities are pending.

If d2011 falls back, fill them with --target fallback --release TAG --apply. Then, in one reviewed commit, move to the fallback:

  • config.PRIMARY_DATASET;
  • the model and carrier pins, with the lock re-resolved;
  • CI's comment;
  • the bridge endpoints;
  • the d2011 wording.

REBUILD.md lists each.

Microcosm's anchor year (= #40)

Both Microcosm cuts anchor static ageing at 2025, their calibration year. Builds from microcosm#1095 on (a133f37a, a6299504) write the solved weights so that the model's 2025 weights are exactly them. The evidence:

  • build_record.json's export readback weight_year;
  • microcosm's weight_year.py;
  • every target dated 2025.

The pre-Budget cross-check 5c6b3f68 predates #1095, so its 2025 weights are its solved ones times 1.0072. #40 merged as f47493e6; this branch carries the same text, with a6299504 named.

Invariants

  • No pending identity certifies. A None version, digest, certifying PR or commit, or any part of the local-area cut refuses certification and the publication preflight.
  • Each certified pair is exact:
    • model, core and carrier;
    • artifact bytes, build id and manifest URIs;
    • the full region routing;
    • the local-area cut's tag and bytes, on the pair's own basis. The binding pair has no mismatch record; the fallback has exactly #699's.
  • The fill and the installed check cannot disagree on the cut: both call _local_area_routed.
  • The certified core is one that policyengine.py's own receipt also treats as certified, and it must equal the installed core.
  • The released manifest is exactly the release workflow's rewrite of the certifying merge's: only the carrier version fields, the countries' bundle ids, the install requirements and the citation may differ, and source may be dropped. The comparison is on the tag's own bytes.
  • The fill is all-or-nothing. It writes nothing unless every check passes and every file it writes is valid. It never writes a value the release doesn't supply, and it never touches model, core or dataset pins.
  • Every test holds in both states: pending, or filled (and then, once installed, certifying). A pair is wholly pending or wholly filled.
  • Data step. The bridge's data-step endpoint is the registry's binding entry, on the certified bundle's model version.

Verification

No survey or Microcosm simulation was run.

  • Release night, at c48aa2a, on the 6.11.1 lock (installed in a fresh .venv, as CI does):

    • the fill at the tag passed 32 of 32 checks;
    • rerun with --manifest on the installed wheel's manifest, it passed 37 of 37, the filled identities included;
    • check_upstream() passed;
    • certified_bundle_preflight() passed ("exact policyengine 6.11.1 UK Budget bundle and microcosm_uk_2024_25@a6299504 certified"), and so did housing_benefit_passport_preflight();
    • the model step's --validate-only on data/binding-bridge.json validated with 0 jobs run;
    • the nine focused files gave 458 passed;
    • the full suite gave 2297 passed, 5 skipped and the 3 documented stale-results failures. scripts/check_prebuild_tests.py, run as a PR into main, accepts those: 2305 completed.

    The data step validates only after Tuesday's model run, because its --from-receipt is that run's output.

Earlier rounds, on the preparatory lock (UK 2.151.0 / core 3.33.3 / policyengine 6.10.1):

  • Against the certifying PR, before release. The certifying PR is policyengine.py #720, María's draft. At head 99a3e48b it adds the local-area cut microcosm-uk-2024-25-dense-20261026T105309Z-c9df4b86. fill_release_identities.py --pr 720 --manifest <#720's manifest>, reading the cut's own release manifest from the Hub, passes all 29 checks:

    • every national identity: carrier and bundle id, core 3.33.3, model 2.151.0 and its wheel SHA-256, build id, both manifest URIs, and the a6299504 artifact;
    • region routing, both area types to microcosm_uk_2024_25_dense.h5;
    • the dense datasets entry: tag c9df4b86, SHA-256 cb3712f2…;
    • regional_release_kind local_area, both regional URIs, and no regional_certification;
    • the cut's own manifest (SHA-256 30be4754…): built on 2.151.0 and core 3.33.3, role non_default_local_area, and the same artifact.

    The release supplied the rest at c48aa2a: the carrier version, the tag's manifest SHA-256 and #720's merge commit. The merge's manifest was byte-identical to that head's.

  • At 6a3f00e: the nine focused files gave 458 passed and 0 failed. The fixes for round 3's five non-blocking items are:

    • the as_released None contract and the dropped source, now stated accurately;
    • tags that equal the rewrite in content but not in bytes refusing, through certifying_checks and main();
    • non-ASCII text written escaped;
    • non-dict data_releases entries left alone.

    All 15 comparator and uniqueness mutants are caught, including the review's four survivors.

  • At ece7c36: the nine focused files (test_fill_release_identities, test_budget_bundle, test_certified_preflight, test_datasets, test_binding_bridge, test_microcosm_primary, test_budget_model_projection, test_model_horizon_upstream, test_prebuild_ci) gave 446 passed and 0 failed. At 88550bf they gave 417.

  • Round-2 review fixes (aac81df):

    • Finding 1. The review's input now refuses: the real #704 merge and 6.11.0, with data_releases.us.source_manifest_uri at @6.10.2 in the merge and @6.11.0 in the tag. Synthetic cases refuse too: old-version URIs in the UK and US releases, a changed package version, added markers, and 1 against true.
    • Mutants. All 9 comparator mutants are caught: the r1 string replacement, parsed equality, a skipped country rewrite, policyengine-only requirements, dropped markers, a kept source, a merged citation, no required-field guard, and a status-only check.
    • Finding 2. A duplicate dense datasets entry refuses through both _certified_by_installed_bundle and the script. The review's mutants (!= 1 to < 1 in datasets.py; == 1 to >= 1 in the script) are each caught.
    • Finding 3. REBUILD.md's fill commands run .venv/bin/python scripts/fill_release_identities.py.
  • Real-data replay: main(--pr 704 --release 6.11.0 --target fallback) on local upstream blobs and the ee5c2dbe manifest exits 1, with 20 checks passing and 12 failing. All three certifying checks pass. The failures are expected, because 6.11.0 carries neither pair; this matches round 2's online result.

  • The merge of main (ece7c36): both conflicts resolve to this branch's side. docs/d2011-upstream.md takes Review policyengine-uk 2.151.0 as an exact Budget wheel beside 2.147.2 #38's final audit wording.

  • Protected material is unchanged against main: the C2 frozen section (5,114 bytes, ce198c83…), the redact_records/RECORD_FIELDS AST, expected_value.py, handoffs, receipts, data/pilot and data/certification.

  • The lock re-resolution command reproduces the current 86 pins byte for byte, comment lines aside (verified at 88550bf).

  • Independent review: GPT-6.1 Sol requested changes on 72898f6 and 88550bf. It approved ece7c36 (round 3, pr39-review-ece7c36.md), with no blocking defects and five non-blocking items, fixed in 6a3f00e. That review also ran a Hypothesis differential of 3,000 generated merges against upstream's own sync_bundle_versions and manifest_text, with no disagreement. Round 4 approved 6a3f00e with no defects (pr39-review-6a3f00e.md). Round 5 approved c48aa2a (pr39-review-c48aa2a.md): it verified all 8 release identities independently, reran the fill from 6a3f00e (32 and 37 checks passing) and got 458 focused tests passing on 6.11.1. Its one non-blocking item, wording that still called the carrier pending, is fixed in 9452630. That commit also updates method_limitations() (whose sentence goes into the results file) and the preflight's refusal text. Later rounds approved each head with no blocking defects. Their non-blocking items are fixed:

    • Round 6 (9452630): older wording, fixed in 30961ed.
    • Round 7 (30961ed): a tampered-manifest preflight test that refused before reaching provenance. Fixed in f08f85d; the new test catches a mutant that drops the preflight's certified check.
    • Round 8 (f08f85d): no test caught the deletion of the installed manifest's digest check. Fixed in 61363c1, which adds a same-content, other-bytes test for both pairs; that mutant now fails 6 tests.
    • Round 9 approved 61363c1 with no defects (pr39-review-61363c1.md): 464 focused tests pass, and 137 with the identities reset to pending.

🤖 Generated with Claude Code

d2011 = A (Max, 25 Oct): the binding primary moves from #715's a133f37a /
UK 2.147.2 pair to the 2.151.0 national and local-area pair built at
microcosm#1396. The model pin, lock, CI, config.PRIMARY_DATASET, the
certified bundle (d2011 wheel attestation), the dataset registry, the
pending bridge endpoints, the preflight and the release wording move to it.

The staged national's bytes (b96a8cd6) and its expected release tag are
pinned. The carrier version and manifest digest, the certifying pull
request and commit, and the local-area file stay None, and each fails
closed. The certified-bundle check now requires the pair's exact region
routing (national plus constituency and local-authority to the local-area
file) and refuses a pending path. #715's pair stays registered, with its
own pending identity, as d2011's fallback.

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

vercel Bot commented Oct 25, 2026 •

Copy link
Copy Markdown

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

Project Deployment Actions Updated
uk-triple-lock Ready Ready Preview Oct 27, 2026 4:31am UTC

Request Review

Cherry-picks #40 (4edb1c0) onto the bind, and applies the same correction to
d2011's a6299504. Each build solves its household weights at 2025 and
writes them at the 2024 data year divided by policyengine-uk's own
2024-to-2025 projection (build_record.json export readback weight_year:
dataset 2024, solve 2025, factor 1.0072; microcosm weight_year.py, #796
A19). Its calibration_diagnostics.json dates every target 2025 (1,259 for
a133f37a, 1,268 for a6299504). So the model's 2025 weights are the solved
ones, and the registry's rule (a build's calibration year is its anchor)
puts both anchors at 2025. a133f37a's entry had said no calibration year
was declared. A new test holds that rule for every registry entry.

No binding Microcosm run exists yet, so no result moves.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…s, and script the release fill

- Read the certificate's covered core by policyengine.py's own rule
  (provenance/manifest.py DataCertification, provenance/receipt.py
  _certificate_fields): the named certified_for_core_version under
  core_binding "certified", else the bundle's core pin ("bundle_pin", or
  no binding before October 2026). 6.11.0's bundle_pin certificate has no
  certified_for_core_version, so a genuine release in that form was
  refused.
- d2011's fallback is a133f37a with policyengine.py #699's area routing,
  not #715's national-only candidate: the entry now requires national plus
  constituency and local authority to one local-area file, with every
  release identity pending in datasets.FALLBACK_*.
- scripts/fill_release_identities.py reads the UK bundle manifest at the
  release tag (the release workflow's version commit rewrites it after the
  certifying merge), checks every pinned identity, and with --apply fills
  the five pending ones, the carrier pins and data/binding-bridge.json. A
  rerun on the installed wheel's manifest checks the filled identities.
- The release-manifest tests run for both pairs; new core-binding and fill
  tests. Stale d2011 and #715 wording updated outside the frozen C2 section.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
MaxGhenis and others added 2 commits October 25, 2026 16:49
…nding

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… weights are calibrated x 0.9956

Review of 4edb1c0: the release wording and the a133 registry note called both
datasets' 2025 weights the calibrated ones, but METHOD.md's Enhanced FRS level
note (policyengine-uk-data#538) gives runtime = calibrated x 0.9956. demography's
module note still said the binding Microcosm cut anchors at 2024.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
MaxGhenis and others added 2 commits October 25, 2026 17:34
Review of 8901d55: demography's note gave the identity to every Microcosm
cut, but 5c6b3f68 (built at microcosm 64c460b) predates #1095's division by
the model's projection factor, so its 2025 weights are its solved ones times
1.0072. METHOD's level note and CALIBRATION_ANCHOR's superseded note now say
which builds divide, and that 5c6b3f68 also anchors at 2025 (since 95732e2).

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

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

Answers the review of 72898f6 (blocking 1-3; blocking 4 was fac3d5d).

Local-area cut (blocking 1). Every cut publishes microcosm_uk_2024_25_dense.h5,
so the file name identified nothing: a6299504 routed to any dense cut certified.
datasets.local_area_cut now pins a cut's file, tag, SHA-256, release manifest
URIs and digest, the model its build ran and the basis of the routing.
- The fallback's 19 October cut (ee5c2dbe, 8e10e130..., manifest b9dc7cae...,
  built on 2.132.6) is pinned now, on #699's accepted mismatch: the bundle must
  carry #699's regional_certification for exactly that mismatch and the
  regional manifest digest.
- The binding cut is pending in four BINDING_LOCAL_AREA_* identities. Its basis
  is "built_with" 2.151.0, so a regional_certification block refuses.
- _local_area_routed is the one check: the installed-bundle check and the fill
  script both call it.
- A released-manifest certificate now also needs its certifying pull request
  and commit (non-blocking 3).

Certifying merge (blocking 2). In --release mode the fill requires the pull
request merged, its merge commit in the tag (compare: ahead or identical), and
the manifest at the merge commit equal to the tag's apart from the version
strings the release workflow rewrites. On the real releases: #704 against 6.11.0
passes, #555 against 6.11.0 fails. --apply needs --release (non-blocking 6).

The fill reads the cut's own release manifest at its tag (or
--regional-manifest): cut_tag, build model and core, dataset role and the
microdata artifact must match. On the real 6.11.0 release the binding target
refuses its ee5c2dbe cut ("local-area build model 2.132.6"), the review's
failing input.

State-independent tests (blocking 3). Tests now hold whether the identities are
pending or filled.
- The fill tests build a pending copy of the tree and patch datasets to
  pending (tests/released_pair.py builds the release manifest).
- The pin, provenance and preflight tests branch on BINDING_BUNDLE_VERSION.
  Filled and installed, provenance must certify the pair.
- New: a pair is wholly pending or wholly filled, and the lock satisfies the
  installed carrier's requirements.

Also:
- fill() builds and checks every file before writing any, and replaces with a
  function, not a template (non-blocking 1 and 10).
- Tests cover the --release path: the tag read, the version check and the
  merge checks (non-blocking 2).
- The preflight reads the bundle of whichever of datasets.D2011_PAIRS
  config.PRIMARY_DATASET names, and REBUILD lists every move a fallback commit
  makes (non-blocking 5).
- REBUILD documents re-resolving the lock: at the preparatory carrier the uv
  command reproduces all 86 pins exactly. The pyproject, lock and CI comments
  are version-neutral (non-blocking 7).
- Stale text fixed: the a6299504 tag exists with the pinned bytes, the runtime
  note, and "stricter than policyengine.py's rule" (non-blocking 8 and 9).

The frozen C2 section is unchanged (d69a7b4a7429). expected_value.py,
redact_records, handoffs and receipts are not touched.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@MaxGhenis
MaxGhenis changed the base branch from d2011-uk-2151-support to main October 26, 2026 04:45
MaxGhenis and others added 2 commits October 25, 2026 22:26
…ng merge

The r2 review found that the certifying check read the old carrier version as
the new one in every string, so a source URI that changed from @6.10.2 to
@6.11.0 passed as a version rewrite.

fill_release_identities.as_released now replays the release workflow as at
policyengine.py 6.11.0. bump_version.py's sync_bundle_versions sets the carrier
version fields and each country's bundle id. generate_bundle_artifacts.py's
normalized_manifest sets each package's install requirement and the citation,
and drops source. The tag's manifest bytes must equal that rewrite of the
merge's manifest exactly. Nothing else may differ, so a value Python compares
equal (1 and true) also refuses.

Tests:
- A differential test against four vendored public policyengine.py manifests
  (#704's merge and 6.11.0, #555's merge and 6.2.6): the replay writes both real
  releases byte for byte, and #555's manifest is not 6.11.0's.
- The review's old-version source URI, on real and synthetic manifests.
- A duplicate local-area datasets entry refuses through both the installed check
  and the script.
- Every comparator and uniqueness mutant tried is caught.

The REBUILD.md fill commands now run the script with .venv/bin/python.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Both conflicts resolve to this branch's side: the #40 text it cherry-picked, with
a6299504 named, and the pair's re-pointed registry entry. #38's final LBTT and
#2129/#2569 audit wording comes from main.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Round 3 approved ece7c36 and raised five non-blocking items:

1. as_released's docstring said it returns None wherever the workflow would
   fail. It returns None only where sync_bundle_versions or
   normalized_manifest would fail on the merge's structure. The workflow's
   validation and pre-versioning checks are not replayed; the tag must equal
   the rewrite in any case.
2. The module docstring and REBUILD.md now also say that source is dropped.
3. Tags equal to the rewrite in content but not in bytes now refuse, both
   through certifying_checks and through main(). The cases are compact JSON,
   no final newline, unsorted keys, and unescaped non-ASCII.
4. Non-ASCII text is written escaped, as the workflow writes it, whether the
   merge's bytes were escaped or UTF-8.
5. Non-dict data_releases entries are left as sync_bundle_versions leaves
   them.

All 15 comparator and uniqueness mutants are caught, including the review's
four survivors.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
policyengine.py 6.11.1 (tag b14ee554, 27 October 01:30Z) carries d2011's
2.151.0 pair, certified by policyengine.py#720 (merge 610ebc42 of reviewed
head 99a3e48b), before d2011's Tuesday 18:00Z deadline, so the fallback is
not taken. `scripts/fill_release_identities.py --pr 720 --release 6.11.1
--apply` passed all 32 checks at the tag, including that the tag's manifest
is byte for byte the release workflow's rewrite of the merge's (the release
workflow files are unchanged from 6.11.0 to 6.11.1), and wrote:

- datasets.BINDING_*: carrier 6.11.1, manifest SHA-256 ab60903b..., #720
  and 610ebc42, and the local-area cut c9df4b86
  (microcosm_uk_2024_25_dense.h5, cb3712f2..., release manifest 30be4754...);
- policyengine==6.11.1 in pyproject.toml and the lock;
- data/binding-bridge.json, the ready copy of the pending bridge config.

The lock re-resolve (`uv pip compile ... --upgrade-package policyengine`)
moved only policyengine, 6.10.1 to 6.11.1. Installed in a fresh .venv:

- the fill rerun on the installed wheel's manifest passed all 37 checks;
- check_upstream, both preflights and the model step's --validate-only
  passed;
- the nine focused files gave 458 passed;
- the full suite gave 2297 passed, 5 skipped and the 3 documented
  stale-results failures, which CI's gate accepts for a PR into main.

The pending-release wording now describes the release, in:

- the lock's first comment and CI's install comment;
- datasets.py's docstring, the preparatory-carrier comment and the
  UNCERTIFIED reason (tests accept any reason starting "uncertified");
- README, which still named the superseded d1727 release;
- METHOD.md, outside the frozen C2 section, whose bytes are unchanged;
- REBUILD.md.

The fallback's identities stay pending.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@MaxGhenis MaxGhenis changed the title Bind the d2011 pair: UK 2.151.0 and Microcosm a6299504 (pending release) Bind the d2011 pair: UK 2.151.0 and Microcosm a6299504 (policyengine.py 6.11.1) Oct 27, 2026
Round 5 approved c48aa2a with one non-blocking item: four comments still
called the carrier or its manifest pending or future. They now describe
the release:

- pyproject.toml's pin comment;
- the lock's third comment;
- the a6299504 entry's `certified` comment in datasets.py;
- pipeline.py's module docstring.

Two more strings said the same thing:

- method_limitations(), whose sentence goes into the binding results
  file, said publication fails closed until the release exists. It now
  says 6.11.1 (policyengine.py#720) certifies the pair, and publication
  fails closed without exactly that installed bundle, as
  certified_bundle_preflight requires;
- the preflight's refusal text now covers both states: it refuses while
  the pair's identities in datasets.py are pending, and the fill pins
  them from the release (6.11.1 for the 2.151.0 pair). It still matches
  the tests' "d2011.*pending" in the pending state.

scripts/binding_bridge.py's docstring drops "pending". The pending
config's own refusal is unchanged.

Comments and wording only. The nine focused files and test_results gave
522 passed, with only the 2 documented stale-results failures, and the
preflight still certifies 6.11.1.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Round 6 approved 9452630 and listed four older sites that still described
publication as waiting for the release. A repository-wide sweep found two
more. All six now describe the release:

- engine.py's module docstring and config.py's dataset comment: the pair
  is released in 6.11.1, and publication requires exactly that installed
  bundle;
- the comment above datasets.BINDING_*: filled from the release, each
  failing closed while None;
- tests/test_certified_preflight.py's fixture comment;
- run_model_v2_j_bridge.binding_main's docstring: "the released bundle"
  for "the unreleased bundle";
- docs/RESULTS_SCHEMA.md: the binding build uses d2011's 6.11.1 pair,
  replacing the superseded d1727 promise.

Left as they are:

- historical review records;
- the fallback's pending identities;
- the pending bridge config's own refusal;
- the runbook's conditional fill instructions.

Comments, docstrings and one doc sentence only. Fifteen files, the nine
focused ones plus results, scenarios, cache-key, certification,
pilot-evidence and ageing-report, gave 887 passed, with only the 3
documented stale-results failures.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Round 7 approved 30961ed with two pre-existing P3 items:

- test_certified_preflight_refuses_tampered_installed_release_manifest
  installed carrier 99.0.0 against the pinned one, so the preflight
  refused on versions before reading provenance. The test's broad
  "d2011|released manifest" match accepted that. In the pending state it
  refused even earlier, on the unset identities. The test now pins a
  fictional released carrier, installed exactly, so only the tampered
  manifest can refuse. It requires the preflight's "installed released
  manifest does not certify the pinned pair" refusal. A mutant that drops
  the preflight's `certified is not True` check now fails the test; the
  old test passed it. The test passes in both the filled and the pending
  state.
- docs/d2011-upstream.md said certification stays closed until a release
  carries the pair. It now says 6.11.1 did, and certification requires
  exactly that installed bundle.

The nine focused files gave 458 passed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Round 8 approved f08f85d with two non-blocking test items:

- No test exercised the installed manifest's digest. Every tampered
  manifest was "{}", which also fails the structural checks. A mutant
  deleting `_certified_by_installed_bundle`'s SHA-256 comparison
  survived all 153 tests in the three provenance files.
  test_an_installed_manifest_with_the_released_content_but_other_bytes_is_rejected
  rewrites the released fixture's manifest with the same parsed content
  but other bytes: indented, key-sorted, or with a trailing newline. It
  requires certification first, and refusal after. It runs for both
  d2011 pairs, filled or pending, through tests/released_pair.py. The
  mutant now fails 6 tests.
- The tampered-manifest preflight test's docstring said only the
  manifest bytes could refuse. While the cut is pending, the pending
  local-area cut refuses inside provenance first. The docstring now says
  so.

Tests only. The nine focused files gave 464 passed; with the binding
identities reset to pending, test_budget_bundle and
test_certified_preflight gave 137 passed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@MaxGhenis
MaxGhenis marked this pull request as ready for review October 27, 2026 04:41
@MaxGhenis
MaxGhenis merged commit d6741e3 into main Oct 27, 2026
5 of 6 checks passed
@MaxGhenis

Copy link
Copy Markdown
Contributor Author

Merged on gates at reviewed head 61363c135df95fcde936a14c80f8b446cff0007a (merge commit d6741e34), as a merge commit.

  • Ruling: d2011 = A (Max, 25 October). The pair was certified by policyengine.py 6.11.1 / #720 before the 27 October 18:00Z deadline, so the fallback was not taken.

  • CI: gh pr checks 39 exited 0 on the latest run at this head. Pipeline tests and committed-output checks passed in 25m8s; dashboard lint, test and build passed; Vercel passed.

  • Mergeable: MERGEABLE, not a draft, no CHANGES_REQUESTED review.

  • Independent reviews: GPT-6.1 Sol, hard tier, via Subfleet. Each delta review approved its head:

    • round 5, c48aa2a (the release-night fill, rerun independently from the tag, the PyPI wheel and the Hub manifest): out/pr39-review-c48aa2a.md
    • round 6, 9452630: out/pr39-review-9452630.md
    • round 7, 30961ed: out/pr39-review-30961ed.md
    • round 8, f08f85d: out/pr39-review-f08f85d.md
    • round 9, 61363c1, with no defects: out/pr39-review-61363c1.md

    Paths are under ~/reviews/uk-triple-lock-2026-09-29/.

  • No survey or Microcosm simulation was run for this PR. The binding bridge runs next under the Fleet ops booking uk-tl-bridge-2026-10-27.

@MaxGhenis
MaxGhenis deleted the d2011-bind-2151-pair branch October 27, 2026 07:12

This branch was successfully deployed

1 active deployment
Preview — 61363c13 Deployed Oct 27, 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.

1 participant