Repository navigation
Reset negative HBAI household income to zero before housing costs, as HBAI does - #2402
Conversation
HBAI: "Negative incomes BHC are reset to zero, but negative AHC incomes calculated from the adjusted BHC incomes are possible." (Background Information and Methodology report FYE 2025.) - hbai_household_net_income is now max(0, the new hbai_household_net_income_before_reset_to_zero), which holds the old formula. AHC, equivalised income, deciles, poverty flags and gaps follow from the reset figure. - household_income_decile no longer gives -1 to negative incomes: the reset figure is never negative, and HBAI ranks those households in the bottom decile. - Labour supply responses measure the figure before the reset, the household's actual budget constraint. Fixes #2401 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- test_hbai_negative_income_properties: the reset, a differential against the components summed outside the model, AHC from the reset figure, unchanged poverty headcounts, gaps measured from the reset, the means identity, deciles 1-10 rising with income, and the labour supply default. Nine planted mutants are each caught. - The PAWHP property checks its accounting identity on HBAI income before the reset, which the reset would break for a negative income. - docs: a "Negative incomes" section on the HBAI page. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…2085 - #2085's channel identity (test_trading_loss_properties) now measures HBAI income before the reset, the sum the identity holds for. - household_income_decile documents the tie rule: households at zero share the rank at the top of their group, so they are in decile 1 while they hold at most a tenth of people. Unit tests pin both sides of that line; the property test checks they share the lowest decile, and decile 1 below a tenth (new pinned population). - When the median before the reset is at or below zero, the reset makes it zero and no one is in relative poverty before housing costs: checked. - YAML: the reset under gov.contrib.abolish_council_tax. - Changelog: headcounts, gaps, bottom-decile moves and unchanged labour supply responses. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Round 2 review wording fixes: - docs and the relative poverty docstrings: a reset income is below the relative line while the median person's income is positive. - docs and changelog: households at zero are in the bottom decile while they hold at most a tenth of people (0.26% to 0.29% on the enhanced FRS, 2025-26 to 2030-31). - changelog: income totals, not means, rise by the sum of the negative incomes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
UK hub: coordination with #2411 (ground rent and service charges in AHC), which lands first. #2411 is approved at
#2411's own tests supply BHC directly, so they stay valid after this PR's reset. The review found no incompatible income mechanism. The UK hub will pick this PR up after #2411 merges. |
|
UK hub: adopting under d1280's fallback (owner session gone). A hub build job (20261015-000509-adopt-uk2402) is merging main (with #2411), reconciling |
|
UK hub hand-off — adopted #2402 Head: Since the last approved head:
Validation: 84 Python tests passed, 15 distinct YAML cases passed, foreground Exactly one real 2026 enhanced-FRS simulation per side, sequentially, using uk-data 1.58.1:
Dataset SHA256: Open item / draft retained: the manifest permits UK 2.122.2/2.130.1 and Core 3.32.13/3.33.0, whereas both runs use merged UK 2.132.3 / locked Core 3.33.2. The artifact is certified; this newer model/Core pairing is not listed as compatible. This is disclosed in the PR body and job records. The hub owns the independent delta review and certification follow-up. No self-review, merge, dataset build, or data upload was performed. |
|
UK hub merge audit, head
|
|
Merged by the merge queue at reviewed head |
Fixes #2401
Reproducer: policyengine_uk/tests/test_hbai_negative_income_properties.py::test_reset_income_and_its_measures
Also guards #2411's gap:
policyengine_uk/tests/test_hbai_housing_costs_properties.py::test_service_charges_do_not_change_computed_bhc. This is a computed-BHC check that service charges never reduce BHC. It does not reproduce #2401.HBAI resets negative household income before housing costs (BHC) to zero, then derives income after housing costs (AHC) from that reset figure. This implements the DWP HBAI negative-income convention.
Behaviour
hbai_household_net_income = max(0, hbai_household_net_income_before_reset_to_zero). The new before-reset variable preserves the previous component accounting, including trading losses and the Council Tax abolition branch.housing_service_charges(ground rent and property service charges). AHC can remain negative.Adoption and merge
Adopted under the UK hub's fallback with the author and existing history preserved. Main
9a9b52cb8c25c617a5494b7cb57eaa0df9811906is merged into head06f47f7885ac64b3b63107432f382f1debface19, including #2411, #2407, #2415 and #2391; no rebase or force-push.The two conflicts were reconciled as follows:
docs/book/validation/hbai.mdretains the reset explanation, all five housing costs and Deduct ground rent and service charges from HBAI AHC income #2411's FRS service-charge guidance. It also incorporates the prior round-3 wording correction about people at or below zero.hbai_household_net_income_ahc.pyretains the reset BHC input, Deduct ground rent and service charges from HBAI AHC income #2411's fifth subtraction, metadata explaining both mechanisms, and references to both DWP methodology sections.The reset properties now include service charges in their independent oracle and positive generated/pinned inputs. Four YAML cases include charges and adjusted AHC/equivalised/gap expectations. #2411's P3 follow-up is closed by a computed-BHC check in 2024–2026 which computes positive BHC from earnings, raises service charges by £1,200, and verifies before-reset/reset BHC are unchanged while AHC falls by exactly £1,200.
Invariants
For before-reset income b and nonnegative total housing costs HC:
max(0, b); equivalised and real BHC remain nonnegative. The before-reset figure equals the sum of income components less deductions.max(0, b) − HC, with all five housing costs included exactly once. Service charges do not reduce BHC.Validation at the adopted head
Locked environment: UK 2.132.3, Core 3.33.2, Python 3.13.9,
UV_LINK_MODE=clone uv sync --frozen --extra dev.make format: passed (Ruff formatting and lint).git diff --check: passed.Foreground
uv run --frozen --no-sync pytest -n 4 --dist worksteal -o xfail_strict=true ... -q: 84 passed, no failures/skips, 111 existing MicroSeries warnings, 1229.55s. Files:test_hbai_negative_income_properties.py,test_hbai_housing_costs_properties.py,test_household_income_decile.py,test_relative_poverty_median.py,test_absolute_poverty_reference_year.py,test_labour_supply_response_formulas.py,test_labour_supply_dynamics_properties.py,test_behavioral_responses.py,test_marginal_rate_precision.py,test_pawhp_household_income_properties.py,test_trading_loss_properties.py(all underpolicyengine_uk/tests/).Foreground YAML with
pytest -n 4 --dist worksteal -p hbai_yaml_plugin --junitxml=.job/pytest-yaml.xml: 15 passed, no warnings, 75.81s. Files:policyengine_uk/tests/policy/baseline/household/income/hbai_negative_income.yaml,.../hbai_housing_costs.yaml,policyengine_uk/tests/policy/reforms/parametric/hbai_council_tax_lvt.yaml. Workspace-only harness loads Core's collector per worker and assigns unique IDs; JUnit confirms every intended case passed exactly once. Core CLI-nfilters names, so it was not used as a worker flag. An initial 15-pass invocation had duplicate IDs/teardown warnings and was superseded by this clean run.Main source provenance: all 2,931 archived tracked blobs match
origin/main; local Git bundle verifies.Required
uvx ruff format --check .: passed (3,420 files already formatted), with uv tool/cache paths inside.job/for the sandbox.Both sequential 2026 microsimulations and the aggregate comparison checks passed. The manifest version compatibility check reports false for this newer model/Core pair, as disclosed below.
Expected-failure evidence: after merging #2411, introducing positive service-charge generated/pinned inputs while retaining the old four-cost oracle caused
test_reset_income_and_its_measuresto fail at its AHC identity (1 failed in 94.81s). It passes after the fifth oracle cost is restored. The evidence log is retained in the job folder.The full suite was not run, as requested. The documentation change is prose in an existing page; the full book build was not run.
2026 enhanced-FRS impact
Exactly one real 2026 microsimulation per side, run sequentially using the owner's
impact.pymetrics, restricted to 2026 and augmented with provenance/resource guards and HBAI child/State Pension age groups. These are static baseline comparisons; the earlier reform-specific labour-supply and decile-impact runs were not repeated.Data: uk-data 1.58.1,
enhanced_frs_2024_25.h5; release manifest at HF commit89be6b73fc1e6eeba6dae2f9400676d8510bcd51, artifact at2526edbbb687a3b54dbb11272e5389e4b62d2ac2. Dataset SHA256:056e80fd8e9151d78f432a25cde863340baee81304c6216a37fb575ce8563784. Manifest SHA256:545797bf231cd3681e64b677065d921304e9a32f1e46e757a940a412b4136c17. Artifact bytes/hash match the manifest.Compatibility limitation: the manifest's
compatible_model_packageslists UK==2.122.2and==2.130.1;compatible_core_packageslists Core==3.32.13and==3.33.0. Both source revisions run UK 2.132.3 with locked Core 3.33.2, outside those exact certified versions. These measurements use the latest certified data artifact, but this newer model/Core pairing is not certified by that manifest. No version metadata was changed to bypass the check.Main SHA:
9a9b52cb8c25c617a5494b7cb57eaa0df9811906. Branch SHA:06f47f7885ac64b3b63107432f382f1debface19.All poverty headcounts below are exactly unchanged (millions of people; values apply to both sides).
Children use
is_hbai_dependent_child; pensioners useis_SP_age, accounting for the 2026 State Pension age transition. The owner’s under-18 and age-66+ groups are retained in the aggregate JSON and are also exactly unchanged.Before-reset negative income remains identical: 677 survey households, 142,005 weighted households and 183,355 people. All 677 move from decile −1 to decile 1; every original nonnegative decile is exactly unchanged.
Post-reset zero-BHC people hold 0.2717% of the population, below 10%. The person-weighted equivalised BHC/AHC medians are £40,696.95 / £34,891.94, identical on both sides and positive.
Income-total and gap changes match the £0.832718568bn negative part within a recorded £953.67 aggregate float32 tolerance (largest observed residual £365.20). All provenance, matched-weight, reset, headcount and decile checks pass.
Preflight readings (decimal GB): main compressor 0.812, free disk 62.560; branch compressor 0.808, free disk 62.309. Both satisfy compressor <30 GB and free disk >60 GB. Both runs verify the dataset hash and size against the manifest.
Hand-off
Prior independent rounds 1–3 approved earlier heads, most recently
59d57bdafdb5feda95baa14092cc19bab5f992dc. The merged code/test delta requires the hub's independent delta review; no self-review was performed and this PR is not merged.Retained as a draft because the manifest does not certify this newer model/Core pairing. All code tests and formatting checks pass. The hub owns independent delta review and certification follow-up.
axiom: n/a: statistics (the HBAI income measure), not law