Rowwise local solve surface under the doctrine (#495 increment 6b) - #541
Merged
Conversation
…e doctrine Increment 6b of the UK dense/local epic (#495) — the US Build-N shape for the UK. build_uk_rowwise_local_matrix places each cloned household's metrics only in its assigned constituency's target rows (one column per household, never area x household stacking) and fails closed when the target surface does not cover an assigned area: local misses are support or target work, never silent exclusion. solve_uk_rowwise_weights_under_doctrine mirrors the stacked doctrine solve's structural knob-freedom (no per-target parameters, no doctrine injection point, uniform-surface refusal) with rowwise initial weights: the household base weights floored at min_initial_weight, never split across areas, since a rowwise household exists in exactly one area. The shared torch core is extracted as solve_prepared_local_weights — the stacked path routes through it unchanged (regression-tested) and both shapes carry the #492 past-cap census. rowwise_area_support_summary reports per-area assigned/nonzero households, distinct sources, weight mass, and effective sample size over every target area. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…w fence, calibration mass record, hardened core Adjudicated findings from the sol review of #541 (all three blockers confirmed): - The matrix builder fails closed on unreachable rows: a nonzero target whose area has zero household support would sit invisibly inside the loss cap; it now refuses with named (area, metric) examples, while zero targets with zero support remain consistent. - The doctrine solve refuses zero base weights outright — the positivity floor must not resurrect dead rows; reviving them is upstream work with a recorded mass change. min_initial_weight=0 is now allowed (parity with the stacked path) since positivity is guaranteed by the refusal. - rowwise_calibration_mass_record constructs the mass-change record a calibration must append before write; the #501 writer's chain-currency fence already refuses an unrecorded mass change, and the solve docstring now points at that contract explicitly. - solve_prepared_local_weights validates dimensionality, finiteness, matrix/target/frame alignment, and non-empty surfaces (NaN weights and (n,1) broadcasting no longer slip through); the stacked path's established base_weights error message is restored. - The builder refuses duplicate metric labels by name and metric columns colliding with target-frame metadata names (silent metadata calibration). - Support summary normalizes inputs: 1-D weight enforcement and composite (tuple) source ids handled without object-array coercion. - Nine review tests added covering each refusal, the mass-record helper, and the zero-target-with-zero-support allowance. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Contributor
Author
|
Cross-family review completed (sol adversarial pass, fable adjudication) — all three blockers confirmed and fixed in the second commit:
Should-fixes all fixed: prepared-core validation (NaN/shape/alignment/empty-surface, finding 4), metadata-name collision refusal (finding 5), named duplicate-label refusal (finding 6), support-summary input normalization incl. composite ids (finding 7), restored stacked error fidelity (finding 8), and the nine tests (finding 9). Sol's bitwise-equivalence verification of the refactor across ordinary/conserving/L0/budget solves (finding 11) is the strongest evidence the shared core preserved behavior. 41 solve-family tests green; ruff clean. |
This was referenced Jul 25, 2026
MaxGhenis
added a commit
that referenced
this pull request
Jul 25, 2026
Increment 6d of the UK dense/local epic (#495): one command from the national staging H5 to a calibrated rowwise candidate, composing the three merged increments — the ladder clone route (#540), the rowwise solve surface (#541), and the census household-count family (#542). Pipeline: load the ladder, clone through the ladder route (release gate runs before a result exists), bind the constituency household-count targets from the SAME loaded ladder (pairing provenance recorded), solve one weight per cloned household under the reviewed doctrine, append the canonical rowwise_calibration_mass_record, re-gate on the calibrated weights, transition the weight kind to CALIBRATED through assert_kind_transition, and write the candidate H5 with evidence sidecars. The candidate is an adjudicated partial by construction: exactly one target family is bound and named in the manifest as bound_target_families; unbound census families stay unbound rather than approximated. Publication is deliberately NOT automated — the tool writes a local candidate and its evidence, nothing more. Implementation delegated to sol (gpt-5.6-sol) cross-family and verified here: tests and lint re-run independently, the calibration path read line by line, and assert_kind_transition confirmed as a real populace.frame contract rather than an invented helper. Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
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.
What
Increment 6b of #495: the solve shape the rowwise candidate uses — one weight vector over the cloned households, where each household supports only its assigned constituency's target rows (the US Build-N structure).
build_uk_rowwise_local_matrix: one column per household; an area's rows draw support only from households assigned there; fails closed when the target surface misses an assigned area (the 650/650 requirement — misses are support or target work, never silent exclusion); reuses the stacked path'salign_area_targetscontract.solve_uk_rowwise_weights_under_doctrine: structurally knob-free exactly like the UK local solve doctrine: uniform operator, declared bounds, past-cap census (#495 increment 4) #503 stacked doctrine solve (no per-target parameters, no doctrine injection point, duplicate-surface refusal), with the one rowwise-correct difference: initial weights are the household base weights floored atmin_initial_weight— never split across areas, because a rowwise household exists in exactly one area.solve_prepared_local_weights: the stacked path routes through it unchanged (pinned by a regression test asserting the split-initialization behavior), and both shapes carry the Loss shape: flat cap at 1.0 makes past-cap rows free dumping grounds (17 rows pushed out in Build N); bounded-tail experiment + past-cap census diagnostic #492 past-cap census.rowwise_area_support_summary: per-area assigned/nonzero households, distinct source households, weight mass, ESS — over every target area, zeros included.Testing
8 new tests (matrix placement asserted cell-by-cell against hand values, uncovered-area/alignment/finiteness refusals, base-weight initialization pinned, knob-freedom signature + TypeError, duplicate-surface refusal, support summary hand-checked, stacked-behavior regression) plus the existing doctrine/solver/runner suites green (36 total in the solve family). Ruff clean.
Part of #495.
🤖 Generated with Claude Code