Skip to content

Relieve trading losses by each programme's rule - #2085

Merged
MaxGhenis merged 18 commits into
mainfrom
self-employment-loss
Oct 14, 2026
Merged

MaxGhenis merged 18 commits into
mainfrom
self-employment-loss

Conversation

@MaxGhenis

@MaxGhenis MaxGhenis commented Oct 2, 2026 •

Copy link
Copy Markdown
Collaborator

Fixes #1916

Trading losses now follow each programme's rule: Income Tax can relieve a loss against general income; UC nets concurrent trades; tax credits deduct the claimants' losses; HB does not offset another employment's earnings. Profits remain non-negative self_employment_income, and losses are supplied separately as positive trading_loss. Market and HBAI income count losses as negative income.

The branch preserves the original author's commits and merges main 714b1438c1f6f2a46e279728caa5c7d77835f981 at 379f504b934ec2ed255ef9dd0dbc5b375676522b. Main's independent Class 4 loss pool, net UC minimum income floor, Pension Credit tax-credit passport and winter-heating income components are retained. Claimant-only tax-credit losses enter the shared tax_credits_current_year_income calculation before passporting.

The UC conflict combines this PR's concurrent trading-loss netting with main's reg.77 company earnings and separate employment/trade tax and NI deductions. The loss helper caps relief at the positive combined result of the person's own trades and signed company earnings. #2399 now carries the benefit-cap earnings change on main; this PR no longer touches is_benefit_cap_exempt_earnings.py. The UC loss helper continues to feed actual earned income, including company trade results. Four new YAML cases cover a loss against company-only profit, the cap transition from £12,000 to £7,000 with identical paid deductions and a £20,000 MIF, a signed company loss leaving employment unchanged, and fixed trade/employment tax and NI deductions when losses cancel all trade profit.

Trading allowance election

ITTOIA 2005 s.783AF makes every relevant trade's profits and losses nil under full relief; s.783AL makes the opt-out election for the individual's year. HMRC BIM86076 explains electing out to claim a loss. The model compares the raw loss supplied for the individual's tax year, before the s.24A and available-net-income caps, with the allowance's effective saving after capital allowances and explicit prior losses. Ordinary expense treatment and a loss claim win when that raw supplied loss is larger; a tie uses allowance treatment. Comparing the raw loss preserves possible unrelieved carry-forward even when both treatments yield nil current net income. Otherwise allowance treatment suppresses current Income Tax and Class 4 expense-based loss relief across the person's trades. This is a modelled choice, rather than an automatic HMRC opt-out, and does not optimise future loss use, carry-back, optimal allocation across income components or benefit effects. Missing receipts retain the documented existing allowance fallback.

The election uses supplied_input for the election's annual trading_loss, as Class 4 already does: a prior year's carried/uprated input cannot cancel this year's allowance. Income Tax's documented trading_loss input behaviour remains: an unset year can inherit and uprate an earlier input; callers must supply explicit zeros when that is not intended.

Partial relief also replaces all trades' current expenses (s.783AI, BIM86018); prior carry-forward losses remain separate and may follow partial relief (BIM86015).

  • Required 2026 England regression: age 40, employment £40,000, profitable trade £800, other trade receipts £100 and expenses £2,100; total receipts £900, loss £2,000. Allowance deduction £0, net income £38,800, Income Tax £5,246. Six election regressions fail before the fix and pass after it, including smaller losses, partial relief and prior losses.
  • Class 4 follows the same election: current expense losses are excluded under elected allowance treatment; independent prior nominal NIC balances are retained. A £700 allowance advantage with losses £699/£700/£701 gives contributions £403.80/£403.80/£403.74, with an additional multi-year carry-forward regression.
  • Unset annual-loss regression: age 40, 2025 employment £50,000 and loss £10,000; 2026 employment £0 and profit/receipts £900, with 2026 trading_loss unset. The 2026 allowance is £900, Class 4 profits before losses and current Class 4 loss are £0, and the entire prior £10,000 nominal Class 4 balance remains unconsumed. The multi-year property reference now uses each year's supplied loss for this election.
  • HBAI permits free_tv_licence_value to move with its Pension Credit passport. The exact age 76/pension £19,500/loss £10,000/child-age 1 case is pinned and directly tested.
  • Both pinned tax populations now contain 16 people: 8 in London and 8 in Scotland. Scottish entries are exercised instead of being discarded by zip.

Programme law and limits

trading_loss is included alongside profits in policyengine_uk/data/uprating_indices.yaml:128; its metadata uses the same cumulative OBR per-capita mixed-income index.

Earlier findings mapped to the merged head

Both earlier reviews/responses and their cited law memo were read. Their confirmed findings and accepted deferrals are mapped below to source at 379f504b934ec2ed255ef9dd0dbc5b375676522b.

Finding Source at 379f504b9 (policyengine_uk/ paths)
R1.1: statutory cap base and age 75 limit variables/gov/hmrc/income_tax/reliefs/adjusted_total_income.py:49 and :62
R1.2/R2.3: optimal allocation Accepted deferral to #2106; fixed order remains at variables/gov/hmrc/income_tax/allowances/received_allowances/received_allowances_savings_income.py:18
R1.3: UC concurrent trades variables/gov/dwp/universal_credit/income/uc_individual_earned_income_before_mif.py:79
R1.4: claimant-only tax-credit losses variables/gov/dwp/tax_credits_current_year_income.py:53
R1.5: independent Class 4 carry-forward variables/gov/hmrc/national_insurance/class_4/ni_class_4_losses_brought_forward.py:36
R1.6: taxable basic income variables/gov/hmrc/income_tax/reliefs/net_income_before_trade_loss_relief.py:26
R2.1: benefit-cap earnings exemption variables/gov/dwp/is_benefit_cap_exempt_earnings.py:29 (now carried by main #2399)
R2.2: taxable SMP and pension relevant earnings variables/gov/hmrc/income_tax/reliefs/adjusted_total_income.py:56
R3.1: taxpayer/year allowance and loss election variables/gov/hmrc/income_tax/allowances/trading_allowance_deduction.py:90; variables/gov/hmrc/income_tax/reliefs/trade_loss_relief_against_general_income.py:44
NI election and nominal carry-forward variables/gov/hmrc/national_insurance/class_4/ni_class_4_trading_loss.py:62; tests/test_ni_class_4_profits_properties.py:121; tests/policy/baseline/gov/hmrc/national_insurance/class_4/ni_class_4_trading_loss.yaml:62
R3.2: HBAI TV-licence passport and pinned family tests/test_trading_loss_properties.py:116, :478 and :762
R3.3: pinned Scottish populations tests/test_trading_loss_properties.py:216 and :349
R4.1: election excludes inherited losses variables/gov/hmrc/income_tax/allowances/trading_allowance_deduction.py:90; unset-year YAML tests/policy/baseline/gov/hmrc/national_insurance/class_4/ni_class_4_trading_loss.yaml:200; property reference tests/test_ni_class_4_profits_properties.py:682
R4.2: raw-loss comparison and carry-forward rationale variables/gov/hmrc/income_tax/allowances/trading_allowance_deduction.py:21; variables/gov/hmrc/income_tax/reliefs/trade_loss_relief_against_general_income.py:19
R4.3: unrelated DOB suppression is disclosed tests/test_date_of_birth.py:87, :128, :268; disclosure below; its test-only release note is removed
Uprating: losses beside profits, matching variable index data/uprating_indices.yaml:128; variables/input/trading_loss.py:31

Review rounds through r4 are addressed: original-review fixes are incorporated in eac9df01376c00f1fb74e987ebccf41b519eab95; r3 election/TV-licence/Scotland changes are in 31a877b7a15b9128d606ea3d5caab99960432316 and Class 4 coordination in e1debd40ecc20194bd1eec7446c3f95c08ae32f4; r4 supplied-year-loss/tie fixes are in 2d408a2af17e6380d1fcea0ee303cb7e8168e107. Main/company integration and fixture updates are 3de25876d999f88c910d4a9373a93e59de5f9d47 and 60ae5a5ae6821adfcd80deec3cc6b8d35f0afb21. The hub's #2399 merge is 379f504b934ec2ed255ef9dd0dbc5b375676522b.

The latest review's stale cap release-note clause has been removed. The test-only DOB release note and its unrelated Reproducer entries are also removed; the timing-health suppression itself remains, documented below. The pension-relief overlap with #2240 remains an integration follow-up: whichever PR merges second must reconcile adjusted_total_income with the contribution relief actually allowed under ss.190–194. No model code was changed in round 5.

Validation

At final head 4c85dfa0d6023f3f6cffdf10d947313013cfab6d, 122 focused Python checks and 166 policy YAML cases passed, with no skips, xfails or failures. This covers trading-loss and allowance properties; all four Class 4 Python files and the Class 4 YAML directory; UC claimant earnings, deductions, MIF, company and statutory-pay properties; and loss/relief, UC earned-income, tax-credit and HB YAML. The model/test tree is identical to the measured checkpoint 379f504b934ec2ed255ef9dd0dbc5b375676522b.

Commands ran in the foreground: uv run --frozen --no-sync pytest ... -n 4 --dist worksteal -o xfail_strict=true and uv run --frozen --no-sync policyengine-core test ... -c policyengine_uk. Exact paths, commands and results are retained in .job/validation-r5.json. The requested nice +10 was attempted but the sandbox denied setpriority. All BLAS/OpenMP limits were four threads. make format, uvx ruff format --check ., git diff --check and the fix-evidence checker pass. A verified recovery bundle is saved in .job/self-employment-loss-r5.bundle.

Locked environment: Python 3.13.9, policyengine-core 3.33.2 and policyengine-uk 2.130.1; installed with UV_LINK_MODE=clone uv sync --frozen --extra dev. uv.lock SHA-256: 72f8b9da78db07a5af32eec54a80cb1375fff56749b7fa21227f91e231a85139. Repository make format passes; required uvx ruff format --check . is recorded with the final validation below.

No new full local suite under the round-5 instruction; CI runs it. The previous full local run completed with failures that passed subsequent focused reruns; it was not a single green full local run. Checkpoint CI at 379f504b9 and final-head CI status are recorded in the hand-off.

The retained DOB change is unrelated to trading-loss policy: it suppresses only HealthCheck.too_slow on three properties. Their 30/25/25 example counts, pinned examples, bounds, assertions and other health checks remain unchanged. No new skips or xfails were added.

The zero-profit property compares Income Tax with the same zero-loss person. Benefit comparisons hold paid tax/NI and other benefits consistently to isolate each programme's loss rule; annual tax-payment timing and passport changes can otherwise lower an award (#2108). Axiom parity remains queued at #429 with the recorded signed-encoder/corpus blockers.

Reproducer: policyengine_uk/tests/policy/baseline/gov/hmrc/income_tax/reliefs/trade_loss_relief_against_general_income.yaml

2026 enhanced-FRS impact

Fresh round-5 comparison: 2026 in the same locked interpreter, seed 0, unchanged entity weights and committed source archives.

  • Main: 714b1438c1f6f2a46e279728caa5c7d77835f981.
  • Branch: 379f504b934ec2ed255ef9dd0dbc5b375676522b (round-5 release-note edits leave model code unchanged).
  • Dataset SHA-256, rehashed before each load: 5ba399ea5ab9a6c7d4e9aaf6c623080beb34d9ad5f330f6244dbad72b8d960b6.
  • Artifact: ~/reviews/pepy-uk-data-1.58.0-cert/data/1.58.0/enhanced_frs_2024_25.h5.
Outcome Main (£bn) Branch (£bn) Branch − main (£)
Income Tax 322.074529 322.074529 0.00
Universal Credit 83.577892 83.577892 0.00
Tax credits 0.000000 0.000000 0.00
Housing Benefit 8.456238 8.456238 0.00
Household net income 1,709.003765 1,709.003765 0.00
HBAI household net income 1,522.867061 1,522.867061 0.00
Class 4 NICs 2.739884 2.739884 0.00

All seven differences are exactly £0, before rounding. The former +£8.924m UC uplift was #2399's cap change, now on main; the refreshed comparison supersedes it. This PR no longer changes the cap-earnings file.

The certified artifact has no trading_loss input or negative self-employment income; both runs have zero effective losses. This cannot update the historical £13m–£18m Income Tax loss-relief estimate. Tax credits are inactive in 2026. A losses-enabled dataset is needed to measure the policy's actual fiscal effect.

Both runs stayed foreground and sequential, with at most four BLAS/OpenMP threads; pre-run free disk exceeded 110 GB and compressor use stayed below 20 GB. Source file hashes, full entity-weight hashes, matching dependency versions and aggregate-only totals are retained in .job/impact-r5.json. Outcomes were calculated, inputs/weights preserved, and no survey records were exported. Temporary source copies are deleted after verification.

PolicyEngine/policyengine-uk-data#528 relocks after this model PR releases. Its rebuilt artifact must measure effective loss prevalence/amounts and compare losses present versus zeroed before reporting updated fiscal impact. No dataset build or merge is performed by this job. The hub dispatches the independent review at the final pushed head.

axiom: TheAxiomFoundation/rulespec-uk#429 queued

trading_loss (a loss as a positive amount, separate from the profit in
self_employment_income) now reaches each programme by its own rule:

- Income Tax: trade loss relief against general income (ITA 2007 s.64)
  reduces net income, and so adjusted net income, for the loss-making year.
  It is limited to net income (s.25(4)) and to the s.24A cap, the greater
  of £50,000 and 25% of adjusted total income (s.24A(5), (8)). It comes off
  non-savings income first, then savings, then dividends.
- Class 4 and Class 2 NICs: the relief reduces trading profits only
  (SSCBA 1992 Sch 2 para 3(4); s.11(3) relevant profits), with losses
  brought forward (loss_relief, s.83).
- Tax credits: the claimants' losses come off their income
  (SI 2002/2006 reg 3(1) Step 4).
- Market income and HBAI household income count the loss as negative
  income.
- Means tests read neither the loss nor anything net of it, so it never
  offsets other earnings (UC reg 57, HB reg 38(10), IS reg 38(11) etc.).

loss_relief now holds only losses brought forward (s.83). It no longer
adds the previous year's trading_loss, which relief against general income
may already have used. trading_loss is uprated like self-employment income.

Tests: YAML cases for the relief, cap, ordering, Class 4, tax credits and
household income; Hypothesis properties for the relief definition, a
differential against income cut in s.25 order, monotonicity and bounds,
means tests seeing the loss only through tax, tax credit income, and the
channels HBAI income can move through.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
MaxGhenis and others added 3 commits October 2, 2026 23:14
…it loss

- adjusted_total_income follows s.24A(8): Step 1 total income (taxable
  components, losses brought forward added back) less own pension
  contributions given relief, up to the greater of £3,600 and relevant UK
  earnings (FA 2004 s.190) and none from age 75 (s.188(3)(a)).
- net_income_before_trade_loss_relief is the one base for adjusted net
  income, the relief limit and the savings/dividends part; it counts basic
  income where a reform makes it taxable.
- UC sets a trading loss against the person's other trades' profits before
  the minimum income floor, never against employed earnings (UC Regs 2013
  reg 57(2) Steps 1-3).
- Tax credits subtract only the claimants' losses, not a child's.
- New input ni_class_4_losses_brought_forward for losses carried forward
  for Class 4 only (SSCBA 1992 Sch 2 para 3(4)(b)).
- The savings-then-dividends order is the model's allowance order, which
  s.25(2) can beat for the Personal Allowance too: documented, #2106.
- YAML cases for each finding; property tests cover UC netting and
  children's losses, with fewer examples for CI time.

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

- uc_trading_losses_set_against_profits (UC Regs 2013 reg 57(2)) is the one
  netting UC earnings and the reg 82 earnings tests in
  is_benefit_cap_exempt_earnings and is_benefit_cap_exempt_health_disability
  deduct, so a loss-maker's cap matches the same household with netted
  profits.
- adjusted_total_income takes relevant UK earnings (FA 2004 s.189(2)) as
  taxable employment income (incl. taxable benefits and statutory pay)
  plus chargeable trading profits.
- YAML for both review cases; the property test's netted twin compares the
  earnings test and the capped award; property tests run 3 examples per
  property with larger batches to cut CI time (#2099).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
With 3 generated examples per property (to keep CI time down, #2099),
a run could miss the cases that matter, and a mutant that stopped
limiting relief to net income survived. Each property now also checks
pinned inputs: relief limited by net income, both caps, contributions
above relevant earnings, no relief from age 75, profits beside a loss,
income spilling into savings and dividends, the benefit-cap household,
a child's loss and a loss beside pay.

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

Copy link
Copy Markdown
Collaborator Author

UK hub (2026-10-12 12:05Z): the hub adopted this PR under d1280's fallback, because it has no live owner session. A Subfleet build job (adopt-uk2085) is finishing it on top of this branch, with no force-push and the author kept. Its plan is in the triage at ~/reviews/uk-hub/jobs/stale-pr-triage/REPORT.md. An independent GPT-6.1 Sol review will follow at the job's final head. uk-data PRs land only in a batched release on Max's go (d833).

@MaxGhenis

Copy link
Copy Markdown
Collaborator Author

Adoption hand-off for #2085 at head eac9df01376c00f1fb74e987ebccf41b519eab95, merged with main 1d3abecef443d3a142640bb2f6b0567f2004103c. Earlier review fixes are accounted for; main's independent Class 4 loss pool is preserved, and trading_loss uprating is included. Legal references and the finding-to-file:line mapping are in the updated PR body.

Locked validation:

  • Saved reproductions: 29/29 assertions passed.
  • Programme YAML: 90 passed.
  • Full YAML: 3,187 passed.
  • Full Python: corrected run interrupted at 75% after free disk fell to 43.99 GB, below the required 45 GB stop threshold. No failure/error markers observed; no final pytest result. Full Python and explicit merged-head property verification remain pending.
  • Final formatting check: passed: 1,660 files already formatted.

The 2026 enhanced-FRS comparison used the certified artifact, re-hashed before use: SHA-256 5ba399ea5ab9a6c7d4e9aaf6c623080beb34d9ad5f330f6244dbad72b8d960b6. Exact branch-minus-main differences are £0 each for Income Tax, UC, tax credits, HB, household net income and HBAI household net income. The artifact lacks trading_loss; both runs have zero effective losses. This cannot establish loss-relief impact or update the historical £13m–£18m estimate.

Disclosed limitations: round 2 accepted the allocation deferral to #2106, including the saved £107.50 overcharge. #2108 covers existing benefit tax-deduction approximations. UC annual netting assumes even accrual and omits reg.57A's monthly forward-only loss stock and award continuity. Income Tax carry-forward requires explicit unrelieved losses; tax-credit carry-forward needs its own balance.

The hub owns the independent review at the final pushed head; no final approval is claimed here. policyengine-uk-data #528 relocks after this PR releases. This job does not merge either PR.

The committed work is pushed once. The PR remains draft for resumption under the user’s disk-stop instruction; readiness and independent review are pending. Logs, HANDOFF.md, handoffs.jsonl, provenance and a recovery bundle are in .job/ in the assigned workspace. No suites or microsimulations remain running.

@MaxGhenis

Copy link
Copy Markdown
Collaborator Author

Independent review (GPT-6.1 Sol, UK hub): REQUEST_CHANGES at eac9df013. One blocker: the trading allowance and loss relief can't both apply in the same tax year (ITTOIA s.783AF/s.783AL), and the reviewer's worked case shows £160 too little tax. There is also one should-fix (the HBAI property misses the free TV licence passport) and one nit (the Scottish pinned cases are dropped by a zip). The earlier review findings are otherwise fixed, and the £0 impact is expected until uk-data#528. The hub is dispatching a fix round.

VERDICT: REQUEST_CHANGES
Head reviewed: eac9df0

  1. [blocker] Incompatible trading-allowance and loss-relief elections. trade_loss_relief_against_general_income.py:35 grants sideways relief while the automatic trading allowance can exempt another trade’s profits.

    Consider 2026, England, age 40: employment income £40,000; trade A receipts/profit £800; trade B receipts £100 and expenses £2,100. Inputs are self_employment_income=800, self_employment_gross_receipts=900, trading_loss=2000, and capital_allowances=0.

    Static tracing gives an £800 trading-allowance deduction and £2,000 loss relief: net income £38,000 and tax £5,086. Electing out of full allowance relief to claim the loss preserves the £800 profit: net income £38,800 and tax £5,246. The code therefore predicts £160 too little tax.

    ITTOIA s.783AF treats each relevant trade’s profits and losses as nil under full relief; s.783AL makes the opt-out election for the individual’s tax year. Coordinate the elections and add this regression. These figures are static calculations, not simulation results. Statutory provisions, HMRC’s loss-election example.

  2. [should-fix] The HBAI property omits a passported benefit and can fail. test_trading_loss_properties.py:709 requires free_tv_licence_value to remain unchanged because it is absent from HBAI_CHANNELS.

    A valid generated family is an adult aged 76 with £19,500 private pension income, £10,000 trading loss, one child aged 1, and other incomes zero. Static calculation gives tax £1,386 and Pension Credit approximately £94.20 without the loss; with the loss, both become zero. Pension Credit’s disappearance removes the TV concession, contradicting this assertion. Add that component to the permitted channels and pin the case. This is a concrete possible failure among the unverified Python tests; no simulation was run.

  3. [nit] Pinned tax cases never exercise Scotland. test_trading_loss_properties.py:213 supplies eight London entries followed by eight Scottish entries, but both pinned people lists contain only eight people. The zip at line 152 discards every Scottish entry. Align the lengths or duplicate the cases for both regions.

The review covers only 1d3abecef443d3a142640bb2f6b0567f2004103c...HEAD, excluding changes brought in by merging main. I read the PR body, every GitHub discussion comment, and the saved reviews/responses. GitHub has no formal or inline reviews. Round 3 is a pending review request, with no completed findings or verdict.

Earlier finding Status at this head
R1.1: taxable-income cap base and age-75 restriction Fixed at adjusted_total_income.py:49, with the age restriction at line 62.
R1.2 / R2.3: optimal deduction allocation Not fixed; explicitly deferred to #2106, as accepted in round 2. Fixed savings-first allocation remains at received_allowances_savings_income.py:18.
R1.3: concurrent UC trades Fixed at uc_individual_earned_income_before_mif.py:67.
R1.4: children’s tax-credit losses Fixed at tax_credits_applicable_income.py:44.
R1.5: independent Class 4 carry-forward Fixed by main’s preserved implementation at ni_class_4_losses_brought_forward.py:36.
R1.6: taxable basic income Fixed in the shared base at net_income_before_trade_loss_relief.py:26.
R2.1: benefit-cap earnings exemption Fixed at is_benefit_cap_exempt_earnings.py:33; the YAML now checks final UC of £21,124.
R2.2: SMP and pension relevant earnings Fixed at adjusted_total_income.py:56.

The programme-law assessment is qualified:

The uprating entry is correct and consistent: uprating_indices.yaml:125 places profits and losses together under OBR per-capita mixed-income growth. Both variables’ metadata use the corresponding cumulative index.

The £0 impact is expected, supported by impact.json:29: both runs have zero effective losses, identical weights and dependencies, and calculated outcomes rather than supplied outcome columns. The artifact lacks trading_loss and negative self-employment income. Source tracing confirms that tax, UC, tax credits and household-income formulas read the loss input; it is not dead code.

#528’s relock should measure loss prevalence and weighted amounts after imputation/calibration/uprating, then compare the released model with losses present versus zeroed on the same rebuilt artifact. Re-estimate relief, taxes, benefits and household/HBAI income; the historical £13m–£18m figures are not current-head estimates. Tax-credit impact needs an active-policy year.

The zero-profit property directly compares actual tax, but its benefit comparisons hold paid tax/NI deductions fixed. It proves the disclosed programme-rule invariant, not unconditional end-to-end award monotonicity. No new skips, xfails or allowlist changes weaken this PR’s tests; rewritten carry-forward expectations reflect the corrected contract.

The logs support 29/29 reproduction assertions, 90 programme YAML tests and 3,187 full YAML tests passing. Python stopped at 75%, without a final result. Unlabelled worksteal output cannot establish which tests remain; the HBAI property in finding 2 is the concrete outstanding failure risk. I ran no tests or microsimulation and made no changes.

@MaxGhenis
MaxGhenis marked this pull request as ready for review October 13, 2026 14:26
@MaxGhenis

Copy link
Copy Markdown
Collaborator Author

Round-3 fixes are ready for the hub's independent review at 5c0d13b. Original author/history preserved; no force-push or merge.

The taxpayer/year trading-allowance election now coordinates Income Tax and Class 4 current losses, retaining separate prior nominal NIC balances. Required England regression gives net income £38,800 and tax £5,246. The Pension Credit TV-licence passport and both Scottish pinned populations are covered. Full-run DOB timing failures were reproduced and addressed only by suppressing too_slow on three bounded properties, with all assertions and 30/25/25 examples retained.

Validation: the full Python suite completed all 5,680 nodes (5,560 passed, 16 failed, 102 skipped, 2 xfailed); all 16 failures subsequently passed on rerun. 94 focused Python checks, 3,214 policy YAML cases, 29 saved-review assertions, and the NI before/after proof pass. This combines the completed full run with scoped reruns; it is not a single green full run at the final head. The coverage-dependent local skip passed with sys.monitoring; the glibc-only check remains unsupported on macOS. Existing strict xfails are #1986 and #1947. Formatting/lint, required uvx ruff format --check ., diff checks and fix-evidence checks pass.

2026 certified enhanced-FRS comparison: main ea00c02 versus final head above; dataset SHA-256 5ba399ea5ab9a6c7d4e9aaf6c623080beb34d9ad5f330f6244dbad72b8d960b6, rehashed before use. Exact differences are £0 for Income Tax, UC, tax credits, HB, household net income and HBAI income. The artifact has no trading_loss input or negative self-employment income, so this cannot refresh the historical £13m–£18m estimate. Foreground simulations and resource gates passed.

Main advanced during validation; a read-only merge against f64155a is clean. The recorded merged baseline is the one used for local validation and impact.

Open scope remains explicit: accepted #2106 optimal-allocation deferral, #2108 annual benefit-tax approximation, annual UC rather than reg.57A monthly loss stock, and no separate historical tax-credit loss balance. Axiom parity remains queued at rulespec-uk #429. PolicyEngine/policyengine-uk-data #528 relocks after this model PR releases. No data build or merge was performed.

Local hand-off and aggregate-only evidence are in .job/HANDOFF.md, .job/handoffs.jsonl, .job/PROGRESS.md, findings/legal notes and validation/impact logs. A verified .job/self-employment-loss.bundle preserves the private Git branch because the assigned outer checkout's metadata is read-only. The hub dispatches the next review.

@MaxGhenis

Copy link
Copy Markdown
Collaborator Author

UK hub independent review, round 4 (Subfleet, review standard tier, served by Opus 5.5 because the Codex lanes were on hold), head 5c0d13b44:

VERDICT: REQUEST_CHANGES
Head reviewed: 5c0d13b

All three earlier findings are fixed. The Class 4 £699/£700/£701 cases are correct. I'm still requesting changes for one new problem introduced by e1debd4: the allowance election can be triggered by a loss that Class 4 itself says does not exist (finding 1). The fix is small.

  1. [should-fix] The election reads a carried-over loss that Class 4 ignores, which breaks Class 4's "no zeros needed" rule.

    • Cause: trading_allowance_deduction.py:82 reads person("trading_loss", period). If no loss is supplied for that year, that value is the earlier year's loss carried forward and uprated (now confirmed by assert_uprated_loss_cache). ni_class_4_trading_loss.py:55 counts only a loss supplied for that year. Because the election now also drives Class 4 (:62 here and ni_class_4_profits_before_losses.py:41), a carried loss can cancel the allowance for Class 4 without being a Class 4 loss.
    • Example (traced by hand, not run):
      • 2025 inputs: pay £50,000, trading_loss £10,000.
      • 2026 inputs: pay £0, self_employment_income £900, gross receipts £900, no 2026 trading_loss.
      • In 2026 the carried loss of about £10.3k is more than the £900 allowance saving, so trading_allowance_deduction is 0. Class 4 profits before losses are then £900 instead of £0.
      • That £900 eats into the nominal 2025 Class 4 balance, which carries forward £9,100 instead of £10,000.
    • Contradicted docs: this breaks the stated rules in ni_class_4_losses_brought_forward.py:20 ("a one-off loss needs no zeros in later years") and ni_class_4_trading_loss.py:15-20.
    • The test bakes it in: test_ni_class_4_profits_properties.py:685 passes the carried, uprated tax loss into the election (reference_trade, :151) while Class 4 eligibility uses only the supplied loss. The NI YAML at :148-151 avoids the case by setting 2027 to 0 explicitly.
    • Scope: Income Tax already needs explicit zeros for later years (documented at trading_loss.py:24), and per-year microdata is not affected. So this only matters for multi-year situations, but the documented Class 4 rule is now false.
    • Fix, either:
      • base the election's loss on the year's supplied value, as Class 4 does; or
      • change the Class 4 docs to say later-year zeros are also needed for the allowance election.
    • Either way, add a YAML case like the one above with 2026 left unset.
  2. [nit] The tie rule is stated in the docs but not quite implemented. The docs (trading_allowance_deduction.py:20-24, trade_loss_relief_against_general_income.py:18-21) say the model picks the greater current-year deduction and takes the allowance on a tie. Line 82 instead compares the raw loss with the allowance saving, not the loss as limited by net income and the s.24A cap.

    • With no other income, a £900 full-relief profit and a £2,000 loss, both treatments give net income £0, yet the model picks ordinary treatment.
    • Ordinary is arguably the better choice here, since it keeps a carry-forward, so just say so in the docs.
  3. [nit] The DOB health-check change is in a test file this PR doesn't otherwise touch. Commit 5c0d13b edits test_date_of_birth.py:87/128/268 in a trading-loss PR. The change itself is fine; consider splitting it into its own small PR.

  4. [nit] There has been no single green full-suite run at this head. The handoff says so: 5,560 passed and 16 failed in the full run, and the 16 later passed in separate reruns. Confirm GitHub CI is green at 5c0d13b before merging. The PR page doesn't show check status.

The three earlier findings

Finding Status
R3.1 [blocker] allowance and loss-relief election Fixed, with finding 1 above as a remaining edge case. See detail below.
R3.2 [should-fix] HBAI property missed the TV licence Fixed. free_tv_licence_value is now in HBAI_CHANNELS (test_trading_loss_properties.py:116). The reviewer's exact family is pinned at :478 and used as a property example at :720. A direct regression at :762-776 checks tax £1,386 → £0, Pension Credit > 0 → 0, and the TV licence > 0 → 0.
R3.3 [nit] Scottish cases dropped by zip Fixed. PINNED_TAXPAYERS is the 8 cases ×2 (:192-215), matching 8 London + 8 Scotland regions (:216). PINNED_PORTFOLIOS is ×4, giving 16 (:349). The zip at :155 now reaches the Scottish entries.

R3.1 detail. The election is one Person/YEAR variable, so it covers the taxpayer's year. It compares the current loss with the allowance's saving after capital allowances and prior losses (trading_allowance_deduction.py:78-83).

  • Income Tax loses the current loss when the allowance is taken (trade_loss_relief_against_general_income.py:40-44).
  • Class 4 reads the same variable (ni_class_4_trading_loss.py:62-63).
  • Law: this matches ITTOIA s.783AF (full relief makes every relevant trade's profit and loss nil), s.783AL (the opt-out is for the individual's tax year), s.783AI (partial relief replaces expenses) and ITA s.64 (sideways relief only for a loss computed normally).
  • England case: receipts £900 are within £1,000, so the allowance would save £800. The £2,000 loss is larger, so ordinary treatment applies and the loss relief is min(£2,000, cap, £40,800) = £2,000. Net income is £38,800 and tax is (£38,800 − £12,570) × 20% = £5,246, pinned at trade_loss_relief_against_general_income.yaml:213-238. I checked the five companion cases (:240-320) by hand and they are right.
  • Prior Class 4 balance: the brought-forward balance is calculated separately (ni_class_4_losses_brought_forward.py:59-66). ni_class_4_trading_loss.yaml:132-174 shows the 2025 £20,000 nominal balance surviving the 2026 allowance election: £19,300 relieved, £700 carried, and 2027 Class 4 of (29,300 − 12,570) × 6% = £1,003.80.

Other checks

  • Weakened tests: none found. Commit 5c0d13b changes only the import and the three @settings lines, adding suppress_health_check=[HealthCheck.too_slow].

    • max_examples stays 30/25/25, and every strategy, assertion and other health check is unchanged.
    • The failures were slow input generation (single 56–108 s draws of primitives) with no counterexample, and the tests passed when rerun with the original seeds.
    • The same suppression is used in more than 100 other property tests in this repo. Commits 31a877b and e1debd4 add no skip, xfail or allowlist entry.
    • In e1debd4, the replaced == 10_000 checks became exact uprating checks, and the conservation law gained an "excluded by allowance" term. That reflects the new rule, not a weaker test (but see finding 1).
  • Class 4 (ni_class_4_trading_loss.py:62, YAML :62-130): correct.

    • SSCBA s.15 charges Class 4 on profits computed under ITTOIA Part 2 after the Part 7A trading allowance, so the same election must apply to Class 4.
    • Sch 2 para 3 allows ss.64/83 losses only as Income Tax recognises them, so a loss the allowance makes nil cannot also be relieved.
    • Working: total receipts are £20,300, so allowance treatment gives profits of £19,300 and ordinary treatment gives £20,000 − loss.
      • £699: allowance, £403.80.
      • £700: tie goes to the allowance, £403.80.
      • £701: ordinary, profits £19,299, (19,299 − 12,570) × 6% = £403.74.
    • The full-relief case (£800/£900/£699) gives nil.
  • Impact: £0 is expected. The 2024 enhanced-FRS data has no trading_loss and no negative self-employment income, and tax credits are inactive in 2026. uk-data#528 is the right place to measure the real effect: compare losses present vs zeroed on the rebuilt data. Publish a form of cross-validation data #528 should also confirm that 2026 Class 4 loss relief comes out above zero. Class 4 counts only losses supplied for that year, so if the data stores 2024 losses and uprates them, Class 4 could see none in 2026.

  • Merge resolution (be82ffb): the PR's claimant-only loss now sits in tax_credits_current_year_income.py:51-56. It is deducted after the Step 1 disregard and the Step 2 total, which matches SI 2002/2006 reg.3(1) Step Four. The Pension Credit passport logic from main is preserved.

  • Reserved files: untouched. The PR's own commits since the earlier review touch only:

    • changelog entries,
    • trading_allowance_deduction.py, trade_loss_relief_against_general_income.py, input/trading_loss.py and ni_class_4_trading_loss.py,
    • two YAML files,
    • test_trading_loss_properties.py, test_ni_class_4_profits_properties.py and test_date_of_birth.py.

    The net PR diff at eac9df0 (pr-start.diff) also touches none of simulation.py, tax_benefit_system.py, utils/scenario.py, tests/conftest.py or reforms_config.yaml.

Limits of this review: I had no shell, so I ran no tests and couldn't use git or gh. I read the source at the head and the job notes, and got per-commit file lists and diffs from GitHub's public commit pages. The finding 1 example is a hand trace through the code, not a simulation result.

@MaxGhenis MaxGhenis changed the title Relieve trading losses against general income by each programme's rule Relieve trading losses by each programme's rule Oct 13, 2026
@MaxGhenis

Copy link
Copy Markdown
Collaborator Author

Round-4 fixes are ready for the hub's independent review at 60ae5a5, merged with main a98f8f084aeaada63d2b6aab0574748d4d05e1ed. Three coherent commits preserve the original author/history; one non-force push. PR body is updated and the PR remains ready.

The allowance election now reads only the year's supplied loss: the unset-2026-loss regression preserves the £900 allowance and £10,000 nominal Class 4 balance. Raw-loss/tie docs are corrected; the retained DOB health-check suppression is explicitly unrelated to trading losses. The current-main UC conflict is resolved with company-trade netting, separate employment/trade deductions and actual pre-MIF cap earnings.

Validation: 204 unique focused YAML cases and 101 Python checks pass, no focused skips/xfails/failures. The adjusted 8-case UC file passed again at final head (CLI and core API). Locked clone venv, at most 4 workers/BLAS threads, foreground throughout; nice +10 was attempted but sandbox-denied. Format/lint, required uvx Ruff format check, diff/fix-evidence checks and final recovery bundle pass. No new full local suite per round-4 instruction; prior 5c CI had all four Python shards/YAML/Test Result green, new CI pending.

2026 certified enhanced-FRS impact: Income Tax £0; UC +£8,924,131.55; tax credits £0; HB £0; household net income +£8,924,137.99; HBAI +£8,924,131.55; Class 4 £0. Dataset SHA-256 5ba399ea5ab9a6c7d4e9aaf6c623080beb34d9ad5f330f6244dbad72b8d960b6, rehashed before each load. Restoring only main's cap-earnings consumer makes all seven outcomes match main exactly: the uplift comes from that merge integration, while this artifact has no effective trading losses and cannot refresh the historical £13m–£18m tax estimate. Final test-only commit leaves model code unchanged; final branch simulation reproduces the prior results exactly.

Accepted #2106 allocation deferral, #2108 annual benefit-tax approximation, annual UC instead of the reg.57A monthly loss stock, absent historical tax-credit loss stock and queued Axiom #429 remain explicit. PolicyEngine/policyengine-uk-data #528 relocks after this model PR releases; its rebuilt artifact must compare losses present versus zeroed and confirm supplied-year Class 4 eligibility. No data build or merge was performed.

Local hand-off/evidence: .job/HANDOFF.md, .job/handoffs.jsonl, .job/PROGRESS.md, .job/FINDINGS-R4.md, .job/IMPACT-R4.md and aggregate-only impact/control logs. Private Git is selected by .job/environment; verified .job/self-employment-loss-final.bundle and the remote branch preserve ancestry beyond the read-only outer checkout. All foreground checks have finished; the initial stalled bootstrap was interrupted before collection and its clean rerun passed. No in-job reviewer or self-approval; the hub dispatches the next review. No PR merge.

#2399 landed the same benefit-cap earnings exception change this branch made
(is_benefit_cap_exempt_earnings reads uc_individual_earned_income_before_mif).
The only conflict was in that file's comments; take main's version, so this
PR no longer touches it.

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

@vahid-ahmadi vahid-ahmadi left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Fine once the changelog and impact section are brought up to date with the #2399 merge (finding 1). The loss rules themselves check out.

@MaxGhenis, I reviewed the current head 379f504b. The earlier rounds' findings are fixed, and I re-checked the Income Tax core against the statute: s. 64 relief against net income, limited by s. 65(1) to the s. 24A cap and the available income. I also checked the s. 24A(8) adjusted total income steps and the s. 783AF/783AL election. My hand calculations agree with the model:

  • Cap. 2025, London, employment income £300,000 and a £200,000 loss. Cap = max(£50,000, 25% × £300,000) = £75,000. Net income is £225,000 and tax is 7,540 + 34,976 + 44,937 = £87,453. The model gives £75,000 and £87,453.
  • Cap with relief at source. Adding £40,000 of personal contributions gives adjusted total income of £260,000 (s. 24A(8) Step 3) and a £65,000 cap. The model matches.
  • The relief wastes the personal allowance. Employment income £20,000 and a £15,000 loss gives net income £5,000 and tax £0. That follows s. 65: a claim can't be restricted to keep the allowance in use.
  • Trades netted for Income Tax and Class 4. A £30,000 profit and a £10,000 loss on another trade gives Income Tax of £1,486 and Class 4 of (20,000 − 12,570) × 6% = £445.80.
  • HICBC follows the lower adjusted net income. Employment income £70,000 and a £15,000 loss gives adjusted net income £55,000, so no charge. With no loss the charge is £677.
  1. must: one changelog fragment and the impact section describe a change this PR no longer makes.

    • changelog.d/trading-loss-company-merge.fixed.md says the PR applies "the same actual earnings before the minimum income floor in the benefit cap earnings test".
    • At this head, is_benefit_cap_exempt_earnings.py is not in the diff. Main already reads uc_individual_earned_income_before_mif there (#2399, e6564306b), and the merge at 379f504b took main's version.
    • So the release note would claim a change main already made. The impact table's UC row (+£8.924m) and the sentence explaining it were measured at 60ae5a5, before that merge.
    • With no losses in the data, the only UC change left in the diff is the uc_trading_losses_set_against_profits term. I'd expect £0 now, but I haven't re-run it.
    • Please drop that clause from the fragment and re-run or relabel the table.
  2. should: adjusted_total_income re-implements the pension relief limit, and differs from #2240. adjusted_total_income.py:56-67 relieves contributions up to max(£3,600, relevant earnings) for any contribution type. It uses taxable_employment_income plus profits.

    • #2240 rewrites pension_contributions_relief to the same s. 190 limit. It gives the £3,600 increase only through relief at source (s. 191(7)), and it uses employment_income.
    • s. 24A(8) Steps 3-4 deduct the contributions actually given relief at source (s. 192) and excess net pay or claimed relief (ss. 193(4), 194).
    • Once #2240 lands, reading pension_contributions_relief here would keep the two in step, instead of having two versions of s. 190.
    • The amounts are small; it only moves the cap above £200,000 of adjusted total income. But whichever PR merges second should reconcile them.
  3. nit: the date-of-birth test change is unrelated. It brings changelog.d/date-of-birth-properties.fixed.md, a user-facing "fixed" entry for a test-only change, and three test_date_of_birth.py entries on the Reproducer: line. The earlier round already suggested splitting it out. If it stays, I'd drop the fragment and those Reproducer entries.

  4. nit: carry-forward still depends on explicit zeros for Income Tax. trading_loss.py:24-26 documents that an unset later year inherits and uprates the loss, and Income Tax relieves it again as a new current-year loss. That's fine for per-year microdata. In a multi-year household run it repeats the relief. The documentation is clear, so no change is needed. It's worth keeping in mind when #528 decides how the data supplies losses.

Overlap. None of my open PRs touches the same lines.

  • #2382 edits hbai_household_net_income.py and uprating_indices.yaml in different hunks.
  • #1820 rewrites is_benefit_cap_exempt_earnings.py but reads the same uc_individual_earned_income_before_mif, so the UC loss netting reaches the cap test either way.

What I checked

  • I read the PR body, the full diff and all the hub review rounds and responses in the comments. There are no formal reviews.
  • I read ITA 2007 ss. 24A, 64 and 65 on legislation.gov.uk.
  • I ran the hand-computed cases above against this head.
  • At head 379f504b, in a fresh uv sync environment in a worktree:
    • the 7 changed YAML files: 54 passed;
    • test_trading_loss_properties.py and test_ni_class_4_profits_properties.py: 37 passed;
    • ruff check and ruff format --check on the 22 added or changed Python files are clean.
  • Mutation: I forced allowance treatment in trading_allowance_deduction.py. The trade-loss and Class 4 YAML then failed 4 of 34, so the election cases bite. I restored the file afterwards.
  • I did not run test_date_of_birth.py or the national impact. CI is green at this head.
  • I did not re-check the UC reg. 57A, tax-credit Step Four or HB reg. 38(10) treatment beyond the earlier rounds and the YAML.

🤖 Generated with Claude Code

@MaxGhenis

Copy link
Copy Markdown
Collaborator Author

Round-5 hand-off: 4c85dfa, pushed once as a normal fast-forward. PR body updated; PR is ready. The hub dispatches the independent delta review of 5c0d13b44..HEAD.

Fresh 2026 certified enhanced-FRS comparison: main 714b143 versus merged checkpoint 379f504. Exact £0 for Income Tax, UC, tax credits, HB, household net income, HBAI income and Class 4. Dataset SHA-256 5ba399ea5ab9a6c7d4e9aaf6c623080beb34d9ad5f330f6244dbad72b8d960b6, rehashed before each load; matching weights/dependencies, seed 0. The artifact has no trading losses, so it cannot refresh the historical £13m–£18m tax estimate. #2399 now carries the former cap change on main; this PR no longer touches the cap-earnings file.

Validation: 122 focused Python checks and 166 policy YAML cases pass, no skips/xfails/failures; locked clone venv, foreground, at most four workers/threads. Trading-loss/allowance properties, all Class 4 files and UC claimant/deduction/MIF/company/statutory-pay properties are covered, plus touched programme and UC earned-income YAML. make format, uvx ruff format --check ., diff and fix-evidence checks pass. nice +10 was sandbox-denied and recorded. No new full local suite per round-5 instruction; all 14 checkpoint CI checks were green, final-head CI is pending.

The only new commit aligns release notes: removes the stale benefit-cap clause and unrelated DOB test-only fragment. The DOB suppression remains disclosed in the body. Model and test code match the measured checkpoint. Earlier rounds through r4 and their fix commits are mapped in the body and .job/FINDINGS-R5.md.

Open items remain explicit: accepted #2106 allocation deferral, #2108 annual benefit-tax approximation, annual UC rather than monthly reg.57A loss stock, absent historical tax-credit loss stock, Axiom #429 queued, and pension-relief integration with open #2240 when the second PR merges. PolicyEngine/policyengine-uk-data #528 relocks after this model PR releases; its rebuilt artifact must compare losses present versus zeroed and confirm supplied-year Class 4 eligibility.

Hand-off/evidence: .job/HANDOFF.md, .job/handoffs.jsonl, .job/PROGRESS.md, .job/IMPACT-R5.md, .job/impact-r5.json, .job/validation-r5.json. Verified recovery bundle .job/self-employment-loss-r5.bundle; private Git via .job/environment. Temporary source copies deleted; caller checkout untouched; no data build, survey export, PR merge, in-job reviewer or self-approval.

@MaxGhenis
MaxGhenis added this pull request to the merge queue Oct 14, 2026
Merged via the queue into main with commit 3b8ac4f Oct 14, 2026
15 checks passed
@MaxGhenis
MaxGhenis deleted the self-employment-loss branch October 14, 2026 11:15
@MaxGhenis

Copy link
Copy Markdown
Collaborator Author

Merged by the UK hub (audit). Merged with a merge commit at the tested head 4c85dfa0d (expectedHeadOid, through the main merge queue). The hub adopted this PR (d1280) and finished it over five build rounds and four hub reviews.

Gates:

  • CI: gh pr checks passed at the head, including Fix evidence on the final body.
  • MERGEABLE, not a draft. No CHANGES_REQUESTED review.
  • Independent review:
    • GPT-6.1 Sol delta review of 5c0d13b44..4c85dfa0d (~/reviews/uk-hub/reviews/uk2085/review-r3.md) passed every check:
      • the annual-loss election now uses the year's supplied loss, so the 2025/2026 case gives nil Class 4 profits and keeps the £10,000 balance;
      • the main merge leaves is_benefit_cap_exempt_earnings.py byte-identical to main;
      • the impact is £0;
      • no test is weakened;
      • the legal claims (ITTOIA 783AF/AL, ITA ss.64/83, SSCBA Sch 2 para 3, UC reg 57) hold.
    • Its one finding, a five-test Reproducer: line, was fixed in the PR body only. An in-session Opus 5.5 confirmation gave APPROVE at 4c85dfa0d, and main's fix-evidence checker passes on the live body.
  • Earlier rounds: r1–r4 findings were all fixed. These were the taxable-income cap, concurrent UC trades, children's tax-credit losses, Class 4 carry-forward, the benefit-cap earnings exemption, SMP and pension relevant earnings, the allowance and loss election, HBAI and TV-licence coverage, and the Scottish pinned cases.
  • Real-run impact: 2026 enhanced FRS (sha256 5ba399ea…), main 714b143 against the head: exactly £0 on all seven outcomes. The dataset has no trading-loss inputs, and the benefit-cap change that once showed +£8.92m reached main through Fix benefit-cap statutory-pay earnings exemption #2399. uk-data#528 measures the real effect after it relocks.
  • Merge order with Reset negative HBAI household income to zero before housing costs, as HBAI does #2402 (the HBAI reset to zero): whichever lands second points test_trading_loss_properties.py::test_household_income_moves_only_through_its_channels (lines 730 and 756) at hbai_household_net_income_before_reset_to_zero.

MaxGhenis added a commit that referenced this pull request Oct 14, 2026
…2085

- #2085's channel identity (test_trading_loss_properties) now measures
  HBAI income before the reset, the sum the identity holds for.
- household_income_decile documents the tie rule: households at zero share
  the rank at the top of their group, so they are in decile 1 while they
  hold at most a tenth of people. Unit tests pin both sides of that line;
  the property test checks they share the lowest decile, and decile 1 below
  a tenth (new pinned population).
- When the median before the reset is at or below zero, the reset makes it
  zero and no one is in relative poverty before housing costs: checked.
- YAML: the reset under gov.contrib.abolish_council_tax.
- Changelog: headcounts, gaps, bottom-decile moves and unchanged labour
  supply responses.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
MaxGhenis added a commit that referenced this pull request Oct 14, 2026
MaxGhenis added a commit that referenced this pull request Oct 15, 2026
…shared-cap-lha-rules

#2399 changed the shared earnings exception this PR deletes. Its
measure, uc_individual_earned_income_before_mif summed over the
assessed claimants (reg. 82(1)(a), excluding MIF income under reg.
82(4)), is carried over unchanged into the UC-only
is_uc_benefit_cap_exempt_earnings; the shared file stays deleted.

Main's new tests that read the deleted shared names now read the UC
ones, with their expected values unchanged:
- test_uc_statutory_pay_properties.py (#2399; conflict): main's text
  and regression case, reading is_uc_benefit_cap_exempt(_earnings).
- benefit_cap_earnings_exception_earned_income.yaml (#2399) and
  uc_trading_loss.yaml (#2085).
- test_trading_loss_properties.py (#2085).

Targeted YAML (benefit_cap folder, benefit_cap_by_scheme,
uc_trading_loss): 121 passed.

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

This comment has been minimized.

4 similar comments
@MaxGhenis

This comment has been minimized.

@MaxGhenis

This comment has been minimized.

@MaxGhenis

This comment has been minimized.

@MaxGhenis

This comment has been minimized.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Class 4 NICs ignore capital allowances, trading losses and the trading allowance

2 participants