Repository navigation
Gate the ACS local release on district ESS collapse (report-only by default) - #1088
Merged
Merged
Conversation
…efault Finalize reads the calibration summary's Kish ESS by congressional district at the design and the calibrated weights (weight_origin), counts districts whose calibrated ESS is below 0.25 x their design ESS and below an absolute floor of 15, and records the result as the district_ess_collapse gate (gate_summary.json and the build manifest) and the district_effective_sample_size_gate reviewed limitation. Whether it blocks releases awaits review, so blocking is the explicit --district-ess-gate-blocking flag, off by default; under it finalize fails a collapse or missing evidence, and package refuses a report finalize did not block on at the same floors. The default solve is unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
13 tasks
…e-gate # Conflicts: # tools/build_us_acs_local_release.py
- The release refresh recipe now names the district ESS gate's flags when the recorded gate differs from the defaults (non-default floors, or blocking), so a refresh rebuilds the recorded gate. - _district_ess treats a JSON integer too large for a float as malformed evidence instead of raising OverflowError. - Tests pin the below-floor order (smallest first, ties by district) and the tie-break for the smallest ESS and ratio; the property strategy draws factors of 0 or at least 1e-6, keeping subnormal squares out of the differential test's tie band. - The docs list district_ess_collapse among gate_summary.json's entries. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Main now reads consumer_reviewed_null_fills.json as {columns_filled, fills}
for the acs_local_reviewed_fill_consumers gate, so the finalize -> package
test writes that shape, as main's own round-trip test does.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- One example where ratio order and calibrated-ESS order differ, so the collapsed and below-floor sort keys can't be swapped unnoticed. - The parse-time refusal test checks the flag's own error message, not argparse's usage line. - The module docstring states the rescaling property at floors up to 0.99, as the test draws them. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Contributor
Author
|
Merged at head
|
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.
Why
#1078 measured Kish ESS by state and district for the ACS local release ("ESS floor as a release gate" in
experiments/us-acs-local-l2-basis-20260928/README.md). At the release's ACS share of 0.5:soft_chi_s050_0.01).Whether the gate should block a release is still open for review, so this PR builds the gate and records its result, but does not block by default. The tool already records the evidence:
calibration_summary.jsoncarriesweight_origin.{design,calibrated}.effective_sample_size_by_district.What changes
tools/build_us_acs_local_release.py, finalize stage:district_ess_collapse_gatereads both per-district ESS maps from the summary'sweight_origin. It counts:--district-ess-relative-floor(default 0.25) × design-weight ESS;--district-ess-floor(default 15).A floor of 0 turns its check off. Each district list is sorted worst first. The gate also records the smallest district ESS and the smallest ratio.
The result is recorded in three places:
gate_summary.jsonundergates.district_ess_collapse;build_manifest.json, which embedsgatesunchanged;district_effective_sample_size_gate, which reachesrelease_manifest.json. Its text states the counts, the smallest district and whether the gate blocked.Blocking is opt-in (
--district-ess-gate-blocking, default off).criteria_met. This is required, not cosmetic:_check_local_area_gatesinmicrocosm.data.contractrefuses to publish a local-area release with any gate whosepassedis not true, so a report-only gate recordingpassed: falsewould block publication anyway.simulation_readiness_blockerswhen any district collapses or falls below the floor. It does the same when the summary records no per-district ESS (fails closed).--stage package --district-ess-gate-blockingafter a report-only finalize would ship a collapse the flag exists to stop.The release refresh recipe names
--district-ess-relative-floor,--district-ess-floorand--district-ess-gate-blockingwhen the recorded gate differs from the defaults, so a refresh rebuilds the recorded gate. A default report-only build's recipe is unchanged.The default solve is unchanged. The tool edit adds one self-contained block (constants, the gate, its limitation, the package check, the recipe flags), a gate call, a limitation line and a hard-failure check in
do_finalize(10 lines), two calls indo_package, three flags with range checks, and a docstring line. Other open PRs edit this tool, so it touches no shared hunk. In particular it leaves Chi-square design-weight penalty and softmax mass parametrization for calibration; ACS local ESS frontier #1078's_ess_concentration_limitationand penalty flags alone.The README and a changelog fragment document the flags.
Evidence: the gate on #1078's solves
I replayed
district_ess_collapse_gateon the per-district ESS in #1078's 59 run receipts (results/runs/*.json,metrics.concentration.per_cd,kish_essandkish_ess_design). On every one of the 57 solves inresults/frontier.csvit reproduces exactly:cds_below_0.25_of_prior;cd_ess_min;n_cds(436).There were 0 mismatches. The replay was a local check and isn't committed: the receipts live on #1078's branch, and the replay script lived in a session scratchpad that has since been cleared, so nothing in either repo re-runs it.
frontier.csvhas no count below 15, so the "Below 15" column below comes only from that replay. At share 0.5:#1078's rerun of the release solve (
dup_release_repro) gives 16 collapsed, not 15, so the count moves by at least 1 between reruns. At ACS share 0.9 the unpenalized solves leave 261-328 districts collapsed and none below 15. So with share 0.9, the relative gate is the one that binds.Invariants
These are property-tested with Hypothesis in
packages/microcosm-build/tests/engine_free/us/test_us_acs_local_district_ess_gate.py. The weight-origin evidence is built bycd_surface.weight_origin_summary, the functioncalibration_evidenceuses.criteria_metholds exactly when both counts are 0. The entry survives a JSON round trip unchanged.passed,blockingandreport_only. A report-only gate always passes. A blocking gate passes exactly whencriteria_met, and the limitation'scalibration_blockerisnot passed.np.bincountKish ESS finds from the raw weights. Districts within 1e-9 relative of the threshold are excluded as floating-point ties, because the two compute sums in a different order.The replay above is a sixth, differential check against #1078's analysis code. It was executed, not committed.
Intended violation. A report-only gate records
passed: trueeven when districts collapse. This is pinned bytest_the_release_contract_publishes_a_report_only_gate_whatever_it_measured, because the local-area contract publishes only passing gates.Tests
<at both floors, worst-first ordering (collapsed by ratio, below-floor by ESS, with an example where the two orders differ), the tie-break for the smallest ESS and ratio, zero floors, a district with zero design ESS, integer ESS from JSON, 16 kinds of missing or malformed evidence (including an integer too large for a float), out-of-range floors (in the function and the parser), the limitation text, the contract interaction, and refresh-recipe flags that parse back to the recorded gate.test_us_acs_local_release_tool.py:gate_summary.jsonandbuild_manifest.json, with its limitation inrelease_manifest.json, accepted by the contract; both manifests' refresh recipes name--district-ess-gate-blockingexactly when the build blocked.Since the first review
20261002-074454-mc1088-review-1) at29921fb2: APPROVE, with 3 low findings and 5 nits. Lanes ran read-only, so it executed nothing.5cee50ab1addresses them:5cee50ab1: REQUEST_CHANGES on one blocker. The end-to-end test still wrote the pre-Gate reviewed default fills on their means-tested consumer notes (#1022) #1071 null-fill fixture, which CI engine-free (3.14) also caught.7fc818de3fixes it.8d8b75036fixes the nits: a ratio-versus-ESS ordering example, the parse-error message check, and the docstring's 0.99. That review also re-implemented the gate's rule in stdlib Python on Chi-square design-weight penalty and softmax mass parametrization for calibration; ACS local ESS frontier #1078's committed receipts and matched every share-0.5 number in the table, including the below-15 column. Record:~/reviews/mc1088-review-2026-11-11/runs/r2/reviewer.md.f61f64e98, 2026-11-11): one conflict hunk indo_finalize. It keeps main'sconsumer_export=consumer_exportargument tofinalize_reviewed_limitationsand the gate call before it.axiom: n/a: ACS local release tool gate; no policy rules change.🤖 Generated with Claude Code