Skip to content

Model Universal Credit reg 77 for owner-managers of a company - #1965

Merged
MaxGhenis merged 10 commits into
mainfrom
uc-dividends-owner-managers-1948
Oct 13, 2026
Merged

MaxGhenis merged 10 commits into
mainfrom
uc-dividends-owner-managers-1948

Conversation

@MaxGhenis

@MaxGhenis MaxGhenis commented Sep 30, 2026 •

Copy link
Copy Markdown
Collaborator

Fixes #1964. Part of #1948.

Summary

This PR models Universal Credit regulation 77, "Company analogous to a partnership or one person business" (UC Regs 2013; UC Regs (NI) 2016, same number). It applies to a person who stands in a position analogous to a sole owner or partner of a company carrying on a trade or a property business. For that person:

  • Earnings. A trading company's income, or their share of it, is their self-employed earnings. It is on top of any pay they draw as its director or employee (77(3)(b), 77(4)). The company's profit or loss is added to that of any trade they carry on themselves, the income tax and NI they pay in respect of any trade come off that total, and a negative result is nil (reg 57(2) steps 1-3). Only a claimant's or partner's company earnings count (reg 22(1)(b)).
  • Minimum income floor. If the trade is their main employment they are treated as gainfully self-employed, so the floor applies (77(3)(c)).
  • Capital. The value of their shares is disregarded. They are treated as holding the company's capital, or their share of it, less assets used wholly and exclusively for a trade while they work in it (77(2), 77(3)(a)).
  • Exclusion. None of this applies where their income from the company is employed earnings under the intermediaries (IR35) or managed service company rules, as 77(5) stood at the time (77(5), SI 2018/1129).

Every new input defaults to "no such company", so no dataset changes; the Enhanced FRS comparison with main is below.

#1948 asked whether its six-figure-dividend UC units are owner-managers under reg 77. Their dividends are not ones the survey recorded: they are an imputation artefact, fixed in PolicyEngine/policyengine-uk-data#498. The survey cannot settle whether any of these people is an owner-manager; see "What this means for #1948".

The law

UC Regs 2013 reg 77, verbatim from legislation.gov.uk (revised text valid 2026-07-16, no outstanding effects):

(1) Where a person stands in a position analogous to that of a sole owner or partner in relation to a company which is carrying on a trade or a property business, the person is to be treated, for the purposes of this Part, as the sole owner or partner.
(2) Where paragraph (1) applies, the person is to be treated, subject to paragraph (3)(a), as possessing an amount of capital equal to the value, or the person's share of the value, of the capital of the company and the value of the person's holding in the company is to be disregarded.
(3) Where paragraph (1) applies in relation to a company which is carrying on a trade— (a) any assets of the company that are used wholly and exclusively for the purposes of the trade are to be disregarded from the person's capital while they are engaged in activities in the course of that trade; (b) the income of the company or the person's share of that income is to be treated as the person's income and calculated in the manner set out in regulation 57 as if it were self-employed earnings; and (c) where the person's activities in the course of the trade are their main employment, the person is to be treated as if they were in gainful self-employment and, accordingly, regulation 62 (minimum income floor) applies.
(4) Any self-employed earnings which the person is treated as having by virtue of paragraph (3)(b) are in addition to any employed earnings the person receives as a director or employee of the company.
(5) This regulation does not apply where the person derives income from the company that is employed earnings by virtue of Chapter 8 (workers under arrangements made by intermediaries), Chapter 9 (managed service companies) or Chapter 10 (workers' services provided through intermediaries) of Part 2 of ITEPA and that income is derived from activities that are the person's main employment.

Until 27 November 2018, 77(5) read "...Chapter 8 ... or Chapter 9 ... of Part 2 of ITEPA", with no Chapter 10 and no main-employment condition (point-in-time texts 2013-04-29 and 2014-11-26; SI 2018/1129 reg 3(5)). The model dates this with two parameters.

The regulation is mandatory. DWP guidance treats "analogous" as a question of fact:

  • like a sole owner: total influence over day-to-day running, for example owning 99% of the shares;
  • like a partner: a small number of shareholders and meaningful influence over the running of the company.

A shareholder in a widely held company is an investor (ADM H4362-H4364, H1877-H1879, citing R(IS) 8/92 and 13/93 as reported in CA v Hastings BC [2022] UKUT 57 (AAC)). The only Upper Tribunal decision found applying UC reg 77, SSWP v Faghy (UA-2026-000266-USTA, 27 August 2026), accepted the Secretary of State's ground that a property business gets no 77(3)(a) disregard. It was an unopposed paper decision, so this is not the tribunal's own reasoned construction. This model does the same.

Where DWP guidance and the regulation differ, the model follows the regulation.

  • ADM H4372 disregards all of the treated company capital while the person works in the business. The regulation disregards only assets used wholly and exclusively for the trade. H1880 also paraphrases that test as "wholly or mainly".
  • ADM H4375 compares only the company income with the floor. Reg 62(2) compares the claimant's total earned income, and this is what uc_individual_earned_income already does.
  • ADM H1892 takes the company's capital as its net value (assets less liabilities). That is how owned_company_capital is documented.

Company income is before corporation tax. Reg 57(2) step 3 deducts only income tax and NICs paid by the person. Neither the regulations nor ADM H1/H3/H4/H5 provide for deducting corporation tax, so owned_company_income_share is documented as the reg-57 amount before it.

What changes

Inputs, all under variables/input/owned_company/, per person, each defaulting to no company:

  • stands_as_sole_owner_or_partner_of_company
  • owned_company_carries_on_trade
  • owned_company_carries_on_property_business
  • owned_company_intermediary_earnings_chapter (enum: none, or ITEPA Part 2 Chapter 8/9/10)
  • owned_company_intermediary_earnings_from_main_employment
  • owned_company_income_share
  • owned_company_is_main_employment
  • is_engaged_in_owned_company_trade
  • owned_company_capital
  • owned_company_trade_assets
  • owned_company_holding_value

UC variables (gov/dwp/universal_credit/company/):

  • uc_company_intermediary_exclusion_applies (77(5), dated)
  • uc_company_owner_treatment_applies (77(1), (5))
  • uc_company_self_employed_earnings (77(3)(b); the reg 57(2) step 1 profit or loss, so negative for a loss)
  • uc_company_gainful_self_employment (77(3)(c))
  • uc_company_capital (77(2), (3)(a), clamped at zero)
  • uc_company_holding_disregard (77(2))

Parameters: gov.dwp.universal_credit.company_owner.intermediary_exclusion.{chapters, requires_main_employment}.

Wiring:

  • uc_individual_earned_income_before_mif follows reg 57(2) for self-employed earnings: it adds the company's profit or loss to the person's own self-employment profit or loss (step 2), takes off the income tax and NI paid in respect of any trade (step 3), and only then makes a negative result nil. Pay is net of the tax and NI paid in respect of the employment (reg 55(5)). Before, all of a person's tax and NI on earnings came off the combined total after the trade was floored, which was the same thing until a company loss could cancel a taxed trade.
  • uc_is_in_gainful_self_employment adds the 77(3)(c) route. uc_mif_applies reads it, so the floor still needs the all work-related requirements group (reg 62(1)(b), Apply the UC minimum income floor only to claimants subject to all work-related requirements #2081) and is off in a start-up period (reg 62(5)).
  • The benefit cap earnings test is left to Fix benefit cap exemption defects (#1818) #1820. Main's is_benefit_cap_exempt_earnings sums pay and self-employment profit less all income tax and NI, so adding a company term there would carry a signed loss and dividend tax into the test. Fix benefit cap exemption defects (#1818) #1820 rebases the test on uc_individual_earned_income_before_mif for assessed claimants (reg 82(1)(a), (4)) and on the 16-hour National Living Wage threshold, so it will count company earnings correctly whichever PR merges first. Until then, a company owner's company earnings do not count towards the exemption, as on main today.
  • uc_assessable_capital adds the company capital of the claimant and partner (is_uc_claimant, following main's rule that a dependant's capital is not the claimant's) and removes disregarded holdings.
    • The household pool. Every holding except a reporting unit's claimant's or partner's leaves the household capital pool before the pool is shared out among claimants and partners (new household_uc_pool_company_holdings): those of everyone in unreported units, and of dependants in reporting ones, whose capital is nobody's to count. So no unit counts any part of a disregarded holding. A holding is shares, held in the household's corporate_wealth, so no more than that comes out: a holding entered without matching corporate_wealth cannot remove savings or property.
    • Units reporting their own capital. The claimant and partner's holdings come off uc_reported_capital, floored at zero. The reported figure has no share breakdown to cap them against.
  • That capital also reaches the legacy-style local council tax reduction schemes, which read uc_assessable_capital for households with a UC award. This is intended: those schemes take UC's capital figure.
  • A person whose main employment is the company's trade counts as engaged in it for the 77(3)(a) trade-asset disregard.

Dividends are left alone. A shareholder's dividends are not UC unearned income under reg 66(1) at any capital level; #1950 takes them out of uc_unearned_income. Before it merged, main still counted dividends as unearned income when tariff income did not apply. So a household calculation that sets these inputs and also enters that person's dividends would count the company's income twice; owned_company_income_share's documentation says so. #1950 has now merged (main is merged into this branch), so on current main the double count cannot arise.

Invariants (stated and tested)

test_uc_company_owner_properties.py checks these with Hypothesis on generated benefit units: singles and couples, 0-2 children, pay around the floor, self-employment profit, small savings and corporate_wealth, start-up status, and company facts including losses.

  1. Inert. When the person is not a company's sole owner or partner, or 77(5) applies, or the company carries on neither a trade nor a property business, no company fact changes universal_credit, uc_assessable_capital, uc_earned_income, is_benefit_cap_exempt_earnings, uc_individual_earned_income or uc_mif_applies.
  2. Capital identity, one benefit unit per household, none reporting its capital. uc_assessable_capital = capital without the rule − min(Σ owners' holdings, corporate_wealth) + Σ owners' max(0, company capital − trade assets if trade and engaged or main employment). Property 3 covers shared households and property 9 reporting units.
  3. Allocation and conservation, two unreported benefit units per household. Every owner's holding, up to the household's corporate_wealth, leaves the household pool; the rest is shared in proportion to each unit's claimants, and each unit adds its own claimants' company capital: unit capital = (household capital − min(Σ holdings, corporate_wealth)) × claimants in unit ÷ claimants in household + its company capital. The units' capital therefore sums to that pool plus Σ company capital.
  4. Earnings identity. Earned income before the floor = max(0, pay − tax and NI on the employment + max(0, own self-employment profit or loss + company profit or loss − tax and NI on the trade) − own relievable pension contributions), with company profit or loss counted for a trading company only. Independently of the model's tax: where pay and own-trade profit together are within £12,000 and there are no pension contributions, it is exactly pay + max(0, own-trade profit or loss + company profit or loss).
  5. Floor. uc_mif_applies holds exactly for a person in the all work-related requirements group, outside a start-up period, who has self-employment profit or loss or owns a trading company that is their main employment; never for one with limited capability for work and work-related activity. The floor never lowers earned income, and a single claimant it applies to has earned income of max(earned income, floor).
  6. Monotone. Among cases where extra company income leaves the benefit cap earnings exemption unchanged, UC is non-increasing in the company income share (crossing the reg 82(1)(a) threshold lifts the cap and can raise UC). UC is also non-increasing in the company's capital and non-decreasing in the disregarded holding. Extra company capital that is itself a disregarded trade asset changes nothing once the owner works in the trade.
  7. Property companies. The income share and the main-employment flag never change UC or earned income for a property-only company.
  8. Dependants. A qualifying young person's company income and capital (with no holding) change neither the award nor its capital or earned income.
  9. Holdings count for nobody. Adding shares to the household's corporate_wealth as a disregarded holding of a dependant in a family (whether or not the family reports its capital) and of an adult in another, unreported unit changes no unit's assessable capital.

How hard the properties are exercised. Each property runs 10 derandomised examples. Pinned examples make every run reach:

  • the 77(3)(c) floor, and an LCWRA owner who gets none;
  • a company loss netted against the owner's own trade (reg 57(2) step 2);
  • the tax on a trade a company loss cancels (step 3);
  • a disregarded holding in a shared household.

A 77(3)(c) owner in a start-up period, and a holding above corporate_wealth (also pinned by YAML), are reached by the generated examples. A replay of the four properties built on the shared generator covers 362 adults:

Branch Share of adults
Rule applies 51%
Trading-company owner 41%
Company loss 12%
Company loss against the owner's own trade 7%
Company loss against a taxed own trade 4%
Trade-asset disregard active 14%
Holding larger than the household's corporate_wealth 17%
77(5) exclusion 11%
Outside the all work-related requirements group 16%
Floor through 77(3)(c) 10%
Floor raises earned income 16%
In a couple 56%

No generated pair in the monotonicity property crossed the cap threshold, so its exemption filter was never needed.

Mutation check. I reinstated eight defects one at a time, and each makes a property or YAML case fail:

  • a company loss floored before it meets the owner's own trade (reg 57(2) step 2);
  • trade tax and NI taken off pay after the trade is floored (step 3, the round-3 finding);
  • the 77(3)(c) route into gainful self-employment removed;
  • company earnings left out of earned income;
  • a dependant's company capital counted;
  • holdings left in the household pool;
  • a reporting family's dependant's holding left in the pool (the round-3 finding);
  • the corporate_wealth cap on holdings removed.

Without mutants all seven properties pass. The script and its outputs are kept with the evidence (tests-evidence/mutation_check.py, mutation.json, property_coverage.py, coverage.json).

test_uc_company_owner_axiom_parity.py is a golden-case mirror of the independent Axiom encoding, TheAxiomFoundation/rulespec-uk uk/regulations/uksi/2013/376/77.yaml. It copies the four cases of its 77.test.yaml (commit 0644db8) and maps Axiom's inputs one to one (table below). It checks:

  • the 77(5) exclusion and treatment;
  • the trade-asset disregard, treated capital and holding disregard;
  • self-employed earnings, and the 77(4) total through the model's earned income;
  • gainful self-employment and the floor trigger.

It does not run Axiom, so it will not catch drift in that encoding; rulespec-uk#394 covers that side.

Tests

  • YAML (26 cases, hand-computed from the regulation). tests/policy/.../universal_credit/company/uc_company_analogous_business.yaml:

    • ADM H4376 Example 2, Claudia: floor applied.
    • ADM H4376 Example 1, Ezgjan: start-up period, 50% share.
    • 77(4) director pay plus company income.
    • Not main employment: no floor.
    • Taper through uc_income_reduction.
    • ADM H4367, Pablo: property company, capital but no earnings.
    • Trade assets disregarded while engaged, counted when not engaged, and disregarded when the trade is the main employment.
    • 77(5) now, and in 2017 (Chapter 9 excluded, Chapter 10 not).
    • An investor, and a company with neither a trade nor a property business.
    • Joint claimants with two 50% owners.
    • Company capital over the £16,000 limit.
    • A company loss: nil self-employed earnings, pay intact; and a company loss set against the owner's own trading profit (reg 57(2) step 2).
    • A two-benefit-unit household, where the holding leaves the pool before sharing.
    • A benefit unit reporting its own capital.
    • A holding entered without matching corporate_wealth does not remove savings.
    • Tax and NI on a trade that a company loss cancels stay inside the nil trading result (the round-3 review's case: £12,000 pay, £20,000 own-trade profit, a £20,000 company loss, giving £12,000 and no award), with its no-company control.
    • A dependant's holding in a family that reports its capital leaves the household pool.
    • A dependant (a qualifying young person) who owns a trading company: not the claimant's earned income, and no floor.
  • Hypothesis properties: 7 tests (the 9 invariants above), about 90 seconds with -n 4.

  • Axiom golden cases: 4 tests.

  • At 93dd669cc, locally:

    • the whole UC YAML directory and the benefit cap YAML: 581 passed;
    • eleven UC, benefit cap and reg 77 property and capital test files: 82 passed, plus main's one strict xfail.

    CI runs the full suite.

Enhanced FRS impact

Data and runs. The dataset is a private copy of enhanced_frs_2024_25.h5 (sha256 e433e532…). Every number below is from a real microsimulation run with stored weights, 2025-2030: main e3c27c7ab and this branch at 2a52fa09f (main merged in). The head, 93dd669cc, changes only the property tests since then. The branch runs were on a clean tree. Main's run had one local change, the editable package's own version line in uv.lock (2.126.8 → 2.127.0), which no code reads.

Main vs this branch. Not bit-identical, but equal to within float32 rounding. Of the 22 arrays compared (benefit-unit and household), 16 are identical in every year 2025-2030. The other 6 differ only in the last bits:

  • uc_individual_earned_income (before and after the floor) and uc_earned_income: by at most £0.07 per benefit unit;
  • uc_income_reduction and universal_credit: by at most £0.004;
  • household_net_income: by at most £0.04.

Total UC differs by between £3 and £65 a year (against £83.3bn in 2026).

The cause is that uc_individual_earned_income_before_mif now sums its float32 terms in a different order (employment net of its tax and NI, plus the trading total net of its tax and NI). Recomputing main's formula inside a branch run at 93dd669cc gives no difference above £0.50 for any person in 2026, so the logic is unchanged without company income. The per-array maxima and UC-total differences, and that check, are kept with the evidence (impact/branch_v5_vs_main_v5_magnitudes.json, diag/earnings_order_diff_2026.txt). The dataset has no owner-manager inputs, so reg 77 itself is inert.

Preview with the FRS's own director fields (indicative only; not a proposed release). This illustrates what a data build that fills the inputs would do. The FRS 2024-25 job table asks directors of limited companies what share they own (DIRPERC) and what dividends they took (DIVIDEND). For this run only:

  • Owner status. stands_as_sole_owner_or_partner_of_company and owned_company_carries_on_trade are true for directors owning 50% or more. The 50% line is an assumption drawn from the ADM examples, not the law. Both dataset copies of each FRS household get the inputs: the original and its capital-gains clone.
  • Main employment and engagement. Both are true where the director job has positive usual hours, at least as many as the person's other jobs, and the person is in work now (ILO status).
  • Company income. The income share is the director's reported dividends from the company, annualised.
    • The stored DIVIDEND is a weekly net amount. It equals the adult table's DIVIDNET where both exist, despite the question asking about the last 12 months.
    • Dividends are a proxy for the company's income. Retained profit is unobserved, and director income may also sit in the FRS self-employment fields; that overlap is not checked here.
  • Not uprated. The inputs are held at 2024-25 cash values in every year.

Capital inputs stay zero, since the FRS has no company balance sheet. Result, against the branch without inputs:

In every year 2025-2030, UC falls for fewer than ten survey records and rises for none; the change is under £0.1bn a year. Company earnings total £9.5bn in 2026. An earlier preview, at 19323628, was measured before main's net-floor, claimant-only and earned-income changes, and before this PR stopped adding company earnings to the benefit cap test, so the two are not comparable.

Filling the inputs is follow-up data work in policyengine-uk-data. Director shares and dividends are in the FRS job table. Its DIVIDEND is stored as a weekly net amount, and whether director dividends also appear in other FRS income fields has to be checked first.

What this means for #1948

#1948's cohort is the UC benefit units with more than £50,000 of dividends on the Enhanced FRS. Most of them are FRS-half records; the rest are SPI donors. I linked the FRS-half records to the raw FRS 2024-25. The cohort is too small to publish its totals, so these are the conclusions only:

  • The dividends are not the survey's. The raw FRS investment-account dividends in those households are a small fraction of a percent of the model's dividend_income for them.
  • The same holds for every FRS-reported UC unit. Across all benefit units reporting UC in the survey, the model carries £2.91bn of dividends against £0.011bn in the raw FRS (2026, stored weights).
  • No owner-manager income. No director in the cohort's households reports dividends from their company (job table DIRECTOR and DIVIDEND), and few of those households include a director at all.

So the cohort's dividends are not owner-manager income the survey recorded. That does not show that no one in the cohort is an owner-manager under reg 77: the comparison is at household level, and the FRS records neither a company's trading status nor its profits, so a director who takes no dividends would still be within reg 77. What the linkage does show is that the model's dividends are not the survey's. They come from policyengine-uk-data, which has two defects:

  • impute_income replaces every FRS respondent's dividends with a draw from the SPI income model, which predicts from age, gender and region (and, since policyengine-uk-data#529, within earnings groups), not from anything about investments or benefits;
  • frs.py keys the survey's own dividends on row position, so almost none survive.

PolicyEngine/policyengine-uk-data#498 fixes both.

#1948 also asked how #1837 changes the picture. Real runs of the same dataset on main as it was then (44240bd8, before #1950 merged), for 2026:

So nothing in the rules stops these units, whether or not #1837 lands. The fix is in the data.

Not modelled here (tracked separately)

Axiom

axiom: uk:regulations/uksi/2013/376/77 encoded-correct for the law in force from 28.11.2018 (rulespec-uk 77.test.yaml, 4 cases, mirrored by test_uc_company_owner_axiom_parity.py) | TheAxiomFoundation/rulespec-uk#394 queued

The queued issue covers the module's two gaps:

  • 77(5) is undated. A 2017 case gives the opposite of the law in force; the pinned runner confirmed this on a scratch copy.
  • Nothing in Axiom consumes reg 77's outputs: regs 18, 22, 46, 62 and 72 read capital and earnings as free inputs.

Axiom to policyengine-uk mapping (for rulespec-uk#394 and axiom-oracles)

Axiom uk:regulations/uksi/2013/376/77 policyengine-uk (annual)
input person_stands_in_position_analogous_to_sole_owner_or_partner_in_relation_to_company stands_as_sole_owner_or_partner_of_company
input company_carries_on_trade owned_company_carries_on_trade
input company_carries_on_property_business_within_meaning_of_corporation_tax_act_2009_section_204 owned_company_carries_on_property_business
inputs person_derives_company_income_that_is_employed_earnings_by_itepa_part_2_chapter_8 / _9 / _10 owned_company_intermediary_earnings_chapter (enum)
input intermediary_employed_earnings_derived_from_person_main_employment_activities owned_company_intermediary_earnings_from_main_employment
input company_capital_value_or_person_share_value owned_company_capital
input company_trade_asset_value_or_person_share_used_wholly_and_exclusively_for_trade owned_company_trade_assets
input person_engaged_in_activities_in_course_of_company_trade is_engaged_in_owned_company_trade
input person_holding_value_in_company owned_company_holding_value
input company_income_or_person_share_calculated_as_self_employed_earnings_under_regulation_57 (monthly) owned_company_income_share (annual)
input person_employed_earnings_as_director_or_employee_of_company (monthly) employment_income (annual)
input person_activities_in_course_of_company_trade_are_main_employment owned_company_is_main_employment
company_intermediary_employed_earnings_main_employment_exclusion_applies uc_company_intermediary_exclusion_applies (dated as in rulespec-uk#394)
company_analogous_owner_or_partner_treatment_applies uc_company_owner_treatment_applies
person_capital_treated_as_possessed_from_company uc_company_capital
person_company_holding_disregarded_from_capital uc_company_holding_disregard
company_income_treated_as_person_self_employed_earnings uc_company_self_employed_earnings
person_treated_as_gainfully_self_employed_for_company_trade uc_company_gainful_self_employment
minimum_income_floor_applies_due_to_company_trade the 77(3)(c) route into uc_mif_applies (which also applies reg 62(5))

Provenance

Law texts, ADM extracts, case-law notes, the Axiom audit and all impact scripts and outputs are in ~/reviews/uc-dividends-1948-2026-09-30/: law/, axiom/, impact/ and diag/. They are local and private. The *.json run summaries and diag/*.json hold aggregates only. The impact/*.npz arrays and efrs_copy.h5 are record-level survey data (per-benefit-unit amounts and weights) and never leave this machine; nothing in this PR is drawn from them except the aggregates shown.

🤖 Generated with Claude Code

MaxGhenis and others added 3 commits September 30, 2026 16:43
…r one person business

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Until 27 November 2018 any Chapter 8 or 9 ITEPA employed earnings from the
company excluded the owner; from 28 November 2018 Chapters 8-10 exclude only
when derived from main-employment activities. Replace the single boolean with
the ITEPA chapter and a main-employment flag, and parameterise the change.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Company losses count as nil self-employed earnings (reg 57(2)).
- Company earnings count towards the benefit cap earnings exemption (reg 82).
- In multi-benunit households, disregarded holdings leave the household
  capital pool before it is shared; a reporting benunit's holdings come off
  its own reported capital. Both floored at zero.
- Main employment in the company's trade counts as engagement in it for the
  77(3)(a) trade-asset disregard.
- Replace bitwise NOT on a Python bool in the 77(5) exclusion.
- Document dating, trade assets net of secured liabilities, NI references,
  and the dividend double count until dividends leave UC unearned income.
- Strengthen the Hypothesis strategies, add a conservation property, and make
  the Axiom test an explicit golden-case mirror asserting modelled earnings.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Resolve uc_assessable_capital onto main's claimant-based allocation: reg 77
holdings leave the household pool before it is shared among unreported
claimants; company capital and reported-path holdings count only for the
claimant and partner.

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.

Thanks Max. Reviewed at head 19323628.

What I checked:

  • The law. Your reg 77 quote matches legislation.gov.uk word for word, including 77(3)(a) "wholly and exclusively". That wording is stricter than the Sch 10 para 7 business-assets disregard ("wholly or mainly"), so following the regulation over ADM H1880 is right. The dating of 77(5) (Chapters 8/9 until 27.11.2018, then 8/9/10 with the main-employment condition) is right too.
  • Tests at the head. Properties plus Axiom parity: 9 passed. UC YAML directory: 245 passed. CI is green.
  • A probe at the head. A trading-company owner whose main employment is the company, with £6,000 of pay and a £20,000 income share, gets uc_company_self_employed_earnings £20,000, uc_mif_applies true and uc_earned_income £26,000. That is 77(3)(b) and (4) working as intended.
  • Mergeability. It does not merge into current main (b5b09231; the branch is 249 commits behind). There are conflicts in is_benefit_cap_exempt_earnings.py, uc_mif_applies.py and uc_mif_capped_earned_income.py. It merges cleanly with #1969, #1974 and #2131.

Findings:

  1. Blocking. variables/gov/dwp/universal_credit/income/income_floor/uc_mif_capped_earned_income.py:20. Main has deleted this file. #1949 replaced it with uc_individual_earned_income_before_mif and uc_individual_earned_income, which use a net floor, the reg 62(3) couple threshold and a per-person tax/NI slice. If you resolve the conflict by keeping main's side, the company earnings are orphaned: nothing reads them, and reg 77(3)(b) silently does nothing. The body's line that "#1949's uc_individual_earned_income reads this variable" is no longer true. Fix:

    • add uc_company_self_employed_earnings next to self_employed in uc_individual_earned_income_before_mif;
    • check it doesn't pick up personal income tax in uc_income_tax_on_earnings, since reg 57 step 3 deducts only tax the person pays;
    • re-derive invariants 4 and 5 against the net floor and the couple rule.
  2. Blocking. uc_mif_applies.py:25-30 and is_benefit_cap_exempt_earnings.py:32. Main now gates both on is_uc_assessed_claimant (reg 62(1), and reg 82(1)(a)'s "claimant's earned income"). When you rebase, AND uc_company_gainful_self_employment with claimant, and multiply the company term in the benefit-cap sum by claimant. Otherwise a dependant owner-manager gets the floor or lifts the cap.

  3. Blocking (interaction with #1969, which merges cleanly so nothing forces the fix). uc_assessable_capital.py:60-77 and household_uc_unreported_company_holdings.py:22-23. #1969 counts the holding at 90% inside corporate_wealth (or directly_held_shares after #2131), but this PR subtracts it at 100%.

    • On #1969 merged with this branch: savings £5,000, corporate_wealth £10,000, all of it the owner's holding, gives uc_assessable_capital £4,000. It should be £5,000.
    • #1969 will almost certainly land first, so this PR owns the fix, together with finding 4 (one change; see there).
    • Add a YAML case pinning the £5,000.
  4. Should fix. Same lines. A holding that isn't in any capital source eats other capital. At the head: savings £10,000, no corporate_wealth, holding £10,000 gives £0. The body says "a holding cannot reduce other capital", but the only floor is at zero on the total. Fix for 3 and 4 together: in both places, subtract min(holding, share-like capital) × (1 − sale_expenses.rate). Share-like capital is corporate_wealth before #2131 and directly_held_shares + unitemised_corporate_wealth after it. Add the £10,000-savings case as a test.

  5. Should fix (body). Several statements are stale against current main and should be refreshed after the rebase:

    • "Bit-identical to main" was measured at 00fb451d.
    • "Not modelled: … the couple threshold rule (62(3)) and net thresholds (62(4))" no longer holds: main has both. Only 62(1)(b) remains.
    • The impact table needs re-running on the rebased head.
  6. Nit (body, disclosure). There are no record ids or weights in the body, but the "What this means for #1948" section gives dividend totals for a cohort it describes as coming from fewer than ten FRS households. An aggregate that small is close to record-level. I'd keep the conclusion (they aren't owner-managers; it's an imputation artefact) and drop the small-cell totals and row counts.

  7. Nit. uc_company_capital.py:36-38. Treating "main employment is the trade" as "engaged in the trade" for 77(3)(a) is sensible, but it's an inference, not the text. A one-line comment saying so would help the next reader.

MaxGhenis and others added 5 commits October 12, 2026 11:04
Main deleted uc_mif_capped_earned_income (#1949) and now applies the
minimum income floor to net earnings, by the couple rule, only to the all
work-related requirements group (#1973, #2081), with claimant-only earned
income and benefit cap earnings (#1978). The resolution rewires reg 77 onto
that structure instead of orphaning it:

- uc_individual_earned_income_before_mif adds the company's profit or loss
  to the person's own self-employment profit or loss before the nil rule
  (reg 57(2) step 2; reg 77(1) makes the company's trade one more trade).
  uc_company_self_employed_earnings is now that signed step 1 amount.
- The 77(3)(c) route goes into uc_is_in_gainful_self_employment, so main's
  uc_mif_applies (group, start-up) applies to it unchanged.
- is_benefit_cap_exempt_earnings adds company earnings inside main's
  claimant-masked sum, so a dependant owner neither lifts the cap nor
  reduces the award.
- Disregarded holdings of unreported benunits come out of the household
  pool only up to its corporate_wealth, so a holding cannot remove savings.

Tests move to uc_individual_earned_income(_before_mif). New YAML cases:
dependant owner, cap threshold crossing, company loss against own trade,
holding without corporate_wealth. Properties: earnings identity net of own
deductions, exact floor trigger, per-unit allocation in shared households,
income monotonicity only where the cap exemption is unchanged, dependants.

Addresses Vahid's review at 1932362 (findings 1, 2, 4, 7) and the
GPT-6.1 Sol round-2 review (findings 1-3, 6).

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

Addresses the GPT-6.1 Sol round-3 review at e6ebb9c.

- Reg 57(2) step 3 deducts income tax and NI paid in respect of any trade
  from the combined trading result before the nil rule. Earned income took
  all tax and NI on earnings off the total after flooring the trade, so a
  company loss that cancelled a taxed trade left that trade's tax coming
  off pay (12,000 pay, 20,000 own-trade profit, -20,000 company income gave
  7,668.20 instead of 12,000). New uc_income_tax_on_trade (tax on earnings
  less the tax on the other earnings alone, which take the lower slice as
  PAYE codes give the allowance to an employment) and
  uc_national_insurance_on_trade (Class 2 and 4), each capped at the
  earnings figure in use, which can be an input. uc_income_tax_on_earnings
  is unchanged; its computation moved to utils/uc_income_tax.py so both
  take slices of one computation.
- is_benefit_cap_exempt_earnings is main's again. A company term there
  carried signed losses and dividend tax into the test; #1820 rebases the
  test on uc_individual_earned_income_before_mif, which includes company
  earnings, and on the 16-hour National Living Wage threshold. The two
  cap YAML cases (one of which blessed main's out-of-date 10,152) go.
- household_uc_unreported_company_holdings becomes
  household_uc_pool_company_holdings: every holding except a reporting
  unit's claimant's or partner's leaves the household pool, so a
  dependant's holding in a reporting family no longer counts for an
  unrelated unreported claimant.
- Tests: the review's deduction-order case and its control, the
  reporting-family dependant holding case; properties now check the
  reg 57(2) order, an independent no-tax identity at low incomes, LCWRA
  owners get no floor, and disregarded holdings count for no unit.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The derandomised examples had drifted away from three reg 77 branches, so
three reinstated defects passed. Pinned examples now make every run reach
the 77(3)(c) floor, a company loss against the owner's own trade, the tax
on a trade a company loss cancels, an LCWRA owner, and a disregarded
holding in a shared household. All eight mutants in the evidence script
now fail the properties. The module docstring states invariant 4 in reg
57(2) order and lists all nine invariants (round-4 review, non-blocking).

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

Copy link
Copy Markdown
Collaborator Author

Thanks @vahid-ahmadi. Main is merged in (now 93dd669cc, on main e3c27c7ab), and each of your findings is addressed below.

  • Other reviews. Two independent GPT-6.1 Sol rounds, at 19323628 and e6ebb9c8b, overlapped with your findings; their fixes are in the same commits.
  • Review status. The latest Sol round (round 5) approved 93dd669cc.
  1. Orphaned company earnings (blocking).
    • The deleted variable. I took main's deletion of uc_mif_capped_earned_income.
    • Where the earnings go now. uc_individual_earned_income_before_mif follows reg 57(2) for self-employed earnings, in order:
      • Step 2. It adds the company's profit or loss to the person's own trading profit or loss. Reg 77(1) makes the company's trade one more trade the person carries on, so uc_company_self_employed_earnings is now the signed step 1 amount.
      • Step 3. It takes off the income tax and NI paid in respect of any trade (new uc_income_tax_on_trade and uc_national_insurance_on_trade).
      • Nil rule. Only then does a negative result become nil.
    • Why the order matters. Taking all tax and NI off the combined total after flooring the trade let a company loss leave a cancelled trade's tax coming off pay. Without company income the result is arithmetically what main gives.
    • No personal tax on company income. I checked: uc_income_tax_on_earnings slices tax over taxable employment, self-employment and miscellaneous income only. The company income share is not the person's taxable income, so no personal tax or NI is attributed to it.
    • Invariants 4 and 5, re-derived. Earnings are net of the person's own deductions in reg 57(2) order, with an independent check where no tax is due. The floor trigger is an exact identity (all work-related requirements group, outside a start-up period, self-employed or a main-employment trading-company owner), and an LCWRA owner never gets the floor. A single claimant gets max(earned income, floor), and the floor never lowers anyone's earned income, couples included.
  2. Dependants (blocking).
    • The floor. The 77(3)(c) route goes through uc_is_in_gainful_self_employment into main's uc_mif_applies, which needs a work-related group, so claimants only. uc_individual_earned_income applies the floor only to an assessed claimant, and uc_earned_income sums assessed claimants only. There is a dependant-owner YAML case and a property.
    • The benefit cap. I've left is_benefit_cap_exempt_earnings as main has it, because a company term there would carry signed losses and dividend tax into main's approximate sum. Fix benefit cap exemption defects (#1818) #1820 rebases that test on uc_individual_earned_income_before_mif for assessed claimants and on the 16-hour National Living Wage threshold, so company earnings count correctly in either merge order.
  3. Reg 49 interaction with Value means-tested capital less 10% sale expenses and secured debt (UC reg 49 and legacy equivalents) #1969 (blocking once both are in). Value means-tested capital less 10% sale expenses and secured debt (UC reg 49 and legacy equivalents) #1969 hasn't merged, so this PR may land first. Whichever merges second makes the change, as both bodies say: one factor, (1 − sale_expenses.rate), on the holding subtraction in both places. With 4, that factor applies to min(holding, corporate_wealth) in household_uc_pool_company_holdings and to the reported-path subtraction. I'll post the exact lines on Value means-tested capital less 10% sale expenses and secured debt (UC reg 49 and legacy equivalents) #1969 when this merges. If Value means-tested capital less 10% sale expenses and secured debt (UC reg 49 and legacy equivalents) #1969 lands first, I'll make the change here with your £5,000 case.
  4. A holding outside any capital source (should fix). household_uc_pool_company_holdings (renamed) caps the holdings it takes out of the pool at the household's corporate_wealth, where the inputs' documentation says the holding is held.
    • Your case. Savings £10,000, no corporate_wealth, holding £10,000 now gives £10,000; there is a YAML case for it.
    • Dependants. It now also takes out a dependant's holding in a family that reports its capital, so that holding counts for no one. A new property checks that disregarded holdings count for no unit.
    • Reported capital. A reporting unit's claimant or partner still has their holding taken off the reported total, floored at zero, because the reported figure has no share breakdown.
  5. Stale body (should fix). I re-ran the Enhanced FRS comparison and the preview on the new head and current main. The branch now equals main to within float32 rounding (at most £0.06 of earned income per benefit unit), not bit for bit, because the reordered reg 57(2) arithmetic sums in a different order. Reg 62's couple rule, net thresholds and 62(1)(b) are all on main now (Deduct only each person's own tax and NI on earnings from UC earned income #1949, Apply the UC minimum income floor to net earned income against a net threshold #1973, Apply the UC minimum income floor only to claimants subject to all work-related requirements #2081), so the "not modelled" line is gone.
  6. Small cells (nit). The UC-eligible units with six-figure dividends: dividends treated as yield of a few thousand pounds of imputed capital #1948 section of the body gives conclusions only, with no cohort totals or row counts. The UC-eligible units with six-figure dividends: dividends treated as yield of a few thousand pounds of imputed capital #1948 issue comment is edited the same way.
  7. Main employment as engagement (nit). uc_company_capital now says it is an inference from "engaged in activities in the course of that trade", not the text.

🤖 Generated with Claude Code

@MaxGhenis

Copy link
Copy Markdown
Collaborator Author

Hand-off to the UK hub (owner session 251896c0, 2026-10-13).

🤖 Generated with Claude Code

@MaxGhenis
MaxGhenis added this pull request to the merge queue Oct 13, 2026
Merged via the queue into main with commit de51192 Oct 13, 2026
14 of 16 checks passed
@MaxGhenis
MaxGhenis deleted the uc-dividends-owner-managers-1948 branch October 13, 2026 16:16
@MaxGhenis

Copy link
Copy Markdown
Collaborator Author

Merged by the UK hub (audit). Merged with a merge commit at the tested head 93dd669cc (expectedHeadOid, through the main merge queue). This carries out d1478, whose default was "hub merges on gates when green". Gates:

  • CI: gh pr checks passed at the head.
  • MERGEABLE, not a draft, and no CHANGES_REQUESTED review. Vahid's review at 19323628 was a COMMENT and is answered in the thread.
  • Independent review: GPT-6.1 Sol round 5 APPROVE at exact head 93dd669cc9de5a4b255ab746f1b81752c170a633 (~/reviews/uc-dividends-1948-2026-09-30/review/review-r5-hard-1965.md). Rounds 2–4 requested changes, and all were addressed, including round 3's reg 57(2) step 3 ordering and the dependants' holdings disregard. Round 5's non-blocking points are fixed in the description, which now cites impact/branch_v5_vs_main_v5_magnitudes.json and diag/earnings_order_diff_2026.txt.
  • Real-run impact: Enhanced FRS 2025–2030, main e3c27c7 against the branch at 2a52fa0 (the head changes only property tests).
    • The two runs are equal within float32 rounding: total UC differs by £3–£65 a year against £83.3bn.
    • The dataset has no owner-manager inputs yet, so reg 77 is inert on current data.
    • The director-field preview is indicative only.
  • Invariants: stated in the description and tested with property tests, with pins that each kill a reinstated defect (eight mutants killed).
  • Methodology note (d1478): a person's income tax is split between employment and trade with the trade on top (the PAYE convention). The regulations don't specify this. It matters only where a company loss cancels the owner's own taxed trade, and no current data has that case.
  • Merge order:
  • Follow-up owed: fill the owned_company_* inputs from the FRS director fields (DIRPERC, DIVIDEND) in uk-data after this is released.

vahid-ahmadi added a commit that referenced this pull request Oct 14, 2026
Resolve conflicts with #2399, #2076 and #1965:

- is_benefit_cap_exempt_earnings: keep main's per-claimant
  uc_individual_earned_income_before_mif test and documentation; keep this
  PR's dated threshold parameter in place of 10_152 and its reg 57 and
  FA 2004 s.188 references.
- is_benefit_cap_exempt_health_disability: take main's version (#2076) and
  add the UC route for AFIP: on a Universal Credit award only a claimant's
  counts; otherwise Housing Benefit's young person counts too.
- is_benefit_cap_exempt: take main's label.
- test_uc_single_claim_properties: keep main's AFCS assertions and this
  PR's partner-only AFIP example.

Pin main's young-person AFIP YAML case to the Housing Benefit route, and
give the specified-benefits property oracle the family's scheme. Rewrite
the changelog fragment to what the PR still changes relative to main.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ci-recheck Re-triggers Fix evidence without changing the PR (UK hub, 2026-10-12)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Universal Credit: model reg 77 (company analogous to a partnership or one person business)

2 participants