Wire the eCPS parity gate: pinned incumbent reference, reason'd exemption register, release-blocking (#313)#316
Merged
Merged
Conversation
Compute per-variable nonzero record shares of the incumbent enhanced-CPS artifact ONCE and check them in as a frozen reference, plus a reason'd, issue-linked exemption register seeded from the first parity run. This is step 1 of wiring parity_gate into the US release (populace#313). - us/ecps_parity_reference.json: 158 populated input layers of hf://policyengine/policyengine-us-data/enhanced_cps_2024.h5 @ 21280dca (sha256 0a6b961a…805b14, vintage 2024), scoped to engine input variables (formula-owned excluded) with entity-id/membership structural columns removed. Never recomputed from a moving artifact. - us/ecps_parity_known_gaps.json: 110 gaps the current small national candidate (populace_us_2024.h5) does not populate, each with a reason and an existing tracking issue (#312 take-up, #49 wealth, #32 SPM, #253 education credits, #298 QBI, #242 hours, #274 capital-gains detail, #38 remaining tax-input/reported-observation layers). - us_runtime/nonzero_shares.py: us_nonzero_shares — the per-record nonzero-share evidence the parity gate consumes, matching the canonical plan._nonzero_share convention so reference and candidate are measured identically. - Declare both JSONs in us/country_package.json (the loader refuses undeclared files). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
us_runtime/parity_reference.py loads the two checked-in facts the parity gate depends on, with importlib.resources (the fiscal-target idiom) and loud validation: - load_ecps_parity_reference -> EcpsParityReference (shares + artifact provenance). Refuses an empty share map so a corrupted reference can't make the gate vacuously pass. - load_ecps_parity_known_gaps -> tuple[ParityKnownGap]. Refuses any entry missing a reason or issue ref. Tests cover reference-JSON integrity (including that the recorded sha256 matches the real cached incumbent bytes at the pinned revision — runs, not skipped, when the artifact is in the HF cache), the register schema (every entry reason'd + issue-linked), and that the register names only real reference layers. Re-exported from us_runtime. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Pass the enforced parity variant into the manifest builder so build and release manifests null the parity block under --allow-ecps-parity-gaps, and count enforced parity failures in the build_manifest calibration verdict. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…nce from the incumbent-string scan The parity reference must name the incumbent it pins (sha-locked historical record, not a live dependency); the hygiene test gains a three-file documented allowlist. Builder-test fakes widened for the new gate kwarg. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…nto ecps-parity-gate Both-add conflicts resolved keeping all sides: builder-test fakes in stage order (take-up before parity), both gate kwargs and manifest blocks. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This was referenced Jul 6, 2026
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.
Fixes #313.
What ships
us/ecps_parity_reference.json— per-variable nonzero shares computed ONCE from the sha256-verified incumbent eCPS artifact (source sha + vintage recorded in-file; integrity test asserts the recorded sha matches the cached incumbent bytes). Never recomputed from a moving file.us_runtime/parity_reference.py): reference + exemption register, schema-validated.parity_gatethreaded through the release tool (gate computation, failure aggregation, manifest/summary serialization at all three surfaces), release-blocking with an--allow-ecps-parity-gapsescape hatch mirroring the input-mass gate's flag.First-run gap census (from the seeded register)
The first comparison against the current base artifacts surfaces ~110 reference-populated layers the candidate does not populate. By family: 42 general input layers (#38 — retirement distributions, occupation descriptors, fine geography, demographic flags; dedicated children recommended), 16 QBI/passthrough qualification layers (probable root cause of #298's −31/−40% QBI base), 15 SPM inputs (#32), 13 take-up flags (#312), 8 wealth/assets (#49), 7 education-credit inputs (#253), 5 hours-worked (#242), 4 capital-gains detail (#274).
household_weightis a representation difference (incumbent column vs typed Frame weights), not a gap.Verification
ruff checkclean.test_gates.py), reference integrity (sha matches cached incumbent bytes), register schema (reason + issue required, unique entries, reference-layers-only).Provenance
Built by directed agents across three runway-limited sessions with the lead session performing final integration (hygiene-test allowlist, builder-test fakes, suite verification) and PR. Squash-merge recommended (history carries WIP salvage checkpoints). Full working log follows.
PROGRESS — eCPS parity_gate wiring (issue #313)
Branch:
ecps-parity-gate(worktree from origin/main @ 7e9a32d)PR: (not yet opened)
Goal
Wire
parity_gateinto the US release with a pinned incumbent-eCPS reference(committed JSON of per-variable nonzero shares + source sha256/vintage) and a
reason'd, issue-linked exemption register. Failure = nonzero exit; GateResult
details land in the release manifest.
Architecture findings (before writing code)
parity_gate(candidate_nonzero, reference_nonzero, *, known_gaps=())inpackages/populace-build/src/populace/build/gates.py:1347. Two share dicts +known_gaps= iterable of NAMES only (no reason mapping). Details:reference_populated_layers,gaps,exempted.GateReport.to_manifest()(gates.py:126) already serializes gate details.gates.json/GatesManifest(country_spec.py) is aBelgium-only greenfield construct. BE
gates.jsonpolicy note explicitlysays parity/export_surface/target_surface are "deliberately not selected"
(no incumbent).
ALLOWED_GATE_FUNCTIONS(country_spec.py:72) DOES list"parity" — so parity is a known gate id, just never selected by any spec.
tools/build_us_fiscal_refresh_release.py) does NOT loadcountry_spec/GatesManifest at all. US gates run as DIRECT function calls
(e.g.
input_mass_parity_gateat lines 3237/3261). => The seam for wiringparity into US is the direct call in the release tool, alongside the
geography-ladder and weights-audit gates. (Chosen seam; rationale recorded.)
packages/populace-build/src/populace/build/us/*.json,loaded via
from importlib.resources import files→files("populace.build.us").joinpath("X.json").read_text()(seeus_runtime/fiscal_targets.py:715).Reference artifact (incumbent eCPS) — PINNED
policyengine/policyengine-us-data(repo_type=model), fileenhanced_cps_2024.h5, revision21280dca5995e978d706740a8a4b9b7860cfd7b6(refs/main at compute time), sha256
0a6b961ad363a421bde99f2c8e5d8f20370bcba45fd303050537a25bdd805b14(verified: HF LFS blob name == content sha256). vintage/period 2024.
variable/2024HDF5 (244 var keys), NOT theUSSingleYearDatasetentity-table layout Populace publishes — so it cannot beloaded with
load_us_frame; read each variable array directly.(formula-owned excluded), intersected with eCPS keys, minus 10 schema-
structural entity-id/membership columns. => 179 present, 158 populated.
policyengine/populace-uspopulace_us_2024.h5(shac2065b64…), the small national support frame — populates 51 cols, 48 of them
reference-populated (parity OK on those).
us/ecps_parity_reference.json(158 shares + source sha/vintage),declared in
us/country_package.jsonresources.FIRST-RUN GAP LIST — 110 honest gaps (SURPRISING: far exceeds the 3 families)
The issue anticipated take-up (#312) + SCF wealth (#49) + SPM (#32). Those
cover only 36 of 110. Mapped the remaining 74 to EXISTING open trackers (no new
issues filed — lead files). Register
us/ecps_parity_known_gaps.json, 110entries, all reason'd + issue-linked. Distribution:
#38 (42) remaining US tax-input & reported-observation & demographic/geo
layers — the explicit catch-all tracker for exactly this residue
#298 (16) QBI / passthrough qualification (
*_would_be_qualified, sstb_*,REIT/PTP/BDC, UBIA, W2-QBI) — QBI base already off vs targets
#32 (15) SPM inputs (housing, child support, workers comp, MOOP/expenses)
#312 (13) take-up flags (
takes_up_*, WIC, voluntary-filing)#49 ( 8) wealth/assets/vehicles (net worth, SCF assets, auto-loan; see #252)
#253 ( 7) education-credit inputs (AOC / tuition)
#274 ( 4) capital-gains detail (collectibles / 1250 / 4952 / inv-interest)
#242 ( 5) hours-worked / labor inputs
NOTE for lead: #38 is doing heavy lifting (42). Its scope ("remaining US input-
layer work … release diagnostics expose reviewed exclusions") legitimately
covers these, but the lead may want dedicated children for: retirement
distributions (401k/403b/sep/keogh/IRA), occupation/labor-status descriptors,
fine geography codes (block/county/tract), and demographic flags. household_weight
is a genuine type-mismatch (incumbent stored a weight column; Populace carries a
typed Frame weight) — flagged under #38 as reported-obs-vs-exclusion.
Steps
check in JSON with source sha256 + vintage.
reference-JSON integrity (sha match).
Coordination
gates.py exports + release tool gate assembly. Rebase on origin/main before PR.
Log