From e6564306b079747f541498184b18e7948fe5d062 Mon Sep 17 00:00:00 2001 From: Max Ghenis Date: Tue, 13 Oct 2026 13:11:53 -0400 Subject: [PATCH 1/4] Fix benefit-cap earnings exemption for statutory pay --- changelog.d/2397.fixed.md | 1 + ..._cap_earnings_exception_earned_income.yaml | 134 ++++++++++++++++++ .../tests/test_uc_statutory_pay_properties.py | 72 ++++++++-- .../gov/dwp/is_benefit_cap_exempt_earnings.py | 25 ++-- 4 files changed, 213 insertions(+), 19 deletions(-) create mode 100644 changelog.d/2397.fixed.md create mode 100644 policyengine_uk/tests/policy/baseline/gov/dwp/benefit_cap/benefit_cap_earnings_exception_earned_income.yaml diff --git a/changelog.d/2397.fixed.md b/changelog.d/2397.fixed.md new file mode 100644 index 0000000000..606b24625f --- /dev/null +++ b/changelog.d/2397.fixed.md @@ -0,0 +1 @@ +- Fixed the benefit-cap earnings exemption to count statutory pay and use Universal Credit's actual net earnings before the minimum income floor, with a pinned regression for the release failure. diff --git a/policyengine_uk/tests/policy/baseline/gov/dwp/benefit_cap/benefit_cap_earnings_exception_earned_income.yaml b/policyengine_uk/tests/policy/baseline/gov/dwp/benefit_cap/benefit_cap_earnings_exception_earned_income.yaml new file mode 100644 index 0000000000..fc39b28df1 --- /dev/null +++ b/policyengine_uk/tests/policy/baseline/gov/dwp/benefit_cap/benefit_cap_earnings_exception_earned_income.yaml @@ -0,0 +1,134 @@ +# The benefit cap's earnings exception (UC Regs 2013 reg 82(1)(a)) tests "the +# claimant's earned income or, if the claimant is a member of a couple, the +# couple's combined earned income". Earned income is Universal Credit's +# (reg 52): statutory sick, maternity and paternity pay are employed earnings +# (reg 55(4)), and the deductions are the person's own relievable pension +# contributions and the income tax and primary Class 1 contributions paid "in +# respect of the employment" (reg 55(5)). Income the minimum income floor +# treats a person as having does not count (reg 82(4)). The threshold is the +# model's 10,152 a year (issue #1986). Each family is a single claimant aged 40 +# outside London with an entered award of 18,000 before the cap, so the cap +# of 14,753 takes 3,247 unless an exception applies. +# Sources: https://www.legislation.gov.uk/uksi/2013/376/regulation/55 +# https://www.legislation.gov.uk/uksi/2013/376/regulation/82 +# https://www.gov.uk/guidance/rates-and-thresholds-for-employers-2026-to-2027 +# The existing model threshold is retained here; 11,000 and 10,000 also lie +# above and below the 2026 NLW-based threshold of 10,574.72 respectively. + +- name: Statutory sick pay is earned income for the earnings exception + period: 2026 + input: + age: 40 + employment_income: 3_000 + statutory_sick_pay: 8_000 + universal_credit_pre_benefit_cap: 18_000 + region: NORTH_EAST + output: + uc_individual_earned_income_before_mif: 11_000 + is_benefit_cap_exempt_earnings: true + benefit_cap_reduction: 0 + +- name: Statutory paternity pay is earned income for the earnings exception + period: 2026 + input: + age: 40 + employment_income: 3_000 + statutory_paternity_pay: 8_000 + universal_credit_pre_benefit_cap: 18_000 + region: NORTH_EAST + output: + uc_individual_earned_income_before_mif: 11_000 + is_benefit_cap_exempt_earnings: true + benefit_cap_reduction: 0 + +- name: Statutory maternity pay is earned income for the earnings exception + period: 2026 + input: + people: + claimant: + age: 40 + employment_income: 3_000 + statutory_maternity_pay: 8_000 + benunits: + family: + members: [claimant] + universal_credit_pre_benefit_cap: 18_000 + households: + home: + members: [claimant] + region: NORTH_EAST + output: + # 3,000 + 8,000 = 11,000, under the personal allowance and the primary + # threshold, so no tax or NI: 11,000 >= 10,152. Without the maternity + # pay the wages alone, 3,000, are under the threshold. + uc_individual_earned_income_before_mif: 11_000 + is_benefit_cap_exempt_earnings: true + is_benefit_cap_exempt: true + benefit_cap_reduction: 0 + +- name: Tax on a private pension does not come off the earnings the exception tests + period: 2026 + input: + people: + claimant: + age: 40 + employment_income: 11_000 + private_pension_income: 10_000 + benunits: + family: + members: [claimant] + universal_credit_pre_benefit_cap: 18_000 + households: + home: + members: [claimant] + region: NORTH_EAST + output: + # Income tax is (21,000 - 12,570) x 20% = 1,686, all of it on the + # pension: the wages are the lowest slice and the personal allowance + # covers them, so none is in respect of the employment (reg 55(5)(b)). + # No NI on 11,000. 11,000 >= 10,152. Netting the 1,686 off the wages + # would give 9,314, under the threshold. + income_tax: 1_686 + uc_income_tax_on_earnings: 0 + uc_individual_earned_income_before_mif: 11_000 + is_benefit_cap_exempt_earnings: true + benefit_cap_reduction: 0 + +- name: Relievable pension contributions come off the earnings the exception tests + period: 2026 + input: + people: + claimant: + age: 40 + employment_income: 11_000 + employee_pension_contributions: 1_000 + benunits: + family: + members: [claimant] + universal_credit_pre_benefit_cap: 18_000 + households: + home: + members: [claimant] + region: NORTH_EAST + output: + # Reg 55(5)(a): 11,000 - 1,000 = 10,000, with no tax or NI, is under + # 10,152. The cap applies: 18,000 - 14,753 = 3,247. + uc_individual_earned_income_before_mif: 10_000 + is_benefit_cap_exempt_earnings: false + is_benefit_cap_exempt: false + benefit_cap_reduction: 3_247 + +- name: The minimum income floor does not create an earnings exception + period: 2026 + input: + age: 40 + self_employment_income: 5_000 + uc_mif_applies: true + uc_minimum_income_floor: 20_000 + universal_credit_pre_benefit_cap: 18_000 + region: NORTH_EAST + output: + uc_individual_earned_income_before_mif: 5_000 + uc_individual_earned_income: 20_000 + is_benefit_cap_exempt_earnings: false + benefit_cap_reduction: 3_247 diff --git a/policyengine_uk/tests/test_uc_statutory_pay_properties.py b/policyengine_uk/tests/test_uc_statutory_pay_properties.py index ef2de488c3..fdf11d88df 100644 --- a/policyengine_uk/tests/test_uc_statutory_pay_properties.py +++ b/policyengine_uk/tests/test_uc_statutory_pay_properties.py @@ -41,20 +41,17 @@ 82(1)(a) threshold, and the payments are earned income (reg. 55(4)). So a pound of pay can lift the cap and raise the final award. The award after the cap may therefore rise only where the family becomes exempt - (is_benefit_cap_exempt); otherwise it obeys the same bound. Today's - is_benefit_cap_exempt_earnings reads employment income without - statutory pay, so this exception does not yet arise in the model. + (is_benefit_cap_exempt); otherwise it obeys the same bound. The + earnings exemption uses actual UC net earned income before the + minimum income floor, which reg. 82(4) excludes. 2. Same as wages: statutory sick or maternity pay of s on top of wages of e gives the same income tax, National Insurance, earned income and award - before the benefit cap as wages of e + s. This holds for Marriage Allowance + before and after the benefit cap as wages of e + s. This holds for Marriage Allowance claimants too. Two differences in the model's income tax are left out (counts_as_wages): it charges no income tax on statutory paternity pay, and it caps pension contribution relief at employment and self-employment - income without statutory pay. The award after the benefit cap is not - compared, because the cap's earnings exception - (is_benefit_cap_exempt_earnings) reads employment income without statutory - pay. + income without statutory pay. 3. Accounting: a person's earned income before the minimum income floor is their wages, statutory pay and trading profit (a loss counts as nil) less @@ -81,7 +78,7 @@ """ import numpy as np -from hypothesis import HealthCheck, given, settings +from hypothesis import HealthCheck, example, given, settings from hypothesis import strategies as st from policyengine_uk import CountryTaxBenefitSystem, Simulation @@ -265,7 +262,57 @@ def recipient(self, variable, i, version): return self.person(variable, i, version, self.population[i]["recipient"]) +# Release run 38366204407: explicit coverage is independent of Hypothesis's +# local source-constant pool, which differs for source and site-packages. +STATUTORY_SICK_PAY_CAP_REGRESSION = { + "adults": [ + { + "age": 22, + "wages": 12_570.0, + "profit": 0.0, + "startup": False, + "pension_contributions": 0.0, + "pension_income": 6_000.0, + "dividends": 0.0, + "lcwra": False, + "claims_marriage_allowance": False, + } + ], + "child_ages": [1, 1], + "childcare": 0.0, + "region": "NORTH_EAST", + "tenure": "RENT_FROM_COUNCIL", + "rent": 0.0, + "recipient": 0, + "payment": "statutory_sick_pay", + "low": 0.0, + "high": 6_000.0, +} + + +def test_statutory_sick_pay_preserves_benefit_cap_earnings_exemption(): + """Reg. 55(4) pay cannot end this family's reg. 82(1)(a) exception.""" + results = Results([STATUTORY_SICK_PAY_CAP_REGRESSION]) + for version, expected_earnings in [(LOW, 12_570), (HIGH, 16_890)]: + # The private pension absorbs the tax on unearned income. At HIGH, + # actual earnings are 12,570 + 6,000 - 1,200 tax - 480 Class 1 NI. + np.testing.assert_allclose( + results.recipient("uc_individual_earned_income_before_mif", 0, version), + expected_earnings, + atol=TOLERANCE, + rtol=0, + ) + assert results.families("is_benefit_cap_exempt_earnings", version)[0] + assert results.families("is_benefit_cap_exempt", version)[0] + assert results.families("benefit_cap_reduction", version)[0] == 0 + assert ( + results.families("universal_credit", HIGH)[0] + <= results.families("universal_credit", LOW)[0] + TOLERANCE + ) + + @PROPERTY_SETTINGS +@example(population=[STATUTORY_SICK_PAY_CAP_REGRESSION]) @given(population=populations()) def test_award_never_rises_with_a_claimants_statutory_pay(population): results = Results(population) @@ -392,7 +439,12 @@ def test_statutory_pay_counts_as_wages_and_earned_income_adds_up(population): atol=TOLERANCE, err_msg=f"{variable}: {family}", ) - for variable in ["uc_earned_income", "universal_credit_pre_benefit_cap"]: + for variable in [ + "uc_earned_income", + "universal_credit_pre_benefit_cap", + "is_benefit_cap_exempt_earnings", + "universal_credit", + ]: taxed = [counts_as_wages(family) for family in population] np.testing.assert_allclose( results.families(variable, HIGH)[taxed], diff --git a/policyengine_uk/variables/gov/dwp/is_benefit_cap_exempt_earnings.py b/policyengine_uk/variables/gov/dwp/is_benefit_cap_exempt_earnings.py index 76e7dcf27c..c859af32bd 100644 --- a/policyengine_uk/variables/gov/dwp/is_benefit_cap_exempt_earnings.py +++ b/policyengine_uk/variables/gov/dwp/is_benefit_cap_exempt_earnings.py @@ -5,26 +5,33 @@ class is_benefit_cap_exempt_earnings(Variable): value_type = bool entity = BenUnit label = "Exempt from the benefit cap because of earnings" + documentation = ( + "The assessed claimant's or couple's actual net earned income for " + "Universal Credit reaches the earnings threshold. This includes " + "statutory pay and deducts their own relievable pension contributions " + "and tax and National Insurance on earnings. Income imputed by the " + "minimum income floor and a dependant's earnings do not count." + ) definition_period = YEAR - reference = "https://www.gov.uk/benefit-cap/when-youre-not-affected" + reference = ( + "https://www.legislation.gov.uk/uksi/2013/376/regulation/82", + "https://www.legislation.gov.uk/uksi/2013/376/regulation/55", + ) def formula(benunit, period, parameters): person = benunit.members # Earnings exemption for UC (£846/month = £10,152/year) - # Note: Only check earned income, not UC amount itself to avoid circular dependency + # Only check earned income, not the UC amount, to avoid a circular dependency. # UC Regs 2013 reg. 82(1)(a) tests "the claimant's earned income or, # if the claimant is a member of a couple, the couple's combined # earned income": a dependant's earnings do not count. claimant = person("is_uc_assessed_claimant", period) + # Reg. 82(4) excludes earnings imputed under the minimum income + # floor (reg. 62). Use actual UC earnings, before both that floor + # and the work allowance, with the reg. 55 and 57 deductions. uc_earned = benunit.sum( - ( - person("employment_income", period) - + person("self_employment_income", period) - - person("income_tax", period) - - person("national_insurance", period) - ) - * claimant + person("uc_individual_earned_income_before_mif", period) * claimant ) earnings_threshold = 10_152 return uc_earned >= earnings_threshold From 05610e4d700b435eaed6c5a8524bd599f3e762bb Mon Sep 17 00:00:00 2001 From: Max Ghenis Date: Tue, 13 Oct 2026 14:45:48 -0400 Subject: [PATCH 2/4] Remove resolved cap xfail and document income interactions --- .github/test_outcome_allowlist.toml | 6 --- ..._cap_earnings_exception_earned_income.yaml | 45 ++++++++++++++++--- .../test_uc_income_from_capital_properties.py | 21 ++++----- 3 files changed, 47 insertions(+), 25 deletions(-) diff --git a/.github/test_outcome_allowlist.toml b/.github/test_outcome_allowlist.toml index 1b50e36c70..c415bd6a36 100644 --- a/.github/test_outcome_allowlist.toml +++ b/.github/test_outcome_allowlist.toml @@ -25,12 +25,6 @@ outcome = "xfailed" reason = "#1947" why = "Known bug #1947 (Marriage Allowance booked on the recipient), pinned by a strict xfail until it is fixed." -[[allow]] -nodeid = "policyengine_uk/tests/test_uc_income_from_capital_properties.py::test_tax_on_dividends_does_not_remove_the_benefit_cap_earnings_exception" -outcome = "xfailed" -reason = "#1986" -why = "Known bug #1986 (the benefit cap earnings exception nets tax on all income), pinned by a strict xfail until it is fixed." - [[allow]] nodeid = "policyengine_uk/tests/test_build_metadata.py::test_runtime_metadata_uses_bundle_contract_when_available" outcome = "skipped" diff --git a/policyengine_uk/tests/policy/baseline/gov/dwp/benefit_cap/benefit_cap_earnings_exception_earned_income.yaml b/policyengine_uk/tests/policy/baseline/gov/dwp/benefit_cap/benefit_cap_earnings_exception_earned_income.yaml index fc39b28df1..a5679bd3d3 100644 --- a/policyengine_uk/tests/policy/baseline/gov/dwp/benefit_cap/benefit_cap_earnings_exception_earned_income.yaml +++ b/policyengine_uk/tests/policy/baseline/gov/dwp/benefit_cap/benefit_cap_earnings_exception_earned_income.yaml @@ -6,9 +6,9 @@ # contributions and the income tax and primary Class 1 contributions paid "in # respect of the employment" (reg 55(5)). Income the minimum income floor # treats a person as having does not count (reg 82(4)). The threshold is the -# model's 10,152 a year (issue #1986). Each family is a single claimant aged 40 -# outside London with an entered award of 18,000 before the cap, so the cap -# of 14,753 takes 3,247 unless an exception applies. +# model's 10,152 a year (issue #1986). Unless stated otherwise, each family is +# a single claimant aged 40 outside London with an entered award of 18,000 +# before the cap, so the cap of 14,753 takes 3,247 unless an exception applies. # Sources: https://www.legislation.gov.uk/uksi/2013/376/regulation/55 # https://www.legislation.gov.uk/uksi/2013/376/regulation/82 # https://www.gov.uk/guidance/rates-and-thresholds-for-employers-2026-to-2027 @@ -83,9 +83,11 @@ members: [claimant] region: NORTH_EAST output: - # Income tax is (21,000 - 12,570) x 20% = 1,686, all of it on the - # pension: the wages are the lowest slice and the personal allowance - # covers them, so none is in respect of the employment (reg 55(5)(b)). + # Income tax is (21,000 - 12,570) x 20% = 1,686. The model's convention + # in uc_income_tax_on_earnings allocates wages to the lowest slice, + # covered by the personal allowance, leaving all the tax on the pension. + # Reg 55(5)(b) requires tax in respect of employment to be deducted but + # does not prescribe this allocation between wages and pension income. # No NI on 11,000. 11,000 >= 10,152. Netting the 1,686 off the wages # would give 9,314, under the threshold. income_tax: 1_686 @@ -132,3 +134,34 @@ uc_individual_earned_income: 20_000 is_benefit_cap_exempt_earnings: false benefit_cap_reduction: 3_247 + +- name: Means-tested basic income counts toward the couple's earnings exception + period: 2026 + input: + gov.contrib.ubi_center.basic_income.interactions.include_in_means_tests: true + people: + claimant: + age: 40 + employment_income: 0 + basic_income: 5_500 + partner: + age: 40 + employment_income: 0 + basic_income: 5_500 + benunits: + family: + members: [claimant, partner] + universal_credit_pre_benefit_cap: 18_000 + households: + home: + members: [claimant, partner] + region: NORTH_EAST + output: + # The reform includes basic income in UC earned income, so the shared + # expression in #1820 also counts it here: 5,500 + 5,500 >= 10,152. + # The total also exceeds #1820's 2026 NLW-based earnings threshold. + # This records existing reform behavior; its interaction with the + # benefit cap earnings exception remains an open question for #1986. + uc_individual_earned_income_before_mif: [5_500, 5_500] + is_benefit_cap_exempt_earnings: true + benefit_cap_reduction: 0 diff --git a/policyengine_uk/tests/test_uc_income_from_capital_properties.py b/policyengine_uk/tests/test_uc_income_from_capital_properties.py index 4a07d757fd..d21fd673d2 100644 --- a/policyengine_uk/tests/test_uc_income_from_capital_properties.py +++ b/policyengine_uk/tests/test_uc_income_from_capital_properties.py @@ -33,10 +33,12 @@ s. 35), which raises the tax a person pays on their earnings and so changes the deduction from them (see test_uc_earnings_deductions_properties.py). The award after the benefit cap is compared only where the cap exemption is -also unchanged: the model's earnings exception to the cap still nets tax on -all of a person's income off their earnings -(PolicyEngine/policyengine-uk#1986), so capital income can switch the cap on. -A strict xfail pins that case. +also unchanged. The cap's earnings exception now reads each claimant's +Universal Credit earned income (uc_individual_earned_income_before_mif), which +deducts only the tax on their earnings (uc_income_tax_on_earnings), so +interest, dividends and rent leave it alone too, apart from the allowance +effects above. test_tax_on_dividends_does_not_remove_the_benefit_cap_earnings_exception +pins the dividend case. """ import numpy as np @@ -253,8 +255,8 @@ def test_interest_dividends_and_rent_leave_the_award_unchanged(units, scale, yea unchanged = np.isclose( scaled["personal_allowances"], base["personal_allowances"], atol=0.01 ) - # The cap's earnings exception can change with the income (#1986), so - # the capped award is compared only where the exemption is the same. + # Compare the capped award only where the exemption is the same; tax + # on capital income can affect earnings through the allowance taper. same_cap = unchanged & ( scaled["is_benefit_cap_exempt"] == base["is_benefit_cap_exempt"] ) @@ -323,13 +325,6 @@ def test_tax_on_dividends_does_not_raise_a_working_familys_award(): assert values["uc_earned_income"][0] == pytest.approx(10_000, abs=0.01) -@pytest.mark.xfail( - strict=True, - reason=( - "PolicyEngine/policyengine-uk#1986: the benefit cap earnings exception " - "nets tax on all of a person's income off their earnings" - ), -) def test_tax_on_dividends_does_not_remove_the_benefit_cap_earnings_exception(): # 2026: single claimant aged 30 in London, council rent 20,000, earning # 11,000 with no tax or NI on it. Without dividends the model applies no From c0f501b5eb2b9b7b512fe6d500d6edec9dcc7b97 Mon Sep 17 00:00:00 2001 From: Max Ghenis Date: Tue, 13 Oct 2026 18:41:12 -0400 Subject: [PATCH 3/4] Make the basic-income cap case bite and correct two test comments - The basic-income case now enters an award of 25,000, above the couple cap outside London (22,020), so its zero cap reduction shows the exemption working. A control case without the reform toggle shows basic income not counting: no exemption, reduction 2,980. - Say that counting basic income in the earnings exception is new in this PR (main never counted it), not existing behaviour. - The capital-income property compares the capped award only where the exemption is unchanged because capital income can change another exemption route, not because of the allowance taper. Co-Authored-By: Claude Opus 5.5 --- ..._cap_earnings_exception_earned_income.yaml | 38 +++++++++++++++++-- .../test_uc_income_from_capital_properties.py | 5 ++- 2 files changed, 38 insertions(+), 5 deletions(-) diff --git a/policyengine_uk/tests/policy/baseline/gov/dwp/benefit_cap/benefit_cap_earnings_exception_earned_income.yaml b/policyengine_uk/tests/policy/baseline/gov/dwp/benefit_cap/benefit_cap_earnings_exception_earned_income.yaml index a5679bd3d3..2ad812620a 100644 --- a/policyengine_uk/tests/policy/baseline/gov/dwp/benefit_cap/benefit_cap_earnings_exception_earned_income.yaml +++ b/policyengine_uk/tests/policy/baseline/gov/dwp/benefit_cap/benefit_cap_earnings_exception_earned_income.yaml @@ -151,7 +151,7 @@ benunits: family: members: [claimant, partner] - universal_credit_pre_benefit_cap: 18_000 + universal_credit_pre_benefit_cap: 25_000 households: home: members: [claimant, partner] @@ -160,8 +160,40 @@ # The reform includes basic income in UC earned income, so the shared # expression in #1820 also counts it here: 5,500 + 5,500 >= 10,152. # The total also exceeds #1820's 2026 NLW-based earnings threshold. - # This records existing reform behavior; its interaction with the - # benefit cap earnings exception remains an open question for #1986. + # Counting basic income in this test is new in this PR: main's formula + # never counted it. Whether reg 82 should count it is an open question + # for #1986 and #1820. The award of 25,000 is above the couple cap + # outside London (22,020), so without the exemption the cap would take + # 2,980; with it, nothing. uc_individual_earned_income_before_mif: [5_500, 5_500] is_benefit_cap_exempt_earnings: true benefit_cap_reduction: 0 + +- name: Without the basic income reform toggle, basic income does not count toward the earnings exception + period: 2026 + input: + people: + claimant: + age: 40 + employment_income: 0 + basic_income: 5_500 + partner: + age: 40 + employment_income: 0 + basic_income: 5_500 + benunits: + family: + members: [claimant, partner] + universal_credit_pre_benefit_cap: 25_000 + households: + home: + members: [claimant, partner] + region: NORTH_EAST + output: + # The control for the case above. By default basic income is not UC + # earned income, so the couple has no earned income, no exemption + # applies and the couple cap outside London (22,020) takes + # 25,000 - 22,020 = 2,980. + uc_individual_earned_income_before_mif: [0, 0] + is_benefit_cap_exempt_earnings: false + benefit_cap_reduction: 2_980 diff --git a/policyengine_uk/tests/test_uc_income_from_capital_properties.py b/policyengine_uk/tests/test_uc_income_from_capital_properties.py index d21fd673d2..cfeeda4c58 100644 --- a/policyengine_uk/tests/test_uc_income_from_capital_properties.py +++ b/policyengine_uk/tests/test_uc_income_from_capital_properties.py @@ -255,8 +255,9 @@ def test_interest_dividends_and_rent_leave_the_award_unchanged(units, scale, yea unchanged = np.isclose( scaled["personal_allowances"], base["personal_allowances"], atol=0.01 ) - # Compare the capped award only where the exemption is the same; tax - # on capital income can affect earnings through the allowance taper. + # Compare the capped award only where the exemption is the same: + # capital income can change another exemption route, such as Working + # Tax Credit or the pension-age Housing Benefit rules. same_cap = unchanged & ( scaled["is_benefit_cap_exempt"] == base["is_benefit_cap_exempt"] ) From 8b997692ff85e7bba78477bc4f7590a13ae35980 Mon Sep 17 00:00:00 2001 From: Max Ghenis Date: Tue, 13 Oct 2026 19:48:14 -0400 Subject: [PATCH 4/4] Allow the coverage code-object test to skip in wheel mode The release workflow tests the installed wheel without coverage, so test_a_simulation_leaves_coverage_no_new_code_objects skips there ("coverage is not measuring with sys.monitoring"). It had no allowlist entry, so every wheel-mode Release test / Result failed on it, behind the statutory-pay failure this PR fixes. The entry is limited to wheel mode and to that skip reason. The test still runs and passes in source mode on every PR. Replaying this PR's own release run (38479445636) through check_test_shards.py with the entry: every collected test ran in exactly one shard and passed, apart from allowlisted outcomes. Co-Authored-By: Claude Opus 5.5 --- .github/test_outcome_allowlist.toml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.github/test_outcome_allowlist.toml b/.github/test_outcome_allowlist.toml index c415bd6a36..757f2b3a49 100644 --- a/.github/test_outcome_allowlist.toml +++ b/.github/test_outcome_allowlist.toml @@ -38,6 +38,13 @@ reason = "not running from a git checkout" modes = ["wheel"] why = "An installed wheel is not a git checkout, so there is no HEAD to compare with." +[[allow]] +nodeid = "policyengine_uk/tests/test_variable_code_sharing.py::test_a_simulation_leaves_coverage_no_new_code_objects" +outcome = "skipped" +reason = "coverage is not measuring with sys.monitoring" +modes = ["wheel"] +why = "The release workflow tests the installed wheel without coverage, so this check of coverage's code objects has nothing to measure there. It runs and passes against the source tree on every PR, where coverage measures with sys.monitoring." + [[allow]] nodeid = "policyengine_uk/tests/code_health/*" outcome = "collect-skipped"