Align national UC targets with paid claims and explicit source windows - #891
Conversation
vahid-ahmadi
left a comment
There was a problem hiding this comment.
Review pass at 2adb0cb8 (Claude Code, high effort; worktree checkout; without the engine: 935 passed, 7 skipped, 0 failed across fifteen ledger, reference, measurement, seam-driver, national-calibration, feed, gate and contract suites; ruff check and ruff format clean on the 19 changed Python files; ci_test_groups --verify, both census tools and the coverage manifest current; CI green apart from the wheel jobs).
The contract change reproduces from public inputs
- The feed pin is reproducible.
chronicle build-bundle --suite ukplusbuild-consumer-artifactatec7169b5regenerates both pinned digests exactly — facts4a50ee95…(131,450 rows) and manifesta95d0ee9…— so the packagednational_chronicle_feed.jsonis honest and the driver's refusal on either mismatch is safe. - Source-only zero. Main's generator and contract against the rebuilt feed: 430 candidates, 415 active, zero value or status changes.
- Exactly ten references move, and I recomputed every value from the archived #252 cubes as the twelve-month 2025 mean of the
payment_indicator: Yescells:dwp.uc.households6,758,889 → 6,197,311 (now derived from the family cube rather than the deductions table'stotal_units, which sat ~99k below the sum of its own family cells); the four family-type rows viamonthly_window_sum_averageover the ten entitlement operands; the five child-count rows viacalendar_year_averageonchild_entitlement: all/total_benefit_units. Membership shows the ten value changes, fiveuprating_holdsrows removed, nothing else; 415 active both sides. - The grid guard is strong.
_resolve_monthly_window_reference_facts(ledger_targets.py:1263-1345) refuses a wrong count, a duplicate month or cell, a missing cell, multiple series, mixed publication, measure, entity or geography, and non-distinct fact ids, with tests for each and a packaged-fixture refusal in the national-calibration suite. It does not interact with #874's fiscal-year coverage rule: window facts are month-typed and the period validation returns early forsource_window. - The annual/monthly proxy is declared.
uc_paid_comparison_contract(uc_target_measurements.py:43-93:universal_credit > 0, open nil claims not identified, the amount limitation) rides the resolver receipt whenever the paid measures are used, mirroring #883's TCL contract, and the doc repeats it.
Findings
1. Should-fix — the fit results in the body have no receipt in this PR. docs/evidence/uk-uc-882/source-target-diff.json says "no population or fit results"; the −14.37% → −14.01%, −14.77% → −12.78% and 8.97% → 4.72% figures live only in #892's calibration-comparison.json. They check out there, and both bodies agree, but if #891 merges first — as its body asks — it cites unreceipted numbers. Either carry the receipt here or say the numbers are receipted in #892.
2. Should-fix — the four dwp.uc.households_*@2025 deferrals keep rationales written against the old target. The register is untouched here, so those entries still quote "6.76m DWP admin" and the #813 partition while this PR moves the headline to 6.20m; #879's annotations already flagged them for fresh adjudication, and #892 then deletes them on a non-default run. Between the two merges the register is wrong about its own basis. A #879-style annotation here, or an explicit "merge #892 immediately after", closes the gap.
3. Question — "administrative family type from the model standard allowance" oversells what changes. uc_target_measurements.py:110-124 classifies couple by uc_standard_allowance > 12 × max(single rates); in 2.97.0 the allowance keys on the claimant count from is_uc_claimant, which microcosm exports from the same frs_uc_claimant_mask the structural composition uses. So the two partitions coincide by construction — #892's receipt confirms the structural and administrative runs identical on every row — and UNKNOWN is unreachable on the real engine. Children remain the reported proxy (~claimant & (qualifying | age < 20)), not uc_child_index; uc_child_element > 0 is a separate diagnostic. Consistent with the redraw's typing, and the contract doc admits the ineligible-partner gap, so this is framing rather than a defect.
4. Nit — asymmetric holds. The five sum rows drop their 2025-12 → 2025 uprating hold because _apply_uprating_hold skips source_window, while the five child-count rows keep theirs, for identically windowed targets. Metadata only.
Overlap and merge order
#892 contains #891 exactly (its 14 own files touch none of #891's), so #891 → #892 is consistent with the topology. #889 collides on membership, references, uk_population_targets.json, measure_simulation.py, the generator, the fixture rows and four test files, so it should rebase after both. The graph gap from #883 (uc_capital_coherence not consuming head/parent) is on main and fails a full source build with or without #891; #892 owns that fix.
Needs the licensed data
The 2.97.0 paired comparison, the capital-coherence requires_uk skip, and the local surface's reproduction from the 6fb700e feed (untouched here, so trivially identical).
Approving. The contract change is verified end to end from public inputs, and the body is candid that the lone-parent gap is not closed. 1 and 2 are about what a reader of this PR alone can see, not about the code.
|
The controlled comparisons show that this PR improves the broad UC count fit, but does not close the lone-parent gap. The population results are recorded in the companion #892's aggregate calibration receipt and diagnostic report. This PR's source-target diff records source compilation; the population receipt lives in #892. In the fresh paired experiment, both arms use the same rebuilt population, UK 2.97.0 outputs, household/source identities, priors, contribution matrix, active 366-row roster and coefficients. Both use 1,500 updates, learning rate .02, seed 0, free mass, a maximum weight/prior ratio of 10 and Evaluating both sets of weights against the same calendar-2025 paid targets:
Thus the broad fit improves substantially, while the fresh lone-parent estimate rises by about 7,776 claims. Comparing each run against its own differently defined target would show a larger apparent lone-parent improvement, from 17.73% to 14.01%; most of that apparent change is the comparison denominator. The retained-spine control also improves: its lone-parent shortfall against the same paid target falls from 14.77% to 12.78%, and broad-count error from 9.15% to 4.35%. Retained-versus-fresh differences combine pipeline changes and should not be attributed to this target repair alone. The source update by itself changes zero compiled values under the old references. This PR deliberately replaces ten values using paid claims and explicit observation windows, retaining 415 compiled references and 366 active rows. The allowance-based and structural family classifications coincide on the tested UK 2.97.0 population because they use the same claimant inputs; that definition change creates no new support here and does not recover ineligible-partner cases. Two positive-target childless-couple payment bands still have zero records, so reweighting cannot fit them and the fresh production calibration correctly refuses export. The five-plus/TCL contrast still relies on one original family. Monthly cash timing, open/nil claims and exact child/date histories also remain unresolved. These limitations stay visible in #882. The intended merge sequence is #891 followed by #892 after its review changes. The four UC fit-deferral rationales retained here describe the historical pre-repair target basis, including the old 6.76m headline; they are not fresh causal evidence for the new 6.20m paid target. #892 handles the register changes and documents their non-default diagnostic basis. The results above justify the comparison-contract repair, without claiming a passing calibrated release or closure of #882. |
…oint guard, attested and frozen gates, honest draw and stretch keys (#355) 1. The size-checkpoint identity carries the solve doctrine and the doctrine solve asserts the restored max_weight_ratio, mass and target_loss_cap against today's doctrine after a resume; the writing run's code pin and build id ride in the checkpoint's provenance and are reported, not compared. 2. An --out that already holds a size checkpoint is refused before the solve. 3. microcosm.calibrate.gates and microcosm.calibrate.initialization join the seed-protocol implementation digest, and the pre-best-iterate oracle runs with a frozen copy of the gate module loaded as pre_best_iterate_gates, so a gate-behaviour change surfaces as a numeric mismatch on the gated control path instead of being absorbed on both sides. 4. The size receipt reports certainty_share, boundary_draws and zero_target_rows; the manifest distinguishes the realized stretch against the refit's reference from the stretch against the pool design weights. 5. The written-checkpoint receipt carries no timestamp and no absolute path. Rebased over #891. The attestation change moved the seed protocol, the pointer inventory, the field and mode counts and the resolved_seed_protocol claim, the country-bundle digests, the loader golden vector and the US spec digest; all re-cut, the coverage report regenerated. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Vahid (CHANGES_REQUESTED at 0a8787d): - Blocker 1: the candidate manifest keys this PR renamed are read under their new, Chronicle-named shape by the release preflight, the dense-release assembler, the incumbent-surface evaluator and the microcosm-data release contract: identity.targets.chronicle, census_household_uprating with per-grain factors, ladder_assignment_provenance, household_dispersion (ladder_vs_chronicle_household_dispersion / chronicle_households); manifest and dry-run plans are schema_version 3; the contract names a missing identity instead of silently skipping the surface evaluation. Frozen ledger-named surfaces stay per the chronicle_epoch rule. - Blocker 2: rebased onto main 141bfac (previous commit); national references regenerate byte-identical to main, the local surface is unchanged; main's stale national parity receipts refresh on its own pin. - Should-fix 3: the census source rows cite the artifacts Chronicle pinned (Nomis NM_2059_1 TYPE172/TYPE424, NRS UV404 CSVs on UKDS CKAN, NISRA PARLCON24/LGD14). - Should-fix 4: the receipt states the A17 rule is unchanged while its factor moves from 1.0335759 to the LA-grain 1.0335595; all 1,011 cells before and after in docs/evidence/uk-887/census-households-cells.json. The f100 re-measure is deferred by ruling. - Should-fix 5: local_area_support_exclusions.json is schema 3 with a signed bound_despite_support_floor.census_households block; the generator reads excluded areas and binding families from the register. - Questions: ons.census.households carries the occupied-household measurement filter and the exact-signature skip is reverted, so the census cells pair only through the composition bridge, never with dwelling stock; fence and adjudication say so. - Nits: touched files formatted; households-only identities joined by area code; the NISRA lookup sha pinned in local_area_crosswalk.json. Max (source review at 0a8787d): - The households-only scope now runs through uk_local_target_surface, so it applies the per-grain A15 factor and carries the uprating receipt. - openpyxl is declared in the microcosm-build[uk] extra with a named import error in the NISRA loader; the workbook tests skip without it. CI on the rebased commit: main's #891 seam-driver test now asserts the reviewed local pin, and the workbook tests importorskip openpyxl before the loader imports it. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Vahid (CHANGES_REQUESTED at 0a8787d): - Blocker 1: the candidate manifest keys this PR renamed are read under their new, Chronicle-named shape by the release preflight, the dense-release assembler, the incumbent-surface evaluator and the microcosm-data release contract: identity.targets.chronicle, census_household_uprating with per-grain factors, ladder_assignment_provenance, household_dispersion (ladder_vs_chronicle_household_dispersion / chronicle_households); manifest and dry-run plans are schema_version 3; the contract names a missing identity instead of silently skipping the surface evaluation. Frozen ledger-named surfaces stay per the chronicle_epoch rule. - Blocker 2: rebased onto main 141bfac (previous commit); national references regenerate byte-identical to main, the local surface is unchanged; main's stale national parity receipts refresh on its own pin. - Should-fix 3: the census source rows cite the artifacts Chronicle pinned (Nomis NM_2059_1 TYPE172/TYPE424, NRS UV404 CSVs on UKDS CKAN, NISRA PARLCON24/LGD14). - Should-fix 4: the receipt states the A17 rule is unchanged while its factor moves from 1.0335759 to the LA-grain 1.0335595; all 1,011 cells before and after in docs/evidence/uk-887/census-households-cells.json. The f100 re-measure is deferred by ruling. - Should-fix 5: local_area_support_exclusions.json is schema 3 with a signed bound_despite_support_floor.census_households block; the generator reads excluded areas and binding families from the register. - Questions: ons.census.households carries the occupied-household measurement filter and the exact-signature skip is reverted, so the census cells pair only through the composition bridge, never with dwelling stock; fence and adjudication say so. - Nits: touched files formatted; households-only identities joined by area code; the NISRA lookup sha pinned in local_area_crosswalk.json. Max (source review at 0a8787d): - The households-only scope now runs through uk_local_target_surface, so it applies the per-grain A15 factor and carries the uprating receipt. - openpyxl is declared in the microcosm-build[uk] extra with a named import error in the NISRA loader; the workbook tests skip without it. CI on the rebased commit: main's #891 seam-driver test now asserts the reviewed local pin, and the workbook tests importorskip openpyxl before the loader imports it. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Positive annual model UC was calibrated against counts that included open claims with no payment. This changes ten national headline/family/child-count targets to explicitly paid claims using the complete calendar-2025 observations from Chronicle #252, and measures administrative family type from the model standard allowance while retaining structural claimant roles.
The source-window compiler requires a complete month-by-cell grid and averages monthly sums using the declared month denominator. It also supports an explicitly declared fiscal-year window without weakening existing period policies. The national facts and manifest hashes are pinned separately from the existing local surface. Publisher child-entitlement Totals, unknown categories and literal zeros are preserved. No targets, exclusions or family coefficients are added or changed outside the declared ten value replacements and family bindings.
Validation includes synthetic source/measurement/driver tests, full hash-pinned national and unchanged local reference regeneration, and fixed-budget comparisons with UK 2.97.0. The source update alone changes zero compiled values; the repaired contract changes exactly ten of 415 references, retaining 366 active rows. See
docs/uk-uc-paid-target-contract.mdand its source-diff receipt.The repair improves the broad UC count fit but does not close the lone-parent gap. In the fresh paired comparison at 1,500 updates, the same-paid-target shortfall changes from 14.37% to 14.01%; the ten broad count rows' weighted mean absolute percentage error falls from 8.97% to 4.72%. The retained comparison improves the lone-parent shortfall from 14.77% to 12.78%. The allowance and structural classifications agree on that sample.
The companion #892 contains the fresh build repair, reproducible support diagnostics and aggregate results. Two empty upper payment bands still prevent a passing calibration export; concentrated five-plus support, monthly cash timing and exact April claim/birth histories remain unresolved. This PR advances #882; it does not close it. Merge this PR before #892.