Repository: PolicyEngine/policyengine-uk (language: python)

Issue:
Make improvements to income tax-related variables



Discussion / hints:

Fix patch:
diff --git a/changelog_entry.yaml b/changelog_entry.yaml
index e69de29bb..03cd930a9 100644
--- a/changelog_entry.yaml
+++ b/changelog_entry.yaml
@@ -0,0 +1,7 @@
+- bump: patch
+  changes:
+    fixed:
+    - Folder distribution and formatting for income tax-related variables.
+    - pays_scottish_income_tax now returns a Boolean value.
+    added:
+    - References to many income tax provisions.
\ No newline at end of file
diff --git a/docs/summary/VARIABLE_STATS.md b/docs/summary/VARIABLE_STATS.md
index 1b1b5f7bb..8de9dd48b 100644
--- a/docs/summary/VARIABLE_STATS.md
+++ b/docs/summary/VARIABLE_STATS.md
@@ -3140,7 +3140,7 @@ All statistics generated from the uprated (to 2022) 2019-20 Family Resources Sur
   - Non-zero count: 2,307.4921264648438
 
 
-- pension_income:
+- private_pension_income:
   - Type: float
   - Entity: person
   - Description: Severe Disablement Allowance
diff --git a/policyengine_uk/data/datasets/frs/calibration/calibrate.py b/policyengine_uk/data/datasets/frs/calibration/calibrate.py
index 854ab8c05..f5c9f66d6 100644
--- a/policyengine_uk/data/datasets/frs/calibration/calibrate.py
+++ b/policyengine_uk/data/datasets/frs/calibration/calibrate.py
@@ -337,7 +337,7 @@ def generate_model_variables(dataset: str, time_period: str = "2023") -> Tuple:
         "total_national_insurance",
         "employment_income",
         "self_employment_income",
-        "pension_income",
+        "private_pension_income",
         "dividend_income",
         "property_income",
         "savings_interest_income",
diff --git a/policyengine_uk/data/datasets/frs/frs.py b/policyengine_uk/data/datasets/frs/frs.py
index 202f969da..0da42cce7 100644
--- a/policyengine_uk/data/datasets/frs/frs.py
+++ b/policyengine_uk/data/datasets/frs/frs.py
@@ -467,7 +467,7 @@ def add_market_income(
         person.index,
     )
 
-    frs["pension_income"] = (
+    frs["private_pension_income"] = (
         pension_payment + pension_tax_paid + pension_deductions_removed
     ) * 52
 
@@ -740,8 +740,8 @@ def add_benefit_income(
         np.array(frs["winter_fuel_allowance_reported"]) / 52
     )
 
-    frs["SSP"] = person.SSPADJ * 52
-    frs["SMP"] = person.SMPADJ * 52
+    frs["statutory_sick_pay"] = person.SSPADJ * 52
+    frs["statutory_maternity_pay"] = person.SMPADJ * 52
 
     frs["student_loans"] = np.maximum(person.TUBORR, 0)
     if "ADEMA" not in person.columns:
diff --git a/policyengine_uk/data/datasets/frs/imputations/consumption.py b/policyengine_uk/data/datasets/frs/imputations/consumption.py
index 692779875..5eeb4dd76 100644
--- a/policyengine_uk/data/datasets/frs/imputations/consumption.py
+++ b/policyengine_uk/data/datasets/frs/imputations/consumption.py
@@ -32,7 +32,7 @@
     "B303p": "employment_income",
     "B3262p": "self_employment_income",
     "B3381": "state_pension",
-    "P049p": "pension_income",
+    "P049p": "private_pension_income",
 }
 
 CONSUMPTION_VARIABLE_RENAMES = {
@@ -60,7 +60,7 @@
     "region",
     "employment_income",
     "self_employment_income",
-    "pension_income",
+    "private_pension_income",
     "household_net_income",
 ]
 
diff --git a/policyengine_uk/data/datasets/frs/imputations/income.py b/policyengine_uk/data/datasets/frs/imputations/income.py
index 0c0f70e8e..9c55927d0 100644
--- a/policyengine_uk/data/datasets/frs/imputations/income.py
+++ b/policyengine_uk/data/datasets/frs/imputations/income.py
@@ -5,7 +5,7 @@
 
 SPI_TAB_FOLDER = Path("/Users/nikhil/ukda/spi_2019_20")
 SPI_RENAMES = dict(
-    pension_income="PENSION",
+    private_pension_income="PENSION",
     self_employment_income="PROFITS",
     property_income="INCPROP",
     savings_interest_income="INCBBS",
@@ -73,7 +73,7 @@ def generate_spi_table(spi: pd.DataFrame):
     "self_employment_income",
     "savings_interest_income",
     "dividend_income",
-    "pension_income",
+    "private_pension_income",
     "employment_expenses",
     "property_income",
     "gift_aid",
diff --git a/policyengine_uk/data/datasets/frs/imputations/wealth.py b/policyengine_uk/data/datasets/frs/imputations/wealth.py
index 01d6445dc..21e91c9ec 100644
--- a/policyengine_uk/data/datasets/frs/imputations/wealth.py
+++ b/policyengine_uk/data/datasets/frs/imputations/wealth.py
@@ -25,7 +25,7 @@
     "household_net_income",
     "num_adults",
     "num_children",
-    "pension_income",
+    "private_pension_income",
     "employment_income",
     "self_employment_income",
     "capital_income",
@@ -70,7 +70,7 @@ def generate_was_table(was: pd.DataFrame):
         "NumAdultW7": "num_adults",
         "NumCh18W7": "num_children",
         # Household Gross Annual income from occupational or private pensions
-        "DVGIPPENR7_AGGR": "pension_income",
+        "DVGIPPENR7_AGGR": "private_pension_income",
         "DVGISER7_AGGR": "self_employment_income",
         # Household Gross annual income from investments
         "DVGIINVR7_aggr": "capital_income",
diff --git a/policyengine_uk/data/datasets/frs/spi_enhanced_frs.py b/policyengine_uk/data/datasets/frs/spi_enhanced_frs.py
index 139d81edf..5bdaa8759 100644
--- a/policyengine_uk/data/datasets/frs/spi_enhanced_frs.py
+++ b/policyengine_uk/data/datasets/frs/spi_enhanced_frs.py
@@ -132,7 +132,7 @@ def generate(self):
     "self_employment_income",
     "savings_interest_income",
     "dividend_income",
-    "pension_income",
+    "private_pension_income",
     "employment_expenses",
     "property_income",
     "gift_aid",
diff --git a/policyengine_uk/data/datasets/frs/ukmod.py b/policyengine_uk/data/datasets/frs/ukmod.py
index 1dfdac0c8..5a5bc8795 100644
--- a/policyengine_uk/data/datasets/frs/ukmod.py
+++ b/policyengine_uk/data/datasets/frs/ukmod.py
@@ -52,10 +52,10 @@ def generate(self):
         ).astype("S")
         data["employment_income"] = ukmod.yem.values * 12
         data["self_employment_income"] = ukmod.yse.values * 12
-        data["pension_income"] = ukmod.ypp.values * 12
-        data["statutory_sick_pay"] = ukmod.bhlwk.values * 12
-        data["statutory_maternity_pay"] = ukmod.bmact_s.values * 12
-        data["statutory_paternity_pay"] = ukmod.bpact_s.values * 12
+        data["private_pension_income"] = ukmod.ypp.values * 12
+        data["household_statutory_sick_pay"] = ukmod.bhlwk.values * 12
+        data["household_statutory_maternity_pay"] = ukmod.bmact_s.values * 12
+        data["household_statutory_paternity_pay"] = ukmod.bpact_s.values * 12
 
         for variable in data:
             data[variable] = {"2018": data[variable]}
diff --git a/policyengine_uk/parameters/calibration/programs/pension_income/budgetary_impact.yaml b/policyengine_uk/parameters/calibration/programs/private_pension_income/budgetary_impact.yaml
similarity index 100%
rename from policyengine_uk/parameters/calibration/programs/pension_income/budgetary_impact.yaml
rename to policyengine_uk/parameters/calibration/programs/private_pension_income/budgetary_impact.yaml
diff --git a/policyengine_uk/parameters/calibration/programs/pension_income/participants.yaml b/policyengine_uk/parameters/calibration/programs/private_pension_income/participants.yaml
similarity index 100%
rename from policyengine_uk/parameters/calibration/programs/pension_income/participants.yaml
rename to policyengine_uk/parameters/calibration/programs/private_pension_income/participants.yaml
diff --git a/policyengine_uk/parameters/gov/dwp/pension_credit/guarantee_credit/income.yaml b/policyengine_uk/parameters/gov/dwp/pension_credit/guarantee_credit/income.yaml
index 841900709..0bd95fad3 100644
--- a/policyengine_uk/parameters/gov/dwp/pension_credit/guarantee_credit/income.yaml
+++ b/policyengine_uk/parameters/gov/dwp/pension_credit/guarantee_credit/income.yaml
@@ -14,7 +14,7 @@ values:
   - earned_income
   - working_tax_credit
   - state_pension
-  - pension_income
+  - private_pension_income
   - capital_income
   - ESA_contrib
   - JSA_contrib
diff --git a/policyengine_uk/parameters/gov/dwp/pension_credit/guarantee_credit/minimum_guarantee.yaml b/policyengine_uk/parameters/gov/dwp/pension_credit/guarantee_credit/minimum_guarantee.yaml
index 4479eaeca..8ba0da360 100644
--- a/policyengine_uk/parameters/gov/dwp/pension_credit/guarantee_credit/minimum_guarantee.yaml
+++ b/policyengine_uk/parameters/gov/dwp/pension_credit/guarantee_credit/minimum_guarantee.yaml
@@ -25,4 +25,4 @@ metadata:
   unit: currency-GBP
   reference:
     - title: The State Pension Credit Regulations 2002 reg. 6
-      url: https://www.legislation.gov.uk/uksi/2002/1792/regulation/6/2021-04-12
+      href: https://www.legislation.gov.uk/uksi/2002/1792/regulation/6/2021-04-12
diff --git a/policyengine_uk/parameters/gov/dwp/pension_credit/income/sources.yaml b/policyengine_uk/parameters/gov/dwp/pension_credit/income/sources.yaml
index 2ff96c314..4d4bb2a5a 100644
--- a/policyengine_uk/parameters/gov/dwp/pension_credit/income/sources.yaml
+++ b/policyengine_uk/parameters/gov/dwp/pension_credit/income/sources.yaml
@@ -13,7 +13,7 @@ values:
   - earned_income
   - working_tax_credit
   - state_pension
-  - pension_income
+  - private_pension_income
   - capital_income
   - ESA_contrib
   - JSA_contrib
diff --git a/policyengine_uk/parameters/gov/dwp/pension_credit/savings_credit/threshold.yaml b/policyengine_uk/parameters/gov/dwp/pension_credit/savings_credit/threshold.yaml
index 30c7b1f04..db5754f87 100644
--- a/policyengine_uk/parameters/gov/dwp/pension_credit/savings_credit/threshold.yaml
+++ b/policyengine_uk/parameters/gov/dwp/pension_credit/savings_credit/threshold.yaml
@@ -32,4 +32,4 @@ metadata:
   propagate_metadata_to_children: true
   reference:
     - title: The State Pension Credit Regulations 2002 reg. 7
-      url: https://www.legislation.gov.uk/uksi/2002/1792/regulation/7/2021-04-12
+      href: https://www.legislation.gov.uk/uksi/2002/1792/regulation/7/2021-04-12
diff --git a/policyengine_uk/parameters/gov/hmrc/income_tax/adjusted_net_income_components.yaml b/policyengine_uk/parameters/gov/hmrc/income_tax/adjusted_net_income_components.yaml
new file mode 100644
index 000000000..08a81e0c8
--- /dev/null
+++ b/policyengine_uk/parameters/gov/hmrc/income_tax/adjusted_net_income_components.yaml
@@ -0,0 +1,19 @@
+description: Components of adjusted net income
+values:
+  0000-01-01:
+    - taxable_employment_income
+    - taxable_pension_income
+    - taxable_social_security_income
+    - taxable_self_employment_income
+    - taxable_property_income
+    - taxable_savings_interest_income
+    - taxable_dividend_income
+    - taxable_miscellaneous_income
+    
+metadata:
+  unit: list
+  label: Adjusted net income components
+  period: year
+  reference:
+    - title: "Income Tax Act 2007, s. 58 (1)"
+      href: https://www.legislation.gov.uk/ukpga/2007/3/section/58
diff --git a/policyengine_uk/parameters/gov/hmrc/income_tax/allowances/annual_allowance/default.yaml b/policyengine_uk/parameters/gov/hmrc/income_tax/allowances/annual_allowance/default.yaml
index 647703677..efbcb9612 100644
--- a/policyengine_uk/parameters/gov/hmrc/income_tax/allowances/annual_allowance/default.yaml
+++ b/policyengine_uk/parameters/gov/hmrc/income_tax/allowances/annual_allowance/default.yaml
@@ -3,4 +3,6 @@ values:
   2015-06-01: 40_000
 metadata:
   unit: currency-GBP
-  reference: https://www.gov.uk/tax-on-your-private-pension/annual-allowance
+  reference: 
+  - title: Tax on your private pension contributions
+    href: https://www.gov.uk/tax-on-your-private-pension/annual-allowance
diff --git a/policyengine_uk/parameters/gov/hmrc/income_tax/allowances/annual_allowance/minimum.yaml b/policyengine_uk/parameters/gov/hmrc/income_tax/allowances/annual_allowance/minimum.yaml
index 2ae815e97..d2fab7f32 100644
--- a/policyengine_uk/parameters/gov/hmrc/income_tax/allowances/annual_allowance/minimum.yaml
+++ b/policyengine_uk/parameters/gov/hmrc/income_tax/allowances/annual_allowance/minimum.yaml
@@ -3,4 +3,6 @@ values:
   2015-06-01: 4_000
 metadata:
   unit: currency-GBP
-  reference: https://www.gov.uk/guidance/pension-schemes-work-out-your-tapered-annual-allowance
+  reference: 
+  - title: Work out your reduced (tapered) annual allowance
+    href: https://www.gov.uk/guidance/pension-schemes-work-out-your-tapered-annual-allowance
diff --git a/policyengine_uk/parameters/gov/hmrc/income_tax/allowances/annual_allowance/reduction_rate.yaml b/policyengine_uk/parameters/gov/hmrc/income_tax/allowances/annual_allowance/reduction_rate.yaml
index a803e5fe8..79ba30d5c 100644
--- a/policyengine_uk/parameters/gov/hmrc/income_tax/allowances/annual_allowance/reduction_rate.yaml
+++ b/policyengine_uk/parameters/gov/hmrc/income_tax/allowances/annual_allowance/reduction_rate.yaml
@@ -3,4 +3,6 @@ values:
   2015-06-01: 0.5
 metadata:
   unit: marginal-rate
-  reference: https://www.gov.uk/tax-on-your-private-pension/annual-allowance
+  reference: 
+  - title: Tax on your private pension contributions
+    href: https://www.gov.uk/tax-on-your-private-pension/annual-allowance
diff --git a/policyengine_uk/parameters/gov/hmrc/income_tax/allowances/annual_allowance/taper.yaml b/policyengine_uk/parameters/gov/hmrc/income_tax/allowances/annual_allowance/taper.yaml
index 1e5c0b2f2..2d8a69507 100644
--- a/policyengine_uk/parameters/gov/hmrc/income_tax/allowances/annual_allowance/taper.yaml
+++ b/policyengine_uk/parameters/gov/hmrc/income_tax/allowances/annual_allowance/taper.yaml
@@ -3,4 +3,6 @@ values:
   2015-06-01: 240_000
 metadata:
   unit: currency-GBP
-  reference: https://www.gov.uk/tax-on-your-private-pension/annual-allowance
+  reference: 
+  - title: Tax on your private pension contributions
+    href: https://www.gov.uk/tax-on-your-private-pension/annual-allowance
diff --git a/policyengine_uk/parameters/gov/hmrc/income_tax/bases/taxable_self_employment_income_deductions.yaml b/policyengine_uk/parameters/gov/hmrc/income_tax/bases/taxable_self_employment_income_deductions.yaml
new file mode 100644
index 000000000..4a12eac2a
--- /dev/null
+++ b/policyengine_uk/parameters/gov/hmrc/income_tax/bases/taxable_self_employment_income_deductions.yaml
@@ -0,0 +1,17 @@
+description: Pre-tax deductions applied to self-employment income
+values:
+  0000-01-01:
+    - loss_relief
+    - capital_allowances
+    - trading_allowance
+metadata:
+  unit: list
+  label: Deductions from self-employment income
+  period: year
+  reference:
+    - title: "Income Tax Act 2007, s. 64"
+      href:  https://www.legislation.gov.uk/ukpga/2007/3/section/64
+    - title: "Capital Allowances Act 2001, s. 1"
+      href:  https://www.legislation.gov.uk/ukpga/2001/2/section/1
+    - title: "Income Tax (Trading and Other Income) Act 2005, s. 783A"
+      href:  https://www.legislation.gov.uk/ukpga/2005/5/section/783A
diff --git a/policyengine_uk/parameters/gov/hmrc/income_tax/earned_taxable_income_exclusions.yaml b/policyengine_uk/parameters/gov/hmrc/income_tax/earned_taxable_income_exclusions.yaml
new file mode 100644
index 000000000..b3fff61ae
--- /dev/null
+++ b/policyengine_uk/parameters/gov/hmrc/income_tax/earned_taxable_income_exclusions.yaml
@@ -0,0 +1,16 @@
+description: Exclusions to earned taxable income
+values:
+  0000-01-01:
+    - taxable_savings_interest_income
+    - taxable_dividend_income
+    - allowances
+    - marriage_allowance
+    - pension_contributions_relief
+    
+metadata:
+  unit: list
+  label: Earned taxable income exclusions
+  period: year
+  reference:
+    - title: "Income Tax Act 2007, s. 24 (1)"
+      href: https://www.legislation.gov.uk/ukpga/2007/3/section/24
diff --git a/policyengine_uk/parameters/gov/hmrc/income_tax/rates/savings_starter_rate/allowance.yaml b/policyengine_uk/parameters/gov/hmrc/income_tax/rates/savings_starter_rate/allowance.yaml
index 6c1a83065..cb23fc9da 100644
--- a/policyengine_uk/parameters/gov/hmrc/income_tax/rates/savings_starter_rate/allowance.yaml
+++ b/policyengine_uk/parameters/gov/hmrc/income_tax/rates/savings_starter_rate/allowance.yaml
@@ -4,4 +4,6 @@ values:
 metadata:
   period: week
   unit: currency-GBP
-  reference: https://www.gov.uk/apply-tax-free-interest-on-savings
+  reference: 
+  - title: Tax on savings interest
+    href: https://www.gov.uk/apply-tax-free-interest-on-savings
diff --git a/policyengine_uk/parameters/gov/hmrc/income_tax/rates/scotland/pre_starter_rate.yaml b/policyengine_uk/parameters/gov/hmrc/income_tax/rates/scotland/pre_starter_rate.yaml
index 614226a89..a93303605 100644
--- a/policyengine_uk/parameters/gov/hmrc/income_tax/rates/scotland/pre_starter_rate.yaml
+++ b/policyengine_uk/parameters/gov/hmrc/income_tax/rates/scotland/pre_starter_rate.yaml
@@ -19,6 +19,8 @@ metadata:
   period: year
   propagate_metadata_to_children: true
   rate_unit: /1
-  reference: https://www.gov.uk/government/publications/rates-and-allowances-income-tax/income-tax-rates-and-allowances-current-and-past
+  reference: 
+  - title: Income Tax rates and allowances for current and previous tax years
+    href: https://www.gov.uk/government/publications/rates-and-allowances-income-tax/income-tax-rates-and-allowances-current-and-past
   threshold_unit: currency-GBP
   type: marginal_rate
diff --git a/policyengine_uk/parameters/gov/hmrc/income_tax/rates/uk.yaml b/policyengine_uk/parameters/gov/hmrc/income_tax/rates/uk.yaml
index 4d6436383..e8fa1e949 100644
--- a/policyengine_uk/parameters/gov/hmrc/income_tax/rates/uk.yaml
+++ b/policyengine_uk/parameters/gov/hmrc/income_tax/rates/uk.yaml
@@ -6,7 +6,7 @@ brackets:
       label: Basic rate
       reference:
       - href: https://www.legislation.gov.uk/ukpga/2022/3/section/2/enacted
-        title: Finance Act 2022 s. 2
+        title: Finance Act 2022 s. 2 (a)
       unit: /1
     values:
       2015-06-01: 0.2
@@ -14,8 +14,8 @@ brackets:
     description: The starting threshold for the basic rate, after allowances.
     metadata:
       reference:
-      - href: https://www.legislation.gov.uk/ukpga/2022/3/section/2/enacted
-        title: Finance Act 2022 s. 2
+      - title: Income Tax Act 2007, s. 6 (1)(b)
+        href: https://www.legislation.gov.uk/ukpga/2007/3/section/6
     values:
       2015-06-05: 0
 - rate:
@@ -24,7 +24,7 @@ brackets:
       label: Higher rate
       reference:
       - href: https://www.legislation.gov.uk/ukpga/2022/3/section/2/enacted
-        title: Finance Act 2022 s. 2
+        title: Finance Act 2022 s. 2 (b)
       unit: /1
     values:
       2015-06-05: 0.4
@@ -35,8 +35,8 @@ brackets:
       label: Higher rate threshold
       period: year
       reference:
-      - href: https://www.legislation.gov.uk/ukpga/2022/3/section/2/enacted
-        title: Finance Act 2022 s. 2
+      - href: https://www.legislation.gov.uk/ukpga/2021/26/section/5
+        title: Finance Act 2021 s. 5 (1)
       unit: currency-GBP
       uprating: gov.benefit_uprating_cpi
     values:
@@ -53,7 +53,7 @@ brackets:
       label: Additional rate
       reference:
       - href: https://www.legislation.gov.uk/ukpga/2022/3/section/2/enacted
-        title: Finance Act 2022 s. 2
+        title: Finance Act 2022 s. 2 (c)
       tests:
       - decreases_net_income: true
         period: 2022
@@ -72,9 +72,9 @@ brackets:
     values:
       2015-06-05: 150_000
       2023-01-01: 
-        value: 125_140 # Not actually hard-coded: it's defined as the PA phase-out threshold + 2 * the PA
+        value: 125_140 
         reference:
-          - title: Finance Act 2023 s. 6
+          - title: Finance Act 2023 s. 6 (4)
             href: https://www.legislation.gov.uk/ukpga/2023/1/section/6/enacted
 - rate:
     description: An extra tax bracket.
diff --git a/policyengine_uk/parameters/gov/hmrc/income_tax/reliefs/pension_contribution/basic_amount.yaml b/policyengine_uk/parameters/gov/hmrc/income_tax/reliefs/pension_contribution/basic_amount.yaml
index c22509f54..24a7af2f0 100644
--- a/policyengine_uk/parameters/gov/hmrc/income_tax/reliefs/pension_contribution/basic_amount.yaml
+++ b/policyengine_uk/parameters/gov/hmrc/income_tax/reliefs/pension_contribution/basic_amount.yaml
@@ -2,7 +2,9 @@ description: The 'basic amount' - the maximum amount of tax relief from pension
 metadata:
   economy: false
   propagate_metadata_to_children: true
-  reference: Finance Act 2004 s. 190(4)
+  reference: 
+  - title: Finance Act 2004 s. 190 (4)
+    href: https://www.legislation.gov.uk/ukpga/2004/12/section/190
   unit: currency-GBP
 values:
-  2004-07-22: 3600
+  2004-07-22: 3_600
diff --git a/policyengine_uk/parameters/gov/hmrc/pensions/pension_contributions_relief_age_limit.yaml b/policyengine_uk/parameters/gov/hmrc/pensions/pension_contributions_relief_age_limit.yaml
new file mode 100644
index 000000000..120b3b785
--- /dev/null
+++ b/policyengine_uk/parameters/gov/hmrc/pensions/pension_contributions_relief_age_limit.yaml
@@ -0,0 +1,10 @@
+description: The pensions contributions relief is limited to filers below this age threshold.
+values:
+  2004-01-01: 75
+metadata:
+  unit: year
+  label: pension contributions relief age limit
+  period: year
+  reference:
+    - title: Finance Act 2004, s. 188 (3)(a)
+      href: https://www.legislation.gov.uk/ukpga/2004/12/section/188
diff --git a/policyengine_uk/parameters/gov/hmrc/income_tax/reliefs/pension_contribution/pensions_programs.yaml b/policyengine_uk/parameters/gov/hmrc/pensions/pensions_programs.yaml
similarity index 76%
rename from policyengine_uk/parameters/gov/hmrc/income_tax/reliefs/pension_contribution/pensions_programs.yaml
rename to policyengine_uk/parameters/gov/hmrc/pensions/pensions_programs.yaml
index b0ac8439a..a373b6fcf 100644
--- a/policyengine_uk/parameters/gov/hmrc/income_tax/reliefs/pension_contribution/pensions_programs.yaml
+++ b/policyengine_uk/parameters/gov/hmrc/pensions/pensions_programs.yaml
@@ -5,6 +5,6 @@ values:
     - occupational_pension_contributions
     
 metadata:
-  unit: program
-  label: Refundable tax credits
+  unit: list
+  label: Pensions programs
   period: year
diff --git a/policyengine_uk/reforms/policyengine/budget_change.py b/policyengine_uk/reforms/policyengine/budget_change.py
index 7ffd492de..5c0f1dfdf 100644
--- a/policyengine_uk/reforms/policyengine/budget_change.py
+++ b/policyengine_uk/reforms/policyengine/budget_change.py
@@ -31,8 +31,8 @@ class pre_budget_change_household_benefits(Variable):
         "sda",
         "state_pension",
         "maternity_allowance",
-        "SSP",
-        "SMP",
+        "statutory_sick_pay",
+        "statutory_maternity_pay",
         "ssmg",
         "basic_income",
         "epg_subsidy",
@@ -390,8 +390,8 @@ class household_benefits(Variable):
         "sda",
         "state_pension",
         "maternity_allowance",
-        "SSP",
-        "SMP",
+        "statutory_sick_pay",
+        "statutory_maternity_pay",
         "ssmg",
         "basic_income",
         "epg_subsidy",
diff --git a/policyengine_uk/variables/gov/dwp/JSA_income.py b/policyengine_uk/variables/gov/dwp/JSA_income.py
index ecc7c5b95..bda32c2af 100644
--- a/policyengine_uk/variables/gov/dwp/JSA_income.py
+++ b/policyengine_uk/variables/gov/dwp/JSA_income.py
@@ -102,7 +102,7 @@ def formula(benunit, period, parameters):
             "employment_income",
             "self_employment_income",
             "property_income",
-            "pension_income",
+            "private_pension_income",
         ]
         bi = parameters(period).gov.contrib.ubi_center.basic_income
         if bi.interactions.include_in_means_tests:
diff --git a/policyengine_uk/variables/gov/dwp/housing_benefit.py b/policyengine_uk/variables/gov/dwp/housing_benefit.py
new file mode 100644
index 000000000..e69de29bb
diff --git a/policyengine_uk/variables/gov/dwp/housing_benefit/applicable_income/housing_benefit_applicable_income.py b/policyengine_uk/variables/gov/dwp/housing_benefit/applicable_income/housing_benefit_applicable_income.py
index d68e0c9a9..69e1026ba 100644
--- a/policyengine_uk/variables/gov/dwp/housing_benefit/applicable_income/housing_benefit_applicable_income.py
+++ b/policyengine_uk/variables/gov/dwp/housing_benefit/applicable_income/housing_benefit_applicable_income.py
@@ -19,7 +19,7 @@ def formula(benunit, period, parameters):
             "employment_income",
             "self_employment_income",
             "property_income",
-            "pension_income",
+            "private_pension_income",
         ]
         bi = parameters(period).gov.contrib.ubi_center.basic_income
         # Add personal benefits, credits and total benefits to income
diff --git a/policyengine_uk/variables/gov/dwp/income_support.py b/policyengine_uk/variables/gov/dwp/income_support.py
index 2179f1ac6..7ec3ee9c0 100644
--- a/policyengine_uk/variables/gov/dwp/income_support.py
+++ b/policyengine_uk/variables/gov/dwp/income_support.py
@@ -46,7 +46,7 @@ def formula(benunit, period, parameters):
             "employment_income",
             "self_employment_income",
             "property_income",
-            "pension_income",
+            "private_pension_income",
         ]
         bi = parameters(period).gov.contrib.ubi_center.basic_income
         if bi.interactions.include_in_means_tests:
diff --git a/policyengine_uk/variables/gov/dwp/tax_credits.py b/policyengine_uk/variables/gov/dwp/tax_credits.py
index 29179ebab..2bdb0c03d 100644
--- a/policyengine_uk/variables/gov/dwp/tax_credits.py
+++ b/policyengine_uk/variables/gov/dwp/tax_credits.py
@@ -28,7 +28,7 @@ class tax_credits_applicable_income(Variable):
     def formula(benunit, period, parameters):
         TC = parameters(period).gov.dwp.tax_credits
         STEP_1_COMPONENTS = [
-            "pension_income",
+            "private_pension_income",
             "savings_interest_income",
             "dividend_income",
             "property_income",
diff --git a/policyengine_uk/variables/gov/hmrc/benefits/statutory_maternity_pay.py b/policyengine_uk/variables/gov/hmrc/benefits/statutory_maternity_pay.py
new file mode 100644
index 000000000..4d81b25e0
--- /dev/null
+++ b/policyengine_uk/variables/gov/hmrc/benefits/statutory_maternity_pay.py
@@ -0,0 +1,13 @@
+from policyengine_uk.model_api import *
+
+
+class statutory_maternity_pay(Variable):
+    value_type = float
+    entity = Person
+    label = "Statutory Maternity Pay"
+    definition_period = YEAR
+    unit = GBP
+    reference = dict(
+        title="Social Security Contributions and Benefits Act 1992, Part XII",
+        href="http://www.legislation.gov.uk/ukpga/1992/4/part/XII",
+    )
diff --git a/policyengine_uk/variables/gov/hmrc/benefits/statutory_sick_pay.py b/policyengine_uk/variables/gov/hmrc/benefits/statutory_sick_pay.py
new file mode 100644
index 000000000..544d45092
--- /dev/null
+++ b/policyengine_uk/variables/gov/hmrc/benefits/statutory_sick_pay.py
@@ -0,0 +1,13 @@
+from policyengine_uk.model_api import *
+
+
+class statutory_sick_pay(Variable):
+    value_type = float
+    entity = Person
+    label = "Statutory Sick Pay"
+    definition_period = YEAR
+    unit = GBP
+    reference = dict(
+        title="Social Security Contributions and Benefits Act 1992, Part XI",
+        href="http://www.legislation.gov.uk/ukpga/1992/4/part/XI",
+    )
diff --git a/policyengine_uk/variables/gov/hmrc/income_tax/adjusted_net_income.py b/policyengine_uk/variables/gov/hmrc/income_tax/adjusted_net_income.py
new file mode 100644
index 000000000..3723b6a60
--- /dev/null
+++ b/policyengine_uk/variables/gov/hmrc/income_tax/adjusted_net_income.py
@@ -0,0 +1,30 @@
+from policyengine_uk.model_api import *
+
+
+class adjusted_net_income(Variable):
+    value_type = float
+    entity = Person
+    label = "Taxable income after tax reliefs and before allowances"
+    definition_period = YEAR
+    reference = dict(
+        title="Income Tax Act 2007, s. 23",
+        href="https://www.legislation.gov.uk/ukpga/2007/3/section/23",
+    )
+    unit = GBP
+
+    def formula(person, period, parameters):
+        adjusted_net_income_components = parameters(
+            period
+        ).gov.hmrc.income_tax.adjusted_net_income_components
+
+        # Find adjusted net income
+        ani = add(person, period, adjusted_net_income_components)
+
+        # For basic income contributions, add basic income
+        # Modifying param list directly is mutative, hence two-step process
+        if parameters(
+            period
+        ).gov.contrib.ubi_center.basic_income.interactions.include_in_taxable_income:
+            ani += person("basic_income", period)
+
+        return max_(0, ani)
diff --git a/policyengine_uk/variables/gov/hmrc/income_tax/base.py b/policyengine_uk/variables/gov/hmrc/income_tax/base.py
index 1d96208e0..2983126ac 100644
--- a/policyengine_uk/variables/gov/hmrc/income_tax/base.py
+++ b/policyengine_uk/variables/gov/hmrc/income_tax/base.py
@@ -20,7 +20,7 @@ class total_pension_income(Variable):
     value_type = float
     unit = GBP
 
-    adds = ["pension_income", "state_pension"]
+    adds = ["private_pension_income", "state_pension"]
 
 
 class social_security_income(Variable):
diff --git a/policyengine_uk/variables/gov/hmrc/income_tax/bases/savings_income/ISA_interest_income.py b/policyengine_uk/variables/gov/hmrc/income_tax/bases/savings_income/ISA_interest_income.py
new file mode 100644
index 000000000..0d8a1d85a
--- /dev/null
+++ b/policyengine_uk/variables/gov/hmrc/income_tax/bases/savings_income/ISA_interest_income.py
@@ -0,0 +1,13 @@
+from policyengine_uk.model_api import *
+
+
+class individual_savings_account_interest_income(Variable):
+    value_type = float
+    entity = Person
+    label = "Amount received in interest from Individual Savings Accounts"
+    definition_period = YEAR
+    unit = GBP
+    reference = dict(
+        title="Income Tax (Trading and Other Income) Act 2005, Part VI, s. 3",
+        href="https://www.legislation.gov.uk/ukpga/2005/5/part/6/chapter/3",
+    )
diff --git a/policyengine_uk/variables/gov/hmrc/income_tax/bases/savings_income/tax_free_savings_income.py b/policyengine_uk/variables/gov/hmrc/income_tax/bases/savings_income/tax_free_savings_income.py
new file mode 100644
index 000000000..51a27a353
--- /dev/null
+++ b/policyengine_uk/variables/gov/hmrc/income_tax/bases/savings_income/tax_free_savings_income.py
@@ -0,0 +1,11 @@
+from policyengine_uk.model_api import *
+
+
+class tax_free_savings_income(Variable):
+    value_type = float
+    entity = Person
+    label = "Income from savings in tax-free accounts"
+    definition_period = YEAR
+    unit = GBP
+
+    adds = ["individual_savings_account_interest_income"]
diff --git a/policyengine_uk/variables/gov/hmrc/income_tax/bases/savings_income/taxable_savings_interest_income.py b/policyengine_uk/variables/gov/hmrc/income_tax/bases/savings_income/taxable_savings_interest_income.py
new file mode 100644
index 000000000..67121d9f0
--- /dev/null
+++ b/policyengine_uk/variables/gov/hmrc/income_tax/bases/savings_income/taxable_savings_interest_income.py
@@ -0,0 +1,18 @@
+from policyengine_uk.model_api import *
+
+
+class taxable_savings_interest_income(Variable):
+    value_type = float
+    entity = Person
+    label = "Amount of savings interest which is taxable"
+    definition_period = YEAR
+    reference = dict(
+        title="Income Tax Act (Trading and Other Income) 2005, s. 369",
+        href="https://www.legislation.gov.uk/ukpga/2005/5/section/369",
+    )
+    unit = GBP
+
+    def formula(person, period, parameters):
+        total_interest = person("savings_interest_income", period)
+        exempt_interest = person("tax_free_savings_income", period)
+        return max_(0, total_interest - exempt_interest)
diff --git a/policyengine_uk/variables/gov/hmrc/income_tax/bases/taxable_dividend_income.py b/policyengine_uk/variables/gov/hmrc/income_tax/bases/taxable_dividend_income.py
new file mode 100644
index 000000000..752040c0b
--- /dev/null
+++ b/policyengine_uk/variables/gov/hmrc/income_tax/bases/taxable_dividend_income.py
@@ -0,0 +1,20 @@
+from policyengine_uk.model_api import *
+
+
+class taxable_dividend_income(Variable):
+    value_type = float
+    entity = Person
+    label = "Amount of dividend income that is taxable"
+    definition_period = YEAR
+    reference = dict(
+        title="Income Tax Act (Trading and Other Income) 2005, s. 383",
+        href="https://www.legislation.gov.uk/ukpga/2005/5/section/383",
+    )
+    unit = GBP
+
+    def formula(person, period, parameters):
+        return max_(
+            0,
+            person("dividend_income", period)
+            - person("deficiency_relief", period),
+        )
diff --git a/policyengine_uk/variables/gov/hmrc/income_tax/bases/taxable_employment_income.py b/policyengine_uk/variables/gov/hmrc/income_tax/bases/taxable_employment_income.py
new file mode 100644
index 000000000..cb82e8af7
--- /dev/null
+++ b/policyengine_uk/variables/gov/hmrc/income_tax/bases/taxable_employment_income.py
@@ -0,0 +1,19 @@
+from policyengine_uk.model_api import *
+
+
+class taxable_employment_income(Variable):
+    value_type = float
+    entity = Person
+    label = "Net taxable earnings"
+    definition_period = YEAR
+    reference = dict(
+        title="Income Tax (Earnings and Pensions) Act 2003, s. 11",
+        href="https://www.legislation.gov.uk/ukpga/2003/1/section/11",
+    )
+    unit = GBP
+
+    def formula(person, period, parameters):
+        taxable_earnings = person("employment_income", period)
+        deductions = add(person, period, ["employment_deductions"])
+        benefits = person("employment_benefits", period)
+        return max_(0, taxable_earnings + benefits - deductions)
diff --git a/policyengine_uk/variables/gov/hmrc/income_tax/bases/taxable_miscellaneous_income.py b/policyengine_uk/variables/gov/hmrc/income_tax/bases/taxable_miscellaneous_income.py
new file mode 100644
index 000000000..30f407bf4
--- /dev/null
+++ b/policyengine_uk/variables/gov/hmrc/income_tax/bases/taxable_miscellaneous_income.py
@@ -0,0 +1,15 @@
+from policyengine_uk.model_api import *
+
+
+class taxable_miscellaneous_income(Variable):
+    value_type = float
+    entity = Person
+    label = "Amount of miscellaneous income that is taxable"
+    definition_period = YEAR
+    reference = dict(
+        title="Income Tax Act (Trading and Other Income) 2005, s. 574",
+        href="https://www.legislation.gov.uk/ukpga/2005/5/section/574",
+    )
+    unit = GBP
+
+    adds = ["miscellaneous_income"]
diff --git a/policyengine_uk/variables/gov/hmrc/income_tax/bases/taxable_pension_income.py b/policyengine_uk/variables/gov/hmrc/income_tax/bases/taxable_pension_income.py
new file mode 100644
index 000000000..737c57caa
--- /dev/null
+++ b/policyengine_uk/variables/gov/hmrc/income_tax/bases/taxable_pension_income.py
@@ -0,0 +1,15 @@
+from policyengine_uk.model_api import *
+
+
+class taxable_pension_income(Variable):
+    value_type = float
+    entity = Person
+    label = "Amount of pension income that is taxable"
+    definition_period = YEAR
+    reference = dict(
+        title="Income Tax (Earnings and Pensions) Act 2003, s. 567",
+        href="https://www.legislation.gov.uk/ukpga/2003/1/section/567",
+    )
+    unit = GBP
+
+    adds = ["private_pension_income"]
diff --git a/policyengine_uk/variables/gov/hmrc/income_tax/bases/taxable_property_income.py b/policyengine_uk/variables/gov/hmrc/income_tax/bases/taxable_property_income.py
new file mode 100644
index 000000000..dffe186de
--- /dev/null
+++ b/policyengine_uk/variables/gov/hmrc/income_tax/bases/taxable_property_income.py
@@ -0,0 +1,20 @@
+from policyengine_uk.model_api import *
+
+
+class taxable_property_income(Variable):
+    value_type = float
+    entity = Person
+    label = "Amount of property income that is taxable"
+    definition_period = YEAR
+    reference = dict(
+        title="Income Tax (Trading and Other Income) Act 2005, s. 268",
+        href="https://www.legislation.gov.uk/ukpga/2005/5/section/268",
+    )
+    unit = GBP
+
+    def formula(person, period, parameters):
+        return max_(
+            0,
+            person("property_income", period)
+            - person("property_allowance", period),
+        )
diff --git a/policyengine_uk/variables/gov/hmrc/income_tax/bases/taxable_self_employment_income.py b/policyengine_uk/variables/gov/hmrc/income_tax/bases/taxable_self_employment_income.py
new file mode 100644
index 000000000..ead8fea31
--- /dev/null
+++ b/policyengine_uk/variables/gov/hmrc/income_tax/bases/taxable_self_employment_income.py
@@ -0,0 +1,21 @@
+from policyengine_uk.model_api import *
+
+
+class taxable_self_employment_income(Variable):
+    value_type = float
+    entity = Person
+    label = "Amount of trading income that is taxable"
+    definition_period = YEAR
+    reference = dict(
+        title="Income Tax Act (Trading and Other Income) 2005, s. 5",
+        href="https://www.legislation.gov.uk/ukpga/2005/5/section/5",
+    )
+    unit = GBP
+
+    def formula(person, period, parameters):
+        self_employment_income = person("self_employment_income", period)
+        deductions_list = parameters(
+            period
+        ).gov.hmrc.income_tax.bases.taxable_self_employment_income_deductions
+        deductions = add(person, period, deductions_list)
+        return max_(0, self_employment_income - deductions)
diff --git a/policyengine_uk/variables/gov/hmrc/income_tax/bases/taxable_social_security_income.py b/policyengine_uk/variables/gov/hmrc/income_tax/bases/taxable_social_security_income.py
new file mode 100644
index 000000000..43d56440d
--- /dev/null
+++ b/policyengine_uk/variables/gov/hmrc/income_tax/bases/taxable_social_security_income.py
@@ -0,0 +1,15 @@
+from policyengine_uk.model_api import *
+
+
+class taxable_social_security_income(Variable):
+    value_type = float
+    entity = Person
+    label = "Amount of social security income that is taxable"
+    definition_period = YEAR
+    reference = dict(
+        title="Income Tax (Earnings and Pensions) Act 2003, s. 658",
+        href="https://www.legislation.gov.uk/ukpga/2003/1/section/658",
+    )
+    unit = GBP
+
+    adds = ["social_security_income"]
diff --git a/policyengine_uk/variables/gov/hmrc/income_tax/bases/taxed_dividend_income.py b/policyengine_uk/variables/gov/hmrc/income_tax/bases/taxed_dividend_income.py
new file mode 100644
index 000000000..ff110c7b9
--- /dev/null
+++ b/policyengine_uk/variables/gov/hmrc/income_tax/bases/taxed_dividend_income.py
@@ -0,0 +1,20 @@
+from policyengine_uk.model_api import *
+
+
+class taxed_dividend_income(Variable):
+    value_type = float
+    entity = Person
+    label = "Dividend income which is taxed"
+    definition_period = YEAR
+    unit = GBP
+    reference = dict(
+        title="Income Tax (Trading and Other Income) Act 2005 s. 383",
+        href="https://www.legislation.gov.uk/ukpga/2005/5/section/383",
+    )
+
+    def formula(person, period, parameters):
+        return max_(
+            0,
+            person("taxable_dividend_income", period)
+            - person("dividend_allowance", period),
+        )
diff --git a/policyengine_uk/variables/gov/hmrc/income_tax/bases/trading_loss.py b/policyengine_uk/variables/gov/hmrc/income_tax/bases/trading_loss.py
new file mode 100644
index 000000000..0277b37f8
--- /dev/null
+++ b/policyengine_uk/variables/gov/hmrc/income_tax/bases/trading_loss.py
@@ -0,0 +1,13 @@
+from policyengine_uk.model_api import *
+
+
+class trading_loss(Variable):
+    value_type = float
+    entity = Person
+    label = "Loss from trading in the current year."
+    reference = dict(
+        title="Income Tax Act 2007 s. 64",
+        href="https://www.legislation.gov.uk/ukpga/2007/3/section/64",
+    )
+    definition_period = YEAR
+    unit = GBP
diff --git a/policyengine_uk/variables/gov/hmrc/income_tax/bracketized_earned_income/add_rate_earned_income.py b/policyengine_uk/variables/gov/hmrc/income_tax/bracketized_earned_income/add_rate_earned_income.py
new file mode 100644
index 000000000..73ba9eaaa
--- /dev/null
+++ b/policyengine_uk/variables/gov/hmrc/income_tax/bracketized_earned_income/add_rate_earned_income.py
@@ -0,0 +1,18 @@
+from policyengine_uk.model_api import *
+
+
+class add_rate_earned_income(Variable):
+    value_type = float
+    entity = Person
+    label = "Earned income (non-savings, non-dividend) at the additional rate"
+    definition_period = YEAR
+    unit = GBP
+    reference = dict(
+        title="Income Tax Act 2007, s. 10",
+        href="https://www.legislation.gov.uk/ukpga/2007/3/section/10",
+    )
+
+    def formula(person, period, parameters):
+        income = person("earned_taxable_income", period)
+        thresholds = parameters(period).gov.hmrc.income_tax.rates.uk.thresholds
+        return clip(income, thresholds[2], inf) - thresholds[2]
diff --git a/policyengine_uk/variables/gov/hmrc/income_tax/bracketized_earned_income/basic_rate_earned_income.py b/policyengine_uk/variables/gov/hmrc/income_tax/bracketized_earned_income/basic_rate_earned_income.py
new file mode 100644
index 000000000..7fdf1c463
--- /dev/null
+++ b/policyengine_uk/variables/gov/hmrc/income_tax/bracketized_earned_income/basic_rate_earned_income.py
@@ -0,0 +1,18 @@
+from policyengine_uk.model_api import *
+
+
+class basic_rate_earned_income(Variable):
+    value_type = float
+    entity = Person
+    label = "Earned income (non-savings, non-dividend) at the basic rate"
+    definition_period = YEAR
+    unit = GBP
+    reference = dict(
+        title="Income Tax Act 2007, s. 10",
+        href="https://www.legislation.gov.uk/ukpga/2007/3/section/10",
+    )
+
+    def formula(person, period, parameters):
+        income = person("earned_taxable_income", period)
+        thresholds = parameters(period).gov.hmrc.income_tax.rates.uk.thresholds
+        return clip(income, thresholds[0], thresholds[1])
diff --git a/policyengine_uk/variables/gov/hmrc/income_tax/bracketized_earned_income/earned_taxable_income.py b/policyengine_uk/variables/gov/hmrc/income_tax/bracketized_earned_income/earned_taxable_income.py
new file mode 100644
index 000000000..98dba2b51
--- /dev/null
+++ b/policyengine_uk/variables/gov/hmrc/income_tax/bracketized_earned_income/earned_taxable_income.py
@@ -0,0 +1,21 @@
+from policyengine_uk.model_api import *
+
+
+class earned_taxable_income(Variable):
+    value_type = float
+    entity = Person
+    label = "Non-savings, non-dividend income for Income Tax"
+    definition_period = YEAR
+    reference = dict(
+        title="Income Tax Act 2007, s. 10",
+        href="https://www.legislation.gov.uk/ukpga/2007/3/section/10",
+    )
+    unit = GBP
+
+    def formula(person, period, parameters):
+        exclusion_list = parameters(
+            period
+        ).gov.hmrc.income_tax.earned_taxable_income_exclusions
+        ani = person("adjusted_net_income", period)
+        exclusions = add(person, period, exclusion_list)
+        return max_(0, ani - exclusions)
diff --git a/policyengine_uk/variables/gov/hmrc/income_tax/bracketized_earned_income/higher_rate_earned_income.py b/policyengine_uk/variables/gov/hmrc/income_tax/bracketized_earned_income/higher_rate_earned_income.py
new file mode 100644
index 000000000..6ea178bb9
--- /dev/null
+++ b/policyengine_uk/variables/gov/hmrc/income_tax/bracketized_earned_income/higher_rate_earned_income.py
@@ -0,0 +1,18 @@
+from policyengine_uk.model_api import *
+
+
+class higher_rate_earned_income(Variable):
+    value_type = float
+    entity = Person
+    label = "Earned income (non-savings, non-dividend) at the higher rate"
+    definition_period = YEAR
+    unit = GBP
+    reference = dict(
+        title="Income Tax Act 2007, s. 10",
+        href="https://www.legislation.gov.uk/ukpga/2007/3/section/10",
+    )
+
+    def formula(person, period, parameters):
+        income = person("earned_taxable_income", period)
+        thresholds = parameters(period).gov.hmrc.income_tax.rates.uk.thresholds
+        return clip(income, thresholds[1], thresholds[2]) - thresholds[1]
diff --git a/policyengine_uk/variables/gov/hmrc/income_tax/bracketized_liability/add_rate_earned_income_tax.py b/policyengine_uk/variables/gov/hmrc/income_tax/bracketized_liability/add_rate_earned_income_tax.py
new file mode 100644
index 000000000..6de13e6c8
--- /dev/null
+++ b/policyengine_uk/variables/gov/hmrc/income_tax/bracketized_liability/add_rate_earned_income_tax.py
@@ -0,0 +1,19 @@
+from policyengine_uk.model_api import *
+
+
+class add_rate_earned_income_tax(Variable):
+    value_type = float
+    entity = Person
+    label = "Income tax on earned income at the additional rate"
+    definition_period = YEAR
+    unit = GBP
+    reference = dict(
+        title="Income Tax Act 2007, s. 10",
+        href="https://www.legislation.gov.uk/ukpga/2007/3/section/10",
+    )
+
+    def formula(person, period, parameters):
+        amount = person("add_rate_earned_income", period)
+        return (
+            parameters(period).gov.hmrc.income_tax.rates.uk.rates[2] * amount
+        )
diff --git a/policyengine_uk/variables/gov/hmrc/income_tax/bracketized_liability/basic_rate_earned_income_tax.py b/policyengine_uk/variables/gov/hmrc/income_tax/bracketized_liability/basic_rate_earned_income_tax.py
new file mode 100644
index 000000000..05f09d412
--- /dev/null
+++ b/policyengine_uk/variables/gov/hmrc/income_tax/bracketized_liability/basic_rate_earned_income_tax.py
@@ -0,0 +1,19 @@
+from policyengine_uk.model_api import *
+
+
+class basic_rate_earned_income_tax(Variable):
+    value_type = float
+    entity = Person
+    label = "Income tax on earned income at the basic rate"
+    definition_period = YEAR
+    unit = GBP
+    reference = dict(
+        title="Income Tax Act 2007, s. 10",
+        href="https://www.legislation.gov.uk/ukpga/2007/3/section/10",
+    )
+
+    def formula(person, period, parameters):
+        amount = person("basic_rate_earned_income", period)
+        return (
+            parameters(period).gov.hmrc.income_tax.rates.uk.rates[0] * amount
+        )
diff --git a/policyengine_uk/variables/gov/hmrc/income_tax/bracketized_liability/higher_rate_earned_income_tax.py b/policyengine_uk/variables/gov/hmrc/income_tax/bracketized_liability/higher_rate_earned_income_tax.py
new file mode 100644
index 000000000..1676af503
--- /dev/null
+++ b/policyengine_uk/variables/gov/hmrc/income_tax/bracketized_liability/higher_rate_earned_income_tax.py
@@ -0,0 +1,19 @@
+from policyengine_uk.model_api import *
+
+
+class higher_rate_earned_income_tax(Variable):
+    value_type = float
+    entity = Person
+    label = "Income tax on earned income at the higher rate"
+    definition_period = YEAR
+    unit = GBP
+    reference = dict(
+        title="Income Tax Act 2007, s. 10",
+        href="https://www.legislation.gov.uk/ukpga/2007/3/section/10",
+    )
+
+    def formula(person, period, parameters):
+        amount = person("higher_rate_earned_income", period)
+        return (
+            parameters(period).gov.hmrc.income_tax.rates.uk.rates[1] * amount
+        )
diff --git a/policyengine_uk/variables/gov/hmrc/income_tax/bracketized_liability/tax_band.py b/policyengine_uk/variables/gov/hmrc/income_tax/bracketized_liability/tax_band.py
new file mode 100644
index 000000000..141431cd1
--- /dev/null
+++ b/policyengine_uk/variables/gov/hmrc/income_tax/bracketized_liability/tax_band.py
@@ -0,0 +1,86 @@
+from policyengine_uk.model_api import *
+
+
+class TaxBand(Enum):
+    NONE = "None"
+    STARTER = "Starter (Scottish rates)"
+    BASIC = "Basic"
+    INTERMEDIATE = "Intermediate (Scottish rates)"
+    HIGHER = "Higher"
+    ADDITIONAL = "Additional"
+
+
+class tax_band(Variable):
+    value_type = Enum
+    possible_values = TaxBand
+    default_value = TaxBand.NONE
+    entity = Person
+    label = "Tax band of the individual"
+    definition_period = YEAR
+    reference = dict(
+        title="Income Tax Act 2007, s. 10",
+        href="https://www.legislation.gov.uk/ukpga/2007/3/section/10",
+    )
+
+    def formula(person, period, parameters):
+        allowances = person("allowances", period)
+        ani = person("adjusted_net_income", period)
+        rates = parameters(period).gov.hmrc.income_tax.rates
+        basic = allowances + rates.uk.thresholds[0]
+        higher = allowances + rates.uk.thresholds[-2]
+        add = allowances + rates.uk.thresholds[-1]
+        return select(
+            [ani >= add, ani >= higher, ani > basic],
+            [TaxBand.ADDITIONAL, TaxBand.HIGHER, TaxBand.BASIC],
+            default=TaxBand.NONE,
+        )
+
+    def formula_2017_04_06(person, period, parameters):
+        allowances = person("allowances", period)
+        ani = person("adjusted_net_income", period)
+        rates = parameters(period).gov.hmrc.income_tax.rates
+        scot = person("pays_scottish_income_tax", period)
+        income = ani - allowances
+        uk_band = select(
+            [income < threshold for threshold in rates.uk.thresholds[:3]],
+            [TaxBand.NONE, TaxBand.BASIC, TaxBand.HIGHER],
+            default=TaxBand.ADDITIONAL,
+        )
+        scottish_band = select(
+            [
+                income < threshold
+                for threshold in rates.scotland.pre_starter_rate.thresholds[:3]
+            ],
+            [TaxBand.NONE, TaxBand.BASIC, TaxBand.HIGHER],
+            default=TaxBand.ADDITIONAL,
+        )
+        return where(scot, scottish_band, uk_band)
+
+    def formula_2018_06_01(person, period, parameters):
+        allowances = person("allowances", period)
+        ani = person("adjusted_net_income", period)
+        rates = parameters(period).gov.hmrc.income_tax.rates
+        scot = person("pays_scottish_income_tax", period)
+        income = ani - allowances
+        uk_band = select(
+            [income < threshold for threshold in rates.uk.thresholds[:3]],
+            [TaxBand.NONE, TaxBand.BASIC, TaxBand.HIGHER],
+            default=TaxBand.ADDITIONAL,
+        )
+        scottish_band = select(
+            [
+                income < threshold
+                for threshold in rates.scotland.post_starter_rate.thresholds[
+                    :5
+                ]
+            ],
+            [
+                TaxBand.NONE,
+                TaxBand.STARTER,
+                TaxBand.BASIC,
+                TaxBand.INTERMEDIATE,
+                TaxBand.HIGHER,
+            ],
+            default=TaxBand.ADDITIONAL,
+        )
+        return where(scot, scottish_band, uk_band)
diff --git a/policyengine_uk/variables/gov/hmrc/income_tax/bracketized_savings_income/add_rate_savings_income.py b/policyengine_uk/variables/gov/hmrc/income_tax/bracketized_savings_income/add_rate_savings_income.py
new file mode 100644
index 000000000..7d5314c7b
--- /dev/null
+++ b/policyengine_uk/variables/gov/hmrc/income_tax/bracketized_savings_income/add_rate_savings_income.py
@@ -0,0 +1,34 @@
+from policyengine_uk.model_api import *
+
+
+class add_rate_savings_income(Variable):
+    value_type = float
+    entity = Person
+    label = "Savings income at the higher rate"
+    definition_period = YEAR
+    reference = dict(
+        title="Income Tax Act 2007, s. 11D",
+        href="https://www.legislation.gov.uk/ukpga/2007/3/section/11D",
+    )
+    unit = GBP
+
+    def formula(person, period, parameters):
+        thresholds = parameters(period).gov.hmrc.income_tax.rates.uk.thresholds
+        other_income = person("earned_taxable_income", period)
+        savings_deductions = add(
+            person,
+            period,
+            ["savings_allowance", "savings_starter_rate_income"],
+        )
+        savings_income_less_deductions = max_(
+            0,
+            person("taxable_savings_interest_income", period)
+            - savings_deductions,
+        )
+        add_rate_amount_with = clip(
+            other_income + savings_income_less_deductions,
+            thresholds[2],
+            inf,
+        )
+        add_rate_amount_without = clip(other_income, thresholds[2], inf)
+        return max_(0, add_rate_amount_with - add_rate_amount_without)
diff --git a/policyengine_uk/variables/gov/hmrc/income_tax/bracketized_savings_income/basic_rate_savings_income.py b/policyengine_uk/variables/gov/hmrc/income_tax/bracketized_savings_income/basic_rate_savings_income.py
new file mode 100644
index 000000000..f8269b0f8
--- /dev/null
+++ b/policyengine_uk/variables/gov/hmrc/income_tax/bracketized_savings_income/basic_rate_savings_income.py
@@ -0,0 +1,36 @@
+from policyengine_uk.model_api import *
+
+
+class basic_rate_savings_income(Variable):
+    value_type = float
+    entity = Person
+    label = "Savings income at the basic rate"
+    definition_period = YEAR
+    reference = dict(
+        title="Income Tax Act 2007, s. 11D",
+        href="https://www.legislation.gov.uk/ukpga/2007/3/section/11D",
+    )
+    unit = GBP
+
+    def formula(person, period, parameters):
+        thresholds = parameters(period).gov.hmrc.income_tax.rates.uk.thresholds
+        other_income = person("earned_taxable_income", period)
+        savings_deductions = add(
+            person,
+            period,
+            ["savings_allowance", "savings_starter_rate_income"],
+        )
+        savings_income_less_deductions = max_(
+            0,
+            person("taxable_savings_interest_income", period)
+            - savings_deductions,
+        )
+        basic_rate_amount_with = clip(
+            other_income + savings_income_less_deductions,
+            thresholds[0],
+            thresholds[1],
+        )
+        basic_rate_amount_without = clip(
+            other_income, thresholds[0], thresholds[1]
+        )
+        return max_(0, basic_rate_amount_with - basic_rate_amount_without)
diff --git a/policyengine_uk/variables/gov/hmrc/income_tax/bracketized_savings_income/basic_rate_savings_income_pre_starter.py b/policyengine_uk/variables/gov/hmrc/income_tax/bracketized_savings_income/basic_rate_savings_income_pre_starter.py
new file mode 100644
index 000000000..46276a21c
--- /dev/null
+++ b/policyengine_uk/variables/gov/hmrc/income_tax/bracketized_savings_income/basic_rate_savings_income_pre_starter.py
@@ -0,0 +1,33 @@
+from policyengine_uk.model_api import *
+
+
+class basic_rate_savings_income_pre_starter(Variable):
+    value_type = float
+    entity = Person
+    label = "Savings income which would otherwise be taxed at the basic rate, without the starter rate"
+    definition_period = YEAR
+    unit = GBP
+    reference = dict(
+        title="Income Tax Act 2007, s. 12",
+        href="https://www.legislation.gov.uk/ukpga/2007/3/section/12",
+    )
+
+    def formula(person, period, parameters):
+        thresholds = parameters(period).gov.hmrc.income_tax.rates.uk.thresholds
+        savings_income_total = person(
+            "taxable_savings_interest_income", period
+        )
+        savings_allowance = person("savings_allowance", period)
+        savings_income = max_(0, savings_income_total - savings_allowance)
+        other_income = person("earned_taxable_income", period)
+        basic_rate_amount_with_savings = clip(
+            savings_income + other_income,
+            thresholds[0],
+            thresholds[1],
+        )
+        basic_rate_amount_without_savings = clip(
+            other_income, thresholds[0], thresholds[1]
+        )
+        return (
+            basic_rate_amount_with_savings - basic_rate_amount_without_savings
+        )
diff --git a/policyengine_uk/variables/gov/hmrc/income_tax/bracketized_savings_income/higher_rate_savings_income.py b/policyengine_uk/variables/gov/hmrc/income_tax/bracketized_savings_income/higher_rate_savings_income.py
new file mode 100644
index 000000000..ae87d2baf
--- /dev/null
+++ b/policyengine_uk/variables/gov/hmrc/income_tax/bracketized_savings_income/higher_rate_savings_income.py
@@ -0,0 +1,36 @@
+from policyengine_uk.model_api import *
+
+
+class higher_rate_savings_income(Variable):
+    value_type = float
+    entity = Person
+    label = "Savings income at the higher rate"
+    definition_period = YEAR
+    reference = dict(
+        title="Income Tax Act 2007, s. 11D",
+        href="https://www.legislation.gov.uk/ukpga/2007/3/section/11D",
+    )
+    unit = GBP
+
+    def formula(person, period, parameters):
+        thresholds = parameters(period).gov.hmrc.income_tax.rates.uk.thresholds
+        other_income = person("earned_taxable_income", period)
+        savings_deductions = add(
+            person,
+            period,
+            ["savings_allowance", "savings_starter_rate_income"],
+        )
+        savings_income_less_deductions = max_(
+            0,
+            person("taxable_savings_interest_income", period)
+            - savings_deductions,
+        )
+        higher_rate_amount_with = clip(
+            other_income + savings_income_less_deductions,
+            thresholds[1],
+            thresholds[2],
+        )
+        higher_rate_amount_without = clip(
+            other_income, thresholds[1], thresholds[2]
+        )
+        return max_(0, higher_rate_amount_with - higher_rate_amount_without)
diff --git a/policyengine_uk/variables/gov/hmrc/income_tax/bracketized_savings_income/savings_starter_rate_income.py b/policyengine_uk/variables/gov/hmrc/income_tax/bracketized_savings_income/savings_starter_rate_income.py
new file mode 100644
index 000000000..4c3371175
--- /dev/null
+++ b/policyengine_uk/variables/gov/hmrc/income_tax/bracketized_savings_income/savings_starter_rate_income.py
@@ -0,0 +1,20 @@
+from policyengine_uk.model_api import *
+
+
+class savings_starter_rate_income(Variable):
+    value_type = float
+    entity = Person
+    label = "Savings income which is tax-free under the starter rate"
+    definition_period = YEAR
+    reference = dict(
+        title="Income Tax Act 2007, s. 12",
+        href="https://www.legislation.gov.uk/ukpga/2007/3/section/12",
+    )
+    unit = GBP
+
+    def formula(person, period, parameters):
+        income = person("basic_rate_savings_income_pre_starter", period)
+        limit = parameters(
+            period
+        ).gov.hmrc.income_tax.rates.savings_starter_rate.allowance
+        return max_(0, limit - income)
diff --git a/policyengine_uk/variables/gov/hmrc/income_tax/bracketized_savings_income/taxed_savings_income.py b/policyengine_uk/variables/gov/hmrc/income_tax/bracketized_savings_income/taxed_savings_income.py
new file mode 100644
index 000000000..ab4c9255a
--- /dev/null
+++ b/policyengine_uk/variables/gov/hmrc/income_tax/bracketized_savings_income/taxed_savings_income.py
@@ -0,0 +1,19 @@
+from policyengine_uk.model_api import *
+
+
+class taxed_savings_income(Variable):
+    value_type = float
+    entity = Person
+    label = "Savings income which advances the person's income tax schedule"
+    definition_period = YEAR
+    reference = dict(
+        title="Income Tax Act 2007, s. 11D",
+        href="https://www.legislation.gov.uk/ukpga/2007/3/section/11D",
+    )
+    unit = GBP
+
+    adds = [
+        "basic_rate_savings_income",
+        "higher_rate_savings_income",
+        "add_rate_savings_income",
+    ]
diff --git a/policyengine_uk/variables/gov/hmrc/income_tax/deductions/employment_deductions.py b/policyengine_uk/variables/gov/hmrc/income_tax/deductions/employment_deductions.py
new file mode 100644
index 000000000..e45d9bfaa
--- /dev/null
+++ b/policyengine_uk/variables/gov/hmrc/income_tax/deductions/employment_deductions.py
@@ -0,0 +1,15 @@
+from policyengine_uk.model_api import *
+
+
+class employment_deductions(Variable):
+    value_type = float
+    entity = Person
+    label = "Deductions from employment income"
+    definition_period = YEAR
+    reference = dict(
+        title="Income Tax Act (Earnings and Pensions) Act 2003 s. 327",
+        href="https://www.legislation.gov.uk/ukpga/2003/1/section/327",
+    )
+    unit = GBP
+
+    adds = ["employment_expenses"]
diff --git a/policyengine_uk/variables/gov/hmrc/income_tax/deductions/employment_expenses.py b/policyengine_uk/variables/gov/hmrc/income_tax/deductions/employment_expenses.py
new file mode 100644
index 000000000..c54688064
--- /dev/null
+++ b/policyengine_uk/variables/gov/hmrc/income_tax/deductions/employment_expenses.py
@@ -0,0 +1,15 @@
+from policyengine_uk.model_api import *
+
+
+class employment_expenses(Variable):
+    value_type = float
+    entity = Person
+    label = (
+        "Cost of expenses necessarily incurred and reimbursed by employment"
+    )
+    definition_period = YEAR
+    reference = dict(
+        title="Income Tax Act (Earnings and Pensions) Act 2003 s. 333",
+        href="https://www.legislation.gov.uk/ukpga/2003/1/section/333",
+    )
+    unit = GBP
diff --git a/policyengine_uk/variables/gov/hmrc/income_tax/earned_income_tax.py b/policyengine_uk/variables/gov/hmrc/income_tax/earned_income_tax.py
new file mode 100644
index 000000000..919150516
--- /dev/null
+++ b/policyengine_uk/variables/gov/hmrc/income_tax/earned_income_tax.py
@@ -0,0 +1,17 @@
+from policyengine_uk.model_api import *
+
+
+class earned_income_tax(Variable):
+    value_type = float
+    entity = Person
+    label = "Income tax on earned income"
+    definition_period = YEAR
+    reference = dict(
+        title="Income Tax Act 2007, s. 10",
+        href="https://www.legislation.gov.uk/ukpga/2007/3/section/10",
+    )
+    unit = GBP
+
+    def formula(person, period, parameters):
+        rates = parameters(period).gov.hmrc.income_tax.rates
+        return rates.uk.calc(person("earned_taxable_income", period))
diff --git a/policyengine_uk/variables/gov/hmrc/income_tax/income_tax.py b/policyengine_uk/variables/gov/hmrc/income_tax/income_tax.py
new file mode 100644
index 000000000..3bfe184a2
--- /dev/null
+++ b/policyengine_uk/variables/gov/hmrc/income_tax/income_tax.py
@@ -0,0 +1,24 @@
+from policyengine_uk.model_api import *
+
+
+class income_tax(Variable):
+    value_type = float
+    entity = Person
+    label = "Income Tax"
+    documentation = "Total Income Tax liability"
+    definition_period = YEAR
+    unit = GBP
+    reference = dict(
+        title="Income Tax Act 2007 s. 23",
+        href="https://www.legislation.gov.uk/ukpga/2007/3/section/23",
+    )
+    category = TAX
+    adds = [
+        "earned_income_tax",
+        "savings_income_tax",
+        "dividend_income_tax",
+        "CB_HITC",
+    ]
+    subtracts = [
+        "capped_mcad",
+    ]
diff --git a/policyengine_uk/variables/gov/hmrc/income_tax/income_tax_pre_charges.py b/policyengine_uk/variables/gov/hmrc/income_tax/income_tax_pre_charges.py
new file mode 100644
index 000000000..141671bb5
--- /dev/null
+++ b/policyengine_uk/variables/gov/hmrc/income_tax/income_tax_pre_charges.py
@@ -0,0 +1,19 @@
+from policyengine_uk.model_api import *
+
+
+class income_tax_pre_charges(Variable):
+    value_type = float
+    entity = Person
+    label = "Income Tax before any tax charges"
+    definition_period = YEAR
+    reference = dict(
+        title="Income Tax Act 2007 s. 23",
+        href="https://www.legislation.gov.uk/ukpga/2007/3/section/23",
+    )
+    unit = GBP
+
+    adds = [
+        "earned_income_tax",
+        "savings_income_tax",
+        "dividend_income_tax",
+    ]
diff --git a/policyengine_uk/variables/gov/hmrc/income_tax/liability.py b/policyengine_uk/variables/gov/hmrc/income_tax/liability.py
deleted file mode 100644
index f2bbae89f..000000000
--- a/policyengine_uk/variables/gov/hmrc/income_tax/liability.py
+++ /dev/null
@@ -1,504 +0,0 @@
-from policyengine_uk.model_api import *
-
-"""
-This file calculates the overall liability for Income Tax.
-"""
-
-
-class earned_taxable_income(Variable):
-    value_type = float
-    entity = Person
-    label = "Non-savings, non-dividend income for Income Tax"
-    definition_period = YEAR
-    reference = "Income Tax Act 2007 s. 10"
-    unit = GBP
-
-    def formula(person, period, parameters):
-        EXCLUSIONS = [
-            "taxable_savings_interest_income",
-            "taxable_dividend_income",
-            "allowances",
-            "marriage_allowance",
-            "pension_contributions_relief",
-        ]
-        ANI = person("adjusted_net_income", period)
-        exclusions = add(person, period, EXCLUSIONS)
-        return max_(0, ANI - exclusions)
-
-
-class taxed_income(Variable):
-    value_type = float
-    entity = Person
-    label = "Income which is taxed"
-    definition_period = YEAR
-    unit = GBP
-
-    adds = [
-        "earned_taxable_income",
-        "taxed_savings_income",
-        "taxed_dividend_income",
-    ]
-
-
-class basic_rate_earned_income(Variable):
-    value_type = float
-    entity = Person
-    label = "Earned income (non-savings, non-dividend) at the basic rate"
-    definition_period = YEAR
-    unit = GBP
-
-    def formula(person, period, parameters):
-        income = person("earned_taxable_income", period)
-        thresholds = parameters(period).gov.hmrc.income_tax.rates.uk.thresholds
-        return clip(income, thresholds[0], thresholds[1])
-
-
-class higher_rate_earned_income(Variable):
-    value_type = float
-    entity = Person
-    label = "Earned income (non-savings, non-dividend) at the higher rate"
-    definition_period = YEAR
-    unit = GBP
-
-    def formula(person, period, parameters):
-        income = person("earned_taxable_income", period)
-        thresholds = parameters(period).gov.hmrc.income_tax.rates.uk.thresholds
-        return clip(income, thresholds[1], thresholds[2]) - thresholds[1]
-
-
-class add_rate_earned_income(Variable):
-    value_type = float
-    entity = Person
-    label = "Earned income (non-savings, non-dividend) at the additional rate"
-    definition_period = YEAR
-    unit = GBP
-
-    def formula(person, period, parameters):
-        income = person("earned_taxable_income", period)
-        thresholds = parameters(period).gov.hmrc.income_tax.rates.uk.thresholds
-        return clip(income, thresholds[2], inf) - thresholds[2]
-
-
-class basic_rate_earned_income_tax(Variable):
-    value_type = float
-    entity = Person
-    label = "Income tax on earned income at the basic rate"
-    definition_period = YEAR
-    unit = GBP
-
-    def formula(person, period, parameters):
-        amount = person("basic_rate_earned_income", period)
-        return (
-            parameters(period).gov.hmrc.income_tax.rates.uk.rates[0] * amount
-        )
-
-
-class higher_rate_earned_income_tax(Variable):
-    value_type = float
-    entity = Person
-    label = "Income tax on earned income at the higher rate"
-    definition_period = YEAR
-    unit = GBP
-
-    def formula(person, period, parameters):
-        amount = person("higher_rate_earned_income", period)
-        return (
-            parameters(period).gov.hmrc.income_tax.rates.uk.rates[1] * amount
-        )
-
-
-class add_rate_earned_income_tax(Variable):
-    value_type = float
-    entity = Person
-    label = "Income tax on earned income at the additional rate"
-    definition_period = YEAR
-    unit = GBP
-
-    def formula(person, period, parameters):
-        amount = person("add_rate_earned_income", period)
-        return (
-            parameters(period).gov.hmrc.income_tax.rates.uk.rates[2] * amount
-        )
-
-
-class earned_income_tax(Variable):
-    value_type = float
-    entity = Person
-    label = "Income tax on earned income"
-    definition_period = YEAR
-    reference = "Income Tax Act 2007 s. 10"
-    unit = GBP
-
-    def formula(person, period, parameters):
-        rates = parameters(period).gov.hmrc.income_tax.rates
-        return rates.uk.calc(person("earned_taxable_income", period))
-
-    def formula_2017_04_06(person, period, parameters):
-        rates = parameters(period).gov.hmrc.income_tax.rates
-        scot = person("pays_scottish_income_tax", period)
-        uk_amount = rates.uk.calc(person("earned_taxable_income", period))
-        scot_amount = rates.scotland.pre_starter_rate.calc(
-            person("earned_taxable_income", period)
-        )
-        return where(scot, scot_amount, uk_amount)
-
-    def formula_2018_04_06(person, period, parameters):
-        rates = parameters(period).gov.hmrc.income_tax.rates
-        scot = person("pays_scottish_income_tax", period)
-        uk_amount = rates.uk.calc(person("earned_taxable_income", period))
-        scot_amount = rates.scotland.post_starter_rate.calc(
-            person("earned_taxable_income", period)
-        )
-        return where(scot, scot_amount, uk_amount)
-
-
-class TaxBand(Enum):
-    NONE = "None"
-    STARTER = "Starter (Scottish rates)"
-    BASIC = "Basic"
-    INTERMEDIATE = "Intermediate (Scottish rates)"
-    HIGHER = "Higher"
-    ADDITIONAL = "Additional"
-
-
-class pays_scottish_income_tax(Variable):
-    value_type = float
-    entity = Person
-    label = "Whether the individual pays Scottish Income Tax rates"
-    definition_period = YEAR
-
-    def formula(person, period, parameters):
-        country = person.household("country", period)
-        countries = country.possible_values
-        return person.household("country", period) == countries.SCOTLAND
-
-
-class tax_band(Variable):
-    value_type = Enum
-    possible_values = TaxBand
-    default_value = TaxBand.NONE
-    entity = Person
-    label = "Tax band of the individual"
-    definition_period = YEAR
-
-    def formula(person, period, parameters):
-        allowances = person("allowances", period)
-        ANI = person("adjusted_net_income", period)
-        rates = parameters(period).gov.hmrc.income_tax.rates
-        basic = allowances + rates.uk.thresholds[0]
-        higher = allowances + rates.uk.thresholds[-2]
-        add = allowances + rates.uk.thresholds[-1]
-        return select(
-            [ANI >= add, ANI >= higher, ANI > basic],
-            [TaxBand.ADDITIONAL, TaxBand.HIGHER, TaxBand.BASIC],
-            default=TaxBand.NONE,
-        )
-
-    def formula_2017_04_06(person, period, parameters):
-        allowances = person("allowances", period)
-        ANI = person("adjusted_net_income", period)
-        rates = parameters(period).gov.hmrc.income_tax.rates
-        scot = person("pays_scottish_income_tax", period)
-        income = ANI - allowances
-        uk_band = select(
-            [income < threshold for threshold in rates.uk.thresholds[:3]],
-            [TaxBand.NONE, TaxBand.BASIC, TaxBand.HIGHER],
-            default=TaxBand.ADDITIONAL,
-        )
-        scottish_band = select(
-            [
-                income < threshold
-                for threshold in rates.scotland.pre_starter_rate.thresholds[:3]
-            ],
-            [TaxBand.NONE, TaxBand.BASIC, TaxBand.HIGHER],
-            default=TaxBand.ADDITIONAL,
-        )
-        return where(scot, scottish_band, uk_band)
-
-    def formula_2018_06_01(person, period, parameters):
-        allowances = person("allowances", period)
-        ANI = person("adjusted_net_income", period)
-        rates = parameters(period).gov.hmrc.income_tax.rates
-        scot = person("pays_scottish_income_tax", period)
-        income = ANI - allowances
-        uk_band = select(
-            [income < threshold for threshold in rates.uk.thresholds[:3]],
-            [TaxBand.NONE, TaxBand.BASIC, TaxBand.HIGHER],
-            default=TaxBand.ADDITIONAL,
-        )
-        scottish_band = select(
-            [
-                income < threshold
-                for threshold in rates.scotland.post_starter_rate.thresholds[
-                    :5
-                ]
-            ],
-            [
-                TaxBand.NONE,
-                TaxBand.STARTER,
-                TaxBand.BASIC,
-                TaxBand.INTERMEDIATE,
-                TaxBand.HIGHER,
-            ],
-            default=TaxBand.ADDITIONAL,
-        )
-        return where(scot, scottish_band, uk_band)
-
-
-class basic_rate_savings_income_pre_starter(Variable):
-    value_type = float
-    entity = Person
-    label = "Savings income which would otherwise be taxed at the basic rate, without the starter rate"
-    definition_period = YEAR
-    unit = GBP
-
-    def formula(person, period, parameters):
-        thresholds = parameters(period).gov.hmrc.income_tax.rates.uk.thresholds
-        savings_income_total = person(
-            "taxable_savings_interest_income", period
-        )
-        savings_allowance = person("savings_allowance", period)
-        savings_income = max_(0, savings_income_total - savings_allowance)
-        other_income = person("earned_taxable_income", period)
-        basic_rate_amount_with_savings = clip(
-            savings_income + other_income,
-            thresholds[0],
-            thresholds[1],
-        )
-        basic_rate_amount_without_savings = clip(
-            other_income, thresholds[0], thresholds[1]
-        )
-        return (
-            basic_rate_amount_with_savings - basic_rate_amount_without_savings
-        )
-
-
-class savings_starter_rate_income(Variable):
-    value_type = float
-    entity = Person
-    label = "Savings income which is tax-free under the starter rate"
-    definition_period = YEAR
-    reference = "Income Tax Act 2007 s. 12"
-    unit = GBP
-
-    def formula(person, period, parameters):
-        income = person("basic_rate_savings_income_pre_starter", period)
-        limit = parameters(
-            period
-        ).gov.hmrc.income_tax.rates.savings_starter_rate.allowance
-        return max_(0, limit - income)
-
-
-class basic_rate_savings_income(Variable):
-    value_type = float
-    entity = Person
-    label = "Savings income at the basic rate"
-    definition_period = YEAR
-    reference = "Income Tax Act 2007 s. 11D"
-    unit = GBP
-
-    def formula(person, period, parameters):
-        thresholds = parameters(period).gov.hmrc.income_tax.rates.uk.thresholds
-        other_income = person("earned_taxable_income", period)
-        savings_deductions = add(
-            person,
-            period,
-            ["savings_allowance", "savings_starter_rate_income"],
-        )
-        savings_income_less_deductions = max_(
-            0,
-            person("taxable_savings_interest_income", period)
-            - savings_deductions,
-        )
-        basic_rate_amount_with = clip(
-            other_income + savings_income_less_deductions,
-            thresholds[0],
-            thresholds[1],
-        )
-        basic_rate_amount_without = clip(
-            other_income, thresholds[0], thresholds[1]
-        )
-        return max_(0, basic_rate_amount_with - basic_rate_amount_without)
-
-
-class higher_rate_savings_income(Variable):
-    value_type = float
-    entity = Person
-    label = "Savings income at the higher rate"
-    definition_period = YEAR
-    reference = "Income Tax Act 2007 s. 11D"
-    unit = GBP
-
-    def formula(person, period, parameters):
-        thresholds = parameters(period).gov.hmrc.income_tax.rates.uk.thresholds
-        other_income = person("earned_taxable_income", period)
-        savings_deductions = add(
-            person,
-            period,
-            ["savings_allowance", "savings_starter_rate_income"],
-        )
-        savings_income_less_deductions = max_(
-            0,
-            person("taxable_savings_interest_income", period)
-            - savings_deductions,
-        )
-        higher_rate_amount_with = clip(
-            other_income + savings_income_less_deductions,
-            thresholds[1],
-            thresholds[2],
-        )
-        higher_rate_amount_without = clip(
-            other_income, thresholds[1], thresholds[2]
-        )
-        return max_(0, higher_rate_amount_with - higher_rate_amount_without)
-
-
-class add_rate_savings_income(Variable):
-    value_type = float
-    entity = Person
-    label = "Savings income at the higher rate"
-    definition_period = YEAR
-    reference = "Income Tax Act 2007 s. 11D"
-    unit = GBP
-
-    def formula(person, period, parameters):
-        thresholds = parameters(period).gov.hmrc.income_tax.rates.uk.thresholds
-        other_income = person("earned_taxable_income", period)
-        savings_deductions = add(
-            person,
-            period,
-            ["savings_allowance", "savings_starter_rate_income"],
-        )
-        savings_income_less_deductions = max_(
-            0,
-            person("taxable_savings_interest_income", period)
-            - savings_deductions,
-        )
-        add_rate_amount_with = clip(
-            other_income + savings_income_less_deductions,
-            thresholds[2],
-            inf,
-        )
-        add_rate_amount_without = clip(other_income, thresholds[2], inf)
-        return max_(0, add_rate_amount_with - add_rate_amount_without)
-
-
-class taxed_savings_income(Variable):
-    value_type = float
-    entity = Person
-    label = "Savings income which advances the person's income tax schedule"
-    definition_period = YEAR
-    reference = "Income Tax Act 2007 s. 11D"
-    unit = GBP
-
-    adds = [
-        "basic_rate_savings_income",
-        "higher_rate_savings_income",
-        "add_rate_savings_income",
-    ]
-
-
-class taxed_dividend_income(Variable):
-    value_type = float
-    entity = Person
-    label = "Dividend income which is taxed"
-    definition_period = YEAR
-    unit = GBP
-
-    def formula(person, period, parameters):
-        return max_(
-            0,
-            person("taxable_dividend_income", period)
-            - person("dividend_allowance", period),
-        )
-
-
-class savings_income_tax(Variable):
-    value_type = float
-    entity = Person
-    label = "Income tax on savings income"
-    definition_period = YEAR
-    reference = "Income Tax Act 2007 s. 11D"
-    unit = GBP
-
-    def formula(person, period, parameters):
-        rates = parameters(period).gov.hmrc.income_tax.rates.uk.rates
-        basic_rate_amount = person("basic_rate_savings_income", period)
-        higher_rate_amount = person("higher_rate_savings_income", period)
-        add_rate_amount = person("add_rate_savings_income", period)
-        return (
-            rates[0] * basic_rate_amount
-            + rates[1] * higher_rate_amount
-            + rates[2] * add_rate_amount
-        )
-
-
-class dividend_income_tax(Variable):
-    value_type = float
-    entity = Person
-    label = "Income tax on dividend income"
-    definition_period = YEAR
-    reference = "Income Tax Act 2007 s. 13"
-    unit = GBP
-
-    def formula(person, period, parameters):
-        rates = parameters(period).gov.hmrc.income_tax.rates
-        other_income = person("earned_taxable_income", period) + person(
-            "taxed_savings_income", period
-        )
-        taxable_dividends = person("taxed_dividend_income", period)
-        tax_with_dividends = rates.dividends.calc(
-            other_income + taxable_dividends
-        )
-        tax_without_dividends = rates.dividends.calc(other_income)
-        return tax_with_dividends - tax_without_dividends
-
-
-class income_tax_pre_charges(Variable):
-    value_type = float
-    entity = Person
-    label = "Income Tax before any tax charges"
-    definition_period = YEAR
-    reference = "Income Tax Act 2007 s. 23"
-    unit = GBP
-
-    adds = [
-        "earned_income_tax",
-        "savings_income_tax",
-        "dividend_income_tax",
-    ]
-
-
-class is_higher_earner(Variable):
-    value_type = bool
-    entity = Person
-    label = "Whether this person is the highest earner in a family"
-    definition_period = YEAR
-
-    def formula(person, period, parameters):
-        income = person("adjusted_net_income", period)
-        # Add noise to incomes in order to avoid ties
-        return (
-            person.get_rank(person.benunit, -income + random(person) * 1e-2)
-            == 0
-        )
-
-
-class income_tax(Variable):
-    value_type = float
-    entity = Person
-    label = "Income Tax"
-    documentation = "Total Income Tax liability"
-    definition_period = YEAR
-    unit = GBP
-    reference = "Income Tax Act 2007 s. 23"
-    category = TAX
-    adds = [
-        "earned_income_tax",
-        "savings_income_tax",
-        "dividend_income_tax",
-        "CB_HITC",
-    ]
-    subtracts = [
-        "capped_mcad",
-    ]
diff --git a/policyengine_uk/variables/gov/hmrc/income_tax/liability/dividend_income_tax.py b/policyengine_uk/variables/gov/hmrc/income_tax/liability/dividend_income_tax.py
new file mode 100644
index 000000000..2fdc3d060
--- /dev/null
+++ b/policyengine_uk/variables/gov/hmrc/income_tax/liability/dividend_income_tax.py
@@ -0,0 +1,25 @@
+from policyengine_uk.model_api import *
+
+
+class dividend_income_tax(Variable):
+    value_type = float
+    entity = Person
+    label = "Income tax on dividend income"
+    definition_period = YEAR
+    reference = dict(
+        title="Income Tax Act 2007, s. 13",
+        href="https://www.legislation.gov.uk/ukpga/2007/3/section/13",
+    )
+    unit = GBP
+
+    def formula(person, period, parameters):
+        rates = parameters(period).gov.hmrc.income_tax.rates
+        other_income = person("earned_taxable_income", period) + person(
+            "taxed_savings_income", period
+        )
+        taxable_dividends = person("taxed_dividend_income", period)
+        tax_with_dividends = rates.dividends.calc(
+            other_income + taxable_dividends
+        )
+        tax_without_dividends = rates.dividends.calc(other_income)
+        return max_(0, tax_with_dividends - tax_without_dividends)
diff --git a/policyengine_uk/variables/gov/hmrc/income_tax/liability/savings_income_tax.py b/policyengine_uk/variables/gov/hmrc/income_tax/liability/savings_income_tax.py
new file mode 100644
index 000000000..07c52e498
--- /dev/null
+++ b/policyengine_uk/variables/gov/hmrc/income_tax/liability/savings_income_tax.py
@@ -0,0 +1,24 @@
+from policyengine_uk.model_api import *
+
+
+class savings_income_tax(Variable):
+    value_type = float
+    entity = Person
+    label = "Income tax on savings income"
+    definition_period = YEAR
+    reference = dict(
+        title="Income Tax Act 2007, s. 11D",
+        href="https://www.legislation.gov.uk/ukpga/2007/3/section/11D",
+    )
+    unit = GBP
+
+    def formula(person, period, parameters):
+        rates = parameters(period).gov.hmrc.income_tax.rates.uk.rates
+        basic_rate_amount = person("basic_rate_savings_income", period)
+        higher_rate_amount = person("higher_rate_savings_income", period)
+        add_rate_amount = person("add_rate_savings_income", period)
+        return (
+            rates[0] * basic_rate_amount
+            + rates[1] * higher_rate_amount
+            + rates[2] * add_rate_amount
+        )
diff --git a/policyengine_uk/variables/gov/hmrc/income_tax/relief.py b/policyengine_uk/variables/gov/hmrc/income_tax/relief.py
deleted file mode 100644
index e8c67861a..000000000
--- a/policyengine_uk/variables/gov/hmrc/income_tax/relief.py
+++ /dev/null
@@ -1,329 +0,0 @@
-from policyengine_uk.model_api import *
-
-"""
-These variables calculate the tax reliefs that a taxpayer is eligible for, following the Income Tax Act (2007) s. 23.
-Tax reliefs are amounts to be deducted from the assessed total income of a person.
-The section detailing some tax reliefs applicable is section 24 of the Act, but others are described in the 2003 and 2005 Acts as deductions from the respective components.
-Not all reliefs are calculated here - only the major ones.
-"""
-
-# Employment income
-
-
-class taxable_employment_income(Variable):
-    value_type = float
-    entity = Person
-    label = "Net taxable earnings"
-    definition_period = YEAR
-    reference = "Income Tax (Earnings and Pensions) Act 2003 s. 11"
-    unit = GBP
-
-    def formula(person, period, parameters):
-        taxable_earnings = person("employment_income", period)
-        deductions = add(person, period, ["employment_deductions"])
-        benefits = person("employment_benefits", period)
-        return max_(0, taxable_earnings + benefits - deductions)
-
-
-class employment_benefits(Variable):
-    value_type = float
-    entity = Person
-    label = "Employment benefits"
-    definition_period = YEAR
-    unit = GBP
-
-    adds = ["SSP", "SMP"]
-
-
-class SMP(Variable):
-    value_type = float
-    entity = Person
-    label = "Statutory Maternity Pay"
-    definition_period = YEAR
-    unit = GBP
-
-
-class SSP(Variable):
-    value_type = float
-    entity = Person
-    label = "Statutory Sick Pay"
-    definition_period = YEAR
-    unit = GBP
-
-
-class employment_deductions(Variable):
-    value_type = float
-    entity = Person
-    label = "Deductions from employment income"
-    definition_period = YEAR
-    reference = "Income Tax Act (Earnings and Pensions) Act 2003 s. 327"
-    unit = GBP
-
-    adds = ["employment_expenses"]
-
-
-class employment_expenses(Variable):
-    value_type = float
-    entity = Person
-    label = (
-        "Cost of expenses necessarily incurred and reimbursed by employment"
-    )
-    definition_period = YEAR
-    reference = "Income Tax Act (Earnings and Pensions) Act 2003 s. 333"
-    unit = GBP
-
-
-class pension_contributions(Variable):
-    value_type = float
-    entity = Person
-    label = "Amount contributed to registered pension schemes paid by the individual (not the employer)"
-    definition_period = YEAR
-    unit = GBP
-
-    adds = "gov.hmrc.income_tax.reliefs.pension_contribution.pensions_programs"
-
-
-class pension_contributions_relief(Variable):
-    value_type = float
-    entity = Person
-    label = "Reduction in taxable income from pension contributions"
-    definition_period = YEAR
-    reference = "Finance Act 2004 s. 188-194"
-    unit = GBP
-
-    def formula_2004_07_22(person, period, parameters):
-        contributions = person("pension_contributions", period)
-        pay = add(
-            person, period, ["employment_income", "self_employment_income"]
-        )
-        under_75 = person("age", period) < 75
-        basic_amount = parameters(
-            period
-        ).gov.hmrc.income_tax.reliefs.pension_contribution.basic_amount
-        tax_relief = min_(pay, contributions) * under_75
-        return min_(
-            tax_relief,
-            max_(basic_amount, person("pension_annual_allowance", period)),
-        )
-
-
-# Savings interest income
-
-
-class taxable_savings_interest_income(Variable):
-    value_type = float
-    entity = Person
-    label = "Amount of savings interest which is taxable"
-    definition_period = YEAR
-    reference = "Income Tax Act (Trading and Other Income) 2005 s. 369"
-    unit = GBP
-
-    def formula(person, period, parameters):
-        total_interest = person("savings_interest_income", period)
-        exempt_interest = person("tax_free_savings_income", period)
-        return max_(0, total_interest - exempt_interest)
-
-
-class tax_free_savings_income(Variable):
-    value_type = float
-    entity = Person
-    label = "Income from savings in tax-free accounts"
-    definition_period = YEAR
-    unit = GBP
-
-    adds = ["ISA_interest_income"]
-
-
-class ISA_interest_income(Variable):
-    value_type = float
-    entity = Person
-    label = "Amount received in interest from Individual Savings Accounts"
-    definition_period = YEAR
-    unit = GBP
-
-
-# Trading income
-
-
-class trading_loss(Variable):
-    value_type = float
-    entity = Person
-    label = "Loss from trading in the current year."
-    definition_period = YEAR
-    unit = GBP
-
-
-class capital_allowances(Variable):
-    value_type = float
-    entity = Person
-    label = "Full relief from capital expenditure allowances"
-    definition_period = YEAR
-    reference = "Capital Allowances Act 2001 s. 1"
-    unit = GBP
-
-
-class loss_relief(Variable):
-    value_type = float
-    entity = Person
-    label = "Tax relief from trading losses"
-    definition_period = YEAR
-    reference = "Income Tax (Trading and Other Income) Act 2005 s. 59"
-    documentation = "Can be set against general income."
-    unit = GBP
-
-    def formula(person, period, parameters):
-        current_loss = person("trading_loss", period)
-        previous_loss = person("trading_loss", period.last_year)
-        return current_loss + previous_loss
-
-
-# Pension income
-
-
-class taxable_pension_income(Variable):
-    value_type = float
-    entity = Person
-    label = "Amount of pension income that is taxable"
-    definition_period = YEAR
-    reference = "Income Tax (Earnings and Pensions) Act 2003 s. 567"
-    unit = GBP
-
-    adds = ["pension_income"]
-
-
-# Social security income
-
-
-class taxable_social_security_income(Variable):
-    value_type = float
-    entity = Person
-    label = "Amount of social security income that is taxable"
-    definition_period = YEAR
-    reference = "Income Tax (Earnings and Pensions) Act 2003 s. 658"
-    unit = GBP
-
-    adds = ["social_security_income"]
-
-
-# Trading income
-
-
-class taxable_self_employment_income(Variable):
-    value_type = float
-    entity = Person
-    label = "Amount of trading income that is taxable"
-    definition_period = YEAR
-    reference = "Income Tax (Trading and Other Income) Act 2005 s. 5"
-    unit = GBP
-
-    def formula(person, period, parameters):
-        self_employment_income = person("self_employment_income", period)
-        DEDUCTIONS = ["loss_relief", "capital_allowances", "trading_allowance"]
-        deductions = add(person, period, DEDUCTIONS)
-        return max_(0, self_employment_income - deductions)
-
-
-# Property income
-
-
-class taxable_property_income(Variable):
-    value_type = float
-    entity = Person
-    label = "Amount of property income that is taxable"
-    definition_period = YEAR
-    reference = "Income Tax (Trading and Other Income) Act 2005 s. 268"
-    unit = GBP
-
-    def formula(person, period, parameters):
-        return max_(
-            0,
-            person("property_income", period)
-            - person("property_allowance", period),
-        )
-
-
-# Dividend income
-
-
-class deficiency_relief(Variable):
-    value_type = float
-    entity = Person
-    label = "Deficiency relief"
-    definition_period = YEAR
-    unit = GBP
-
-
-class taxable_dividend_income(Variable):
-    value_type = float
-    entity = Person
-    label = "Amount of dividend income that is taxable"
-    definition_period = YEAR
-    reference = "Income Tax (Trading and Other Income) Act 2005 s. 383"
-    unit = GBP
-
-    def formula(person, period, parameters):
-        return max_(
-            0,
-            person("dividend_income", period)
-            - person("deficiency_relief", period),
-        )
-
-
-# Miscellaneous income
-
-
-class taxable_miscellaneous_income(Variable):
-    value_type = float
-    entity = Person
-    label = "Amount of miscellaneous income that is taxable"
-    definition_period = YEAR
-    reference = "Income Tax (Trading and Other Income) Act 2005 s. 574"
-    unit = GBP
-
-    adds = ["miscellaneous_income"]
-
-
-class total_income(Variable):
-    value_type = float
-    entity = Person
-    label = "Taxable income after tax reliefs and before allowances"
-    definition_period = YEAR
-    reference = "Income Tax Act 2007 s. 23"
-    unit = GBP
-
-    adds = [
-        "employment_income",
-        "pension_income",
-        "social_security_income",
-        "self_employment_income",
-        "property_income",
-        "savings_interest_income",
-        "dividend_income",
-        "miscellaneous_income",
-    ]
-
-
-class adjusted_net_income(Variable):
-    value_type = float
-    entity = Person
-    label = "Taxable income after tax reliefs and before allowances"
-    definition_period = YEAR
-    reference = "Income Tax Act 2007 s. 23"
-    unit = GBP
-
-    def formula(person, period, parameters):
-        COMPONENTS = [
-            "taxable_employment_income",
-            "taxable_pension_income",
-            "taxable_social_security_income",
-            "taxable_self_employment_income",
-            "taxable_property_income",
-            "taxable_savings_interest_income",
-            "taxable_dividend_income",
-            "taxable_miscellaneous_income",
-        ]
-        if parameters(
-            period
-        ).gov.contrib.ubi_center.basic_income.interactions.include_in_taxable_income:
-            COMPONENTS.append("basic_income")
-        return max_(0, add(person, period, COMPONENTS))
diff --git a/policyengine_uk/variables/gov/hmrc/income_tax/reliefs/capital_allowances.py b/policyengine_uk/variables/gov/hmrc/income_tax/reliefs/capital_allowances.py
new file mode 100644
index 000000000..acb536811
--- /dev/null
+++ b/policyengine_uk/variables/gov/hmrc/income_tax/reliefs/capital_allowances.py
@@ -0,0 +1,17 @@
+from policyengine_uk.model_api import *
+
+"""
+The section detailing some tax reliefs applicable is section 24 of the Act, but others are described in the 2003 and 2005 Acts as deductions from the respective components.
+"""
+
+
+class capital_allowances(Variable):
+    value_type = float
+    entity = Person
+    label = "Full relief from capital expenditure allowances"
+    definition_period = YEAR
+    reference = dict(
+        title="Capital Allowances Act 2001 s. 1",
+        href="https://www.legislation.gov.uk/ukpga/2001/2/section/1",
+    )
+    unit = GBP
diff --git a/policyengine_uk/variables/gov/hmrc/income_tax/reliefs/deficiency_relief.py b/policyengine_uk/variables/gov/hmrc/income_tax/reliefs/deficiency_relief.py
new file mode 100644
index 000000000..43d0e8f8d
--- /dev/null
+++ b/policyengine_uk/variables/gov/hmrc/income_tax/reliefs/deficiency_relief.py
@@ -0,0 +1,17 @@
+from policyengine_uk.model_api import *
+
+"""
+The section detailing some tax reliefs applicable is section 24 of the Act, but others are described in the 2003 and 2005 Acts as deductions from the respective components.
+"""
+
+
+class deficiency_relief(Variable):
+    value_type = float
+    entity = Person
+    label = "Deficiency relief"
+    definition_period = YEAR
+    unit = GBP
+    reference = dict(
+        title="Income Tax Act 2007, Part 4",
+        href="https://www.legislation.gov.uk/ukpga/2007/3/part/4",
+    )
diff --git a/policyengine_uk/variables/gov/hmrc/income_tax/reliefs/loss_relief.py b/policyengine_uk/variables/gov/hmrc/income_tax/reliefs/loss_relief.py
new file mode 100644
index 000000000..fc5aaecc6
--- /dev/null
+++ b/policyengine_uk/variables/gov/hmrc/income_tax/reliefs/loss_relief.py
@@ -0,0 +1,24 @@
+from policyengine_uk.model_api import *
+
+
+"""
+The section detailing some tax reliefs applicable is section 24 of the Act, but others are described in the 2003 and 2005 Acts as deductions from the respective components.
+"""
+
+
+class loss_relief(Variable):
+    value_type = float
+    entity = Person
+    label = "Tax relief from trading losses"
+    definition_period = YEAR
+    reference = dict(
+        title="Income Tax (Trading and Other Income) Act 2005 s. 59",
+        href="https://www.legislation.gov.uk/ukpga/2005/5/section/59",
+    )
+    documentation = "Can be set against general income."
+    unit = GBP
+
+    def formula(person, period, parameters):
+        current_loss = person("trading_loss", period)
+        previous_loss = person("trading_loss", period.last_year)
+        return current_loss + previous_loss
diff --git a/policyengine_uk/variables/gov/hmrc/income_tax/taxed_income.py b/policyengine_uk/variables/gov/hmrc/income_tax/taxed_income.py
new file mode 100644
index 000000000..3729ad042
--- /dev/null
+++ b/policyengine_uk/variables/gov/hmrc/income_tax/taxed_income.py
@@ -0,0 +1,19 @@
+from policyengine_uk.model_api import *
+
+
+class taxed_income(Variable):
+    value_type = float
+    entity = Person
+    label = "Income which is taxed"
+    definition_period = YEAR
+    unit = GBP
+    reference = dict(
+        title="Income Tax Act 2007 s. 23",
+        href="https://www.legislation.gov.uk/ukpga/2007/3/section/23",
+    )
+
+    adds = [
+        "earned_taxable_income",
+        "taxed_savings_income",
+        "taxed_dividend_income",
+    ]
diff --git a/policyengine_uk/variables/gov/hmrc/income_tax/total_income.py b/policyengine_uk/variables/gov/hmrc/income_tax/total_income.py
new file mode 100644
index 000000000..f13a71fb4
--- /dev/null
+++ b/policyengine_uk/variables/gov/hmrc/income_tax/total_income.py
@@ -0,0 +1,24 @@
+from policyengine_uk.model_api import *
+
+
+class total_income(Variable):
+    value_type = float
+    entity = Person
+    label = "Taxable income after tax reliefs and before allowances"
+    definition_period = YEAR
+    reference = dict(
+        title="Income Tax Act 2007 s. 23",
+        href="https://www.legislation.gov.uk/ukpga/2007/3/section/23",
+    )
+    unit = GBP
+
+    adds = [
+        "employment_income",
+        "private_pension_income",
+        "social_security_income",
+        "self_employment_income",
+        "property_income",
+        "savings_interest_income",
+        "dividend_income",
+        "miscellaneous_income",
+    ]
diff --git a/policyengine_uk/variables/gov/hmrc/national_insurance/class_1/ni_class_1_income.py b/policyengine_uk/variables/gov/hmrc/national_insurance/class_1/ni_class_1_income.py
index f79e81fba..ec122e8fc 100644
--- a/policyengine_uk/variables/gov/hmrc/national_insurance/class_1/ni_class_1_income.py
+++ b/policyengine_uk/variables/gov/hmrc/national_insurance/class_1/ni_class_1_income.py
@@ -10,8 +10,8 @@ class ni_class_1_income(Variable):
     unit = GBP
     adds = [
         "employment_income",
-        "statutory_sick_pay",
-        "statutory_maternity_pay",
-        "statutory_paternity_pay",
+        "household_statutory_sick_pay",
+        "household_statutory_maternity_pay",
+        "household_statutory_paternity_pay",
     ]
     reference = "https://www.legislation.gov.uk/ukpga/1992/4/section/3"
diff --git a/policyengine_uk/variables/gov/hmrc/pensions/pension_contributions.py b/policyengine_uk/variables/gov/hmrc/pensions/pension_contributions.py
new file mode 100644
index 000000000..1e5d096eb
--- /dev/null
+++ b/policyengine_uk/variables/gov/hmrc/pensions/pension_contributions.py
@@ -0,0 +1,11 @@
+from policyengine_uk.model_api import *
+
+
+class pension_contributions(Variable):
+    value_type = float
+    entity = Person
+    label = "Amount contributed to registered pension schemes paid by the individual (not the employer)"
+    definition_period = YEAR
+    unit = GBP
+
+    adds = "gov.hmrc.pensions.pensions_programs"
diff --git a/policyengine_uk/variables/gov/hmrc/pensions/pension_contributions_relief.py b/policyengine_uk/variables/gov/hmrc/pensions/pension_contributions_relief.py
new file mode 100644
index 000000000..564f8d84a
--- /dev/null
+++ b/policyengine_uk/variables/gov/hmrc/pensions/pension_contributions_relief.py
@@ -0,0 +1,31 @@
+from policyengine_uk.model_api import *
+
+
+class pension_contributions_relief(Variable):
+    value_type = float
+    entity = Person
+    label = "Reduction in taxable income from pension contributions"
+    definition_period = YEAR
+    reference = dict(
+        title="Finance Act 2004 s. 188-194",
+        href="https://www.legislation.gov.uk/ukpga/2004/12/section/188",
+    )
+    unit = GBP
+
+    def formula(person, period, parameters):
+        contributions = person("pension_contributions", period)
+        pension_allowance = person("pension_annual_allowance", period)
+        age_limit = parameters(
+            period
+        ).gov.hmrc.pensions.pension_contributions_relief_age_limit
+        income = add(
+            person, period, ["employment_income", "self_employment_income"]
+        )
+        under_age_limit = person("age", period) < age_limit
+        basic_amount = parameters(
+            period
+        ).gov.hmrc.income_tax.reliefs.pension_contribution.basic_amount
+        tax_relief = min_(income, contributions) * under_age_limit
+        max_pension_relief = max_(basic_amount, pension_allowance)
+
+        return min_(tax_relief, max_pension_relief)
diff --git a/policyengine_uk/variables/gov/hmrc/regional/pays_scottish_income_tax.py b/policyengine_uk/variables/gov/hmrc/regional/pays_scottish_income_tax.py
new file mode 100644
index 000000000..d3f915b6c
--- /dev/null
+++ b/policyengine_uk/variables/gov/hmrc/regional/pays_scottish_income_tax.py
@@ -0,0 +1,13 @@
+from policyengine_uk.model_api import *
+
+
+class pays_scottish_income_tax(Variable):
+    value_type = bool
+    entity = Person
+    label = "Whether the individual pays Scottish Income Tax rates"
+    definition_period = YEAR
+
+    def formula(person, period, parameters):
+        country = person.household("country", period)
+        countries = country.possible_values
+        return person.household("country", period) == countries.SCOTLAND
diff --git a/policyengine_uk/variables/household/benefits/employment_benefits.py b/policyengine_uk/variables/household/benefits/employment_benefits.py
new file mode 100644
index 000000000..279a31333
--- /dev/null
+++ b/policyengine_uk/variables/household/benefits/employment_benefits.py
@@ -0,0 +1,11 @@
+from policyengine_uk.model_api import *
+
+
+class employment_benefits(Variable):
+    value_type = float
+    entity = Person
+    label = "Employment benefits"
+    definition_period = YEAR
+    unit = GBP
+
+    adds = ["statutory_sick_pay", "statutory_maternity_pay"]
diff --git a/policyengine_uk/variables/household/demographic/is_higher_earner.py b/policyengine_uk/variables/household/demographic/is_higher_earner.py
new file mode 100644
index 000000000..353b6fad8
--- /dev/null
+++ b/policyengine_uk/variables/household/demographic/is_higher_earner.py
@@ -0,0 +1,16 @@
+from policyengine_uk.model_api import *
+
+
+class is_higher_earner(Variable):
+    value_type = bool
+    entity = Person
+    label = "Whether this person is the highest earner in a family"
+    definition_period = YEAR
+
+    def formula(person, period, parameters):
+        income = person("adjusted_net_income", period)
+        # Add noise to incomes in order to avoid ties
+        return (
+            person.get_rank(person.benunit, -income + random(person) * 1e-2)
+            == 0
+        )
diff --git a/policyengine_uk/variables/household/income/benefit.py b/policyengine_uk/variables/household/income/benefit.py
index 3789c9c41..def1b5dac 100644
--- a/policyengine_uk/variables/household/income/benefit.py
+++ b/policyengine_uk/variables/household/income/benefit.py
@@ -79,8 +79,8 @@ class household_benefits(Variable):
         "sda",
         "state_pension",
         "maternity_allowance",
-        "SSP",
-        "SMP",
+        "statutory_sick_pay",
+        "statutory_maternity_pay",
         "ssmg",
         "basic_income",
         "epg_subsidy",
@@ -278,8 +278,8 @@ class personal_benefits(Variable):
         "student_payments",
         "student_loans",
         "maternity_allowance",
-        "SSP",
-        "SMP",
+        "statutory_sick_pay",
+        "statutory_maternity_pay",
         "ssmg",
         "basic_income",
     ]
diff --git a/policyengine_uk/variables/household/income/income.py b/policyengine_uk/variables/household/income/income.py
index a2758ab39..1e0a7cbd8 100644
--- a/policyengine_uk/variables/household/income/income.py
+++ b/policyengine_uk/variables/household/income/income.py
@@ -13,7 +13,7 @@ def formula(person, period, parameters):
         COMPONENTS = [
             "employment_income",
             "self_employment_income",
-            "pension_income",
+            "private_pension_income",
         ]
         return add(person, period, COMPONENTS)
 
@@ -34,7 +34,7 @@ def formula(person, period, parameters):
             "dividend_income",
             "miscellaneous_income",
             "property_income",
-            "pension_income",
+            "private_pension_income",
             "private_transfer_income",
             "maintenance_income",
         ]
@@ -354,7 +354,7 @@ class household_market_income(Variable):
         "dividend_income",
         "miscellaneous_income",
         "property_income",
-        "pension_income",
+        "private_pension_income",
         "private_transfer_income",
         "maintenance_income",
         "capital_gains",
@@ -393,7 +393,7 @@ def formula(person, period, parameters):
         return person.household("household_income_decile", period)
 
 
-class statutory_maternity_pay(Variable):
+class household_statutory_maternity_pay(Variable):
     label = "Statutory maternity pay"
     entity = Person
     definition_period = YEAR
@@ -401,7 +401,7 @@ class statutory_maternity_pay(Variable):
     unit = GBP
 
 
-class statutory_paternity_pay(Variable):
+class household_statutory_paternity_pay(Variable):
     label = "Statutory paternity pay"
     entity = Person
     definition_period = YEAR
@@ -409,7 +409,7 @@ class statutory_paternity_pay(Variable):
     unit = GBP
 
 
-class statutory_sick_pay(Variable):
+class household_statutory_sick_pay(Variable):
     label = "Statutory sick pay"
     entity = Person
     definition_period = YEAR
diff --git a/policyengine_uk/variables/input/income.py b/policyengine_uk/variables/input/income.py
index c0ea2269e..d7d2f2257 100644
--- a/policyengine_uk/variables/input/income.py
+++ b/policyengine_uk/variables/input/income.py
@@ -28,6 +28,31 @@ class employment_income_before_lsr(Variable):
     uprating = "calibration.programs.employment_income.budgetary_impact.UNITED_KINGDOM"
 
 
+class private_pension_income(Variable):
+    value_type = float
+    entity = Person
+    label = "pension income"
+    documentation = "Income from private or occupational pensions (not including the State Pension)"
+    definition_period = YEAR
+    unit = GBP
+    reference = "Income Tax (Earnings and Pensions) Act 2003 s. 1(1)(b)"
+    quantity_type = FLOW
+    uprating = (
+        "calibration.programs.private_pension_income.budgetary_impact.ENGLAND"
+    )
+
+    def formula(person, period, parameters):
+        # Don't have data, use the old pension income
+        pension_income = person("pension_income", period)
+        if pension_income.sum() != 0:
+            logging.warn(
+                "`pension_income` is deprecated and will be removed- use `private_pension_income` instead"
+            )
+            return pension_income
+        else:
+            return 0
+
+
 class pension_income(Variable):
     value_type = float
     entity = Person
@@ -37,7 +62,9 @@ class pension_income(Variable):
     unit = GBP
     reference = "Income Tax (Earnings and Pensions) Act 2003 s. 1(1)(b)"
     quantity_type = FLOW
-    uprating = "calibration.programs.pension_income.budgetary_impact.ENGLAND"
+    uprating = (
+        "calibration.programs.private_pension_income.budgetary_impact.ENGLAND"
+    )
 
 
 class state_pension(Variable):


Test patch:
diff --git a/policyengine_uk/parameters/gov/dwp/universal_credit/means_test/income_definitions/unearned.yaml b/policyengine_uk/parameters/gov/dwp/universal_credit/means_test/income_definitions/unearned.yaml
index c6c7020df..cbef9ba31 100644
--- a/policyengine_uk/parameters/gov/dwp/universal_credit/means_test/income_definitions/unearned.yaml
+++ b/policyengine_uk/parameters/gov/dwp/universal_credit/means_test/income_definitions/unearned.yaml
@@ -14,7 +14,7 @@ values:
   2010-01-01:
   - carers_allowance
   - JSA_contrib
-  - pension_income
+  - private_pension_income
   - savings_interest_income
   - dividend_income
   - property_income
diff --git a/policyengine_uk/tests/integration/income.yaml b/policyengine_uk/tests/integration/income.yaml
deleted file mode 100644
index e291602a1..000000000
--- a/policyengine_uk/tests/integration/income.yaml
+++ /dev/null
@@ -1,17 +0,0 @@
-- name: Net income with base income
-  period: 2020
-  absolute_error_margin: 0
-  input:
-    gross_income: 400
-    tax: 50
-  output:
-    net_income: 350
-- name: Household net income can be negative
-  period: 2020
-  absolute_error_margin: 0
-  input:
-    household_market_income: 1
-    household_tax: 2
-    household_benefits: 0
-  output:
-    household_net_income: -1
diff --git a/policyengine_uk/tests/microsimulation/test_uprating.py b/policyengine_uk/tests/microsimulation/test_uprating.py
index 4d7706e68..ae32d600a 100644
--- a/policyengine_uk/tests/microsimulation/test_uprating.py
+++ b/policyengine_uk/tests/microsimulation/test_uprating.py
@@ -6,7 +6,7 @@
 UPRATED_VARIABLES = (
     "council_tax",
     "employment_income",
-    "pension_income",
+    "private_pension_income",
     "self_employment_income",
     "property_income",
     "savings_interest_income",
diff --git a/policyengine_uk/tests/policy/baseline/finance/benefit/family/housing_benefit/applicable_income/housing_benefit_applicable_income.yaml b/policyengine_uk/tests/policy/baseline/finance/benefit/family/housing_benefit/applicable_income/housing_benefit_applicable_income.yaml
index f62cf743d..6d1a7bb23 100644
--- a/policyengine_uk/tests/policy/baseline/finance/benefit/family/housing_benefit/applicable_income/housing_benefit_applicable_income.yaml
+++ b/policyengine_uk/tests/policy/baseline/finance/benefit/family/housing_benefit/applicable_income/housing_benefit_applicable_income.yaml
@@ -10,7 +10,7 @@
     employment_income: 0
     self_employment_income: 0
     property_income: 0
-    pension_income: 0
+    private_pension_income: 0
     # Tax
     income_tax: 0
     national_insurance: 0
@@ -35,7 +35,7 @@
     employment_income: 0
     self_employment_income: 0
     property_income: 0
-    pension_income: 0
+    private_pension_income: 0
     # Tax
     income_tax: 0
     national_insurance: 0
@@ -60,7 +60,7 @@
     employment_income: 0
     self_employment_income: 0
     property_income: 0
-    pension_income: 0
+    private_pension_income: 0
     # Tax
     income_tax: 0
     national_insurance: 0
@@ -85,7 +85,7 @@
     employment_income: 0
     self_employment_income: 0
     property_income: 1_000
-    pension_income: 0
+    private_pension_income: 0
     # Tax
     income_tax: 0
     national_insurance: 0
@@ -110,7 +110,7 @@
     employment_income: 0
     self_employment_income: 0
     property_income: 1_000
-    pension_income: 0
+    private_pension_income: 0
     # Tax
     income_tax: 0
     national_insurance: 0
diff --git a/policyengine_uk/tests/policy/baseline/finance/benefit/family/universal_credit/income/uc_unearned_income.yaml b/policyengine_uk/tests/policy/baseline/finance/benefit/family/universal_credit/income/uc_unearned_income.yaml
index e09887f3d..dc1f8dbcd 100644
--- a/policyengine_uk/tests/policy/baseline/finance/benefit/family/universal_credit/income/uc_unearned_income.yaml
+++ b/policyengine_uk/tests/policy/baseline/finance/benefit/family/universal_credit/income/uc_unearned_income.yaml
@@ -4,7 +4,7 @@
   input:
     carers_allowance: 10_000
     JSA_contrib: 1_000
-    pension_income: 100
+    private_pension_income: 100
     savings_interest_income: 10
     dividend_income: 1
   output:
diff --git a/policyengine_uk/tests/policy/baseline/gov/dwp/pension_credit/housing_benefit.yaml b/policyengine_uk/tests/policy/baseline/gov/dwp/pension_credit/housing_benefit.yaml
index e2ad2ef34..7fa7c3188 100644
--- a/policyengine_uk/tests/policy/baseline/gov/dwp/pension_credit/housing_benefit.yaml
+++ b/policyengine_uk/tests/policy/baseline/gov/dwp/pension_credit/housing_benefit.yaml
@@ -68,7 +68,7 @@
     tenure_type: RENT_FROM_COUNCIL
     housing_benefit_reported: true
     is_single_person: true
-    pension_income: 100*52
+    private_pension_income: 100*52
   output:
     housing_benefit: 80*52
   
\ No newline at end of file
diff --git a/policyengine_uk/tests/policy/baseline/gov/dwp/pension_credit/pension_credit_income.yaml b/policyengine_uk/tests/policy/baseline/gov/dwp/pension_credit/pension_credit_income.yaml
index aef446fe8..270989abe 100644
--- a/policyengine_uk/tests/policy/baseline/gov/dwp/pension_credit/pension_credit_income.yaml
+++ b/policyengine_uk/tests/policy/baseline/gov/dwp/pension_credit/pension_credit_income.yaml
@@ -4,7 +4,7 @@
     earned_income: 1
     working_tax_credit: 2
     state_pension: 4
-    pension_income: 8
+    private_pension_income: 8
     capital_income: 16
     ESA_contrib: 32
     JSA_contrib: 64
diff --git a/policyengine_uk/tests/policy/baseline/gov/hmrc/income_tax/adjusted_net_income.yaml b/policyengine_uk/tests/policy/baseline/gov/hmrc/income_tax/adjusted_net_income.yaml
new file mode 100644
index 000000000..e704ece8e
--- /dev/null
+++ b/policyengine_uk/tests/policy/baseline/gov/hmrc/income_tax/adjusted_net_income.yaml
@@ -0,0 +1,121 @@
+- name: No income from any source
+  period: 2024
+  input:
+    taxable_employment_income: 0
+    taxable_pension_income: 0
+    taxable_social_security_income: 0
+    taxable_self_employment_income: 0
+    taxable_property_income: 0
+    taxable_savings_interest_income: 0
+    taxable_dividend_income: 0
+    taxable_miscellaneous_income: 0
+    basic_income: 0
+  output:
+    adjusted_net_income: 0
+
+- name: Income from all sources
+  period: 2024
+  input:
+    taxable_employment_income: 30000
+    taxable_pension_income: 5000
+    taxable_social_security_income: 2000
+    taxable_self_employment_income: 10000
+    taxable_property_income: 5000
+    taxable_savings_interest_income: 1000
+    taxable_dividend_income: 3000
+    taxable_miscellaneous_income: 500
+    basic_income: 0
+  output:
+    adjusted_net_income: 56500
+
+- name: Only employment income
+  period: 2024
+  input:
+    taxable_employment_income: 40000
+    taxable_pension_income: 0
+    taxable_social_security_income: 0
+    taxable_self_employment_income: 0
+    taxable_property_income: 0
+    taxable_savings_interest_income: 0
+    taxable_dividend_income: 0
+    taxable_miscellaneous_income: 0
+    basic_income: 0
+  output:
+    adjusted_net_income: 40000
+
+- name: High income from multiple sources
+  period: 2024
+  input:
+    taxable_employment_income: 100000
+    taxable_pension_income: 50000
+    taxable_social_security_income: 0
+    taxable_self_employment_income: 75000
+    taxable_property_income: 25000
+    taxable_savings_interest_income: 10000
+    taxable_dividend_income: 20000
+    taxable_miscellaneous_income: 5000
+    basic_income: 0
+  output:
+    adjusted_net_income: 285000
+
+- name: Low income from multiple sources
+  period: 2024
+  input:
+    taxable_employment_income: 5000
+    taxable_pension_income: 1000
+    taxable_social_security_income: 500
+    taxable_self_employment_income: 2000
+    taxable_property_income: 1000
+    taxable_savings_interest_income: 100
+    taxable_dividend_income: 200
+    taxable_miscellaneous_income: 50
+    basic_income: 0
+  output:
+    adjusted_net_income: 9850
+
+- name: Decimal values
+  period: 2024
+  input:
+    taxable_employment_income: 30000.50
+    taxable_pension_income: 5000.25
+    taxable_social_security_income: 2000.75
+    taxable_self_employment_income: 10000.00
+    taxable_property_income: 5000.50
+    taxable_savings_interest_income: 1000.25
+    taxable_dividend_income: 3000.75
+    taxable_miscellaneous_income: 500.00
+    basic_income: 0
+  output:
+    adjusted_net_income: 56503.00
+
+- name: With basic income included
+  period: 2024
+  input:
+    gov.contrib.ubi_center.basic_income.interactions.include_in_taxable_income: true
+    taxable_employment_income: 30000
+    taxable_pension_income: 5000
+    taxable_social_security_income: 2000
+    taxable_self_employment_income: 10000
+    taxable_property_income: 5000
+    taxable_savings_interest_income: 1000
+    taxable_dividend_income: 3000
+    taxable_miscellaneous_income: 500
+    basic_income: 10000
+  output:
+    adjusted_net_income: 66500
+
+- name: Only basic income
+  period: 2024
+  input:
+    gov.contrib.ubi_center.basic_income.interactions.include_in_taxable_income: true
+    taxable_employment_income: 0
+    taxable_pension_income: 0
+    taxable_social_security_income: 0
+    taxable_self_employment_income: 0
+    taxable_property_income: 0
+    taxable_savings_interest_income: 0
+    taxable_dividend_income: 0
+    taxable_miscellaneous_income: 0
+    basic_income: 10000
+  output:
+    adjusted_net_income: 10000
\ No newline at end of file
diff --git a/policyengine_uk/tests/policy/baseline/gov/hmrc/income_tax/base.yaml b/policyengine_uk/tests/policy/baseline/gov/hmrc/income_tax/base.yaml
index f4203034f..77e138726 100644
--- a/policyengine_uk/tests/policy/baseline/gov/hmrc/income_tax/base.yaml
+++ b/policyengine_uk/tests/policy/baseline/gov/hmrc/income_tax/base.yaml
@@ -3,7 +3,7 @@
   absolute_error_margin: 0
   output:
     employment_income: 0
-    pension_income: 0
+    private_pension_income: 0
     social_security_income: 0
     self_employment_income: 0
     property_income: 0
diff --git a/policyengine_uk/tests/policy/baseline/gov/hmrc/income_tax/bases/savings_income/taxable_savings_interest_income.yaml b/policyengine_uk/tests/policy/baseline/gov/hmrc/income_tax/bases/savings_income/taxable_savings_interest_income.yaml
new file mode 100644
index 000000000..5bdf56a23
--- /dev/null
+++ b/policyengine_uk/tests/policy/baseline/gov/hmrc/income_tax/bases/savings_income/taxable_savings_interest_income.yaml
@@ -0,0 +1,71 @@
+- name: No savings interest income
+  period: 2024
+  input:
+    savings_interest_income: 0
+    tax_free_savings_income: 0
+  output:
+    taxable_savings_interest_income: 0
+
+- name: Savings interest income fully covered by tax-free allowance
+  period: 2024
+  input:
+    savings_interest_income: 1000
+    tax_free_savings_income: 1000
+  output:
+    taxable_savings_interest_income: 0
+
+- name: Savings interest income partially taxable
+  period: 2024
+  input:
+    savings_interest_income: 1500
+    tax_free_savings_income: 1000
+  output:
+    taxable_savings_interest_income: 500
+
+- name: High savings interest income, standard tax-free allowance
+  period: 2024
+  input:
+    savings_interest_income: 10000
+    tax_free_savings_income: 1000
+  output:
+    taxable_savings_interest_income: 9000
+
+- name: Savings interest income, no tax-free allowance
+  period: 2024
+  input:
+    savings_interest_income: 5000
+    tax_free_savings_income: 0
+  output:
+    taxable_savings_interest_income: 5000
+
+- name: Very low positive savings interest income
+  period: 2024
+  input:
+    savings_interest_income: 1
+    tax_free_savings_income: 0
+  output:
+    taxable_savings_interest_income: 1
+
+- name: Tax-free allowance exceeds savings interest income
+  period: 2024
+  input:
+    savings_interest_income: 500
+    tax_free_savings_income: 1000
+  output:
+    taxable_savings_interest_income: 0
+
+- name: High values for both inputs
+  period: 2024
+  input:
+    savings_interest_income: 100000
+    tax_free_savings_income: 50000
+  output:
+    taxable_savings_interest_income: 50000
+
+- name: Decimal values
+  period: 2024
+  input:
+    savings_interest_income: 1234.56
+    tax_free_savings_income: 1000.00
+  output:
+    taxable_savings_interest_income: 234.56
\ No newline at end of file
diff --git a/policyengine_uk/tests/policy/baseline/gov/hmrc/income_tax/bases/taxable_dividend_income.yaml b/policyengine_uk/tests/policy/baseline/gov/hmrc/income_tax/bases/taxable_dividend_income.yaml
new file mode 100644
index 000000000..2cb9eef84
--- /dev/null
+++ b/policyengine_uk/tests/policy/baseline/gov/hmrc/income_tax/bases/taxable_dividend_income.yaml
@@ -0,0 +1,71 @@
+- name: No dividend income or deficiency relief
+  period: 2024
+  input:
+    dividend_income: 0
+    deficiency_relief: 0
+  output:
+    taxable_dividend_income: 0
+
+- name: Dividend income fully offset by deficiency relief
+  period: 2024
+  input:
+    dividend_income: 5000
+    deficiency_relief: 5000
+  output:
+    taxable_dividend_income: 0
+
+- name: Dividend income partially taxable
+  period: 2024
+  input:
+    dividend_income: 10000
+    deficiency_relief: 2000
+  output:
+    taxable_dividend_income: 8000
+
+- name: High dividend income with some deficiency relief
+  period: 2024
+  input:
+    dividend_income: 50000
+    deficiency_relief: 5000
+  output:
+    taxable_dividend_income: 45000
+
+- name: Dividend income with no deficiency relief
+  period: 2024
+  input:
+    dividend_income: 15000
+    deficiency_relief: 0
+  output:
+    taxable_dividend_income: 15000
+
+- name: Very low positive dividend income
+  period: 2024
+  input:
+    dividend_income: 1
+    deficiency_relief: 0
+  output:
+    taxable_dividend_income: 1
+
+- name: Deficiency relief exceeds dividend income
+  period: 2024
+  input:
+    dividend_income: 3000
+    deficiency_relief: 5000
+  output:
+    taxable_dividend_income: 0
+
+- name: High values for both dividend income and deficiency relief
+  period: 2024
+  input:
+    dividend_income: 100000
+    deficiency_relief: 40000
+  output:
+    taxable_dividend_income: 60000
+
+- name: Decimal values
+  period: 2024
+  input:
+    dividend_income: 1234.56
+    deficiency_relief: 234.56
+  output:
+    taxable_dividend_income: 1000.00
\ No newline at end of file
diff --git a/policyengine_uk/tests/policy/baseline/gov/hmrc/income_tax/bases/taxable_employment_income.yaml b/policyengine_uk/tests/policy/baseline/gov/hmrc/income_tax/bases/taxable_employment_income.yaml
new file mode 100644
index 000000000..c33f10689
--- /dev/null
+++ b/policyengine_uk/tests/policy/baseline/gov/hmrc/income_tax/bases/taxable_employment_income.yaml
@@ -0,0 +1,25 @@
+- name: Deductions from employment
+  period: 2020
+  absolute_error_margin: 0
+  input:
+    employment_income: 15000
+    employment_deductions: 5000
+  output:
+    taxable_employment_income: 10000
+- name: Deductions from employment stay positive
+  period: 2020
+  absolute_error_margin: 0
+  input:
+    employment_income: 15000
+    employment_deductions: 25000
+  output:
+    taxable_employment_income: 0
+- name: Specific deductions from employment (not pension contributions at this stage)
+  period: 2020
+  absolute_error_margin: 0
+  input:
+    employment_income: 15000
+    pension_contributions: 1000
+    employment_expenses: 2000
+  output:
+    taxable_employment_income: 13000
\ No newline at end of file
diff --git a/policyengine_uk/tests/policy/baseline/gov/hmrc/income_tax/bases/taxable_property_income.yaml b/policyengine_uk/tests/policy/baseline/gov/hmrc/income_tax/bases/taxable_property_income.yaml
new file mode 100644
index 000000000..860bef689
--- /dev/null
+++ b/policyengine_uk/tests/policy/baseline/gov/hmrc/income_tax/bases/taxable_property_income.yaml
@@ -0,0 +1,71 @@
+- name: No property income or allowance
+  period: 2024
+  input:
+    property_income: 0
+    property_allowance: 0
+  output:
+    taxable_property_income: 0
+
+- name: Property income fully covered by allowance
+  period: 2024
+  input:
+    property_income: 1000
+    property_allowance: 1000
+  output:
+    taxable_property_income: 0
+
+- name: Property income partially taxable
+  period: 2024
+  input:
+    property_income: 10000
+    property_allowance: 1000
+  output:
+    taxable_property_income: 9000
+
+- name: High property income with standard allowance
+  period: 2024
+  input:
+    property_income: 50000
+    property_allowance: 1000
+  output:
+    taxable_property_income: 49000
+
+- name: Property income with no allowance
+  period: 2024
+  input:
+    property_income: 5000
+    property_allowance: 0
+  output:
+    taxable_property_income: 5000
+
+- name: Very low positive property income
+  period: 2024
+  input:
+    property_income: 1
+    property_allowance: 0
+  output:
+    taxable_property_income: 1
+
+- name: Property allowance exceeds income
+  period: 2024
+  input:
+    property_income: 500
+    property_allowance: 1000
+  output:
+    taxable_property_income: 0
+
+- name: High values for both income and allowance
+  period: 2024
+  input:
+    property_income: 100000
+    property_allowance: 50000
+  output:
+    taxable_property_income: 50000
+
+- name: Decimal values
+  period: 2024
+  input:
+    property_income: 1234.56
+    property_allowance: 1000.00
+  output:
+    taxable_property_income: 234.56
\ No newline at end of file
diff --git a/policyengine_uk/tests/policy/baseline/gov/hmrc/income_tax/bases/taxable_self_employment_income.yaml b/policyengine_uk/tests/policy/baseline/gov/hmrc/income_tax/bases/taxable_self_employment_income.yaml
new file mode 100644
index 000000000..111e30083
--- /dev/null
+++ b/policyengine_uk/tests/policy/baseline/gov/hmrc/income_tax/bases/taxable_self_employment_income.yaml
@@ -0,0 +1,116 @@
+- name: Trading loss relief
+  period: 2020
+  absolute_error_margin: 0
+  input:
+    self_employment_income: 1000
+    loss_relief: 2000
+  output:
+    taxable_self_employment_income: 0
+- name: Trading loss relief of previous year
+  period: 2020
+  absolute_error_margin: 0
+  input:
+    self_employment_income: 1000
+    loss_relief:
+      2019: 2000
+  output:
+    taxable_self_employment_income: 0
+- name: Trading loss relief doesn't offset other income
+  period: 2020
+  absolute_error_margin: 0
+  input:
+    self_employment_income: 1000
+    employment_income: 1000
+    loss_relief: 2000
+  output:
+    taxable_self_employment_income: 0
+    taxable_employment_income: 1000
+- name: No self-employment income or deductions
+  period: 2024
+  input:
+    self_employment_income: 0
+    loss_relief: 0
+    capital_allowances: 0
+    trading_allowance: 0
+  output:
+    taxable_self_employment_income: 0
+
+- name: Self-employment income with no deductions
+  period: 2024
+  input:
+    self_employment_income: 50000
+    loss_relief: 0
+    capital_allowances: 0
+    trading_allowance: 0
+  output:
+    taxable_self_employment_income: 50000
+
+- name: Self-employment income fully offset by deductions
+  period: 2024
+  input:
+    self_employment_income: 30000
+    loss_relief: 10000
+    capital_allowances: 15000
+    trading_allowance: 5000
+  output:
+    taxable_self_employment_income: 0
+
+- name: Self-employment income partially offset by deductions
+  period: 2024
+  input:
+    self_employment_income: 50000
+    loss_relief: 5000
+    capital_allowances: 10000
+    trading_allowance: 1000
+  output:
+    taxable_self_employment_income: 34000
+
+- name: High self-employment income with some deductions
+  period: 2024
+  input:
+    self_employment_income: 200000
+    loss_relief: 20000
+    capital_allowances: 30000
+    trading_allowance: 1000
+  output:
+    taxable_self_employment_income: 149000
+
+- name: Low self-employment income with low deductions
+  period: 2024
+  input:
+    self_employment_income: 1000
+    loss_relief: 100
+    capital_allowances: 200
+    trading_allowance: 300
+  output:
+    taxable_self_employment_income: 400
+
+- name: Deductions exceed self-employment income
+  period: 2024
+  input:
+    self_employment_income: 50000
+    loss_relief: 30000
+    capital_allowances: 25000
+    trading_allowance: 1000
+  output:
+    taxable_self_employment_income: 0
+
+- name: Very high values
+  period: 2024
+  input:
+    self_employment_income: 1000000
+    loss_relief: 200000
+    capital_allowances: 300000
+    trading_allowance: 1000
+  output:
+    taxable_self_employment_income: 499000
+
+- name: Decimal values
+  period: 2024
+  input:
+    self_employment_income: 50000.50
+    loss_relief: 10000.25
+    capital_allowances: 5000.75
+    trading_allowance: 1000.00
+  output:
+    taxable_self_employment_income: 33999.50
\ No newline at end of file
diff --git a/policyengine_uk/tests/policy/baseline/gov/hmrc/income_tax/liability.yaml b/policyengine_uk/tests/policy/baseline/gov/hmrc/income_tax/bases/taxed_dividend_income.yaml
similarity index 54%
rename from policyengine_uk/tests/policy/baseline/gov/hmrc/income_tax/liability.yaml
rename to policyengine_uk/tests/policy/baseline/gov/hmrc/income_tax/bases/taxed_dividend_income.yaml
index f90a32fe3..9ed5dc925 100644
--- a/policyengine_uk/tests/policy/baseline/gov/hmrc/income_tax/liability.yaml
+++ b/policyengine_uk/tests/policy/baseline/gov/hmrc/income_tax/bases/taxed_dividend_income.yaml
@@ -1,57 +1,3 @@
-- name: Allowances are deducted to zero
-  period: 2020
-  absolute_error_margin: 0
-  input:
-    employment_income: 10000
-    pension_income: 10000
-    allowances: 20000
-  output:
-    earned_taxable_income: 0
-- name: Earned income is split correctly
-  period: 2020
-  absolute_error_margin: 0
-  input:
-    earned_taxable_income: 100000
-  output:
-    basic_rate_earned_income: 37500
-    higher_rate_earned_income: 62500
-    add_rate_earned_income: 0
-- name: Earned income is taxed correctly
-  period: 2020
-  absolute_error_margin: 0
-  input:
-    employment_income: 100000
-  output:
-    allowances: 12500
-    earned_taxable_income: 87500
-    basic_rate_earned_income_tax: 7500
-    higher_rate_earned_income_tax: 20000
-    add_rate_earned_income_tax: 0
-    earned_income_tax: 27500
-    tax_band: "HIGHER"
-    taxed_income: 87500
-- name: Savings slice of basic rate band
-  period: 2020
-  absolute_error_margin: 0
-  input:
-    employment_income: 40000
-    savings_interest_income: 15000
-  output:
-    basic_rate_savings_income_pre_starter: 10000
-    savings_starter_rate_income: 0
-    basic_rate_savings_income: 10000
-    savings_allowance: 500
-    higher_rate_savings_income: 4500
-    taxed_savings_income: 14500
-- name: Dividends taxed at the marginal rates
-  period: 2020
-  absolute_error_margin: 0
-  input:
-    dividend_income: 50000
-  output:
-    dividend_income_tax: 6225
-
-# taxed_dividend_income
 - name: No dividend income
   period: 2024
   input:
@@ -131,4 +77,3 @@
     dividend_allowance: 1000
   output:
     taxed_dividend_income: 0.01
-
diff --git a/policyengine_uk/tests/policy/baseline/gov/hmrc/income_tax/bracketized.yaml b/policyengine_uk/tests/policy/baseline/gov/hmrc/income_tax/bracketized.yaml
new file mode 100644
index 000000000..627ed316c
--- /dev/null
+++ b/policyengine_uk/tests/policy/baseline/gov/hmrc/income_tax/bracketized.yaml
@@ -0,0 +1,9 @@
+- name: Earned income is split correctly
+  period: 2020
+  absolute_error_margin: 0
+  input:
+    earned_taxable_income: 100000
+  output:
+    basic_rate_earned_income: 37500
+    higher_rate_earned_income: 62500
+    add_rate_earned_income: 0
\ No newline at end of file
diff --git a/policyengine_uk/tests/policy/baseline/gov/hmrc/income_tax/earned_taxable_income.yaml b/policyengine_uk/tests/policy/baseline/gov/hmrc/income_tax/earned_taxable_income.yaml
new file mode 100644
index 000000000..ab959a525
--- /dev/null
+++ b/policyengine_uk/tests/policy/baseline/gov/hmrc/income_tax/earned_taxable_income.yaml
@@ -0,0 +1,9 @@
+- name: Allowances are deducted to zero
+  period: 2020
+  absolute_error_margin: 0
+  input:
+    employment_income: 10000
+    private_pension_income: 10000
+    allowances: 20000
+  output:
+    earned_taxable_income: 0
\ No newline at end of file
diff --git a/policyengine_uk/tests/policy/baseline/gov/hmrc/income_tax/relief.yaml b/policyengine_uk/tests/policy/baseline/gov/hmrc/income_tax/relief.yaml
deleted file mode 100644
index ba7d4d2fe..000000000
--- a/policyengine_uk/tests/policy/baseline/gov/hmrc/income_tax/relief.yaml
+++ /dev/null
@@ -1,663 +0,0 @@
-- name: Deductions from employment
-  period: 2020
-  absolute_error_margin: 0
-  input:
-    employment_income: 15000
-    employment_deductions: 5000
-  output:
-    taxable_employment_income: 10000
-- name: Deductions from employment stay positive
-  period: 2020
-  absolute_error_margin: 0
-  input:
-    employment_income: 15000
-    employment_deductions: 25000
-  output:
-    taxable_employment_income: 0
-- name: Specific deductions from employment (not pension contributions at this stage)
-  period: 2020
-  absolute_error_margin: 0
-  input:
-    employment_income: 15000
-    pension_contributions: 1000
-    employment_expenses: 2000
-  output:
-    taxable_employment_income: 13000
-- name: Pension relief
-  period: 2020
-  absolute_error_margin: 0
-  input:
-    employment_income: 76000
-    pension_contributions: 40000
-  output:
-    pension_contributions_relief: 40000
-- name: Pension relief excessive
-  period: 2020
-  absolute_error_margin: 0
-  input:
-    employment_income: 2000000
-    pension_contributions: 400000
-  output:
-    pension_contributions_relief: 4000
-- name: Trading loss relief
-  period: 2020
-  absolute_error_margin: 0
-  input:
-    self_employment_income: 1000
-    loss_relief: 2000
-  output:
-    taxable_self_employment_income: 0
-- name: Trading loss relief of previous year
-  period: 2020
-  absolute_error_margin: 0
-  input:
-    self_employment_income: 1000
-    loss_relief:
-      2019: 2000
-  output:
-    taxable_self_employment_income: 0
-- name: Trading loss relief doesn't offset other income
-  period: 2020
-  absolute_error_margin: 0
-  input:
-    self_employment_income: 1000
-    employment_income: 1000
-    loss_relief: 2000
-  output:
-    taxable_self_employment_income: 0
-    taxable_employment_income: 1000
-- name: Property income within allowance
-  period: 2020
-  absolute_error_margin: 0
-  input:
-    property_income: 1000
-  output:
-    taxable_property_income: 0
-- name: Dividend income with deficiency relief
-  period: 2020
-  absolute_error_margin: 0
-  input:
-    dividend_income: 10000
-    deficiency_relief: 1000
-  output:
-    taxable_dividend_income: 9000
-
-# pension_contributions
-- name: No pension contributions
-  period: 2024
-  input:
-    private_pension_contributions: 0
-    occupational_pension_contributions: 0
-  output:
-    pension_contributions: 0
-
-- name: Only private pension contributions
-  period: 2024
-  input:
-    private_pension_contributions: 5000
-    occupational_pension_contributions: 0
-  output:
-    pension_contributions: 5000
-
-- name: Only occupational pension contributions
-  period: 2024
-  input:
-    private_pension_contributions: 0
-    occupational_pension_contributions: 7500
-  output:
-    pension_contributions: 7500
-
-- name: Both types of pension contributions
-  period: 2024
-  input:
-    private_pension_contributions: 3000
-    occupational_pension_contributions: 4000
-  output:
-    pension_contributions: 7000
-
-- name: High contribution amounts
-  period: 2024
-  input:
-    private_pension_contributions: 20000
-    occupational_pension_contributions: 30000
-  output:
-    pension_contributions: 50000
-
-- name: Very low positive contributions
-  period: 2024
-  input:
-    private_pension_contributions: 1
-    occupational_pension_contributions: 1
-  output:
-    pension_contributions: 2
-
-- name: Uneven contributions
-  period: 2024
-  input:
-    private_pension_contributions: 1234.56
-    occupational_pension_contributions: 9876.54
-  output:
-    pension_contributions: 11111.10
-
-- name: Maximum allowed annual contributions (for 2023/2024 tax year)
-  period: 2024
-  input:
-    private_pension_contributions: 40000
-    occupational_pension_contributions: 20000
-  output:
-    pension_contributions: 60000
-
-# taxable_savings_interest_income
-- name: No savings interest income
-  period: 2024
-  input:
-    savings_interest_income: 0
-    tax_free_savings_income: 0
-  output:
-    taxable_savings_interest_income: 0
-
-- name: Savings interest income fully covered by tax-free allowance
-  period: 2024
-  input:
-    savings_interest_income: 1000
-    tax_free_savings_income: 1000
-  output:
-    taxable_savings_interest_income: 0
-
-- name: Savings interest income partially taxable
-  period: 2024
-  input:
-    savings_interest_income: 1500
-    tax_free_savings_income: 1000
-  output:
-    taxable_savings_interest_income: 500
-
-- name: High savings interest income, standard tax-free allowance
-  period: 2024
-  input:
-    savings_interest_income: 10000
-    tax_free_savings_income: 1000
-  output:
-    taxable_savings_interest_income: 9000
-
-- name: Savings interest income, no tax-free allowance
-  period: 2024
-  input:
-    savings_interest_income: 5000
-    tax_free_savings_income: 0
-  output:
-    taxable_savings_interest_income: 5000
-
-- name: Very low positive savings interest income
-  period: 2024
-  input:
-    savings_interest_income: 1
-    tax_free_savings_income: 0
-  output:
-    taxable_savings_interest_income: 1
-
-- name: Tax-free allowance exceeds savings interest income
-  period: 2024
-  input:
-    savings_interest_income: 500
-    tax_free_savings_income: 1000
-  output:
-    taxable_savings_interest_income: 0
-
-- name: High values for both inputs
-  period: 2024
-  input:
-    savings_interest_income: 100000
-    tax_free_savings_income: 50000
-  output:
-    taxable_savings_interest_income: 50000
-
-- name: Decimal values
-  period: 2024
-  input:
-    savings_interest_income: 1234.56
-    tax_free_savings_income: 1000.00
-  output:
-    taxable_savings_interest_income: 234.56
-
-# loss_relief
-- name: No trading losses
-  period: 2024
-  input:
-    trading_loss:
-      2023: 0
-      2024: 0
-  output:
-    loss_relief: 0
-
-- name: Current year trading loss only
-  period: 2024
-  input:
-    trading_loss:
-      2023: 0
-      2024: 5000
-  output:
-    loss_relief: 5000
-
-- name: Previous year trading loss only
-  period: 2024
-  input:
-    trading_loss:
-      2023: 3000
-      2024: 0
-  output:
-    loss_relief: 3000
-
-- name: Trading losses in both years
-  period: 2024
-  input:
-    trading_loss:
-      2023: 2500
-      2024: 3500
-  output:
-    loss_relief: 6000
-
-- name: High trading losses
-  period: 2024
-  input:
-    trading_loss:
-      2023: 50000
-      2024: 75000
-  output:
-    loss_relief: 125000
-
-- name: Very low positive trading losses
-  period: 2024
-  input:
-    trading_loss:
-      2023: 1
-      2024: 1
-  output:
-    loss_relief: 2
-
-- name: Uneven trading losses
-  period: 2024
-  input:
-    trading_loss:
-      2023: 1234.56
-      2024: 5678.90
-  output:
-    loss_relief: 6913.46
-
-- name: Large previous year loss, small current year loss
-  period: 2024
-  input:
-    trading_loss:
-      2023: 100000
-      2024: 1000
-  output:
-    loss_relief: 101000
-
-- name: Small previous year loss, large current year loss
-  period: 2024
-  input:
-    trading_loss:
-      2023: 1000
-      2024: 100000
-  output:
-    loss_relief: 101000
-
-# taxable_self_employment_income
-- name: No self-employment income or deductions
-  period: 2024
-  input:
-    self_employment_income: 0
-    loss_relief: 0
-    capital_allowances: 0
-    trading_allowance: 0
-  output:
-    taxable_self_employment_income: 0
-
-- name: Self-employment income with no deductions
-  period: 2024
-  input:
-    self_employment_income: 50000
-    loss_relief: 0
-    capital_allowances: 0
-    trading_allowance: 0
-  output:
-    taxable_self_employment_income: 50000
-
-- name: Self-employment income fully offset by deductions
-  period: 2024
-  input:
-    self_employment_income: 30000
-    loss_relief: 10000
-    capital_allowances: 15000
-    trading_allowance: 5000
-  output:
-    taxable_self_employment_income: 0
-
-- name: Self-employment income partially offset by deductions
-  period: 2024
-  input:
-    self_employment_income: 50000
-    loss_relief: 5000
-    capital_allowances: 10000
-    trading_allowance: 1000
-  output:
-    taxable_self_employment_income: 34000
-
-- name: High self-employment income with some deductions
-  period: 2024
-  input:
-    self_employment_income: 200000
-    loss_relief: 20000
-    capital_allowances: 30000
-    trading_allowance: 1000
-  output:
-    taxable_self_employment_income: 149000
-
-- name: Low self-employment income with low deductions
-  period: 2024
-  input:
-    self_employment_income: 1000
-    loss_relief: 100
-    capital_allowances: 200
-    trading_allowance: 300
-  output:
-    taxable_self_employment_income: 400
-
-- name: Deductions exceed self-employment income
-  period: 2024
-  input:
-    self_employment_income: 50000
-    loss_relief: 30000
-    capital_allowances: 25000
-    trading_allowance: 1000
-  output:
-    taxable_self_employment_income: 0
-
-- name: Very high values
-  period: 2024
-  input:
-    self_employment_income: 1000000
-    loss_relief: 200000
-    capital_allowances: 300000
-    trading_allowance: 1000
-  output:
-    taxable_self_employment_income: 499000
-
-- name: Decimal values
-  period: 2024
-  input:
-    self_employment_income: 50000.50
-    loss_relief: 10000.25
-    capital_allowances: 5000.75
-    trading_allowance: 1000.00
-  output:
-    taxable_self_employment_income: 33999.50
-
-# taxable_property_income
-- name: No property income or allowance
-  period: 2024
-  input:
-    property_income: 0
-    property_allowance: 0
-  output:
-    taxable_property_income: 0
-
-- name: Property income fully covered by allowance
-  period: 2024
-  input:
-    property_income: 1000
-    property_allowance: 1000
-  output:
-    taxable_property_income: 0
-
-- name: Property income partially taxable
-  period: 2024
-  input:
-    property_income: 10000
-    property_allowance: 1000
-  output:
-    taxable_property_income: 9000
-
-- name: High property income with standard allowance
-  period: 2024
-  input:
-    property_income: 50000
-    property_allowance: 1000
-  output:
-    taxable_property_income: 49000
-
-- name: Property income with no allowance
-  period: 2024
-  input:
-    property_income: 5000
-    property_allowance: 0
-  output:
-    taxable_property_income: 5000
-
-- name: Very low positive property income
-  period: 2024
-  input:
-    property_income: 1
-    property_allowance: 0
-  output:
-    taxable_property_income: 1
-
-- name: Property allowance exceeds income
-  period: 2024
-  input:
-    property_income: 500
-    property_allowance: 1000
-  output:
-    taxable_property_income: 0
-
-- name: High values for both income and allowance
-  period: 2024
-  input:
-    property_income: 100000
-    property_allowance: 50000
-  output:
-    taxable_property_income: 50000
-
-- name: Decimal values
-  period: 2024
-  input:
-    property_income: 1234.56
-    property_allowance: 1000.00
-  output:
-    taxable_property_income: 234.56
-
-# taxable_dividend_income
-- name: No dividend income or deficiency relief
-  period: 2024
-  input:
-    dividend_income: 0
-    deficiency_relief: 0
-  output:
-    taxable_dividend_income: 0
-
-- name: Dividend income fully offset by deficiency relief
-  period: 2024
-  input:
-    dividend_income: 5000
-    deficiency_relief: 5000
-  output:
-    taxable_dividend_income: 0
-
-- name: Dividend income partially taxable
-  period: 2024
-  input:
-    dividend_income: 10000
-    deficiency_relief: 2000
-  output:
-    taxable_dividend_income: 8000
-
-- name: High dividend income with some deficiency relief
-  period: 2024
-  input:
-    dividend_income: 50000
-    deficiency_relief: 5000
-  output:
-    taxable_dividend_income: 45000
-
-- name: Dividend income with no deficiency relief
-  period: 2024
-  input:
-    dividend_income: 15000
-    deficiency_relief: 0
-  output:
-    taxable_dividend_income: 15000
-
-- name: Very low positive dividend income
-  period: 2024
-  input:
-    dividend_income: 1
-    deficiency_relief: 0
-  output:
-    taxable_dividend_income: 1
-
-- name: Deficiency relief exceeds dividend income
-  period: 2024
-  input:
-    dividend_income: 3000
-    deficiency_relief: 5000
-  output:
-    taxable_dividend_income: 0
-
-- name: High values for both dividend income and deficiency relief
-  period: 2024
-  input:
-    dividend_income: 100000
-    deficiency_relief: 40000
-  output:
-    taxable_dividend_income: 60000
-
-- name: Decimal values
-  period: 2024
-  input:
-    dividend_income: 1234.56
-    deficiency_relief: 234.56
-  output:
-    taxable_dividend_income: 1000.00
-
-# adjusted_net_income
-- name: No income from any source
-  period: 2024
-  input:
-    taxable_employment_income: 0
-    taxable_pension_income: 0
-    taxable_social_security_income: 0
-    taxable_self_employment_income: 0
-    taxable_property_income: 0
-    taxable_savings_interest_income: 0
-    taxable_dividend_income: 0
-    taxable_miscellaneous_income: 0
-    basic_income: 0
-  output:
-    adjusted_net_income: 0
-
-- name: Income from all sources
-  period: 2024
-  input:
-    taxable_employment_income: 30000
-    taxable_pension_income: 5000
-    taxable_social_security_income: 2000
-    taxable_self_employment_income: 10000
-    taxable_property_income: 5000
-    taxable_savings_interest_income: 1000
-    taxable_dividend_income: 3000
-    taxable_miscellaneous_income: 500
-    basic_income: 0
-  output:
-    adjusted_net_income: 56500
-
-- name: Only employment income
-  period: 2024
-  input:
-    taxable_employment_income: 40000
-    taxable_pension_income: 0
-    taxable_social_security_income: 0
-    taxable_self_employment_income: 0
-    taxable_property_income: 0
-    taxable_savings_interest_income: 0
-    taxable_dividend_income: 0
-    taxable_miscellaneous_income: 0
-    basic_income: 0
-  output:
-    adjusted_net_income: 40000
-
-- name: High income from multiple sources
-  period: 2024
-  input:
-    taxable_employment_income: 100000
-    taxable_pension_income: 50000
-    taxable_social_security_income: 0
-    taxable_self_employment_income: 75000
-    taxable_property_income: 25000
-    taxable_savings_interest_income: 10000
-    taxable_dividend_income: 20000
-    taxable_miscellaneous_income: 5000
-    basic_income: 0
-  output:
-    adjusted_net_income: 285000
-
-- name: Low income from multiple sources
-  period: 2024
-  input:
-    taxable_employment_income: 5000
-    taxable_pension_income: 1000
-    taxable_social_security_income: 500
-    taxable_self_employment_income: 2000
-    taxable_property_income: 1000
-    taxable_savings_interest_income: 100
-    taxable_dividend_income: 200
-    taxable_miscellaneous_income: 50
-    basic_income: 0
-  output:
-    adjusted_net_income: 9850
-
-- name: Decimal values
-  period: 2024
-  input:
-    taxable_employment_income: 30000.50
-    taxable_pension_income: 5000.25
-    taxable_social_security_income: 2000.75
-    taxable_self_employment_income: 10000.00
-    taxable_property_income: 5000.50
-    taxable_savings_interest_income: 1000.25
-    taxable_dividend_income: 3000.75
-    taxable_miscellaneous_income: 500.00
-    basic_income: 0
-  output:
-    adjusted_net_income: 56503.00
-
-- name: With basic income included
-  period: 2024
-  input:
-    gov.contrib.ubi_center.basic_income.interactions.include_in_taxable_income: true
-    taxable_employment_income: 30000
-    taxable_pension_income: 5000
-    taxable_social_security_income: 2000
-    taxable_self_employment_income: 10000
-    taxable_property_income: 5000
-    taxable_savings_interest_income: 1000
-    taxable_dividend_income: 3000
-    taxable_miscellaneous_income: 500
-    basic_income: 10000
-  output:
-    adjusted_net_income: 66500
-
-- name: Only basic income
-  period: 2024
-  input:
-    gov.contrib.ubi_center.basic_income.interactions.include_in_taxable_income: true
-    taxable_employment_income: 0
-    taxable_pension_income: 0
-    taxable_social_security_income: 0
-    taxable_self_employment_income: 0
-    taxable_property_income: 0
-    taxable_savings_interest_income: 0
-    taxable_dividend_income: 0
-    taxable_miscellaneous_income: 0
-    basic_income: 10000
-  output:
-    adjusted_net_income: 10000
\ No newline at end of file
diff --git a/policyengine_uk/tests/policy/baseline/gov/hmrc/income_tax/reliefs/loss_relief.yaml b/policyengine_uk/tests/policy/baseline/gov/hmrc/income_tax/reliefs/loss_relief.yaml
new file mode 100644
index 000000000..8d976948f
--- /dev/null
+++ b/policyengine_uk/tests/policy/baseline/gov/hmrc/income_tax/reliefs/loss_relief.yaml
@@ -0,0 +1,80 @@
+- name: No trading losses
+  period: 2024
+  input:
+    trading_loss:
+      2023: 0
+      2024: 0
+  output:
+    loss_relief: 0
+
+- name: Current year trading loss only
+  period: 2024
+  input:
+    trading_loss:
+      2023: 0
+      2024: 5000
+  output:
+    loss_relief: 5000
+
+- name: Previous year trading loss only
+  period: 2024
+  input:
+    trading_loss:
+      2023: 3000
+      2024: 0
+  output:
+    loss_relief: 3000
+
+- name: Trading losses in both years
+  period: 2024
+  input:
+    trading_loss:
+      2023: 2500
+      2024: 3500
+  output:
+    loss_relief: 6000
+
+- name: High trading losses
+  period: 2024
+  input:
+    trading_loss:
+      2023: 50000
+      2024: 75000
+  output:
+    loss_relief: 125000
+
+- name: Very low positive trading losses
+  period: 2024
+  input:
+    trading_loss:
+      2023: 1
+      2024: 1
+  output:
+    loss_relief: 2
+
+- name: Uneven trading losses
+  period: 2024
+  input:
+    trading_loss:
+      2023: 1234.56
+      2024: 5678.90
+  output:
+    loss_relief: 6913.46
+
+- name: Large previous year loss, small current year loss
+  period: 2024
+  input:
+    trading_loss:
+      2023: 100000
+      2024: 1000
+  output:
+    loss_relief: 101000
+
+- name: Small previous year loss, large current year loss
+  period: 2024
+  input:
+    trading_loss:
+      2023: 1000
+      2024: 100000
+  output:
+    loss_relief: 101000
\ No newline at end of file
diff --git a/policyengine_uk/tests/policy/baseline/gov/hmrc/national_insurance/class_1/ni_class_1_income.yaml b/policyengine_uk/tests/policy/baseline/gov/hmrc/national_insurance/class_1/ni_class_1_income.yaml
index abeae1edc..ff0ea35b7 100644
--- a/policyengine_uk/tests/policy/baseline/gov/hmrc/national_insurance/class_1/ni_class_1_income.yaml
+++ b/policyengine_uk/tests/policy/baseline/gov/hmrc/national_insurance/class_1/ni_class_1_income.yaml
@@ -2,8 +2,8 @@
   period: 2023
   input:
     employment_income: 1
-    statutory_sick_pay: 2
-    statutory_maternity_pay: 4
-    statutory_paternity_pay: 8
+    household_statutory_sick_pay: 2
+    household_statutory_maternity_pay: 4
+    household_statutory_paternity_pay: 8
   output:
     ni_class_1_income: 15
diff --git a/policyengine_uk/tests/policy/baseline/gov/hmrc/pensions/pension_contributions.yaml b/policyengine_uk/tests/policy/baseline/gov/hmrc/pensions/pension_contributions.yaml
new file mode 100644
index 000000000..7d0fa5dbe
--- /dev/null
+++ b/policyengine_uk/tests/policy/baseline/gov/hmrc/pensions/pension_contributions.yaml
@@ -0,0 +1,63 @@
+- name: No pension contributions
+  period: 2024
+  input:
+    private_pension_contributions: 0
+    occupational_pension_contributions: 0
+  output:
+    pension_contributions: 0
+
+- name: Only private pension contributions
+  period: 2024
+  input:
+    private_pension_contributions: 5000
+    occupational_pension_contributions: 0
+  output:
+    pension_contributions: 5000
+
+- name: Only occupational pension contributions
+  period: 2024
+  input:
+    private_pension_contributions: 0
+    occupational_pension_contributions: 7500
+  output:
+    pension_contributions: 7500
+
+- name: Both types of pension contributions
+  period: 2024
+  input:
+    private_pension_contributions: 3000
+    occupational_pension_contributions: 4000
+  output:
+    pension_contributions: 7000
+
+- name: High contribution amounts
+  period: 2024
+  input:
+    private_pension_contributions: 20000
+    occupational_pension_contributions: 30000
+  output:
+    pension_contributions: 50000
+
+- name: Very low positive contributions
+  period: 2024
+  input:
+    private_pension_contributions: 1
+    occupational_pension_contributions: 1
+  output:
+    pension_contributions: 2
+
+- name: Uneven contributions
+  period: 2024
+  input:
+    private_pension_contributions: 1234.56
+    occupational_pension_contributions: 9876.54
+  output:
+    pension_contributions: 11111.10
+
+- name: Maximum allowed annual contributions (for 2023/2024 tax year)
+  period: 2024
+  input:
+    private_pension_contributions: 40000
+    occupational_pension_contributions: 20000
+  output:
+    pension_contributions: 60000
\ No newline at end of file
diff --git a/policyengine_uk/tests/policy/baseline/gov/hmrc/income_tax/pension_contributions_relief.yaml b/policyengine_uk/tests/policy/baseline/gov/hmrc/pensions/pension_contributions_relief.yaml
similarity index 71%
rename from policyengine_uk/tests/policy/baseline/gov/hmrc/income_tax/pension_contributions_relief.yaml
rename to policyengine_uk/tests/policy/baseline/gov/hmrc/pensions/pension_contributions_relief.yaml
index 844eb76e1..24b6b8307 100644
--- a/policyengine_uk/tests/policy/baseline/gov/hmrc/income_tax/pension_contributions_relief.yaml
+++ b/policyengine_uk/tests/policy/baseline/gov/hmrc/pensions/pension_contributions_relief.yaml
@@ -1,3 +1,19 @@
+- name: Pension relief
+  period: 2020
+  absolute_error_margin: 0
+  input:
+    employment_income: 76000
+    pension_contributions: 40000
+  output:
+    pension_contributions_relief: 40000
+- name: Pension relief excessive
+  period: 2020
+  absolute_error_margin: 0
+  input:
+    employment_income: 2000000
+    pension_contributions: 400000
+  output:
+    pension_contributions_relief: 4000
 - name: £30k self-employment income, no private pension contributions
   period: 2023
   absolute_error_margin: 0.01
diff --git a/policyengine_uk/tests/policy/integration/income.yaml b/policyengine_uk/tests/policy/integration/income.yaml
new file mode 100644
index 000000000..5df324c12
--- /dev/null
+++ b/policyengine_uk/tests/policy/integration/income.yaml
@@ -0,0 +1,55 @@
+- name: Earned income is taxed correctly
+  period: 2020
+  absolute_error_margin: 0
+  input:
+    employment_income: 100_000
+  output:
+    allowances: 12_500
+    earned_taxable_income: 87_500
+    basic_rate_earned_income_tax: 7_500
+    higher_rate_earned_income_tax: 20_000
+    add_rate_earned_income_tax: 0
+    earned_income_tax: 27_500
+    tax_band: "HIGHER"
+    taxed_income: 87_500
+
+- name: Savings slice of basic rate band
+  period: 2020
+  absolute_error_margin: 0
+  input:
+    employment_income: 40_000
+    savings_interest_income: 15_000
+  output:
+    basic_rate_savings_income_pre_starter: 10_000
+    savings_starter_rate_income: 0
+    basic_rate_savings_income: 10_000
+    savings_allowance: 500
+    higher_rate_savings_income: 4_500
+    taxed_savings_income: 14_500
+
+- name: Dividends taxed at the marginal rates
+  period: 2020
+  absolute_error_margin: 0
+  input:
+    dividend_income: 50_000
+  output:
+    dividend_income_tax: 6_225
+
+- name: Net income with base income
+  period: 2020
+  absolute_error_margin: 0
+  input:
+    gross_income: 400
+    tax: 50
+  output:
+    net_income: 350
+
+- name: Household net income can be negative
+  period: 2020
+  absolute_error_margin: 0
+  input:
+    household_market_income: 1
+    household_tax: 2
+    household_benefits: 0
+  output:
+    household_net_income: -1
\ No newline at end of file
diff --git a/policyengine_uk/tests/integration/tax.yaml b/policyengine_uk/tests/policy/integration/tax.yaml
similarity index 71%
rename from policyengine_uk/tests/integration/tax.yaml
rename to policyengine_uk/tests/policy/integration/tax.yaml
index a21f7e62c..ab6328524 100644
--- a/policyengine_uk/tests/integration/tax.yaml
+++ b/policyengine_uk/tests/policy/integration/tax.yaml
@@ -4,11 +4,12 @@
   output:
     income_tax: 0
     national_insurance: 0
+
 - name: Some employed income
   period: 2019
   absolute_error_margin: 30
   input:
-    employment_income: 41223
+    employment_income: 41_223
   output:
-    national_insurance: 3935
-    income_tax: 5875
+    national_insurance: 3_935
+    income_tax: 5_875