Skip to content

Add the April 2023 minimum wage rates and cite every rate's statutory instrument - #2053

Draft
MaxGhenis wants to merge 2 commits into
mainfrom
minimum-wage-2023-rates
Draft

MaxGhenis wants to merge 2 commits into
mainfrom
minimum-wage-2023-rates

Conversation

@MaxGhenis

@MaxGhenis MaxGhenis commented Oct 2, 2026 •

Copy link
Copy Markdown
Collaborator

Fixes #2044

Problem

gov.hmrc.minimum_wage.non_apprentice and .apprentice jumped from 2022-04-01 to 2024-04-01 in every band. convert_to_fiscal_year_parameters reads these parameters at 30 April, so 2023 read the April 2022 rates. S.I. 2023/354 sets the 1 April 2023 rates:

Band 2023 on main 2023 with this PR
23 and over (national living wage) 9.50 10.42
21 to 22 9.18 10.18
18 to 20 6.83 7.49
Under 18 4.81 5.28
Apprentice 4.81 5.28

Changes

  • Rates. Adds the 1 April 2023 rates to both files. All other values are unchanged; a parsed before-and-after diff shows only the new rows.
  • Citations. Every dated rate from October 2012 to April 2026 now cites the S.I. and regulation that set it (S.I. 2011/2345, 2012/2397, 2013/1975, 2014/2485, 2015/1724, 2016/68, 2016/953, 2017/465, 2018/455, 2019/603, 2020/338, 2021/329, 2022/382, 2023/354, 2024/432, 2025/401 and 2026/357). This replaces the GOV.UK reference on the 2026 rates. Four 2016-04-01 entries (same values) cite S.I. 2016/68 reg. 3, which re-enacted the age rates under the new reg. 4A, matching the entry the 21 band already had.
  • Age bands. The thresholds 0/18/21/23/25 stay constant and are correct every year. A band carries the rate of the band above it while the law groups them: the national living wage applied from 25 (April 2016, S.I. 2016/68), from 23 (April 2021, S.I. 2021/329 reg. 2(3)(b)) and from 21 (April 2024, S.I. 2024/432 reg. 2(3)(a)). The YAML header now records this history.
  • Tests.
    • New policyengine_uk/tests/test_minimum_wage_rates.py checks two hand-transcribed tables:
      • RATES_FROM_COMMENCEMENT: the rates each S.I. set, October 2012 to April 2026.
      • RATES_AT_30_APRIL: the fiscal-year values for 2015 to 2026.
    • The test checks every band for every year in three places: the processed parameters, the minimum_wage variable (one simulation, all years) and the raw YAML at each commencement date.
    • It also adds property and differential tests (see the invariants below).
    • New 2023 YAML cases for minimum_wage: the same five cases as Use each rule's own Universal Credit earned income in the benefit cap, targeted childcare and local CTR #1999, so that hunk merges cleanly. Plus three 2023 Tax-Free Childcare income-condition boundary cases.
  • programs.yaml. The minimum_wage entry now has variable: minimum_wage and parameter_prefix: gov.hmrc.minimum_wage (it was all of gov.hmrc). verified_start_year moves from 2022 to 2017, with a note that 2015 and 2016 use the 30 April values. The new test covers 2015-2026, but 30 April sampling drops the October 2015 and October 2016 changes, so coverage is exact only from 2017. The old entry claimed 2022 onwards while 2023 was wrong.

Verification of the transcribed rates

The rates were transcribed from the S.I. texts on legislation.gov.uk (/made/data.xml). Three independent agents then re-derived the rates in force on 19 check dates (each 1 October from 2012 to 2016 and each 30 April from 2013 to 2026). None of them could see this PR's files, and each used a different source:

  • the amending S.I.s as made;
  • point-in-time versions of NMW Regs 2015 regs. 4 and 4A;
  • GOV.UK, HMRC rates-and-thresholds pages and Low Pay Commission reports.

All three found 0 differences from the tables in the test. legislation.gov.uk has no point-in-time versions of the 1999 Regulations, so for dates before 6 April 2015 the second agent read the amending S.I.s instead. A fourth agent checked all 91 dated references against the cited S.I.s: titles, commencement dates, regulation pinpoints and values. It found every citation correct; its one wording fix to the header comment is applied.

Consumers and test impact

  • Only minimum_wage reads gov.hmrc.minimum_wage (grep). minimum_wage feeds:

    • uc_minimum_income_floor (minimum_wage × 35 × 52);
    • tax_free_childcare_meets_income_requirements (× 16 × 13);
    • extended_childcare_entitlement_meets_income_requirements (× 16 × 13).

    Their 2023 thresholds rise with the rate.

  • No existing YAML test changes. The full suite passes on main and on this branch: 1,373 of 1,373 before the new cases were added.

  • A sensitivity probe set every 2023 rate to £1,000 in memory and ran the suite: all 1,373 tests still passed, so no existing test exercised the 2023 rate. A positive control does the same for 2025 and fails 10 tests (minimum_wage, extended childcare and Tax-Free Childcare), which shows the probe works.

  • The new 2023 YAML cases fail under the pre-fix rates (7 of 25 in those two files) and pass with the fix. The new pytest fails on main's YAML at 2023 and passes on this branch.

  • No microsimulation was run, and this PR reports no fiscal figures.

Invariants

These are checked in test_minimum_wage_rates.py. The properties use Hypothesis (300 derandomized examples each):

  1. Fiscal-year value (differential). For each year from 2015 to the latest dated rate, the processed value equals the value in force on 30 April in the raw YAML, for every age from 16 to 100 and for apprentices. The raw lookup is an independent implementation of the dated-value semantics.
  2. Monotone in age. For 2015-2040, no rate falls as age rises, and the apprenticeship rate is never above any age rate.
  3. No year-to-year cut. For 2015-2040, no rate falls from one year to the next. This is a property of every rate enacted from October 2011 to April 2026, not a rule in the Act.
  4. Change dates. Every change date in the YAML up to the last transcribed S.I. is an S.I. commencement date, and each of those rates cites a legislation.gov.uk S.I. Later rows (announced rates before their S.I. is made) need only a reference, so adding 2027 rates is not blocked.

Overlap and follow-ups

Review

Independent review (subfleet run --task review --tier standard) returned APPROVE. It re-checked every 2023 value, the 2016, 2021 and 2024 band changes and the regulation pinpoints against the S.I.s on legislation.gov.uk, and confirmed that no value other than the 2023 rows changed. Its one should-fix, that verified_start_year: 2015 overclaimed, is applied (now 2017). It could not run commands, so its test results rest on CI.

Commands run

  • uv run --frozen pytest policyengine_uk/tests/test_minimum_wage_rates.py: 46 passed. On main's YAML, the first version of this test failed at 2023.
  • uv run --frozen policyengine-core test policyengine_uk/tests/policy -c policyengine_uk: 1,373 passed on the first branch head (before the new 2023 cases and before rebasing). After rebasing onto main at 3525263, the touched and consumer YAML directories (minimum_wage.yaml, tax_free_childcare/, extended_childcare_entitlement/, income_floor/) pass 156 of 156. CI runs the full suites.
  • Full pytest policyengine_uk/tests/: not rerun locally after the rebase; CI's Test job covers it.
  • uv run --frozen ruff format --check . and ruff check .: clean.

axiom: uk/regulation/uksi/2015/621/4 and /4A encoded-correct for 2026-27 (4.test.yaml, 4A.test.yaml); dated versions queued: reg 4 in TheAxiomFoundation/rulespec-uk#399, reg 4A in TheAxiomFoundation/rulespec-uk#421

🤖 Generated with Claude Code

MaxGhenis and others added 2 commits October 2, 2026 09:36
The minimum wage parameters jumped from 2022-04-01 to 2024-04-01 in every
band, so the fiscal year 2023 (sampled at 30 April) read the April 2022
rates: £9.50 instead of the £10.42 national living wage, and likewise for
every other band (S.I. 2023/354).

- Add the 1 April 2023 rates to non_apprentice.yaml and apprentice.yaml.
- Cite the amending S.I. and regulation for every dated rate from October
  2012 to April 2026, replacing the GOV.UK reference on the 2026 rates with
  S.I. 2026/357, and document the age-band history in the file header.
- Add tests/test_minimum_wage_rates.py: tables transcribed from the S.I.s
  (rates from each commencement date, and rates at 30 April for 2015-2026),
  checked against the processed parameters, the minimum_wage variable and
  the raw YAML, plus property tests (monotone in age and over time) and a
  differential check of the fiscal-year conversion.
- Add 2023 YAML cases for minimum_wage and the Tax-Free Childcare income
  condition.
- programs.yaml: point the minimum_wage entry at its variable and
  parameters and verify it from 2015.

Fixes #2044

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

Fiscal-year sampling at 30 April drops the October 2015 and October 2016
rate changes, so the programs.yaml entry is exact only from 2017; note the
earlier convention instead of claiming 2015 (review on #2053).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@MaxGhenis
MaxGhenis force-pushed the minimum-wage-2023-rates branch from 47e78a8 to 02633b6 Compare October 2, 2026 13:37
MaxGhenis added a commit that referenced this pull request Oct 2, 2026
#2053 adds the same S.I. 2023/354 rates with regulation-level citations
and tests, so #1999 no longer carries them and the two do not conflict.
The benefit cap's 2023-24 threshold follows once #2053 merges (722 a
month; 658 until then). The 2023 benefit cap cases move to 2024-25
(793 a month = 9,516 a year): the 9,520/9,500 pair and the Housing Benefit
regression (9,600 earnings, cap 25,323). The property tests sample 2024
instead of 2023.

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

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.

Minimum wage parameters have no 2023-24 rates, so 2023 uses the 2022-23 rates

1 participant