Skip to content

Re-bind the DWP UC composition and TCL disability-children targets to the publisher's grain (#808, #809) - #813

Merged
juaristi22 merged 2 commits into
mainfrom
808-809-rebind
Aug 28, 2026
Merged

Re-bind the DWP UC composition and TCL disability-children targets to the publisher's grain (#808, #809)#813
juaristi22 merged 2 commits into
mainfrom
808-809-rebind

Conversation

@juaristi22

@juaristi22 juaristi22 commented Aug 28, 2026

Copy link
Copy Markdown
Collaborator

Closes #808 and closes #809 (mechanism 3). Part of the #796 capstone queue — these bindings own 5 of the 6 cells still blocking uk_target_fit.

The defect

DWP's "household" is the UC unit of assessment — the benefit unit — and the spine carries FRS benunit ids natively. But the nine composition targets (households_children_1..5_or_more + the four family-type cells) were bound at household grain: "children == 2" summed is_child over the whole dwelling (other benunits' children included), and "SINGLE" meant "any benunit in the household". A single childless claimant sharing a dwelling with another family's child was deleted from single_no_children (−26.5%); a 1-child claim beside another benunit's child was counted as 2-children (children_2 −36.9% while 1/3/4 fit — the signature of mass leaking across adjacent counts). The headline dwp.uc.households and the payment_distribution_* targets were already benunit-grain, so the composition cells weren't even a partition of the headline. The #757 audit patched this same overcount class on the ONS composition cells (lone_households_under_65, couple_no_children) but missed the UC ones. This is also the same defect class as #791households_single_no_children was literally the union of the two #791-excluded ONS cells minus their disambiguating predicates — but the UC fix needs no relationship-to-head column, just the grain the spine already carries.

The two TCL disability children cells (#808, −56.5%/−40.2%) had a second binding bug: they summed uc_is_child_limit_affected (~1.27 affected children per household) against DWP sheet 04B facts that count every child in the affected household — the 3- and 4-children sibling rows divide to exactly 3.00 and 4.00 children/household, and these cells run 3.6–3.7. A structural ~2.8× shortfall no reweighting or disability-flagging could close; every sibling from the same sheet already sums is_child.

The change

  • Nine composition targets → benunit_count / from_entity: benunit with per-benunit filters over universal_credit, num_children (model BenUnit variable, age<18), and family_type; the single_with_children SINGLE∪LONE_PARENT compound collapses to family_type == LONE_PARENT at benunit grain. The QYP residue (DWP counts 16–19 qualifying young persons; age<18 doesn't) is declared in each binding's notes.
  • Two TCL children targets → value_variable/value_reduction sum is_child, structurally identical to the proven children_in_affected_households sibling.
  • Nine target_references.json rows flip entity to benunit per the authoring derivation rule. Membership, parity fixtures, and signed-differences resources untouched (comparators key on name/period/value).
  • Tests pin the new contract shape and the discriminating materialization cases (a LONE_PARENT claim counts its own child; a childless UC single counts despite a housemate's child; claimant-PIP materializes all-children counts, 4.0 not 3.0, beside the untouched children_affected pin).

Implemented by Codex from a reviewed plan (.codex-work/PLAN.md protocol), zero deviations; independently verified (129 delta-surface tests + ruff green).

Expected measurement (seam run follows on this branch)

Initial estimates for the two TCL cells should rise ~2.5–3× toward 235,270 / 479,460; the composition cells re-grain; the four family-type estimates must now sum exactly to the dwp.uc.households estimate — a coherence identity the old grain could never satisfy. Must-not-move: dwp.uc.households, payment_distribution_*, the TCL household cells and children_in_* (<0.4%), all non-UC families. The frozen scoring-register version flips; the candidate-eval pin re-freezes after acceptance.

Same-defect follow-ups deliberately out of scope: dwp.uc.scotland_households_child_under_1 (fits at −0.1% under the old grain; re-bind with its own measurement) and the local constituency matrix uc_hh_*_children (uk_runtime/local_targets.py:218-227, local-lane PR).

🤖 Generated with Claude Code

juaristi22 and others added 2 commits August 28, 2026 16:51
… the publisher's grain

DWP's "household" is the UC unit of assessment - the benefit unit, which
the spine carries natively from FRS BENUNIT. The nine composition targets
(households_children_1..5_or_more and the four family-type cells) move
from household_conditions (dwelling-wide is_child sums that counted other
benunits' children and any-benunit family types that deleted single
claimants sharing with children) to benunit_count with per-benunit
filters over universal_credit, num_children, and family_type - the
grain dwp.uc.households and the payment_distribution targets already
use. The single_with_children SINGLE-or-LONE_PARENT compound collapses
to family_type == LONE_PARENT at benunit grain. The age<18 num_children
concept omits DWP's 16-19 qualifying young persons - declared residue in
each binding's notes.

The two TCL disability children targets sum is_child instead of
uc_is_child_limit_affected: sheet 04B counts every child in the affected
household (the 3- and 4-children sibling rows divide to exactly 3.00 and
4.00 children per household; these cells run ~3.6-3.7), so the old
binding measured a ~1.27-per-household flag against a ~3.6-per-household
concept - a structural ~2.8x shortfall no reweighting could close
(microcosm#808). The nine reference rows flip entity to benunit per the
authoring derivation rule; membership, parity fixtures, and
signed-differences resources are untouched (comparators key on
name/period/value).

Addresses microcosm#808 and microcosm#809 (mechanism 3).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…tests

The contract-shape test asserts the nine composition targets are
benunit-grain (benunit_count, no household_conditions, filters only over
universal_credit/num_children/family_type) and the two TCL disability
children targets bind is_child in both value fields. The materialization
tests pin the discriminating cases the old grain got wrong: a LONE_PARENT
UC claim with one child counts in claimants_with_1_children while its
household-mate SINGLE benunit does not, a childless UC single counts in
single_no_children even when another benunit's child shares the dwelling,
and the claimant-PIP row materializes all-children household counts
(4.0, not the 3.0 affected-flag count) beside the untouched
children_affected pin.

Implemented by Codex from .codex-work/PLAN.md, zero deviations.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@juaristi22

Copy link
Copy Markdown
Collaborator Author

v13 seam measurement (spine-j, this branch, first run under the floored policyengine-uk 2.92.1) — the re-bind does what the diagnosis said. Receipts: runs/uk-623-first-calibrated/spine-assessment-v13/.

#808 cells clear exactly:

cell v12 v13 initial support
children_disabled_child_element −56.5% +0.1% 72,118 → 190,414
children_claimant_pip −40.2% −0.3% 72,943 → 182,933

The coherence identity holds to the household: the four family-type estimates sum to dwp.uc.households exactly, at initial (4,242,978) and final (5,501,928) — the composition cells are a true partition of the headline for the first time.

The honest composition picture (v12 → v13): single_no_children −26.5% → −7.4%, couple_no_children −0.0%, couple_with_children −5.9%, headline −20.6% → −18.6%, loss 0.030 → 0.0254. The COUPLE_WITH_CHILDREN payment band (−46.4%) also cleared — no uc_payment_dist cell is past the gate.

What the honest grain exposes — the residual concentrates in claims with children: single_with_children (LONE_PARENT) −35.7%, children_1 −29.6%, children_2 −35.4%, children_5_or_more −29.1% (cells that "fit" before were fitting a mis-measured concept). This is the real #809 residual and the take-up lever re-measurement's target.

Must-not-move held: all TCL household cells and children_in_* within 0.4%; children_affected +0.0%; payment distribution inside; non-UC families flat.

Watch item: the three #807-lifted hmrc cells drift up as the solver presses on genuine UC composition — private_pension_income_count_100_000_to_150_000 +23.3% → +25.5% (0.5pp past the gate), state_pension 50–70k +24.2%, self_employment 50–70k +20.3%. Marginal; expected to relax if the lever raise closes the UC gap from support rather than weight mass. v13 blocks on 5 cells: the 4 genuine composition cells plus that marginal hmrc count.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant