Skip to content

Give children and couples who cannot share a bedroom their own bedrooms in the LHA size criteria - #2080

Draft
MaxGhenis wants to merge 3 commits into
lha-nondep-children-foster-roomsfrom
lha-disabled-cannot-share-rooms
Draft

MaxGhenis wants to merge 3 commits into
lha-nondep-children-foster-roomsfrom
lha-disabled-cannot-share-rooms

Conversation

@MaxGhenis

@MaxGhenis MaxGhenis commented Oct 2, 2026 •

Copy link
Copy Markdown
Collaborator

Fixes #2069. Stacked on #2016 (lha-nondep-children-foster-rooms), which is stacked on #2010 → #2006 → #1896. CI runs once it is retargeted to main.

What changes

The LHA size criteria now give bedrooms to children and couples who cannot share a bedroom because of disability. Until now both the UC and HB variables documented these rooms as "not modelled".

New input. cannot_reasonably_share_bedroom_due_to_disability (Person, default false) records the decision maker's or local authority's judgement. For a child it means the child cannot share with another child; for a member of a couple, with the other member.

Children who cannot share (is_child_who_cannot_share_bedroom): under 16, on the DLA care component at the middle or highest rate, and flagged. bedrooms_for_children gains a cannot_share mask. Each counted child so marked has a room of their own, and the other children are paired as before. A room is therefore added only where the child would otherwise share.

  • UC. Sch 4 para 12(6), (8). The children are those the renter or another member of the extended benefit unit is responsible for: own children, non-dependants' children, and a child placed for adoption, but not a foster child.
  • HB. Reg 13D(3)(ba). The children are occupier children: the claimant's own and those of non-dependants, boarders and lodgers, but not a child placed as a foster child or for adoption.

Couples, one of whom cannot share (is_member_of_couple_who_cannot_share_bedroom): the claimant or partner of a couple, on attendance allowance, AFIP, DLA care at the middle or highest rate, or PIP daily living, and flagged.

  • UC. Para 12(6A), (9)(d): one additional bedroom for the renter's couple.
  • HB. 13D(3)(za)-(zb): a bedroom each instead of one between them. This applies to any occupier couple, including a non-dependant, boarder or lodger couple counted by the household head's family.

HB dwelling condition (13D(3), closing words). These bedrooms count only so far as the dwelling has bedrooms beyond the entitlement if everyone could share, including the (3A)/(3B) rooms. The dwelling's bedrooms come from num_bedrooms. When it is 0, the default meaning "not reported", the room is assumed. The FRS's BEDROOM6 is always 1-6, but the released enhanced FRS does not carry it.

Variables

  • LHA_cannot_share_bedrooms (UC) is included in LHA_additional_bedrooms.
  • housing_benefit_LHA_cannot_share_bedrooms (HB) is added in housing_benefit_LHA_allowed_bedrooms, after a new helper housing_benefit_bedrooms_if_able_to_share.

Dates

  • Children: from 4 December 2013 (SI 2013/2828).
  • Couples: from 1 April 2017 (SI 2017/213).
  • Attendance allowance counts for couples only at the higher rate before 27 January 2025 (SI 2025/3 regs 3-5). This needed a new variable, receives_higher_rate_attendance_allowance.

Law checked

Revised texts were fetched from legislation.gov.uk on 2026-10-01, and the amending SIs were read as made (2013/2828, 2017/213, 2025/3). Notes and quotes: ~/reviews/lha-disabled-cannot-share-2026-10-01/law/LAW.md (local).

legislation.gov.uk's revised text of 13D(3) has editorial errors in both HB instruments:

  • SI 2006/213 shows the 2017 couple words in (ba) instead of the closing words.
  • SI 2006/214 lists (za)/(zb) after (a), although SI 2017/213 reg 5(3)(a)(i) inserts them "before sub-paragraph (a)".

The model follows the amending SIs.

Judgement calls

  1. Several children who cannot share. The model gives the fewest rooms in which none of them shares. Example: girls 12, 8 and 6, where the two youngest cannot share. Either disabled girl could be the one alone in a two-room allocation, but not both, so the model gives a third room. This is the literal HB (ba) categorisation and matches UC 12(8)'s "each such child has their own bedroom". A child-by-child reading of A21/2013 para 13 ("no combination of sharing ... which allows them their own bedroom") would give no room here. For a single child the two readings coincide. The child can be alone in some fewest-room allocation exactly when one room plus the fewest rooms for the other children equals the fewest rooms overall, and that is the case in which the model adds nothing.
  2. The HB dwelling condition counts the (3A)/(3B) rooms. "Those to which the claimant would be entitled" is read as the whole entitlement. A dwelling must therefore also have the overnight carer's or foster child's room before a disabled child's room is allowed.
  3. Unreported bedrooms (0) are assumed sufficient. This matches how Count other families' children and add the foster and overnight-care bedrooms in the LHA size criteria #2016 treats the carer's and foster child's rooms. The released data lack num_bedrooms, so in the microsimulation the HB condition never binds.
  4. AFIP before 2025 in UC. UC's "attendance allowance" (reg 2) includes AFIP, which has no "higher rate". The model counts AFIP in 2017-2024, as HB's definition does explicitly.
  5. Scottish devolved benefits (CDP, ADP, Scottish adult DLA, PADP) count only where the data record them as the DWP benefit. This is the same limitation as the existing overnight-care list; see Include the Scottish devolved disability benefits in the LHA size-criteria benefit lists #2041.

Invariants (property tests in tests/test_lha_bedroom_young_people_properties.py)

The brute-force reference (invariant 5) now covers the new rules:

  • children who cannot share are forbidden any room-mate in the brute-force pairing, which is an independent formulation, not the model's arithmetic;
  • couple rooms;
  • the HB dwelling condition, with the households' num_bedrooms drawn from {unreported, 1..6}.

New properties:

  • 6. Flagging one more child as unable to share raises any family's bedrooms by 0 or 1 under each scheme. Only the families whose size criteria count that child change.
  • 7. With the dwelling's bedrooms reported, HB bedrooms lie between the count if everyone could share and the count with bedrooms unreported. They exceed the dwelling's bedrooms only where the could-share count already does.
  • 8. Flagging one or both members of another family's couple gives the couple's own claim exactly one more bedroom under each scheme. The household head's family gets exactly one more HB bedroom, and no more UC bedrooms, if it counts the couple as occupiers. No other family changes.

Invariants 1-4 (from #2010/#2016) now run on populations that include children and couples who cannot share.

Tests

  • YAML: LHA_cannot_share_bedroom.yaml, 26 cases.

    • ADM F3135 examples 1-3, F3136, and F3138 (combined conditions).
    • A21/2013 Annex 2 examples 1-6, including the dwelling condition.
    • Several disabled children; a non-dependant's disabled child; disabled foster and adopted children; a non-dependant couple in HB; the dwelling condition with an overnight carer; the 2016, 2024 and 2026 benefit rules; no qualifying benefit; a 16-year-old.
  • Policy YAML: the new file passes (27 cases). Every case sets the new input, which the base does not have. The full family suite and the policy suite run before this leaves draft.

  • Property tests: all 7 then-existing properties pass at b2942e3; invariant 8 (4e7cfd7) passes (exit 0; the host was heavily loaded, so the run took ~25 minutes). This also answers Count other families' children and add the foster and overnight-care bedrooms in the LHA size criteria #2016's request to run its properties on a merge of its 1f3ce21 head. Mutation checks: four deliberately broken copies of the code (scratch copies), each run against invariants 5-8. Every one fails at least one property:

    • leaving out the child rule;
    • leaving out the HB dwelling condition;
    • counting an occupier couple's extra bedroom once per qualifying member;
    • comparing the dwelling's bedrooms with the entitlement before the (3A)/(3B) rooms.

    The couple mutant survived the reference test's 25 examples, so invariant 8 was added to pin that effect exactly.

Impact

Three real microsimulation runs of the released enhanced FRS 2024-25 (uk-data 1.57.4; h5 sha256 03fe15e40a4c), year 2026. All figures are aggregates. A cell backed by fewer than 10 distinct survey households is suppressed, and so is any figure that would reveal such a cell by subtraction.

As the data stand, nothing changes. The survey does not record the cannot-share judgement, so the new input is false for everyone.

Upper bound. A third run gives every person the judgement, so the rooms go to everyone with a qualifying benefit. It shows how far the rule could reach. It is not an estimate: in practice the decision maker or local authority grants the judgement case by case.

Upper bound vs branch
Children under 16 on DLA care at the middle or highest rate 769k (337 survey households); 235k in privately renting benefit units (69)
Members of couples on a qualifying benefit 2.16m (868); 261k privately renting (133)
Privately renting benefit units with more bedrooms (UC and HB) 383k (159)
UC housing costs element +£357.9m; £288.7m of it to benefit units with no UC award
UC paid +£68.6m a year (gainers: 71k benefit units, 25 survey households)
Housing Benefit, household benefits and net income, poverty suppressed (HB changes in fewer than 10 survey households; household totals would reveal it by subtraction)

Scripts: ~/reviews/lha-disabled-cannot-share-2026-10-01/impact/ (dump_sim.py with an all mode, compare.py, cannot_share_extra.py; outputs efrs_compare_upper_2026.out, efrs_extra_upper_2026.out).

axiom: TheAxiomFoundation/rulespec-uk#411 queued (addendum TheAxiomFoundation/rulespec-uk#411 (comment)) | TheAxiomFoundation/rulespec-uk#406 queued (addendum TheAxiomFoundation/rulespec-uk#406 (comment); pointer on TheAxiomFoundation/rulespec-uk#357)

🤖 Generated with Claude Code

MaxGhenis and others added 2 commits October 2, 2026 09:55
…ms in the LHA size criteria

UC Regs 2013 Sch 4 para 12(6), (6A), (8), (9)(c)-(d) and HB Regs 2006 / HB
(SPC) Regs 2006 reg 13D(3)(za), (zb), (ba) and closing words. A child who
cannot share is taken out of the children's pairing and has a room of their
own; a couple one of whom cannot share has a bedroom each. Housing Benefit
allows these bedrooms only where the dwelling has them (num_bedrooms;
assumed where not reported). New input
cannot_reasonably_share_bedroom_due_to_disability. In force from
4 December 2013 (children) and 1 April 2017 (couples); attendance allowance
only at the higher rate before 27 January 2025 (SI 2025/3).

Fixes #2069.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The property generator now flags none, the first or both adults of a
couple, so the Housing Benefit count of one further bedroom per occupier
couple, however many members qualify, is exercised. Adds the matching YAML
case for a non-dependant couple.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@MaxGhenis

Copy link
Copy Markdown
Collaborator Author

Coordination with #2084 (UC claim by a member of a couple as a single person, UC Regs 2013 reg 3(3)).

UC Sch 4 para 12's disabled person condition applies where a renter "would ... be expected to share a bedroom with a joint renter". Where a member of a couple claims UC as a single person, the other member is not a joint renter. They are not a non-dependant either (Sch 4 para 9(2)(b)), and the renter has one bedroom (para 10(1)(a)). So that couple gets no extra room for not being able to share. That PR adds uc_member_of_couple_claims_as_single_person (BenUnit); is_member_of_couple_who_cannot_share_bedroom should give no room where it is true. Housing Benefit has its own couple rule and no single claim.

Invariant 8 always builds a couple from another family and flags one or
both members: the couple's own claim gains one bedroom under each scheme,
and the household head's family one Housing Benefit bedroom when the
couple are occupiers it counts. A mutation that counted a bedroom per
qualifying member survived the reference test's 25 examples; this test
pins it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@MaxGhenis

Copy link
Copy Markdown
Collaborator Author

#2062 is now on main (merge commit c4659aa). main has one resolved household head: is_resolved_household_head (Person: the eldest member the is_household_head input flags, else the eldest member) and benunit_contains_household_head (BenUnit, defined from it). No formula outside is_resolved_household_head reads is_household_head, and test_only_the_resolved_head_reads_the_flag in policyengine_uk/tests/test_household_head_agreement_properties.py enforces that.

This PR still adds formulas that read the raw flag:

  • policyengine_uk/variables/gov/dwp/housing_benefit_LHA_allowed_bedrooms.py: head_family = person.benunit.any(person("is_household_head", period)); is_head_family = benunit.any(person("is_household_head", period))
  • policyengine_uk/variables/gov/dwp/housing_benefit_LHA_cannot_share_bedrooms.py: is_head_family = benunit.any(person("is_household_head", period))

Each needs to read the resolved head instead:

  • family level: benunit.any(person("is_household_head", period)) becomes benunit("benunit_contains_household_head", period), and person.benunit.any(person("is_household_head", period)) becomes person.benunit("benunit_contains_household_head", period);
  • person level, only where the formula needs the head as a person: person("is_household_head", period) becomes person("is_resolved_household_head", period).

test_only_the_resolved_head_reads_the_flag fails until every such read is moved. Please also add each variable you move to OUTPUTS in that test file, so its metamorphic test (flags matter only through the resolved head) computes it. Test inputs that set is_household_head are fine as they are.

@juaristi22 juaristi22 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Program review

Base repository: PolicyEngine/policyengine-uk
PR number: 2080
Reviewed head SHA: 4e7cfd7
Merge base SHA: 1f3ce21
Mode: full
Scope: All 18 changed disability cannot-share LHA bedroom paths and affected UC/HB category, rent-cap and award dependencies; inherited parent audit and private impact excluded
Source manifest: /private/tmp/policyengine-command-runs/881387a1b745/pr2080-hb1141-review-20261027-review-sources.json
Review status: PARTIAL

Source Documents

Critical

None.

Should Address

None.

Suggestions

None.

Evidence Gaps

  • CODE G1 — Exact-head execution remains unverified: captured matching-head CI is null, and local imports, collection, 27 new YAML cases, eight properties and affected UC/HB final-award regressions were NOT RUN. Static parameter/date/entity/oracle traces do not establish their combined runtime behavior. Qualified matching-head CI or focused integrated execution is needed; author-reported results are not reviewer execution.
  • POLICY-G1 — Historical UC AFIP inclusion for 2017–24 remains unresolved: the broad regulation 2 attendance-allowance definition must be reconciled with the former paragraph 12(6A) higher-rate qualifier. The acquired amendment and current DWP guidance do not conclusively settle that historical interaction; the older-guidance URL redirected to a current edition. This is missing qualification, not a confirmed wrong rule.
  • Role checks incomplete: pr2080-hb1141-review-20261027-review-code.md; see recovered report.
  • Role checks incomplete: pr2080-hb1141-review-20261027-review-policy.md; see recovered report.

Notes

  • No introduced implementation or policy defect was confirmed in the reviewed change. The scheme-specific child/couple allocation, HB physical-bedroom proviso, principal dates and neutral defaults have source-supported static results. The two material checks above prevent approval.
  • The pre-effect parameter-access question was resolved by CODE using the owned UK backdating helper: earliest leaves are supplied from 2015, while the in-effect masks stay false. No supported-2015/16 exception was established; this is not an additional finding or evidence gap. No model execution or pre-2015 support is claimed.
  • The inherited Scottish working-age CTR adoption-mask issue already reported on PR2030 is parent context. This review does not relabel it an introduced PR2080 defect or certify the whole stack. Private survey judgement/bedroom coverage, default assumptions, Scottish benefit mapping, upper-bound population counts, calibration and adoption remain unverified.
  • Eight exact prior official originals/derivatives were reused with explicit hash/applicability qualification; five genuinely missing official originals were acquired. Old PR2030 originals and its closed source window remain unchanged. Current guidance is not backdated to 2024.
  • The 62.730-second scope phase includes dispatch/coordinator overhead and missed its 60-second aim; original wall time and role/source clocks are retained. Parallel review timing includes dispatch overhead and overlaps the scope phase; these spans must not be summed. The first cleanup inspection guessed a receipt key and stopped before any git command; normal cleanup then completed using the actual schema.
  • Generic partial-role aliases added by the assembler refer to the two specific material gaps above. They are not four distinct missing checks.

Validation Summary

Local tests, country/Core imports, collection, model execution and environment work: NOT RUN. Exact-head hosted CI was null. CODE inspected all 18 paths, all 927 YAML lines and the 692-line property module, traced final UC/HB award consumers and parsed 12 changed Python files as AST. POLICY bound 13 official originals/full-text derivatives (8 reuses, 5 new); source window 179.231236/300s CLOSED and manifest checker0. One official DWP PDF was fully text-extracted, with relevant pages inspected and physical page22 rendered; its current edition does not establish historical 2024 guidance. Both roles finished within 600s. Snapshot removed normally after both DONE; hub retained. No private/log/artifact reads, author edits or issue work.

Timing

setup seconds: 75.15s; scope seconds: 62.73s; parallel review seconds: 462.02s; policy role seconds: 348.07s; code role seconds: 423.94s; adjudication seconds: 0.00s; consolidation cleanup seconds: 85.93s; elapsed seconds: 663.58s; source acquisition window seconds: 179.23s

Review Severity

COMMENT. Open findings: 0 critical, 0 should address, 0 suggestions.

This branch has not been deployed

No deployments
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