Skip to content

Repair UC capital graph inputs and document calibration support gaps - #892

Merged
juaristi22 merged 4 commits into
mainfrom
uk-uc-build-diagnostics-882
Sep 9, 2026
Merged

Repair UC capital graph inputs and document calibration support gaps#892
juaristi22 merged 4 commits into
mainfrom
uk-uc-build-diagnostics-882

Conversation

@juaristi22

@juaristi22 juaristi22 commented Sep 9, 2026

Copy link
Copy Markdown
Collaborator

The UK source graph failed at UC capital coherence because executor projection removed person.is_benunit_head and person.is_parent, which the claimant/couple predicate now reads. This PR declares both dependencies and updates the serialized graph fixture. The regression runs the actual projected capital transform with positive SPI reporters and claimant roles that disagree with legal marriage, checking donor values and redraw count. Existing UK-engine integration and H2 parity already exercise all 28 real transforms on synthetic source tables; broader conditional-branch fixture coverage remains follow-up work.

The fresh unsampled source build then completes all 40 graph nodes and 15 source-scope gates. This PR adds authenticated matrix/support diagnostics and aggregate evidence without private records or source IDs. #891 is merged; this PR is rebased onto main and carries the build/diagnostic increment plus its review fixes. It advances #882 without closing it.

The population comparison receipt is the authority for the fit results below. The separate source-only receipt checks target compilation and contains no population fit results.

The review fixes also express the five paid child-count averages as explicit twelve-month source windows, removing misleading December-to-year hold records and recording source months/publication identity. All 415 compiled values/statuses and the ordered 366-target active roster remain unchanged; the other 410 references, including 101 monthly UC references, and unrelated holds are preserved.

The fresh paired comparison moves the same-paid-target lone-parent shortfall from 14.37% to 14.01%, while the ten broad count rows’ weighted mean absolute percentage error falls from 8.97% to 4.72%. These runs use 1,500 updates and family_equal allocation, learning rate .02, seed zero, free mass, cap 10 and no sparsity penalty. They do not establish readiness under the unchanged defaults of 256 updates and uniform allocation. The allowance-based family proxy and structural classification coincide under the tested UK2.97 claimant inputs; the proxy adds no support, does not recover administrative ineligible-partner cases, and uses UNKNOWN defensively for zero model allowance.

Two childless-couple payment bands still have zero support and correctly block calibrated export. The five-plus/TCL contrast still depends on one original family. Named-subset linear programs are feasible, but the full supported system remains infeasible at 5% even after omitting the already-deferred OBR CGT target. A fixed-mass witness restricted to ±25% of current weights can put lone-parent claims within 1% while the other selected rows remain within 25%; income-tax and NI estimates fall 14.05% and 9.87% from current estimates. That witness is a diagnostic trade-off, not a releasable or optimized calibration. Zero rows and CGT are omitted only from the stated diagnostic subsets.

The PR retires these five #796 fit exemptions because their observed errors in the fresh 1,500-update candidate are inside the existing 25% bound:

Exact target ID Candidate relative error
dwp.uc.households_children_1@2025 −19.448861%
dwp.uc.households_children_2@2025 −6.420325%
dwp.uc.households_children_5_or_more@2025 +0.124633%
dwp.uc.households_single_with_children@2025 −14.006391%
hmrc/private_pension_income_count_income_band_100_000_to_150_000@2025 +0.044352%

The historical register preserves the original UC support/capital and related pension solver-pressure rationale, including later historical-basis annotations. The new errors do not revalidate those earlier causal claims. The gate rejects stale exemptions once their rows fit inside the bound, so retirement restores normal enforcement: any renewed absolute error above 25% blocks release. These targets remain bound in the solve. The CGT exemption under #875 remains unchanged (+44.771038% in this candidate). Replaying all 366 saved errors leaves exactly the two empty-tail failures. No calibrated H5 or passing calibration record is created; the original failed receipt is preserved.

The population receipt's retired_fit_deferral_evidence block preserves the full-precision values and canonical diagnostic SHA-256 971e6f8cac94b69ebf82364e83845f27d19fce38490a032524db237eb4884463 behind this table.

The committed tools/diagnose_uk_uc_lp_evidence.py reproduces all three published LP families: named opposition, the full supported system, and bounded redistribution with heterogeneous tolerances and fixed mass. The formatted producer exactly reproduces their deterministic constraint, status, fit, concentration and protected-outcome fields from the authenticated saved archives. New provenance binds the producer, imported helper, inputs, versions and result; original receipt/script hashes are preserved. The report's reproduction instructions give the command. This runs no population engine or Adam calibration and exports no witness weights or source IDs.

The diagnostic report records the controlled comparisons, source support, input hashes, gate evidence, and remaining age/claim/cash questions. Review validation passes 69 LP/support tests and 464 target/ledger/spec tests, with two existing default-feed-path skips; pinned national/local regeneration and exact saved-matrix LP evidence replay pass. Earlier validation covers the projected capital regression, graph/H2 integration, a real UK2.97 matrix-tool smoke case, and gate/battery/country tests. PR checks validate code contracts; they do not certify population artifacts.

@juaristi22
juaristi22 changed the base branch from uk-uc-paid-targets-882 to main September 9, 2026 13:35
@juaristi22
juaristi22 force-pushed the uk-uc-build-diagnostics-882 branch from 76238dc to c4d88c0 Compare September 9, 2026 13:56

@vahid-ahmadi vahid-ahmadi left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review pass at c4d88c00 (Claude Code, high effort; worktree checkout. This PR contains #891 — the merge-base of the two is #891's head — so I reviewed only #892's own 14 files (+8,067/−90); the ledger, target and feed changes in the 43-file stat are #891's and are reviewed there. Without the engine: 545 passed, 7 skipped on the capital, graph, redraw, measurement, parity, gates and diagnostics suites, plus 513 passed, 6 skipped on the #891-shared set; ruff check clean; ci_test_groups --verify, the parity census and the coverage manifest current; CI green apart from the wheel jobs pending.)

The graph repair is right, and #892 should own it

graph.py:195-196 adds exactly ("person", "is_benunit_head") and ("person", "is_parent") to uc_capital_coherence's consumes; the serialized fixture's structural diff touches only that node's person inputs. The new regression is real: with main's graph.py and fixture swapped in it fails with KeyError: "UC relationship person inputs missing: ['is_benunit_head', 'is_parent']" from uc_relationships.py:38, and passes with the PR. The legacy-versus-graph acceptance skips here without the engine; the engine-uk and spine-uk lanes are green. On why #883 did not catch it: _stage_slices checks only that declared consumes are available, nothing checks that a transform reads only declared columns, and #883's tests called cohere_uc_capital on a full frame — so only the graph path, which builds a minimal frame from consumed slices, could fail. The new test is stage-specific; a generic test that runs every stage in _STAGE_CONSUMES through the kernel's projection would catch the next instance of this class.

The same two-line hunk and the same fixture blob appear in #889 byte-identically, so those will not conflict, but the two PRs add differently named tests after the same line of test_uk_uc_capital_coherence.py, and git merge-tree reports that conflict plus five #891-overlap files. #889 should drop its copy and rebase after #891 and #892 land.

Findings

1. Should-fix — the headline LP evidence was produced by code not in the PR. tools/diagnose_uk_uc_support.py hard-codes fixed_mass_constraint: False (:158) and lp_probe takes a single scalar tolerance with bounds (0, cap_ratio). The committed evidence (docs/evidence/uk-uc-882/calibration-comparison.json) carries fresh_bounded_redistribution_lp_probes with fixed_household_mass_constraint: true, per-row tolerances (lone parent 5%, the rest 25%) and current_weight_multiplier_bounds [0.75, 1.25] — none of which the tool can express — and the one family that records a probe_script_sha256 (f99ca727…) does not match the committed tool (15df89f1…); the full-supported and bounded families record no script hash at all. So the tool reproduces its own two probes, but the ±25% witness, the "full supported set infeasible at 5% excluding CGT" claim and the named-opposition probes have no committed producer. Commit the probe script (or extend the tool with per-row tolerances and a fixed-mass mode) and record its sha in the evidence.

2. Should-fix — five signed fit deferrals are deleted on the strength of a non-default run, and the body says so only in passing. target_fit_reviewed_exclusions.json goes from six entries to one: the four dwp.uc.households_*@2025 deferrals and the private-pension count band are removed, leaving obr.capital_gains_tax@2025. The justification is the fresh run's errors, and the new test itself says that run is "1,500 epochs with the explicit family_equal override … not a default-doctrine fit claim". Since the gate fails stale exclusions anyway, removal is defensible — but retiring signed adjudications is a register change and the body should name the five and the basis, not fold them into "remove five obsolete terminal fit exemptions".

Verified good

  • The two zero-support bands are #879's (COUPLE_NO_CHILDREN £27.6–28.8k and £28.8–30k); uk_target_fit_gate is what refuses the export and test_restored_fit_checks_leave_empty_payment_tail_cells_blocked pins it with CGT excluded.
  • The tools are development-only (no import from any package, pyproject or workflow), need the licensed replay directory, and authenticate every input sha against the receipt. The committed evidence contains no ids or row-level data: the only long arrays are target-name lists, and the tool writes ids only to files it documents as local-only.
  • The LP is a highs feasibility problem with per-row relative bounds and independent post-verification; deterministic given the pinned scipy, with a time limit that can yield "inconclusive" on slow hardware.
  • The ±25% witness is labelled a diagnostic in both the evidence and the doc, no weights are exported, and no manifest or artifact is written as releasable.

Needs the licensed data

The policyengine-uk extra (seven skips including the parity acceptance and the matrix smoke), the private replay directory, and — until it is committed — the script behind the three LP evidence families.


Nothing blocks the graph fix; merge order #891#892 matches the branch topology. 1 is the one to settle before this is used as evidence in #882, since the strongest claims in the body currently rest on an uncommitted script; 2 is a body change plus the five names.

@juaristi22
juaristi22 force-pushed the uk-uc-build-diagnostics-882 branch from c4d88c0 to 1df5379 Compare September 9, 2026 16:05
@juaristi22

Copy link
Copy Markdown
Collaborator Author

Vahid, the review fixes are in 1df53792, including the remaining metadata and framing nits from #891.

  • Reproducible LP evidence: the committed producer implements the six named-opposition, three full-supported and one bounded-redistribution probes. One replay from the authenticated saved archives reproduced 3,633 deterministic fields exactly, including row selections, tolerances, statuses, fit, concentration and protected outcomes. Runtime and explicitly identified historical prose/provenance are outside that comparison. The public evidence preserves the original receipts/hashes and adds a separate attestation binding the producer, imported helper, inputs, versions and result. No population engine or Adam calibration was rerun, and no witness weights or source IDs are published. The report gives the reproduction command.

  • Child-count hold metadata: the five paid child-count targets now use the existing explicit twelve-month source-window average. This removes exactly five misleading December-to-year holds. All 415 compiled values/statuses and the ordered 366-target active roster are unchanged, as are the other 410 references, including 101 monthly UC references, and unrelated holds. Paid publisher-total selectors and all twelve CY2025 observations are preserved; no shared compiler rule changes. See the contract.

  • Deferral and fit attribution: the diagnostic report names all five retired WS-E spine deferrals: known bugs and signed inconsistencies awaiting their increment #796 exemptions, their exact errors and canonical evidence. It distinguishes the observed 1,500-update, family_equal candidate from the unchanged 256-update, uniform defaults. The absolute 25% gate remains unchanged: stale exemptions are rejected, and retiring them restores refusal on any renewed breach. The CGT exemption and both zero-support tail failures remain. Fit figures are attributed to the population receipt separately from source-only compilation. The allowance-based family proxy adds no support under the tested UK2.97 inputs, cannot identify ineligible partners, and handles UNKNOWN defensively.

  • Graph coverage: the capital regression exercises the actual transform after executor projection, forcing the reporter-redraw branch with claimant roles that disagree with legal marriage. Existing UK-engine graph/H2 integration already exercises all 28 real transforms on synthetic sources. Broader conditional-branch fixture coverage remains a scoped follow-up; running every stage alone does not establish it.

Local review validation: 69 LP/support tests and 464 target/ledger/spec tests passed, with two existing feed-path skips. Independent code/evidence and prose reviews are clean.

At the time of posting, 20 hosted checks have passed and the two installed-wheel suites are still running, with no failures so far (CI run).

These fixes make the evidence reproducible and its limits explicit; they do not close the lone-parent gap or certify a calibrated release.

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.

2 participants