From 14e98583ef203dfc070aca512f0a163939b6df64 Mon Sep 17 00:00:00 2001 From: Anthony Volk <14987227+anth-volk@users.noreply.github.com> Date: Tue, 20 Oct 2026 01:34:37 +0400 Subject: [PATCH 1/7] v3 household results: the country is required, never read as the US The household section already runs each household in the report's country, but the result code still fell back to the US: - compareHouseholds took the US result rows (its taxes and benefits) for any country without its own, and defaulted its country to "us". The country is now required, and a country without its own result rows is an error instead of a US reading. - HouseholdImpactResult defaulted its currency country to "us"; the section always passes it, and it is now required. - The unused simple-input run (FlagshipHouseholdInput, buildHouseholdPayload, runFlagshipHousehold, describeHouseholdInput and their helpers) built a US household with a US state whatever the report's country. Nothing called it since the section moved to the household builder, so it is removed, and its run tests now cover runFlagshipHouseholdPayload. Co-Authored-By: Claude Opus 5.5 --- .../household/HouseholdImpactResult.tsx | 6 +- app/src/libs/flagship/householdRun.ts | 177 ++-------------- .../libs/flagship/householdRunMocks.ts | 17 +- .../unit/libs/flagship/householdRun.test.ts | 190 +++++------------- 4 files changed, 77 insertions(+), 313 deletions(-) diff --git a/app/src/components/flagship/report/household/HouseholdImpactResult.tsx b/app/src/components/flagship/report/household/HouseholdImpactResult.tsx index 5fd648b0f..b506b02e1 100644 --- a/app/src/components/flagship/report/household/HouseholdImpactResult.tsx +++ b/app/src/components/flagship/report/household/HouseholdImpactResult.tsx @@ -192,15 +192,15 @@ export default function HouseholdImpactResult({ impact, summary, breakdowns, - countryId = 'us', + countryId, }: { impact: FlagshipHouseholdImpact; /** The household the result is for, e.g. "Single · no children · $50,000 earnings · Ohio · 2026". */ summary: string; /** The household run the v2 breakdowns read; without it, only the summary shows. */ breakdowns?: HouseholdBreakdownSource; - /** The report's country: its currency. */ - countryId?: CountryId; + /** The household's country: its currency. */ + countryId: CountryId; }) { const [view, setView] = useState<'summary' | HouseholdBreakdownView>('summary'); const { netIncome, components, programs } = impact; diff --git a/app/src/libs/flagship/householdRun.ts b/app/src/libs/flagship/householdRun.ts index c71eaad5f..1c695b542 100644 --- a/app/src/libs/flagship/householdRun.ts +++ b/app/src/libs/flagship/householdRun.ts @@ -1,127 +1,20 @@ -import { STATE_NAMES } from '@/api/billFeed'; import { createHousehold } from '@/api/household'; import { fetchHouseholdCalculation } from '@/api/householdCalculation'; import type { CountryId } from '@/libs/countries'; -import { Household } from '@/models/Household'; import type { V1HouseholdCreateEnvelope } from '@/models/household/v1Types'; import type { HouseholdCalculationData } from '@/types/calculation/household'; -import { formatCurrency } from '@/utils/formatters'; /** - * A household run for the flagship report: one family, described in a - * few fields, run under the report's baseline and reform policies for - * the report's year through the same v1 household endpoints the v2 - * household flow uses — create the household, then calculate it under - * each policy. + * A household run for the flagship report: a household built in the + * household builder, run under the report's baseline and reform policies + * for the report's year, in the household's own country, through the + * same v1 household endpoints the v2 household flow uses: create the + * household, then calculate it under each policy. */ -/** The household as the report's form describes it. US only for now. */ -export interface FlagshipHouseholdInput { - /** Two-letter state code, e.g. "CA". */ - state: string; - married: boolean; - /** One age per child, each 0–17. */ - childAges: number[]; - /** The head's annual employment income. */ - earnings: number; - /** The partner's annual employment income; read only when married. */ - partnerEarnings: number; -} - -export const MAX_CHILDREN = 6; -export const MAX_CHILD_AGE = 17; -export const DEFAULT_CHILD_AGE = 10; -const DEFAULT_STATE = 'CA'; -const DEFAULT_EARNINGS = 50000; -/** A change smaller than a dollar reads as no change. */ +/** A change smaller than a dollar (or a pound) reads as no change. */ const NEGLIGIBLE = 1; -/** - * The form's starting household: single, no children, $50,000 a year, in - * the report's state — a state or district report's own state, else - * California, the model's default. - */ -export function defaultHouseholdInput(region?: string): FlagshipHouseholdInput { - return { - state: stateFromRegion(region) ?? DEFAULT_STATE, - married: false, - childAges: [], - earnings: DEFAULT_EARNINGS, - partnerEarnings: 0, - }; -} - -/** "state/ny" → "NY", "congressional_district/TX-07" → "TX"; nothing for the country. */ -export function stateFromRegion(region?: string): string | undefined { - const match = region?.match(/^(?:state\/([a-z]{2})|congressional_district\/([a-z]{2})-)/i); - const code = (match?.[1] ?? match?.[2])?.toUpperCase(); - return code && STATE_NAMES[code] ? code : undefined; -} - -const isAmount = (value: number) => Number.isFinite(value) && value >= 0; -const isChildAge = (age: number) => Number.isInteger(age) && age >= 0 && age <= MAX_CHILD_AGE; - -/** Whether the household can run: a known state, amounts of zero or more, children's ages. */ -export function isValidHouseholdInput(input: FlagshipHouseholdInput): boolean { - return ( - !!STATE_NAMES[input.state] && - isAmount(input.earnings) && - (!input.married || isAmount(input.partnerEarnings)) && - input.childAges.length <= MAX_CHILDREN && - input.childAges.every(isChildAge) - ); -} - -/** - * The v1 household for the input, built with the v2 builder's own model - * so the API reads it as it reads a v2 household: the head is "you", and - * the API takes the year to calculate from "you"'s age. - */ -export function buildHouseholdPayload( - input: FlagshipHouseholdInput, - year: string -): V1HouseholdCreateEnvelope { - let household = Household.starter('us', year) - .withBuilderMaritalStatus(year, input.married ? 'married' : 'single') - .withBuilderChildCount(year, input.childAges.length); - const { primaryPersonKey, partnerKey, childKeys } = household.deriveBuilderComposition(year); - if (primaryPersonKey) { - household = household.setPersonVariableAtYear( - primaryPersonKey, - 'employment_income', - year, - input.earnings - ); - } - if (partnerKey) { - household = household.setPersonVariableAtYear( - partnerKey, - 'employment_income', - year, - input.partnerEarnings - ); - } - childKeys.forEach((childKey, index) => { - household = household.setPersonVariableAtYear( - childKey, - 'age', - year, - input.childAges[index] ?? DEFAULT_CHILD_AGE - ); - }); - const householdKey = Object.keys(household.householdData.households ?? {})[0]; - if (householdKey) { - household = household.setGroupVariableAtYear( - 'households', - householdKey, - 'state_name', - year, - input.state - ); - } - return household.toV1CreationPayload(); -} - type EntityPlural = 'people' | 'households' | 'tax_units' | 'spm_units' | 'benunits'; /** The app's camel-case keys, for results already in the app's shape. */ @@ -306,7 +199,7 @@ function benefitLine(variable: string, label: string, entity: EntityPlural): Lin return { id: variable, label, sign: 1, sources: [{ entity, variable }] }; } -/** Each country's parts of net income and programs; a country without its own reads the US's. */ +/** Each country's parts of net income and programs: the countries v3 runs households for. */ const LINES: Partial< Record > = { @@ -314,8 +207,13 @@ const LINES: Partial< uk: { components: UK_COMPONENTS, programs: UK_PROGRAMS }, }; +/** A country's lines; another country has none, and is never read as the US. */ function linesFor(countryId: string) { - return LINES[countryId as CountryId] ?? LINES.us!; + const lines = LINES[countryId as CountryId]; + if (!lines) { + throw new Error(`Household results are not available for ${countryId}.`); + } + return lines; } export interface HouseholdLineChange { @@ -382,7 +280,7 @@ export function compareHouseholds( baseline: HouseholdCalculationData, reform: HouseholdCalculationData, year: string, - countryId: string = 'us' + countryId: string ): FlagshipHouseholdImpact { const lines = linesFor(countryId); const before = readHouseholdTotal(baseline, 'households', 'household_net_income', year); @@ -414,13 +312,6 @@ export function compareHouseholds( }; } -export interface RunFlagshipHouseholdArgs { - year: string; - input: FlagshipHouseholdInput; - baselinePolicyId: string; - reformPolicyId: string; -} - export interface FlagshipHouseholdRun extends FlagshipHouseholdImpact { householdId: string; /** @@ -486,26 +377,9 @@ async function calculateHousehold( } /** - * Creates the household (the API dedupes identical ones) and calculates - * it under the baseline and the reform at once. - */ -export async function runFlagshipHousehold({ - year, - input, - baselinePolicyId, - reformPolicyId, -}: RunFlagshipHouseholdArgs): Promise { - return runFlagshipHouseholdPayload({ - year, - payload: buildHouseholdPayload(input, year), - baselinePolicyId, - reformPolicyId, - }); -} - -/** - * The same run for a household built in full (the household builder's - * own model, any of its inputs), sent as the builder sends it. + * Creates the household (the API dedupes identical ones), as the + * household builder sends it, and calculates it under the baseline and + * the reform at once, in the payload's own country. */ export async function runFlagshipHouseholdPayload({ year, @@ -530,20 +404,3 @@ export async function runFlagshipHouseholdPayload({ ...compareHouseholds(baseline, reform, year, payload.country_id), }; } - -/** "Single · 2 children · $50,000 · California": the household a result is for. */ -export function describeHouseholdInput( - input: FlagshipHouseholdInput, - countryId: CountryId = 'us' -): string { - const money = (value: number) => formatCurrency(value, countryId, { maximumFractionDigits: 0 }); - const children = input.childAges.length; - return [ - input.married ? 'Married' : 'Single', - children === 0 ? 'no children' : children === 1 ? '1 child' : `${children} children`, - input.married - ? `${money(input.earnings)} and ${money(input.partnerEarnings)} earnings` - : `${money(input.earnings)} earnings`, - STATE_NAMES[input.state] ?? input.state, - ].join(' · '); -} diff --git a/app/src/tests/fixtures/libs/flagship/householdRunMocks.ts b/app/src/tests/fixtures/libs/flagship/householdRunMocks.ts index 8be39f781..d6cf2a31c 100644 --- a/app/src/tests/fixtures/libs/flagship/householdRunMocks.ts +++ b/app/src/tests/fixtures/libs/flagship/householdRunMocks.ts @@ -1,4 +1,4 @@ -import type { FlagshipHouseholdInput } from '@/libs/flagship/householdRun'; +import { Household } from '@/models/Household'; import type { HouseholdCalculationData } from '@/types/calculation/household'; export const HOUSEHOLD_YEAR = '2026'; @@ -8,13 +8,14 @@ export const CUSTOM_BASELINE_POLICY_ID = '45678'; export const REFORM_POLICY_ID = '98765'; export const CREATED_HOUSEHOLD_ID = 54321; -export const MARRIED_TWO_CHILDREN: FlagshipHouseholdInput = { - state: 'NY', - married: true, - childAges: [4, 12], - earnings: 60000, - partnerEarnings: 25000, -}; +/** A country without household result lines in v3. */ +export const COUNTRY_WITHOUT_HOUSEHOLD_LINES = 'ca'; + +/** A married couple with two children, as the household builder sends it to the v1 API. */ +export const US_COUPLE_WITH_CHILDREN_PAYLOAD = Household.starter('us', HOUSEHOLD_YEAR) + .withBuilderMaritalStatus(HOUSEHOLD_YEAR, 'married') + .withBuilderChildCount(HOUSEHOLD_YEAR, 2) + .toV1CreationPayload(); interface ResultValues { netIncome: number; diff --git a/app/src/tests/unit/libs/flagship/householdRun.test.ts b/app/src/tests/unit/libs/flagship/householdRun.test.ts index 95898cdaf..3ccace314 100644 --- a/app/src/tests/unit/libs/flagship/householdRun.test.ts +++ b/app/src/tests/unit/libs/flagship/householdRun.test.ts @@ -1,26 +1,20 @@ import { beforeEach, describe, expect, test, vi } from 'vitest'; import { - buildHouseholdPayload, compareHouseholds, - defaultHouseholdInput, - describeHouseholdInput, - isValidHouseholdInput, plainHouseholdError, readHouseholdTotal, - runFlagshipHousehold, runFlagshipHouseholdPayload, - stateFromRegion, } from '@/libs/flagship/householdRun'; import { Household } from '@/models/Household'; import { BASELINE_POLICY_ID, BASELINE_RESULT, + COUNTRY_WITHOUT_HOUSEHOLD_LINES, CREATED_HOUSEHOLD_ID, HOUSEHOLD_YEAR, householdResult, LOW_EARNER_BASELINE_RESULT, LOW_EARNER_REFORM_RESULT, - MARRIED_TWO_CHILDREN, REFORM_POLICY_ID, REFORM_RESULT, REFORM_RESULT_LOSS, @@ -29,6 +23,7 @@ import { UK_FAMILY_BASELINE_RESULT, UK_FAMILY_REFORM_RESULT, UK_REFORM_RESULT, + US_COUPLE_WITH_CHILDREN_PAYLOAD, } from '@/tests/fixtures/libs/flagship/householdRunMocks'; const mockCreateHousehold = vi.fn(); @@ -41,85 +36,6 @@ vi.mock('@/api/householdCalculation', () => ({ fetchHouseholdCalculation: (...args: unknown[]) => mockFetchHouseholdCalculation(...args), })); -describe('defaultHouseholdInput', () => { - test('given a nationwide report then the household is single, childless, in California', () => { - expect(defaultHouseholdInput()).toEqual({ - state: 'CA', - married: false, - childAges: [], - earnings: 50000, - partnerEarnings: 0, - }); - }); - - test("given a state or district report then the household starts in that report's state", () => { - expect(defaultHouseholdInput('state/ny').state).toBe('NY'); - expect(defaultHouseholdInput('congressional_district/TX-07').state).toBe('TX'); - }); - - test('given a region that is not a state then no state is read from it', () => { - expect(stateFromRegion('us')).toBeUndefined(); - expect(stateFromRegion('state/zz')).toBeUndefined(); - }); -}); - -describe('isValidHouseholdInput', () => { - test('given the default household then it can run', () => { - expect(isValidHouseholdInput(defaultHouseholdInput())).toBe(true); - }); - - test('given negative or missing earnings or an adult child then it cannot run', () => { - const base = defaultHouseholdInput(); - expect(isValidHouseholdInput({ ...base, earnings: -1 })).toBe(false); - expect(isValidHouseholdInput({ ...base, earnings: Number.NaN })).toBe(false); - expect(isValidHouseholdInput({ ...base, childAges: [18] })).toBe(false); - expect(isValidHouseholdInput({ ...base, childAges: [2.5] })).toBe(false); - }); - - test("given a single household then the partner's earnings are not read", () => { - expect(isValidHouseholdInput({ ...defaultHouseholdInput(), partnerEarnings: Number.NaN })).toBe( - true - ); - }); -}); - -describe('buildHouseholdPayload', () => { - test('given a married couple with two children then every person carries the year', () => { - const payload = buildHouseholdPayload(MARRIED_TWO_CHILDREN, HOUSEHOLD_YEAR); - const people = payload.data.people; - - expect(payload.country_id).toBe('us'); - // The API reads the year to calculate from "you"'s age. - expect(people.you.age).toEqual({ [HOUSEHOLD_YEAR]: 30 }); - expect(people.you.employment_income).toEqual({ [HOUSEHOLD_YEAR]: 60000 }); - expect(people['your partner'].employment_income).toEqual({ [HOUSEHOLD_YEAR]: 25000 }); - expect(people['your first dependent'].age).toEqual({ [HOUSEHOLD_YEAR]: 4 }); - expect(people['your second dependent'].age).toEqual({ [HOUSEHOLD_YEAR]: 12 }); - expect(people['your second dependent'].is_tax_unit_dependent).toEqual({ - [HOUSEHOLD_YEAR]: true, - }); - }); - - test('given a state then the household lives there', () => { - const payload = buildHouseholdPayload(MARRIED_TWO_CHILDREN, HOUSEHOLD_YEAR); - - expect(payload.data.households?.['your household'].state_name).toEqual({ - [HOUSEHOLD_YEAR]: 'NY', - }); - expect(payload.data.marital_units?.['your marital unit'].members).toEqual([ - 'you', - 'your partner', - ]); - }); - - test('given a single adult then the household has one person', () => { - const payload = buildHouseholdPayload(defaultHouseholdInput(), HOUSEHOLD_YEAR); - - expect(Object.keys(payload.data.people)).toEqual(['you']); - expect(payload.data.tax_units?.['your tax unit'].members).toEqual(['you']); - }); -}); - describe('readHouseholdTotal', () => { test('given a variable in the API result then its year value is read', () => { expect(readHouseholdTotal(BASELINE_RESULT, 'tax_units', 'income_tax', HOUSEHOLD_YEAR)).toBe( @@ -138,7 +54,7 @@ describe('readHouseholdTotal', () => { describe('compareHouseholds', () => { test('given a federal tax cut then net income and the tax line both show it', () => { - const impact = compareHouseholds(BASELINE_RESULT, REFORM_RESULT, HOUSEHOLD_YEAR); + const impact = compareHouseholds(BASELINE_RESULT, REFORM_RESULT, HOUSEHOLD_YEAR, 'us'); expect(impact.netIncome).toEqual({ baseline: 72000, reform: 73000, change: 1000 }); expect(impact.components).toEqual([ @@ -154,7 +70,7 @@ describe('compareHouseholds', () => { }); test('given a bigger Child Tax Credit then the credit is listed and unchanged ones are not', () => { - const impact = compareHouseholds(BASELINE_RESULT, REFORM_RESULT, HOUSEHOLD_YEAR); + const impact = compareHouseholds(BASELINE_RESULT, REFORM_RESULT, HOUSEHOLD_YEAR, 'us'); expect(impact.programs.map((line) => [line.label, line.change])).toEqual([ ['Child Tax Credit', 1000], @@ -165,7 +81,8 @@ describe('compareHouseholds', () => { const impact = compareHouseholds( LOW_EARNER_BASELINE_RESULT, LOW_EARNER_REFORM_RESULT, - HOUSEHOLD_YEAR + HOUSEHOLD_YEAR, + 'us' ); expect(impact.netIncome.change).toBe(0); @@ -182,7 +99,8 @@ describe('compareHouseholds', () => { ctcValue: 1500, grossCtc: 6000, }), - HOUSEHOLD_YEAR + HOUSEHOLD_YEAR, + 'us' ); expect(impact.programs).toEqual([ @@ -198,7 +116,12 @@ describe('compareHouseholds', () => { }); test('given net income moving beyond the listed parts then the rest is "Other"', () => { - const impact = compareHouseholds(BASELINE_RESULT, REFORM_RESULT_WITH_REMAINDER, HOUSEHOLD_YEAR); + const impact = compareHouseholds( + BASELINE_RESULT, + REFORM_RESULT_WITH_REMAINDER, + HOUSEHOLD_YEAR, + 'us' + ); expect(impact.components.at(-1)).toEqual({ id: 'other', @@ -211,7 +134,7 @@ describe('compareHouseholds', () => { }); test('given a tax rise and a benefit cut then both read as losses', () => { - const impact = compareHouseholds(BASELINE_RESULT, REFORM_RESULT_LOSS, HOUSEHOLD_YEAR); + const impact = compareHouseholds(BASELINE_RESULT, REFORM_RESULT_LOSS, HOUSEHOLD_YEAR, 'us'); expect(impact.netIncome.change).toBe(-900); expect(impact.components.map((line) => [line.id, line.effect])).toEqual([ @@ -222,7 +145,7 @@ describe('compareHouseholds', () => { }); test('given the same result twice then nothing changes', () => { - const impact = compareHouseholds(BASELINE_RESULT, BASELINE_RESULT, HOUSEHOLD_YEAR); + const impact = compareHouseholds(BASELINE_RESULT, BASELINE_RESULT, HOUSEHOLD_YEAR, 'us'); expect(impact.netIncome.change).toBe(0); expect(impact.components).toEqual([]); @@ -234,10 +157,21 @@ describe('compareHouseholds', () => { delete (missing.households as Record>)['your household'] .household_net_income; - expect(() => compareHouseholds(BASELINE_RESULT, missing, HOUSEHOLD_YEAR)).toThrow( + expect(() => compareHouseholds(BASELINE_RESULT, missing, HOUSEHOLD_YEAR, 'us')).toThrow( `The result has no net income for ${HOUSEHOLD_YEAR}.` ); - expect(() => compareHouseholds(missing, BASELINE_RESULT, HOUSEHOLD_YEAR)).toThrow(); + expect(() => compareHouseholds(missing, BASELINE_RESULT, HOUSEHOLD_YEAR, 'us')).toThrow(); + }); + + test('given a country without household result lines then the comparison fails, not reads as the US', () => { + expect(() => + compareHouseholds( + BASELINE_RESULT, + REFORM_RESULT, + HOUSEHOLD_YEAR, + COUNTRY_WITHOUT_HOUSEHOLD_LINES + ) + ).toThrow(`Household results are not available for ${COUNTRY_WITHOUT_HOUSEHOLD_LINES}.`); }); }); @@ -321,7 +255,14 @@ describe('runFlagshipHouseholdPayload for the UK', () => { }); }); -describe('runFlagshipHousehold', () => { +describe('runFlagshipHouseholdPayload', () => { + const runArgs = { + year: HOUSEHOLD_YEAR, + payload: US_COUPLE_WITH_CHILDREN_PAYLOAD, + baselinePolicyId: BASELINE_POLICY_ID, + reformPolicyId: REFORM_POLICY_ID, + }; + beforeEach(() => { vi.clearAllMocks(); mockCreateHousehold.mockResolvedValue({ result: { household_id: CREATED_HOUSEHOLD_ID } }); @@ -332,16 +273,9 @@ describe('runFlagshipHousehold', () => { }); test('given a household then it is created once and calculated under both policies', async () => { - const run = await runFlagshipHousehold({ - year: HOUSEHOLD_YEAR, - input: MARRIED_TWO_CHILDREN, - baselinePolicyId: BASELINE_POLICY_ID, - reformPolicyId: REFORM_POLICY_ID, - }); + const run = await runFlagshipHouseholdPayload(runArgs); - expect(mockCreateHousehold).toHaveBeenCalledWith( - buildHouseholdPayload(MARRIED_TWO_CHILDREN, HOUSEHOLD_YEAR) - ); + expect(mockCreateHousehold).toHaveBeenCalledWith(US_COUPLE_WITH_CHILDREN_PAYLOAD); expect(mockFetchHouseholdCalculation.mock.calls).toEqual([ ['us', String(CREATED_HOUSEHOLD_ID), BASELINE_POLICY_ID], ['us', String(CREATED_HOUSEHOLD_ID), REFORM_POLICY_ID], @@ -354,10 +288,8 @@ describe('runFlagshipHousehold', () => { }); test('given the same policy as baseline and reform then it is calculated once', async () => { - const run = await runFlagshipHousehold({ - year: HOUSEHOLD_YEAR, - input: MARRIED_TWO_CHILDREN, - baselinePolicyId: BASELINE_POLICY_ID, + const run = await runFlagshipHouseholdPayload({ + ...runArgs, reformPolicyId: BASELINE_POLICY_ID, }); @@ -368,30 +300,21 @@ describe('runFlagshipHousehold', () => { test('given a calculation failure then the run fails with it', async () => { mockFetchHouseholdCalculation.mockRejectedValue(new Error('Household calculation failed')); - await expect( - runFlagshipHousehold({ - year: HOUSEHOLD_YEAR, - input: MARRIED_TWO_CHILDREN, - baselinePolicyId: BASELINE_POLICY_ID, - reformPolicyId: REFORM_POLICY_ID, - }) - ).rejects.toThrow('Household calculation failed'); + await expect(runFlagshipHouseholdPayload(runArgs)).rejects.toThrow( + 'Household calculation failed' + ); }); test('given a timeout or a network failure then the run fails in plain words', async () => { - const args = { - year: HOUSEHOLD_YEAR, - input: MARRIED_TWO_CHILDREN, - baselinePolicyId: BASELINE_POLICY_ID, - reformPolicyId: REFORM_POLICY_ID, - }; mockFetchHouseholdCalculation.mockRejectedValue( new Error('Household calculation timed out after 50 seconds (client-side timeout)') ); - await expect(runFlagshipHousehold(args)).rejects.toThrow('The calculation took too long.'); + await expect(runFlagshipHouseholdPayload(runArgs)).rejects.toThrow( + 'The calculation took too long.' + ); mockCreateHousehold.mockRejectedValue(new TypeError('Failed to fetch')); - await expect(runFlagshipHousehold(args)).rejects.toThrow( + await expect(runFlagshipHouseholdPayload(runArgs)).rejects.toThrow( 'Could not reach PolicyEngine. Check your connection.' ); }); @@ -410,20 +333,3 @@ describe('plainHouseholdError', () => { expect(plainHouseholdError(error).cause).toBe(error); }); }); - -describe('describeHouseholdInput', () => { - test('given a household then it reads as one short line', () => { - expect(describeHouseholdInput(MARRIED_TWO_CHILDREN)).toBe( - 'Married · 2 children · $60,000 and $25,000 earnings · New York' - ); - expect(describeHouseholdInput(defaultHouseholdInput())).toBe( - 'Single · no children · $50,000 earnings · California' - ); - }); - - test('given the UK then amounts read in pounds', () => { - expect(describeHouseholdInput(MARRIED_TWO_CHILDREN, 'uk')).toContain( - '£60,000 and £25,000 earnings' - ); - }); -}); From ddad7d4ee57bfc50254dbefb19e432239bdd0268 Mon Sep 17 00:00:00 2001 From: Anthony Volk <14987227+anth-volk@users.noreply.github.com> Date: Tue, 20 Oct 2026 01:37:26 +0400 Subject: [PATCH 2/7] v3 household runs keep each calculation's .py bundle and SPM provenance The section's run read only the result of each v1 household calculation (fetchHouseholdCalculation), so the response's policyengine_bundle, spm_config and spm_provenance were dropped. It now calls fetchHouseholdCalculationWithBundle and keeps them per policy on the run (FlagshipHouseholdRun.provenance), for the SPM methodology footnote and for Reproduce in Python. A run that calculates once for both policies gives the reform the baseline's provenance; a response without a bundle records null rather than a guessed version. The section's tests, including the analytics tests from #1334, mock the new call. Co-Authored-By: Claude Opus 5.5 --- app/src/libs/flagship/householdRun.ts | 47 ++++++++++++--- .../libs/flagship/householdRunMocks.ts | 25 ++++++++ .../report/HouseholdImpactAnalytics.test.tsx | 4 +- .../report/HouseholdImpactSection.test.tsx | 4 +- .../report/ReportViewHousehold.test.tsx | 4 +- .../unit/libs/flagship/householdRun.test.ts | 59 ++++++++++++++++++- 6 files changed, 132 insertions(+), 11 deletions(-) diff --git a/app/src/libs/flagship/householdRun.ts b/app/src/libs/flagship/householdRun.ts index 1c695b542..2df3f3bb0 100644 --- a/app/src/libs/flagship/householdRun.ts +++ b/app/src/libs/flagship/householdRun.ts @@ -1,8 +1,13 @@ import { createHousehold } from '@/api/household'; -import { fetchHouseholdCalculation } from '@/api/householdCalculation'; +import { + fetchHouseholdCalculationWithBundle, + type HouseholdCalculationResult, +} from '@/api/householdCalculation'; +import type { PolicyEngineBundle } from '@/api/societyWideCalculation'; import type { CountryId } from '@/libs/countries'; import type { V1HouseholdCreateEnvelope } from '@/models/household/v1Types'; import type { HouseholdCalculationData } from '@/types/calculation/household'; +import type { SPMProvenance, SPMSelection } from '@/types/spm'; /** * A household run for the flagship report: a household built in the @@ -320,6 +325,29 @@ export interface FlagshipHouseholdRun extends FlagshipHouseholdImpact { */ baseline: HouseholdCalculationData; reform: HouseholdCalculationData; + /** + * How each policy's calculation was made, as its response says: the + * methodology footnote and Reproduce in Python read it. + */ + provenance: { baseline: HouseholdCalculationProvenance; reform: HouseholdCalculationProvenance }; +} + +/** What one calculation response says about how it was made. */ +export interface HouseholdCalculationProvenance { + /** The .py bundle that calculated it; null when the response names none. */ + policyengineBundle: PolicyEngineBundle | null; + /** The SPM settings the calculation used (US households only). */ + spmConfig?: SPMSelection; + /** The SPM forecast and thresholds the calculation read (US households only). */ + spmProvenance?: SPMProvenance; +} + +function provenanceOf(response: HouseholdCalculationResult): HouseholdCalculationProvenance { + return { + policyengineBundle: response.policyengine_bundle ?? null, + ...(response.spm_config ? { spmConfig: response.spm_config } : {}), + ...(response.spm_provenance ? { spmProvenance: response.spm_provenance } : {}), + }; } /** @@ -343,12 +371,16 @@ export function plainHouseholdError(error: unknown): Error { * the API keeps calculating and caches the result, so the second ask * usually returns it at once. */ -async function calculateOnce(countryId: string, householdId: string, policyId: string) { +async function calculateOnce( + countryId: string, + householdId: string, + policyId: string +): Promise { try { - return await fetchHouseholdCalculation(countryId, householdId, policyId); + return await fetchHouseholdCalculationWithBundle(countryId, householdId, policyId); } catch (error) { if (error instanceof Error && /timed out/i.test(error.message)) { - return fetchHouseholdCalculation(countryId, householdId, policyId); + return fetchHouseholdCalculationWithBundle(countryId, householdId, policyId); } throw error; } @@ -399,8 +431,9 @@ export async function runFlagshipHouseholdPayload({ ); return { householdId, - baseline, - reform, - ...compareHouseholds(baseline, reform, year, payload.country_id), + baseline: baseline.result, + reform: reform.result, + provenance: { baseline: provenanceOf(baseline), reform: provenanceOf(reform) }, + ...compareHouseholds(baseline.result, reform.result, year, payload.country_id), }; } diff --git a/app/src/tests/fixtures/libs/flagship/householdRunMocks.ts b/app/src/tests/fixtures/libs/flagship/householdRunMocks.ts index d6cf2a31c..81ddddea7 100644 --- a/app/src/tests/fixtures/libs/flagship/householdRunMocks.ts +++ b/app/src/tests/fixtures/libs/flagship/householdRunMocks.ts @@ -1,5 +1,8 @@ +import type { HouseholdCalculationResult } from '@/api/householdCalculation'; +import type { PolicyEngineBundle } from '@/api/societyWideCalculation'; import { Household } from '@/models/Household'; import type { HouseholdCalculationData } from '@/types/calculation/household'; +import type { SPMSelection } from '@/types/spm'; export const HOUSEHOLD_YEAR = '2026'; export const BASELINE_POLICY_ID = '2'; @@ -8,6 +11,28 @@ export const CUSTOM_BASELINE_POLICY_ID = '45678'; export const REFORM_POLICY_ID = '98765'; export const CREATED_HOUSEHOLD_ID = 54321; +/** The .py bundle a calculation response names (synthetic versions, never published pins). */ +export const BASELINE_RUN_BUNDLE: PolicyEngineBundle = { + policyengine_version: '9.1.0', + model_version: '8.1.0', + data_version: null, + dataset: null, +}; +export const REFORM_RUN_BUNDLE: PolicyEngineBundle = { + ...BASELINE_RUN_BUNDLE, + model_version: '8.2.0', +}; +/** The SPM settings a US calculation response echoes. */ +export const NATIONAL_SPM_CONFIG: SPMSelection = { geography_kind: 'national' }; + +/** One policy's calculation as the v1 API answers it: the result and how it was made. */ +export function calculationResponse( + result: HouseholdCalculationData, + provenance: Omit = {} +): HouseholdCalculationResult { + return { result, policyengine_bundle: null, ...provenance }; +} + /** A country without household result lines in v3. */ export const COUNTRY_WITHOUT_HOUSEHOLD_LINES = 'ca'; diff --git a/app/src/tests/unit/components/flagship/report/HouseholdImpactAnalytics.test.tsx b/app/src/tests/unit/components/flagship/report/HouseholdImpactAnalytics.test.tsx index ff313b57c..16799eed6 100644 --- a/app/src/tests/unit/components/flagship/report/HouseholdImpactAnalytics.test.tsx +++ b/app/src/tests/unit/components/flagship/report/HouseholdImpactAnalytics.test.tsx @@ -9,6 +9,7 @@ import { Household } from '@/models/Household'; import { BASELINE_POLICY_ID, BASELINE_RESULT, + calculationResponse, CREATED_HOUSEHOLD_ID, HOUSEHOLD_YEAR, REFORM_POLICY_ID, @@ -22,7 +23,8 @@ vi.mock('@/api/household', () => ({ createHousehold: (...args: unknown[]) => mockCreateHousehold(...args), })); vi.mock('@/api/householdCalculation', () => ({ - fetchHouseholdCalculation: (...args: unknown[]) => mockFetchHouseholdCalculation(...args), + fetchHouseholdCalculationWithBundle: async (...args: unknown[]) => + calculationResponse(await mockFetchHouseholdCalculation(...args)), })); /** An input value no event may carry. */ diff --git a/app/src/tests/unit/components/flagship/report/HouseholdImpactSection.test.tsx b/app/src/tests/unit/components/flagship/report/HouseholdImpactSection.test.tsx index 1ded92ce7..fc2383267 100644 --- a/app/src/tests/unit/components/flagship/report/HouseholdImpactSection.test.tsx +++ b/app/src/tests/unit/components/flagship/report/HouseholdImpactSection.test.tsx @@ -10,6 +10,7 @@ import HouseholdImpactSection from '@/components/flagship/report/household/House import { BASELINE_POLICY_ID, BASELINE_RESULT, + calculationResponse, CREATED_HOUSEHOLD_ID, HOUSEHOLD_YEAR, LOW_EARNER_BASELINE_RESULT, @@ -28,7 +29,8 @@ vi.mock('@/api/household', () => ({ createHousehold: (...args: unknown[]) => mockCreateHousehold(...args), })); vi.mock('@/api/householdCalculation', () => ({ - fetchHouseholdCalculation: (...args: unknown[]) => mockFetchHouseholdCalculation(...args), + fetchHouseholdCalculationWithBundle: async (...args: unknown[]) => + calculationResponse(await mockFetchHouseholdCalculation(...args)), })); // The household builder is the v2 builder, tested on its own: here a stand-in diff --git a/app/src/tests/unit/components/flagship/report/ReportViewHousehold.test.tsx b/app/src/tests/unit/components/flagship/report/ReportViewHousehold.test.tsx index 3bbf9ab9a..3fbf087fe 100644 --- a/app/src/tests/unit/components/flagship/report/ReportViewHousehold.test.tsx +++ b/app/src/tests/unit/components/flagship/report/ReportViewHousehold.test.tsx @@ -4,6 +4,7 @@ import { beforeEach, describe, expect, test, vi } from 'vitest'; import ReportView from '@/components/flagship/report/ReportView'; import { BASELINE_RESULT, + calculationResponse, CREATED_HOUSEHOLD_ID, CUSTOM_BASELINE_POLICY_ID, HOUSEHOLD_YEAR, @@ -21,7 +22,8 @@ vi.mock('@/api/household', () => ({ createHousehold: (...args: unknown[]) => mockCreateHousehold(...args), })); vi.mock('@/api/householdCalculation', () => ({ - fetchHouseholdCalculation: (...args: unknown[]) => mockFetchHouseholdCalculation(...args), + fetchHouseholdCalculationWithBundle: async (...args: unknown[]) => + calculationResponse(await mockFetchHouseholdCalculation(...args)), })); // The v2 household builder, tested on its own, stands in by its state. vi.mock('@/components/household/HouseholdBuilderForm', () => ({ diff --git a/app/src/tests/unit/libs/flagship/householdRun.test.ts b/app/src/tests/unit/libs/flagship/householdRun.test.ts index 3ccace314..66441ddad 100644 --- a/app/src/tests/unit/libs/flagship/householdRun.test.ts +++ b/app/src/tests/unit/libs/flagship/householdRun.test.ts @@ -9,22 +9,27 @@ import { Household } from '@/models/Household'; import { BASELINE_POLICY_ID, BASELINE_RESULT, + BASELINE_RUN_BUNDLE, + calculationResponse, COUNTRY_WITHOUT_HOUSEHOLD_LINES, CREATED_HOUSEHOLD_ID, HOUSEHOLD_YEAR, householdResult, LOW_EARNER_BASELINE_RESULT, LOW_EARNER_REFORM_RESULT, + NATIONAL_SPM_CONFIG, REFORM_POLICY_ID, REFORM_RESULT, REFORM_RESULT_LOSS, REFORM_RESULT_WITH_REMAINDER, + REFORM_RUN_BUNDLE, UK_BASELINE_RESULT, UK_FAMILY_BASELINE_RESULT, UK_FAMILY_REFORM_RESULT, UK_REFORM_RESULT, US_COUPLE_WITH_CHILDREN_PAYLOAD, } from '@/tests/fixtures/libs/flagship/householdRunMocks'; +import { SPM_RECEIPT } from '@/tests/fixtures/spm/spmMocks'; const mockCreateHousehold = vi.fn(); const mockFetchHouseholdCalculation = vi.fn(); @@ -32,8 +37,14 @@ const mockFetchHouseholdCalculation = vi.fn(); vi.mock('@/api/household', () => ({ createHousehold: (...args: unknown[]) => mockCreateHousehold(...args), })); +/** How each policy's calculation was made, as its response says it: nothing unless a test sets it. */ +const mockCalculationProvenance = vi.fn(); vi.mock('@/api/householdCalculation', () => ({ - fetchHouseholdCalculation: (...args: unknown[]) => mockFetchHouseholdCalculation(...args), + fetchHouseholdCalculationWithBundle: async (...args: unknown[]) => + calculationResponse( + await mockFetchHouseholdCalculation(...args), + mockCalculationProvenance(...args) + ), })); describe('readHouseholdTotal', () => { @@ -265,6 +276,7 @@ describe('runFlagshipHouseholdPayload', () => { beforeEach(() => { vi.clearAllMocks(); + mockCalculationProvenance.mockReset(); mockCreateHousehold.mockResolvedValue({ result: { household_id: CREATED_HOUSEHOLD_ID } }); mockFetchHouseholdCalculation.mockImplementation( async (_country: string, _household: string, policyId: string) => @@ -297,6 +309,51 @@ describe('runFlagshipHouseholdPayload', () => { expect(run.netIncome.change).toBe(0); }); + test('given each response names its .py bundle and SPM provenance then the run keeps them per policy', async () => { + mockCalculationProvenance.mockImplementation( + (_country: string, _household: string, policyId: string) => ({ + policyengine_bundle: + policyId === BASELINE_POLICY_ID ? BASELINE_RUN_BUNDLE : REFORM_RUN_BUNDLE, + spm_config: NATIONAL_SPM_CONFIG, + spm_provenance: SPM_RECEIPT, + }) + ); + + const run = await runFlagshipHouseholdPayload(runArgs); + + expect(run.provenance).toEqual({ + baseline: { + policyengineBundle: BASELINE_RUN_BUNDLE, + spmConfig: NATIONAL_SPM_CONFIG, + spmProvenance: SPM_RECEIPT, + }, + reform: { + policyengineBundle: REFORM_RUN_BUNDLE, + spmConfig: NATIONAL_SPM_CONFIG, + spmProvenance: SPM_RECEIPT, + }, + }); + }); + + test('given one calculation for both policies then the reform reads its provenance', async () => { + mockCalculationProvenance.mockReturnValue({ policyengine_bundle: BASELINE_RUN_BUNDLE }); + + const run = await runFlagshipHouseholdPayload({ + ...runArgs, + reformPolicyId: BASELINE_POLICY_ID, + }); + + expect(run.provenance.reform).toEqual(run.provenance.baseline); + expect(run.provenance.reform.policyengineBundle).toEqual(BASELINE_RUN_BUNDLE); + }); + + test('given responses without a bundle or SPM provenance then the run says none, not a guess', async () => { + const run = await runFlagshipHouseholdPayload(runArgs); + + expect(run.provenance.baseline).toEqual({ policyengineBundle: null }); + expect(run.provenance.reform).toEqual({ policyengineBundle: null }); + }); + test('given a calculation failure then the run fails with it', async () => { mockFetchHouseholdCalculation.mockRejectedValue(new Error('Household calculation failed')); From 051839701c73768e75fec7897f8240e1751bbb36 Mon Sep 17 00:00:00 2001 From: Anthony Volk <14987227+anth-volk@users.noreply.github.com> Date: Tue, 20 Oct 2026 01:40:43 +0400 Subject: [PATCH 3/7] v3 households: US SPM geography choice and its methodology footnote The section hid the household builder's Supplemental Poverty Measure geography choice (hideSpmGeography) and ran every US household on national thresholds. It now shows the choice: a US household still starts on national thresholds, and the reader can pick local thresholds by county, with a county FIPS code. The household's spm setting and county_fips are sent with it, as in the household builder. With a real choice, the methodology footnote says something again: - Under the summary and the net income breakdown, the result shows the calculation's SPM settings and receipt (SPMMethodologyFootnote), read from each policy's response. One calculation for both policies shows once. A response without a receipt (any UK household) shows nothing. - The earnings variation and marginal tax rate views no longer hide their own variation footnote. SPMMethodologyFootnote now also takes just a calculation's SPM settings and receipt, so the v3 run's provenance can be shown without a full household output. Co-Authored-By: Claude Opus 5.5 --- .../report/household/HouseholdBreakdowns.tsx | 2 - .../household/HouseholdImpactResult.tsx | 23 ++- .../household/HouseholdImpactSection.tsx | 12 +- .../household/SPMMethodologyFootnote.tsx | 6 +- .../report/HouseholdBreakdownsSPM.test.tsx | 78 ++++++++++ .../report/HouseholdImpactSection.test.tsx | 133 ++++++++++++++++-- 6 files changed, 232 insertions(+), 22 deletions(-) create mode 100644 app/src/tests/unit/components/flagship/report/HouseholdBreakdownsSPM.test.tsx diff --git a/app/src/components/flagship/report/household/HouseholdBreakdowns.tsx b/app/src/components/flagship/report/household/HouseholdBreakdowns.tsx index d34841151..7cd92f466 100644 --- a/app/src/components/flagship/report/household/HouseholdBreakdowns.tsx +++ b/app/src/components/flagship/report/household/HouseholdBreakdowns.tsx @@ -172,8 +172,6 @@ export default function HouseholdBreakdowns({ reform={reform} simulations={simulations} policies={policyQuery.policies} - // v3 households use national thresholds, so the footnote says nothing new. - hideSpmFootnote renderLoading={() => ( ('summary'); const { netIncome, components, programs } = impact; @@ -393,6 +409,11 @@ export default function HouseholdImpactResult({ ) : ( )} + + {/* The variation views show their own calculation's methodology. */} + {methodology && (view === 'summary' || view === 'net-income') && ( + + )} ); } diff --git a/app/src/components/flagship/report/household/HouseholdImpactSection.tsx b/app/src/components/flagship/report/household/HouseholdImpactSection.tsx index bd1f1be79..e1264834b 100644 --- a/app/src/components/flagship/report/household/HouseholdImpactSection.tsx +++ b/app/src/components/flagship/report/household/HouseholdImpactSection.tsx @@ -53,8 +53,9 @@ const EXPECTED_MS = 3 * 60 * 1000; /** * A new household: the household builder's own start, one adult and - * nothing else set. A US household is measured against national poverty - * thresholds; only the US model has them. + * nothing else set. A US household starts on national poverty + * thresholds, which the builder's SPM geography choice can change to a + * county's; only the US model has them. */ function newHousehold(countryId: CountryId, year: string): Household { const household = Household.starter(countryId, year); @@ -511,8 +512,6 @@ function HouseholdCard({ setHousehold(household.withBuilderChildCount(year, count)) } disabled={running} - // National poverty thresholds, the model's default, without the choice. - hideSpmGeography layout="columns" suggestedVariables={suggestedVariables} suggestedLabel="Related to this reform" @@ -577,6 +576,11 @@ function HouseholdCard({ ; + /** Display calculation receipts in the results, without claiming certification. */ export default function SPMMethodologyFootnote({ output, context = 'point', }: { - output: (HouseholdCalculationOutput | null)[]; + /** The baseline's calculation first, then the reform's (null when there is none). */ + output: (HouseholdCalculationOutput | SPMMethodologySource | null)[]; context?: 'point' | 'variation'; }) { const receipts = output diff --git a/app/src/tests/unit/components/flagship/report/HouseholdBreakdownsSPM.test.tsx b/app/src/tests/unit/components/flagship/report/HouseholdBreakdownsSPM.test.tsx new file mode 100644 index 000000000..c2d26de33 --- /dev/null +++ b/app/src/tests/unit/components/flagship/report/HouseholdBreakdownsSPM.test.tsx @@ -0,0 +1,78 @@ +import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; +import { render, screen } from '@test-utils'; +import { beforeEach, describe, expect, test, vi } from 'vitest'; +import HouseholdBreakdowns, { + type HouseholdBreakdownSource, + type HouseholdBreakdownView, +} from '@/components/flagship/report/household/HouseholdBreakdowns'; +import { + BASELINE_POLICY_ID, + BASELINE_RESULT, + CREATED_HOUSEHOLD_ID, + HOUSEHOLD_YEAR, + REFORM_POLICY_ID, + REFORM_RESULT, +} from '@/tests/fixtures/libs/flagship/householdRunMocks'; + +vi.mock('@/api/policy', () => ({ + fetchPolicyById: async (_country: string, policyId: string) => ({ + id: policyId, + country_id: 'us', + api_version: '1', + policy_json: {}, + label: null, + }), +})); +vi.mock('@/hooks/useParameterMetadata', () => ({ + useParameterMetadata: () => ({ parameters: {}, isReady: true }), +})); +// The v2 variation pages, tested on their own: stand-ins show whether the +// SPM methodology footnote under their chart is left out. +vi.mock('@/pages/report-output/earnings-variation/EarningsVariationSubPage', () => ({ + default: ({ hideSpmFootnote }: { hideSpmFootnote?: boolean }) => ( +
{hideSpmFootnote ? 'footnote hidden' : 'footnote'}
+ ), +})); +vi.mock('@/pages/report-output/marginal-tax-rates/MarginalTaxRatesSubPage', () => ({ + default: ({ hideSpmFootnote }: { hideSpmFootnote?: boolean }) => ( +
{hideSpmFootnote ? 'footnote hidden' : 'footnote'}
+ ), +})); + +const SOURCE: HouseholdBreakdownSource = { + countryId: 'us', + year: HOUSEHOLD_YEAR, + householdId: String(CREATED_HOUSEHOLD_ID), + baselinePolicyId: BASELINE_POLICY_ID, + reformPolicyId: REFORM_POLICY_ID, + baseline: BASELINE_RESULT, + reform: REFORM_RESULT, + gains: true, +}; + +function renderBreakdowns(view: HouseholdBreakdownView) { + const queryClient = new QueryClient({ defaultOptions: { queries: { retry: false } } }); + return render( + + + + ); +} + +describe('HouseholdBreakdowns SPM methodology', () => { + beforeEach(() => { + vi.clearAllMocks(); + }); + + test.each([ + ['earnings-variation', 'Earnings variation'], + ['marginal-tax-rates', 'Marginal tax rates'], + ] as const)( + 'given %s then the page keeps its SPM methodology footnote', + async (view, pageName) => { + renderBreakdowns(view); + + expect(await screen.findByLabelText(pageName)).toHaveTextContent(/^footnote$/); + } + ); +}); diff --git a/app/src/tests/unit/components/flagship/report/HouseholdImpactSection.test.tsx b/app/src/tests/unit/components/flagship/report/HouseholdImpactSection.test.tsx index fc2383267..cd17ed1ff 100644 --- a/app/src/tests/unit/components/flagship/report/HouseholdImpactSection.test.tsx +++ b/app/src/tests/unit/components/flagship/report/HouseholdImpactSection.test.tsx @@ -15,12 +15,14 @@ import { HOUSEHOLD_YEAR, LOW_EARNER_BASELINE_RESULT, LOW_EARNER_REFORM_RESULT, + NATIONAL_SPM_CONFIG, REFORM_POLICY_ID, REFORM_RESULT, REFORM_RESULT_LOSS, UK_BASELINE_RESULT, UK_REFORM_RESULT, } from '@/tests/fixtures/libs/flagship/householdRunMocks'; +import { SPM_RECEIPT } from '@/tests/fixtures/spm/spmMocks'; const mockCreateHousehold = vi.fn(); const mockFetchHouseholdCalculation = vi.fn(); @@ -28,28 +30,65 @@ const mockFetchHouseholdCalculation = vi.fn(); vi.mock('@/api/household', () => ({ createHousehold: (...args: unknown[]) => mockCreateHousehold(...args), })); +/** How each policy's calculation was made, as its response says it: nothing unless a test sets it. */ +const mockCalculationProvenance = vi.fn(); vi.mock('@/api/householdCalculation', () => ({ fetchHouseholdCalculationWithBundle: async (...args: unknown[]) => - calculationResponse(await mockFetchHouseholdCalculation(...args)), + calculationResponse( + await mockFetchHouseholdCalculation(...args), + mockCalculationProvenance(...args) + ), })); // The household builder is the v2 builder, tested on its own: here a stand-in // makes the same calls it makes, so the section's own work is what is tested. -vi.mock('@/components/household/HouseholdBuilderForm', () => ({ - default: ({ - household, - year, - maritalStatus, - numChildren, - onChange, - onMaritalStatusChange, - onNumChildrenChange, - variablePickerCommon, - }: any) => ( +vi.mock('@/components/household/HouseholdBuilderForm', async () => { + const { default: SPMGeographyChoice } = await import('@/components/household/SPMGeographyChoice'); + const { RESOLVED_CANONICAL_METADATA } = await import('@/tests/fixtures/spm/spmMocks'); + return { + default: (props: any) => ( + + ), + }; +}); + +/** The builder's stand-in: the real SPM choice (unless hidden), and the builder's own calls. */ +function HouseholdBuilderStandIn({ + household, + year, + maritalStatus, + numChildren, + onChange, + onMaritalStatusChange, + onNumChildrenChange, + variablePickerCommon, + suggestedVariables, + hideSpmGeography, + SPMGeographyChoice, + spmMetadata, +}: any) { + return (
input.name).join(' ')} + data-suggested={(suggestedVariables ?? []).join(' ')} > + {!hideSpmGeography && ( + + )} {`${maritalStatus} · ${numChildren}`} {String( @@ -73,8 +112,8 @@ vi.mock('@/components/household/HouseholdBuilderForm', () => ({ Partner earns 20000
- ), -})); + ); +} // The v2 breakdowns, tested on their own: a stand-in shows what each is given. vi.mock('@/components/flagship/report/household/HouseholdBreakdowns', async (importOriginal) => ({ ...(await importOriginal< @@ -133,6 +172,7 @@ function calculateWith(reformResult: typeof REFORM_RESULT) { describe('HouseholdImpactSection', () => { beforeEach(() => { vi.clearAllMocks(); + mockCalculationProvenance.mockReset(); mockCreateHousehold.mockResolvedValue({ result: { household_id: CREATED_HOUSEHOLD_ID } }); calculateWith(REFORM_RESULT); // Radix Select scrolls its options and captures the pointer, which jsdom lacks. @@ -230,6 +270,63 @@ describe('HouseholdImpactSection', () => { expect(JSON.stringify(sent)).toContain('national'); }); + test('given a US household then the SPM geography choice shows, on national thresholds', () => { + renderSection(); + + expect( + screen.getByRole('combobox', { name: 'Supplemental Poverty Measure geography' }) + ).toHaveValue('national'); + }); + + test('given local thresholds and a county then the household is sent with them', async () => { + const user = userEvent.setup(); + renderSection(); + + await user.selectOptions( + screen.getByRole('combobox', { name: 'Supplemental Poverty Measure geography' }), + 'county' + ); + await user.type(screen.getByRole('textbox', { name: /County FIPS code/ }), '06037'); + await user.click(screen.getByRole('button', { name: 'Calculate' })); + + await waitFor(() => expect(mockCreateHousehold).toHaveBeenCalledTimes(1)); + const sent = mockCreateHousehold.mock.calls[0][0]; + expect(sent.spm).toEqual({ geography_kind: 'county' }); + expect(sent.data.households['your household'].county_fips).toEqual({ + [HOUSEHOLD_YEAR]: '06037', + }); + }); + + test('given a calculation with SPM provenance then its methodology shows under the result', async () => { + const user = userEvent.setup(); + mockCalculationProvenance.mockReturnValue({ + spm_config: NATIONAL_SPM_CONFIG, + spm_provenance: SPM_RECEIPT, + }); + renderSection(); + + await user.click(screen.getByRole('button', { name: 'Calculate' })); + + const result = await screen.findByRole('region', { name: 'Household impact' }); + const methodology = within(result).getByRole('region', { + name: 'SPM point calculation methodology', + }); + expect(methodology).toHaveTextContent('Baseline · Point calculation · National thresholds'); + expect(methodology).toHaveTextContent('Reform · Point calculation · National thresholds'); + }); + + test('given a calculation without SPM provenance then no methodology shows', async () => { + const user = userEvent.setup(); + renderSection(); + + await user.click(screen.getByRole('button', { name: 'Calculate' })); + + const result = await screen.findByRole('region', { name: 'Household impact' }); + expect( + within(result).queryByRole('region', { name: 'SPM point calculation methodology' }) + ).not.toBeInTheDocument(); + }); + test('given Calculate then the run shows its progress, then the change in net income', async () => { const user = userEvent.setup(); let finish!: () => void; @@ -548,6 +645,14 @@ describe('HouseholdImpactSection', () => { expect(result).not.toHaveTextContent('$'); }); + test('then no SPM geography choice shows', () => { + renderSection({ countryId: 'uk' }); + + expect( + screen.queryByRole('combobox', { name: 'Supplemental Poverty Measure geography' }) + ).not.toBeInTheDocument(); + }); + test("then the picker features the UK's inputs", () => { renderSection({ countryId: 'uk' }); const featured = screen From 38db5dde50dec1a781ca297a48c36df8196ec197 Mon Sep 17 00:00:00 2001 From: Anthony Volk <14987227+anth-volk@users.noreply.github.com> Date: Tue, 20 Oct 2026 01:43:35 +0400 Subject: [PATCH 4/7] v3 UK households: suggest the inputs a reform reads, from a traced UK map The household section leads its variable search with the inputs a reform's parameters read, from a dependency map traced from the model. Only policyengine-us had a map, so UK reports suggested nothing. - build-parameter-dependency-map.py takes --country. The UK map traces policyengine-uk 2.130.1 (the version the .py bundle 6.7.5 pins) over 400 generated households: the UK microdata is not public, and which parameters a formula reads does not depend on the households, only on which formulas run, so the population varies ages, couples, children, pensioners, disability, every region, tenure and council tax band, and each income source. All 1,163 variables calculate; the map has 688 parameter paths and 989 consumed variables (195 KB). - loadParameterDependencies(countryId) loads each country's map once; without a country it is the US map the validation surfaces read. - The section loads the report's country's map, and suggests only inputs a reader describes a household with, so microdata-only inputs (such as a public-spending imputation) no longer use up the suggestion list. Co-Authored-By: Claude Opus 5.5 --- app/scripts/build-parameter-dependency-map.py | 157 ++++++++++++++---- .../household/HouseholdImpactSection.tsx | 19 ++- .../flagship/parameterDependencies.uk.json | 1 + .../libs/flagship/parameterDependencies.ts | 64 ++++--- .../report/householdSuggestionMocks.ts | 46 +++++ .../HouseholdImpactSuggestions.test.tsx | 76 +++++++++ .../flagship/householdSuggestions.test.ts | 27 ++- .../flagship/parameterDependencies.test.ts | 25 +++ 8 files changed, 354 insertions(+), 61 deletions(-) create mode 100644 app/src/data/flagship/parameterDependencies.uk.json create mode 100644 app/src/tests/fixtures/components/flagship/report/householdSuggestionMocks.ts create mode 100644 app/src/tests/unit/components/flagship/report/HouseholdImpactSuggestions.test.tsx diff --git a/app/scripts/build-parameter-dependency-map.py b/app/scripts/build-parameter-dependency-map.py index ddf72ccb4..470e54843 100644 --- a/app/scripts/build-parameter-dependency-map.py +++ b/app/scripts/build-parameter-dependency-map.py @@ -2,21 +2,30 @@ The flagship validation layer needs to know which model variables a reform touches, so it can look those variables up in the calibration dashboard and -the scorecard. Grepping formula source for parameter paths misses bracket, -scale, and vectorised accesses; the only exact record is what the model -actually reads at run time. This script runs policyengine-us with -policyengine-core's FullTracer over a subsample of the default microdata, -calculates every variable, and writes two edge sets: +the scorecard, and the report's household section uses the same map to +suggest the household inputs a reform reads. Grepping formula source for +parameter paths misses bracket, scale, and vectorised accesses; the only +exact record is what the model actually reads at run time. This script runs +a country model with policyengine-core's FullTracer, calculates every +variable, and writes two edge sets: readers[parameter_path] -> variables whose formula read that parameter consumers[variable] -> variables whose formula read that variable -Output: app/src/data/flagship/parameterDependencies.json (consumed by -app/src/libs/flagship/parameterDependencies.ts). +The US map traces policyengine-us over a subsample of its default microdata. +The UK map traces policyengine-uk over a generated population of households +(see uk_situation): the UK microdata is not public, and the formula reads do +not depend on which households run, only on which formulas run, so a +population varied enough to reach every program's eligible cases serves. -Run from a Python environment with policyengine-us installed: +Output (consumed by app/src/libs/flagship/parameterDependencies.ts): - python app/scripts/build-parameter-dependency-map.py [--households N] [--year YYYY] + us: app/src/data/flagship/parameterDependencies.json + uk: app/src/data/flagship/parameterDependencies.uk.json + +Run from a Python environment with the country's package installed: + + python app/scripts/build-parameter-dependency-map.py [--country us|uk] [--households N] [--year YYYY] Two core quirks are handled here rather than upstream: * core caches the yearly ParameterNodeAtInstant before its own tracing @@ -35,6 +44,7 @@ import argparse import json +import random import sys import time from collections import defaultdict @@ -42,13 +52,12 @@ from importlib.metadata import version from pathlib import Path -OUTPUT = ( - Path(__file__).resolve().parent.parent - / "src" - / "data" - / "flagship" - / "parameterDependencies.json" -) +DATA_DIRECTORY = Path(__file__).resolve().parent.parent / "src" / "data" / "flagship" +OUTPUTS = { + "us": DATA_DIRECTORY / "parameterDependencies.json", + "uk": DATA_DIRECTORY / "parameterDependencies.uk.json", +} +PACKAGES = {"us": "policyengine-us", "uk": "policyengine-uk"} # The simulation's tracer, once tracing is on (see patch_tracer). TRACING: dict = {} @@ -172,24 +181,110 @@ def walk(node) -> None: return readers, consumers +# The UK inputs the generated population varies, by how each is drawn. Enum +# inputs draw any of the model's own values, so the list never names a value +# the model does not have. +UK_PERSON_AMOUNTS = { + "employment_income": (0.6, 150_000), + "self_employment_income": (0.15, 80_000), + "private_pension_income": (0.2, 40_000), + "savings_interest_income": (0.4, 5_000), + "dividend_income": (0.15, 60_000), + "property_income": (0.1, 30_000), + "childcare_expenses": (0.15, 12_000), + "hours_worked": (0.6, 2_400), +} +UK_PERSON_FLAGS = {"is_disabled_for_benefits": 0.15, "is_blind": 0.03} +UK_PERSON_ENUMS = ("pip_dl_category", "pip_m_category", "dla_sc_category", "dla_m_category") +UK_HOUSEHOLD_AMOUNTS = {"rent": (0.4, 18_000)} +UK_HOUSEHOLD_ENUMS = ("region", "tenure_type", "council_tax_band") + + +def enum_names(system, variable_name: str) -> list[str]: + variable = system.variables[variable_name] + return [member.name for member in variable.possible_values] + + +def uk_situation(system, households: int, year: int, seed: int) -> dict: + """A varied UK population: singles, couples, children, pensioners, carers' cases, + every region, tenure and council tax band, and each income source, drawn with a + fixed seed so the map is reproducible.""" + draw = random.Random(seed) + period = str(year) + people: dict = {} + benunits: dict = {} + household_records: dict = {} + for household_index in range(households): + adult_count = draw.choice((1, 1, 2, 2, 2)) + child_count = draw.choice((0, 0, 1, 2, 3, 4)) + # Some households are of pension age, some of working age. + adult_age_range = draw.choice(((18, 30), (25, 64), (40, 66), (66, 95))) + members = [] + for adult_index in range(adult_count): + person_name = f"household {household_index} adult {adult_index}" + person = {"age": {period: draw.randint(*adult_age_range)}} + for variable_name, (share, ceiling) in UK_PERSON_AMOUNTS.items(): + if draw.random() < share: + person[variable_name] = {period: round(draw.uniform(0, ceiling))} + for variable_name, share in UK_PERSON_FLAGS.items(): + person[variable_name] = {period: draw.random() < share} + for variable_name in UK_PERSON_ENUMS: + if draw.random() < 0.15: + person[variable_name] = { + period: draw.choice(enum_names(system, variable_name)) + } + people[person_name] = person + members.append(person_name) + for child_index in range(child_count): + person_name = f"household {household_index} child {child_index}" + people[person_name] = {"age": {period: draw.randint(0, 19)}} + if draw.random() < 0.05: + people[person_name]["is_disabled_for_benefits"] = {period: True} + members.append(person_name) + benunits[f"household {household_index} benefit unit"] = {"members": members} + household = {"members": list(members)} + for variable_name, (share, ceiling) in UK_HOUSEHOLD_AMOUNTS.items(): + if draw.random() < share: + household[variable_name] = {period: round(draw.uniform(0, ceiling))} + for variable_name in UK_HOUSEHOLD_ENUMS: + household[variable_name] = {period: draw.choice(enum_names(system, variable_name))} + household_records[f"household {household_index}"] = household + return {"people": people, "benunits": benunits, "households": household_records} + + +def load_simulation(country: str, households: int, year: int): + """The traced simulation and the name of the data it runs on.""" + if country == "us": + from policyengine_us import Microsimulation + + simulation = Microsimulation() + # Subsampling rewraps the data as a plain dataframe; keep the real name. + dataset_name = getattr(simulation.dataset, "name", None) + simulation = simulation.subsample(n=households, seed=0) or simulation + return simulation, dataset_name + from policyengine_uk import CountryTaxBenefitSystem, Simulation + + situation = uk_situation(CountryTaxBenefitSystem(), households, year, seed=0) + simulation = Simulation(situation=situation, trace=True) + return simulation, "generated households (scripts/build-parameter-dependency-map.py)" + + def main() -> None: parser = argparse.ArgumentParser(description=__doc__.split("\n\n")[0]) - parser.add_argument("--households", type=int, default=2000) + parser.add_argument("--country", choices=sorted(OUTPUTS), default="us") + parser.add_argument("--households", type=int, default=None) parser.add_argument("--year", type=int, default=2026) - parser.add_argument("--output", type=Path, default=OUTPUT) + parser.add_argument("--output", type=Path, default=None) args = parser.parse_args() + households = args.households or (2000 if args.country == "us" else 400) + output = args.output or OUTPUTS[args.country] patch_tracer() - from policyengine_us import Microsimulation - started = time.time() - simulation = Microsimulation() - # Subsampling rewraps the data as a plain dataframe; keep the real name. - dataset_name = getattr(simulation.dataset, "name", None) - simulation = simulation.subsample(n=args.households, seed=0) or simulation + simulation, dataset_name = load_simulation(args.country, households, args.year) simulation.trace = True enable_parameter_tracing(simulation) - print(f"loaded microdata subsample in {time.time() - started:.0f}s", file=sys.stderr) + print(f"loaded {households} households in {time.time() - started:.0f}s", file=sys.stderr) started = time.time() outcomes = calculate_everything(simulation, args.year) @@ -202,11 +297,11 @@ def main() -> None: payload = { "generatedAt": datetime.now(timezone.utc).isoformat(timespec="seconds"), "model": { - "package": "policyengine-us", - "version": version("policyengine-us"), + "package": PACKAGES[args.country], + "version": version(PACKAGES[args.country]), "coreVersion": version("policyengine-core"), "dataset": dataset_name, - "households": args.households, + "households": households, "year": args.year, }, "variablesCalculated": outcomes["ok"], @@ -214,10 +309,10 @@ def main() -> None: "readers": {path: sorted(names) for path, names in sorted(readers.items())}, "consumers": {name: sorted(users) for name, users in sorted(consumers.items())}, } - args.output.parent.mkdir(parents=True, exist_ok=True) - args.output.write_text(json.dumps(payload, separators=(",", ":")) + "\n") + output.parent.mkdir(parents=True, exist_ok=True) + output.write_text(json.dumps(payload, separators=(",", ":")) + "\n") print( - f"wrote {args.output} — {len(readers)} parameter paths, {len(consumers)} consumed variables", + f"wrote {output} — {len(readers)} parameter paths, {len(consumers)} consumed variables", file=sys.stderr, ) diff --git a/app/src/components/flagship/report/household/HouseholdImpactSection.tsx b/app/src/components/flagship/report/household/HouseholdImpactSection.tsx index e1264834b..a564a8a3d 100644 --- a/app/src/components/flagship/report/household/HouseholdImpactSection.tsx +++ b/app/src/components/flagship/report/household/HouseholdImpactSection.tsx @@ -138,15 +138,22 @@ interface HouseholdImpactSectionProps { } /** - * The household inputs the reform's parameters read, nearest first; none - * until the dependency map loads, or when it traces none of them, or for - * a country without a traced map. + * The household inputs the reform's parameters read, nearest first, from + * the country's own traced map; none until the map loads, or when it + * traces none of them, or for a country without a traced map. Only inputs + * a reader describes a household with are suggested, as the builder's + * search lists only those. */ function useSuggestedInputs(paths: string[], countryId: string): string[] { const metadata = useSelector((state: RootState) => state.metadata); const inputs = useMemo( - () => new Set(getInputVariables(metadata).map((variable) => variable.name)), - [metadata] + () => + new Set( + getInputVariables(metadata) + .filter((variable) => describesAHousehold(variable, countryId)) + .map((variable) => variable.name) + ), + [metadata, countryId] ); const preferred = useMemo( () => new Set(commonHouseholdInputs(countryId).map((input) => input.name)), @@ -160,7 +167,7 @@ function useSuggestedInputs(paths: string[], countryId: string): string[] { setSuggested([]); return; } - loadParameterDependencies() + loadParameterDependencies(countryId) .then((map) => { if (!cancelled) { setSuggested( diff --git a/app/src/data/flagship/parameterDependencies.uk.json b/app/src/data/flagship/parameterDependencies.uk.json new file mode 100644 index 000000000..f5ffb870f --- /dev/null +++ b/app/src/data/flagship/parameterDependencies.uk.json @@ -0,0 +1 @@ +{"generatedAt":"2026-10-19T21:30:47+00:00","model":{"package":"policyengine-uk","version":"2.130.1","coreVersion":"3.33.0","dataset":"generated households (scripts/build-parameter-dependency-map.py)","households":400,"year":2026},"variablesCalculated":1163,"variablesFailed":0,"readers":{"gov.boe.base_rate":["plan_1_interest_rate"],"gov.contrib.abolish_council_tax":["household_benefits","pre_budget_change_household_benefits"],"gov.contrib.benefit_uprating.all":["household_benefits","pre_budget_change_household_benefits"],"gov.contrib.benefit_uprating.non_sp":["household_benefits","pre_budget_change_household_benefits"],"gov.contrib.cec.non_primary_residence_wealth_tax":["non_primary_residence_wealth_tax"],"gov.contrib.disability_basic_income.amount":["disability_basic_income"],"gov.contrib.freeze_pension_credit":["in_receipt_of_guarantee_credit","in_receipt_of_savings_credit_only","pension_credit"],"gov.contrib.labour.private_school_vat":["private_school_vat"],"gov.contrib.policyengine.budget.consumer_incident_tax_change":["consumer_incident_tax_revenue_change"],"gov.contrib.policyengine.budget.corporate_incident_tax_change":["corporate_incident_tax_revenue_change"],"gov.contrib.policyengine.budget.education":["education_budget_change"],"gov.contrib.policyengine.budget.nhs":["nhs_budget_change"],"gov.contrib.policyengine.budget.other_public_spending":["other_public_spending_budget_change"],"gov.contrib.policyengine.economy.gdp_per_capita":["household_market_income"],"gov.contrib.policyengine.employer_ni.capital_incidence":["employer_ni_response_capital_incidence"],"gov.contrib.policyengine.employer_ni.consumer_incidence":["employer_ni_response_consumer_incidence"],"gov.contrib.policyengine.employer_ni.employee_incidence":["employer_ni_fixed_employer_cost_change","employer_ni_response_capital_incidence","employer_ni_response_consumer_incidence"],"gov.contrib.policyengine.employer_ni.exempt_employer_pension_contributions":["adjusted_employer_cost","employer_ni_fixed_employer_cost_change","ni_class_1_employer"],"gov.contrib.ubi_center.basic_income.amount.adult_age":["bi_maximum"],"gov.contrib.ubi_center.basic_income.amount.by_age.child":["bi_maximum"],"gov.contrib.ubi_center.basic_income.amount.by_age.senior":["bi_maximum"],"gov.contrib.ubi_center.basic_income.amount.by_age.working_age":["bi_maximum"],"gov.contrib.ubi_center.basic_income.amount.child_min_age":["bi_maximum"],"gov.contrib.ubi_center.basic_income.amount.flat":["bi_maximum"],"gov.contrib.ubi_center.basic_income.interactions.include_in_means_tests":["council_tax_reduction_applicable_income","housing_benefit_applicable_income","income_support_applicable_income","pension_credit_income","tax_credits_current_year_income","uc_income_tax_on_earnings","uc_income_tax_on_trade","uc_individual_earned_income_before_mif"],"gov.contrib.ubi_center.basic_income.interactions.include_in_taxable_income":["net_income"],"gov.contrib.ubi_center.basic_income.interactions.withdraw_cb":["child_benefit_respective_amount"],"gov.contrib.ubi_center.basic_income.phase_out.household.rate":["bi_household_phaseout"],"gov.contrib.ubi_center.basic_income.phase_out.household.threshold":["bi_household_phaseout"],"gov.contrib.ubi_center.basic_income.phase_out.individual.rate":["bi_individual_phaseout"],"gov.contrib.ubi_center.basic_income.phase_out.individual.threshold":["bi_individual_phaseout"],"gov.contrib.ubi_center.carbon_tax.consumer_incidence":["carbon_tax"],"gov.contrib.ubi_center.carbon_tax.rate":["carbon_tax"],"gov.contrib.ubi_center.land_value_tax.corporate_rate":["LVT"],"gov.contrib.ubi_center.land_value_tax.household_rate":["LVT"],"gov.contrib.ubi_center.land_value_tax.rate":["LVT"],"gov.contrib.ubi_center.wealth_tax":["wealth_tax"],"gov.dcms.bbc.tv_licence.colour":["free_tv_licence_value","tv_licence"],"gov.dcms.bbc.tv_licence.discount.blind.discount":["tv_licence_discount"],"gov.dfe.adult_dependants_grant.income_limit":["adult_dependants_grant_eligible"],"gov.dfe.adult_dependants_grant.other_adult_income_limit":["adult_dependants_grant_adult_eligible"],"gov.dfe.bursary_fund_16_to_19.age.minimum":["bursary_fund_16_to_19_age_eligible"],"gov.dfe.bursary_fund_16_to_19.age.standard_upper":["bursary_fund_16_to_19_age_eligible"],"gov.dfe.care_to_learn.age_limit":["care_to_learn_eligible"],"gov.dfe.childcare_funding_rate":["extended_childcare_entitlement_total_per_child","targeted_childcare_entitlement","universal_childcare_entitlement"],"gov.dfe.childcare_grant.eligible_child.max_age.special_educational_needs":["childcare_grant_child_eligible"],"gov.dfe.childcare_grant.eligible_child.max_age.standard":["childcare_grant_child_eligible"],"gov.dfe.childcare_grant.income_limit.one_child":["childcare_grant_eligible"],"gov.dfe.childcare_grant.income_limit.two_or_more_children":["childcare_grant_eligible"],"gov.dfe.compulsory_school_age":["extended_childcare_entitlement_qualifying_child","is_of_compulsory_school_age","uc_expected_hours"],"gov.dfe.extended_childcare_entitlement.disability_criteria":["extended_childcare_entitlement_limited_capability_or_specified_benefit"],"gov.dfe.extended_childcare_entitlement.exemption.income_limit_applies":["extended_childcare_entitlement_work_condition"],"gov.dfe.extended_childcare_entitlement.exemption.partner_exclusion_criteria":["extended_childcare_entitlement_work_condition"],"gov.dfe.extended_childcare_entitlement.hours":["extended_childcare_entitlement_total_per_child","is_child_receiving_extended_childcare"],"gov.dfe.extended_childcare_entitlement.income.countable_sources":["extended_childcare_entitlement_meets_income_requirements"],"gov.dfe.extended_childcare_entitlement.income.limit":["extended_childcare_entitlement_meets_income_requirements","extended_childcare_entitlement_work_condition"],"gov.dfe.extended_childcare_entitlement.minimum_weekly_hours":["extended_childcare_entitlement_meets_income_requirements"],"gov.dfe.extended_childcare_entitlement.young_child_minimum_age":["extended_childcare_entitlement_qualifying_child"],"gov.dfe.maintenance_loans.full_time.maximum.away_in_london":["maintenance_loan"],"gov.dfe.maintenance_loans.full_time.maximum.away_outside_london":["maintenance_loan"],"gov.dfe.maintenance_loans.full_time.maximum.living_with_parents":["maintenance_loan"],"gov.dfe.maintenance_loans.full_time.maximum_entitled_to_benefits.away_in_london":["maintenance_loan"],"gov.dfe.maintenance_loans.full_time.maximum_entitled_to_benefits.away_outside_london":["maintenance_loan"],"gov.dfe.maintenance_loans.full_time.maximum_entitled_to_benefits.living_with_parents":["maintenance_loan"],"gov.dfe.maintenance_loans.full_time.minimum_rate.entitled_to_benefits.away_in_london":["maintenance_loan"],"gov.dfe.maintenance_loans.full_time.minimum_rate.entitled_to_benefits.away_outside_london":["maintenance_loan"],"gov.dfe.maintenance_loans.full_time.minimum_rate.entitled_to_benefits.living_with_parents":["maintenance_loan"],"gov.dfe.maintenance_loans.full_time.minimum_rate.not_entitled.away_in_london":["maintenance_loan"],"gov.dfe.maintenance_loans.full_time.minimum_rate.not_entitled.away_outside_london":["maintenance_loan"],"gov.dfe.maintenance_loans.full_time.minimum_rate.not_entitled.living_with_parents":["maintenance_loan"],"gov.dfe.maintenance_loans.full_time.taper.entitled_to_benefits.first_stage.away_in_london":["maintenance_loan"],"gov.dfe.maintenance_loans.full_time.taper.entitled_to_benefits.first_stage.away_outside_london":["maintenance_loan"],"gov.dfe.maintenance_loans.full_time.taper.entitled_to_benefits.first_stage.living_with_parents":["maintenance_loan"],"gov.dfe.maintenance_loans.full_time.taper.entitled_to_benefits.second_stage.away_in_london":["maintenance_loan"],"gov.dfe.maintenance_loans.full_time.taper.entitled_to_benefits.second_stage.away_outside_london":["maintenance_loan"],"gov.dfe.maintenance_loans.full_time.taper.entitled_to_benefits.second_stage.living_with_parents":["maintenance_loan"],"gov.dfe.maintenance_loans.full_time.taper.not_entitled.away_in_london":["maintenance_loan"],"gov.dfe.maintenance_loans.full_time.taper.not_entitled.away_outside_london":["maintenance_loan"],"gov.dfe.maintenance_loans.full_time.taper.not_entitled.living_with_parents":["maintenance_loan"],"gov.dfe.maintenance_loans.household_income.higher_threshold":["maintenance_loan"],"gov.dfe.maintenance_loans.household_income.threshold":["maintenance_loan"],"gov.dfe.maintenance_loans.independent_student_age":["maintenance_loan_household_income"],"gov.dfe.maintenance_loans.over_60.max_amount":["maintenance_loan"],"gov.dfe.maintenance_loans.over_60.maximum_income":["maintenance_loan"],"gov.dfe.maintenance_loans.over_60.minimum_amount":["maintenance_loan"],"gov.dfe.maintenance_loans.over_60.reduction_per_pound":["maintenance_loan"],"gov.dfe.parents_learning_allowance.income_limit":["parents_learning_allowance_eligible"],"gov.dfe.targeted_childcare_entitlement.age_eligibility":["is_child_receiving_targeted_childcare","targeted_childcare_entitlement"],"gov.dfe.targeted_childcare_entitlement.hours_entitlement":["targeted_childcare_entitlement"],"gov.dfe.targeted_childcare_entitlement.income_limit.tax_credits":["meets_child_tax_credit_criteria_for_targeted_childcare_entitlement","meets_working_tax_credit_criteria_for_targeted_childcare_entitlement"],"gov.dfe.targeted_childcare_entitlement.income_limit.universal_credit":["meets_universal_credit_criteria_for_targeted_childcare_entitlement"],"gov.dfe.targeted_childcare_entitlement.qualifying_benefits":["targeted_childcare_entitlement_eligible"],"gov.dfe.targeted_childcare_entitlement.qualifying_criteria":["meets_tax_credit_criteria_for_targeted_childcare_entitlement","targeted_childcare_entitlement_eligible"],"gov.dfe.universal_childcare_entitlement.age.max":["is_child_receiving_universal_childcare","universal_childcare_entitlement_eligible"],"gov.dfe.universal_childcare_entitlement.age.min":["is_child_receiving_universal_childcare","universal_childcare_entitlement_eligible"],"gov.dfe.universal_childcare_entitlement.hours":["universal_childcare_entitlement"],"gov.dfe.weeks_per_year":["extended_childcare_entitlement_total_per_child","targeted_childcare_entitlement","universal_childcare_entitlement"],"gov.dft.bus.default_single_fare_share":["local_bus_single_fare_share"],"gov.dft.bus.fare_allocation_weight_by_age":["household_bus_fare_age_weight","person_bus_fare_spending"],"gov.dft.bus.fare_index":["person_bus_fare_spending"],"gov.dft.bus.prior_law_fare_index":["person_bus_fare_spending"],"gov.dft.bus.uncapped_single_fare":["local_bus_uncapped_single_fare"],"gov.dft.rail.fare_index":["rail_subsidy_spending"],"gov.dft.vehicle_excise_duty.alternative_fuel_discount":["car_vehicle_excise_duty"],"gov.dft.vehicle_excise_duty.band_k_max_emissions":["car_vehicle_excise_duty"],"gov.dft.vehicle_excise_duty.band_k_registration_cutoff":["car_vehicle_excise_duty"],"gov.dft.vehicle_excise_duty.engine_size_threshold":["car_vehicle_excise_duty"],"gov.dft.vehicle_excise_duty.expensive_car_supplement":["car_vehicle_excise_duty"],"gov.dft.vehicle_excise_duty.expensive_car_threshold":["car_vehicle_excise_duty"],"gov.dft.vehicle_excise_duty.first_year":["car_vehicle_excise_duty"],"gov.dft.vehicle_excise_duty.first_year_diesel_non_rde2":["car_vehicle_excise_duty"],"gov.dft.vehicle_excise_duty.graduated":["car_vehicle_excise_duty"],"gov.dft.vehicle_excise_duty.graduated_registration_start":["car_vehicle_excise_duty"],"gov.dft.vehicle_excise_duty.large_engine_rate":["car_vehicle_excise_duty"],"gov.dft.vehicle_excise_duty.modern_registration_start":["car_vehicle_excise_duty"],"gov.dft.vehicle_excise_duty.small_engine_rate":["car_vehicle_excise_duty"],"gov.dft.vehicle_excise_duty.standard_rate":["car_vehicle_excise_duty"],"gov.dft.vehicle_excise_duty.supplement_years":["car_vehicle_excise_duty"],"gov.dft.vehicle_excise_duty.zero_emission_exempt":["car_vehicle_excise_duty"],"gov.dft.vehicle_excise_duty.zero_emission_expensive_car_threshold":["car_vehicle_excise_duty"],"gov.dft.vehicle_excise_duty.zero_emission_supplement_registration_start":["car_vehicle_excise_duty"],"gov.dwp.ESA.exempt_work.higher_earnings_limit":["esa_income_claimant_remunerative_work"],"gov.dwp.ESA.exempt_work.hours_limit":["esa_income_claimant_remunerative_work"],"gov.dwp.ESA.exempt_work.lower_earnings_limit":["esa_income_claimant_remunerative_work"],"gov.dwp.ESA.income.capital.limit":["esa_income_eligible","is_on_income_related_esa"],"gov.dwp.ESA.income.capital.person_sources":["esa_income_assessable_capital"],"gov.dwp.ESA.income.capital.sources":["esa_income_assessable_capital"],"gov.dwp.ESA.income.capital.tariff_income.amount":["esa_income_tariff_income"],"gov.dwp.ESA.income.capital.tariff_income.step":["esa_income_tariff_income"],"gov.dwp.ESA.income.capital.tariff_income.threshold":["esa_income_tariff_income"],"gov.dwp.ESA.income.remunerative_work.partner_hours":["esa_income_eligible"],"gov.dwp.ESA.income.self_employment_class_2.above_lower_profits_threshold":["esa_exempt_work_earnings"],"gov.dwp.ESA.income.self_employment_class_2.deducted":["esa_exempt_work_earnings"],"gov.dwp.JSA.income.active":["benefit_cap_reduction","claimant_or_partner_jsa_income","income_support_eligible","is_on_income_based_jsa","jsa_income","legacy_benefits_closed"],"gov.dwp.JSA.income.capital.limit":["is_on_income_based_jsa","jsa_income_eligible"],"gov.dwp.JSA.income.capital.person_sources":["jsa_income_assessable_capital"],"gov.dwp.JSA.income.capital.sources":["jsa_income_assessable_capital"],"gov.dwp.JSA.income.capital.tariff_income.amount":["jsa_income_tariff_income"],"gov.dwp.JSA.income.capital.tariff_income.step":["jsa_income_tariff_income"],"gov.dwp.JSA.income.capital.tariff_income.threshold":["jsa_income_tariff_income"],"gov.dwp.JSA.remunerative_work.claimant_hours":["is_on_income_based_jsa","jsa_income_eligible"],"gov.dwp.JSA.remunerative_work.partner_hours":["jsa_income_eligible"],"gov.dwp.LHA.shared_accommodation_age_threshold":["is_housing_benefit_young_individual","is_lha_shared_accommodation_rate_specified_renter"],"gov.dwp.LHA.shared_accommodation_exception_benefits":["is_lha_shared_accommodation_rate_specified_renter"],"gov.dwp.attendance_allowance.higher":["attendance_allowance","is_severely_disabled_for_benefits"],"gov.dwp.attendance_allowance.lower":["attendance_allowance"],"gov.dwp.benefit_cap.non_single.in_london":["benefit_cap"],"gov.dwp.benefit_cap.non_single.outside_london":["benefit_cap"],"gov.dwp.benefit_cap.single.in_london":["benefit_cap"],"gov.dwp.benefit_cap.single.outside_london":["benefit_cap"],"gov.dwp.carer_premium.single":["carer_premium"],"gov.dwp.carers_allowance.earnings_limit":["is_gainfully_employed_for_carers_allowance"],"gov.dwp.carers_allowance.min_hours":["carers_allowance_pre_overlap","is_carer_for_benefits","partners_care_for_same_severely_disabled_person"],"gov.dwp.carers_allowance.qualifying_disability_benefits":["is_severely_disabled_for_carers_allowance"],"gov.dwp.carers_allowance.rate":["carers_allowance_pre_overlap","uc_unearned_carer_support_payment"],"gov.dwp.disability_premia.disability_couple":["disability_premium"],"gov.dwp.disability_premia.disability_single":["disability_premium"],"gov.dwp.disability_premia.enhanced_couple":["enhanced_disability_premium"],"gov.dwp.disability_premia.enhanced_single":["enhanced_disability_premium"],"gov.dwp.disability_premia.severe_couple":["severe_disability_premium"],"gov.dwp.disability_premia.severe_non_dependant_age":["has_non_dependant_for_severe_disability_premium"],"gov.dwp.disability_premia.severe_qualifying_benefits":["receives_severe_disability_premium_qualifying_benefit"],"gov.dwp.disability_premia.severe_qualifying_benefits_northern_ireland":["receives_severe_disability_premium_qualifying_benefit"],"gov.dwp.disability_premia.severe_single":["severe_disability_premium"],"gov.dwp.dla.mobility.higher":["dla_m"],"gov.dwp.dla.mobility.lower":["dla_m"],"gov.dwp.dla.self_care.higher":["dla_sc","is_enhanced_disabled_for_benefits","is_severely_disabled_for_benefits"],"gov.dwp.dla.self_care.lower":["dla_sc"],"gov.dwp.dla.self_care.middle":["dla_sc"],"gov.dwp.housing_benefit.allowances.age_threshold.older":["council_tax_reduction_applicable_amount","housing_benefit_applicable_amount"],"gov.dwp.housing_benefit.allowances.age_threshold.younger":["council_tax_reduction_applicable_amount","housing_benefit_applicable_amount"],"gov.dwp.housing_benefit.allowances.couple.aged":["council_tax_reduction_applicable_amount","housing_benefit_applicable_amount"],"gov.dwp.housing_benefit.allowances.couple.older":["council_tax_reduction_applicable_amount","housing_benefit_applicable_amount"],"gov.dwp.housing_benefit.allowances.couple.younger":["council_tax_reduction_applicable_amount","housing_benefit_applicable_amount"],"gov.dwp.housing_benefit.allowances.lone_parent.aged":["council_tax_reduction_applicable_amount","housing_benefit_applicable_amount"],"gov.dwp.housing_benefit.allowances.lone_parent.older":["council_tax_reduction_applicable_amount","housing_benefit_applicable_amount"],"gov.dwp.housing_benefit.allowances.lone_parent.younger":["council_tax_reduction_applicable_amount","housing_benefit_applicable_amount"],"gov.dwp.housing_benefit.allowances.single.aged":["council_tax_reduction_applicable_amount","housing_benefit_applicable_amount"],"gov.dwp.housing_benefit.allowances.single.older":["council_tax_reduction_applicable_amount","housing_benefit_applicable_amount"],"gov.dwp.housing_benefit.allowances.single.younger":["council_tax_reduction_applicable_amount","housing_benefit_applicable_amount"],"gov.dwp.housing_benefit.ineligible_charges.meals.at_least_three_a_day.aged_16_or_over":["housing_benefit_meals_deduction"],"gov.dwp.housing_benefit.ineligible_charges.meals.at_least_three_a_day.under_16":["housing_benefit_meals_deduction"],"gov.dwp.housing_benefit.ineligible_charges.meals.breakfast_only":["housing_benefit_meals_deduction"],"gov.dwp.housing_benefit.ineligible_charges.meals.fewer_than_three_a_day.aged_16_or_over":["housing_benefit_meals_deduction"],"gov.dwp.housing_benefit.ineligible_charges.meals.fewer_than_three_a_day.under_16":["housing_benefit_meals_deduction"],"gov.dwp.housing_benefit.means_test.capital.pension_age.limit":["housing_benefit_eligible"],"gov.dwp.housing_benefit.means_test.capital.pension_age.tariff_income.amount":["housing_benefit_tariff_income"],"gov.dwp.housing_benefit.means_test.capital.pension_age.tariff_income.step":["housing_benefit_tariff_income"],"gov.dwp.housing_benefit.means_test.capital.pension_age.tariff_income.threshold":["housing_benefit_tariff_income"],"gov.dwp.housing_benefit.means_test.capital.person_sources":["housing_benefit_assessable_capital"],"gov.dwp.housing_benefit.means_test.capital.sources":["housing_benefit_assessable_capital"],"gov.dwp.housing_benefit.means_test.capital.working_age.limit":["housing_benefit_eligible"],"gov.dwp.housing_benefit.means_test.capital.working_age.tariff_income.amount":["housing_benefit_tariff_income"],"gov.dwp.housing_benefit.means_test.capital.working_age.tariff_income.step":["housing_benefit_tariff_income"],"gov.dwp.housing_benefit.means_test.capital.working_age.tariff_income.threshold":["housing_benefit_tariff_income"],"gov.dwp.housing_benefit.means_test.childcare.child_age_limit.disabled":["num_relevant_children_for_housing_benefit_childcare"],"gov.dwp.housing_benefit.means_test.childcare.child_age_limit.standard":["num_relevant_children_for_housing_benefit_childcare"],"gov.dwp.housing_benefit.means_test.income_disregard.couple":["housing_benefit_applicable_income_disregard"],"gov.dwp.housing_benefit.means_test.income_disregard.lone_parent":["housing_benefit_applicable_income_disregard"],"gov.dwp.housing_benefit.means_test.income_disregard.single":["housing_benefit_applicable_income_disregard"],"gov.dwp.housing_benefit.means_test.income_disregard.specified_or_temporary_accommodation.age_threshold.older":["housing_benefit_specified_or_temporary_accommodation_disregard"],"gov.dwp.housing_benefit.means_test.income_disregard.specified_or_temporary_accommodation.age_threshold.younger":["housing_benefit_specified_or_temporary_accommodation_disregard"],"gov.dwp.housing_benefit.means_test.income_disregard.specified_or_temporary_accommodation.couple.minors":["housing_benefit_specified_or_temporary_accommodation_disregard"],"gov.dwp.housing_benefit.means_test.income_disregard.specified_or_temporary_accommodation.couple.older":["housing_benefit_specified_or_temporary_accommodation_disregard"],"gov.dwp.housing_benefit.means_test.income_disregard.specified_or_temporary_accommodation.couple.younger":["housing_benefit_specified_or_temporary_accommodation_disregard"],"gov.dwp.housing_benefit.means_test.income_disregard.specified_or_temporary_accommodation.lone_parent.older":["housing_benefit_specified_or_temporary_accommodation_disregard"],"gov.dwp.housing_benefit.means_test.income_disregard.specified_or_temporary_accommodation.lone_parent.younger":["housing_benefit_specified_or_temporary_accommodation_disregard"],"gov.dwp.housing_benefit.means_test.income_disregard.specified_or_temporary_accommodation.single.older":["housing_benefit_specified_or_temporary_accommodation_disregard"],"gov.dwp.housing_benefit.means_test.income_disregard.specified_or_temporary_accommodation.single.younger":["housing_benefit_specified_or_temporary_accommodation_disregard"],"gov.dwp.housing_benefit.means_test.income_disregard.worker":["housing_benefit_applicable_income_disregard"],"gov.dwp.housing_benefit.means_test.income_disregard.worker_age":["meets_housing_benefit_additional_earnings_disregard_conditions"],"gov.dwp.housing_benefit.means_test.income_disregard.worker_hours":["meets_housing_benefit_additional_earnings_disregard_conditions"],"gov.dwp.housing_benefit.means_test.income_disregard.worker_hours_lower":["meets_housing_benefit_additional_earnings_disregard_conditions"],"gov.dwp.housing_benefit.means_test.pension_contribution_deduction_rate":["housing_benefit_net_earnings"],"gov.dwp.housing_benefit.means_test.universal_credit_passport.great_britain":["housing_benefit_on_passporting_benefit"],"gov.dwp.housing_benefit.means_test.universal_credit_passport.northern_ireland":["housing_benefit_on_passporting_benefit"],"gov.dwp.housing_benefit.means_test.withdrawal_rate":["housing_benefit_entitlement"],"gov.dwp.housing_benefit.non_dep_deduction.age_threshold":["housing_benefit_individual_non_dep_deduction_eligible"],"gov.dwp.housing_benefit.non_dep_deduction.amount":["household_benefits_individual_non_dep_deduction"],"gov.dwp.housing_benefit.severe_disability_premium.qualifying_benefits":["housing_benefit_severe_disability_premium_applies"],"gov.dwp.income_support.active":["income_support","is_on_income_support","legacy_benefits_closed"],"gov.dwp.income_support.amounts.age_threshold.older":["income_support_applicable_amount"],"gov.dwp.income_support.amounts.age_threshold.younger":["income_support_applicable_amount"],"gov.dwp.income_support.amounts.amount_16_24":["income_support_applicable_amount"],"gov.dwp.income_support.amounts.amount_couples_16_17":["income_support_applicable_amount"],"gov.dwp.income_support.amounts.amount_couples_age_gap":["income_support_applicable_amount"],"gov.dwp.income_support.amounts.amount_couples_over_18":["income_support_applicable_amount"],"gov.dwp.income_support.amounts.amount_lone_16_17":["income_support_applicable_amount"],"gov.dwp.income_support.amounts.amount_lone_over_18":["income_support_applicable_amount"],"gov.dwp.income_support.amounts.amount_over_25":["income_support_applicable_amount"],"gov.dwp.income_support.eligibility.lone_parent_youngest_child_age_limit":["income_support_eligible"],"gov.dwp.income_support.eligibility.remunerative_work.claimant_hours":["income_support_eligible"],"gov.dwp.income_support.eligibility.remunerative_work.partner_hours":["income_support_eligible"],"gov.dwp.income_support.means_test.capital.limit":["income_support_eligible"],"gov.dwp.income_support.means_test.capital.person_sources":["income_support_assessable_capital"],"gov.dwp.income_support.means_test.capital.sources":["income_support_assessable_capital"],"gov.dwp.income_support.means_test.capital.tariff_income.amount":["income_support_tariff_income"],"gov.dwp.income_support.means_test.capital.tariff_income.step":["income_support_tariff_income"],"gov.dwp.income_support.means_test.capital.tariff_income.threshold":["income_support_tariff_income"],"gov.dwp.income_support.means_test.income_disregard_couple":["income_support_applicable_income"],"gov.dwp.income_support.means_test.income_disregard_lone_parent":["income_support_applicable_income"],"gov.dwp.income_support.means_test.income_disregard_single":["income_support_applicable_income"],"gov.dwp.pension_credit.guarantee_credit.carer.addition":["carer_minimum_guarantee_addition"],"gov.dwp.pension_credit.guarantee_credit.child.addition":["child_minimum_guarantee_addition"],"gov.dwp.pension_credit.guarantee_credit.child.disability.addition":["child_minimum_guarantee_addition"],"gov.dwp.pension_credit.guarantee_credit.child.disability.eligibility":["child_minimum_guarantee_addition"],"gov.dwp.pension_credit.guarantee_credit.child.disability.severe.addition":["child_minimum_guarantee_addition"],"gov.dwp.pension_credit.guarantee_credit.child.disability.severe.eligibility":["child_minimum_guarantee_addition"],"gov.dwp.pension_credit.guarantee_credit.child.eligibility.child_age_limit":["is_child_for_pension_credit","meets_qualifying_young_person_age_condition_for_pension_credit"],"gov.dwp.pension_credit.guarantee_credit.child.eligibility.education_or_training_start_age_limit":["meets_qualifying_young_person_entry_condition_for_pension_credit"],"gov.dwp.pension_credit.guarantee_credit.child.eligibility.qualifying_young_person_age_limit":["meets_qualifying_young_person_age_condition_for_pension_credit"],"gov.dwp.pension_credit.guarantee_credit.child.first.addition":["child_minimum_guarantee_addition"],"gov.dwp.pension_credit.guarantee_credit.child.first.born_before":["child_minimum_guarantee_addition"],"gov.dwp.pension_credit.guarantee_credit.earnings_sources":["pension_credit_earnings"],"gov.dwp.pension_credit.guarantee_credit.income":["pension_credit_income"],"gov.dwp.pension_credit.guarantee_credit.minimum_guarantee":["standard_minimum_guarantee"],"gov.dwp.pension_credit.guarantee_credit.severe_disability.addition":["severe_disability_minimum_guarantee_addition"],"gov.dwp.pension_credit.guarantee_credit.severe_disability.other_resident_age_limit":["is_counted_resident_for_severe_disability_addition"],"gov.dwp.pension_credit.guarantee_credit.severe_disability.relevant_benefits":["receives_severe_disability_addition_qualifying_benefit"],"gov.dwp.pension_credit.income.capital.lower_threshold":["pension_credit_deemed_income"],"gov.dwp.pension_credit.income.capital.person_sources":["pension_credit_assessable_capital"],"gov.dwp.pension_credit.income.capital.sources":["pension_credit_assessable_capital"],"gov.dwp.pension_credit.income.capital.tariff_income.amount":["pension_credit_deemed_income"],"gov.dwp.pension_credit.income.capital.tariff_income.step":["pension_credit_deemed_income"],"gov.dwp.pension_credit.income.pension_contributions_deduction":["pension_credit_income"],"gov.dwp.pension_credit.mixed_age_couples.excluded":["meets_pension_credit_age_conditions"],"gov.dwp.pension_credit.mixed_age_couples.saving_latest_birth_date":["has_mixed_age_couple_pension_credit_saving"],"gov.dwp.pension_credit.savings_credit.cutoff_year":["meets_savings_credit_age_requirement"],"gov.dwp.pension_credit.savings_credit.excluded_income":["savings_credit_income"],"gov.dwp.pension_credit.savings_credit.minimum_age":["meets_savings_credit_age_requirement"],"gov.dwp.pension_credit.savings_credit.rate.phase_in":["savings_credit"],"gov.dwp.pension_credit.savings_credit.rate.phase_out":["savings_credit"],"gov.dwp.pension_credit.savings_credit.threshold":["is_savings_credit_eligible","savings_credit"],"gov.dwp.pip.daily_living.enhanced":["is_severely_disabled_for_benefits","pip_dl"],"gov.dwp.pip.daily_living.standard":["pip_dl"],"gov.dwp.pip.mobility.enhanced":["pip_m"],"gov.dwp.pip.mobility.standard":["pip_m"],"gov.dwp.sda.maximum":["sda"],"gov.dwp.ssmg.rate":["ssmg"],"gov.dwp.state_pension.age.age_by_birth_date":["state_pension_age","state_pension_credit_qualifying_age"],"gov.dwp.state_pension.age.day_by_birth_date":["state_pension_age","state_pension_credit_qualifying_age"],"gov.dwp.state_pension.age.male.age":["state_pension_age","state_pension_credit_qualifying_age"],"gov.dwp.state_pension.age.male.born_before":["state_pension_age"],"gov.dwp.tax_credits.active":["legacy_benefits_closed","tax_credit_award","tax_credits","tax_credits_applicable_income"],"gov.dwp.tax_credits.child_tax_credit.elements.child_element":["CTC_child_element"],"gov.dwp.tax_credits.child_tax_credit.elements.dis_child_element":["CTC_disabled_child_element"],"gov.dwp.tax_credits.child_tax_credit.eligibility.child_age_limit":["is_child_for_child_tax_credit","meets_qualifying_young_person_age_condition_for_child_tax_credit"],"gov.dwp.tax_credits.child_tax_credit.eligibility.education_or_training_start_age_limit":["meets_qualifying_young_person_entry_condition_for_child_tax_credit"],"gov.dwp.tax_credits.child_tax_credit.eligibility.qualifying_young_person_age_limit":["meets_qualifying_young_person_age_condition_for_child_tax_credit"],"gov.dwp.tax_credits.child_tax_credit.limit.born_before":["is_CTC_child_limit_exempt"],"gov.dwp.tax_credits.child_tax_credit.limit.child_count":["CTC_child_element","ctc_child_limit_affected"],"gov.dwp.tax_credits.means_test.income_reduction_rate":["tax_credits_reduction"],"gov.dwp.tax_credits.means_test.income_threshold":["tax_credits_reduction"],"gov.dwp.tax_credits.means_test.income_threshold_CTC_only":["tax_credits_reduction"],"gov.dwp.tax_credits.means_test.non_earned_disregard":["tax_credits_current_year_income"],"gov.dwp.tax_credits.means_test.pension_credit_passport":["tax_credits_applicable_income"],"gov.dwp.tax_credits.working_tax_credit.childcare_child_age_limit.disabled":["is_child_for_working_tax_credit_childcare_element"],"gov.dwp.tax_credits.working_tax_credit.childcare_child_age_limit.standard":["is_child_for_working_tax_credit_childcare_element"],"gov.dwp.tax_credits.working_tax_credit.elements.childcare_1":["housing_benefit_applicable_income_childcare_element"],"gov.dwp.tax_credits.working_tax_credit.elements.childcare_2":["housing_benefit_applicable_income_childcare_element"],"gov.dwp.tax_credits.working_tax_credit.elements.severely_disabled":["WTC_severely_disabled_element"],"gov.dwp.tax_credits.working_tax_credit.min_hours.couple_with_children":["is_WTC_eligible"],"gov.dwp.tax_credits.working_tax_credit.min_hours.default":["is_WTC_eligible"],"gov.dwp.tax_credits.working_tax_credit.min_hours.lower":["is_WTC_eligible"],"gov.dwp.tax_credits.working_tax_credit.min_hours.old_age":["is_WTC_eligible"],"gov.dwp.universal_credit.company_owner.intermediary_exclusion.chapters":["uc_company_intermediary_exclusion_applies"],"gov.dwp.universal_credit.company_owner.intermediary_exclusion.requires_main_employment":["uc_company_intermediary_exclusion_applies"],"gov.dwp.universal_credit.deductions.abolish.advance":["uc_deduction_rate"],"gov.dwp.universal_credit.deductions.abolish.government":["uc_deduction_rate"],"gov.dwp.universal_credit.deductions.abolish.third_party":["uc_deduction_rate"],"gov.dwp.universal_credit.deductions.cap":["uc_deduction_rate"],"gov.dwp.universal_credit.deductions.minimum_payable":["uc_deductions"],"gov.dwp.universal_credit.deductions.protected_floor":["universal_credit"],"gov.dwp.universal_credit.elements.child.amount":["two_child_limit_payment","uc_individual_child_element"],"gov.dwp.universal_credit.elements.child.disabled.amount":["uc_individual_disabled_child_element"],"gov.dwp.universal_credit.elements.child.eligibility.child_age_limit":["is_child_for_universal_credit","meets_qualifying_young_person_age_condition_for_universal_credit"],"gov.dwp.universal_credit.elements.child.eligibility.education_or_training_start_age_limit":["meets_qualifying_young_person_entry_condition_for_universal_credit"],"gov.dwp.universal_credit.elements.child.eligibility.qualifying_young_person_age_limit":["meets_qualifying_young_person_age_condition_for_universal_credit"],"gov.dwp.universal_credit.elements.child.eligibility.terminal_date_age_limit":["meets_qualifying_young_person_terminal_date_condition_for_universal_credit"],"gov.dwp.universal_credit.elements.child.first.higher_amount":["uc_individual_child_element"],"gov.dwp.universal_credit.elements.child.limit.born_before":["uc_is_child_born_before_child_limit"],"gov.dwp.universal_credit.elements.child.limit.child_count":["uc_individual_child_element"],"gov.dwp.universal_credit.elements.child.severely_disabled.amount":["uc_individual_severely_disabled_child_element"],"gov.dwp.universal_credit.elements.childcare.cap":["uc_maximum_childcare_element_amount"],"gov.dwp.universal_credit.elements.childcare.coverage_rate":["uc_childcare_element"],"gov.dwp.universal_credit.elements.housing.non_dep_deduction.age_threshold":["uc_individual_non_dep_deduction_eligible"],"gov.dwp.universal_credit.elements.housing.non_dep_deduction.amount":["uc_individual_non_dep_deduction"],"gov.dwp.universal_credit.eligibility.min_age":["meets_uc_minimum_age_condition"],"gov.dwp.universal_credit.eligibility.reduced_min_age":["meets_uc_minimum_age_condition"],"gov.dwp.universal_credit.means_test.capital.limit":["is_uc_eligible"],"gov.dwp.universal_credit.means_test.capital.person_sources":["uc_assessable_capital"],"gov.dwp.universal_credit.means_test.capital.sources":["uc_assessable_capital"],"gov.dwp.universal_credit.means_test.capital.tariff_income.amount":["uc_tariff_income"],"gov.dwp.universal_credit.means_test.capital.tariff_income.step":["uc_tariff_income"],"gov.dwp.universal_credit.means_test.capital.tariff_income.threshold":["uc_tariff_income"],"gov.dwp.universal_credit.means_test.income_definitions.unearned":["uc_unearned_income"],"gov.dwp.universal_credit.means_test.minimum_income_floor.ineligible_partner_hours":["uc_minimum_income_floor_gross"],"gov.dwp.universal_credit.means_test.minimum_income_floor.no_requirements_partner_hours":["uc_minimum_income_floor_gross"],"gov.dwp.universal_credit.means_test.minimum_income_floor.self_employed_national_insurance":["uc_minimum_income_floor_national_insurance"],"gov.dwp.universal_credit.means_test.reduction_rate":["uc_income_reduction"],"gov.dwp.universal_credit.means_test.work_allowance.with_housing":["uc_work_allowance"],"gov.dwp.universal_credit.means_test.work_allowance.without_housing":["uc_work_allowance"],"gov.dwp.universal_credit.standard_allowance.amount":["uc_standard_allowance"],"gov.dwp.universal_credit.standard_allowance.claimant_type.age_threshold":["uc_standard_allowance_claimant_type"],"gov.dwp.universal_credit.work_requirements.default_expected_hours":["uc_expected_hours"],"gov.dwp.universal_credit.work_requirements.interview_or_preparation_threshold_hours":["uc_minimum_income_floor_gross"],"gov.dwp.universal_credit.work_requirements.responsible_carer.child_age.interview_only":["uc_work_related_group_apart_from_earnings"],"gov.dwp.universal_credit.work_requirements.responsible_carer.child_age.no_requirements":["uc_work_related_group_apart_from_earnings"],"gov.dwp.universal_credit.work_requirements.responsible_carer.child_age.work_preparation":["uc_work_related_group_apart_from_earnings"],"gov.dwp.universal_credit.work_requirements.responsible_carer.expected_hours.below_compulsory_school_age":["uc_expected_hours"],"gov.dwp.universal_credit.work_requirements.responsible_carer.expected_hours.child_age_limit":["uc_expected_hours"],"gov.dwp.universal_credit.work_requirements.responsible_carer.expected_hours.compulsory_school_age":["uc_expected_hours"],"gov.dwp.winter_fuel_payment.amount.higher":["winter_fuel_payment"],"gov.dwp.winter_fuel_payment.amount.higher_shared_with_80_or_over":["winter_fuel_payment"],"gov.dwp.winter_fuel_payment.amount.higher_shared_with_under_80":["winter_fuel_payment"],"gov.dwp.winter_fuel_payment.amount.lower":["winter_fuel_payment"],"gov.dwp.winter_fuel_payment.amount.lower_shared":["winter_fuel_payment"],"gov.dwp.winter_fuel_payment.eligibility.countries":["winter_fuel_payment_eligible"],"gov.dwp.winter_fuel_payment.eligibility.higher_age_requirement":["winter_fuel_payment"],"gov.dwp.winter_fuel_payment.eligibility.minimum_tax_credit_award":["is_on_winter_fuel_payment_relevant_benefit","winter_fuel_payment_eligible"],"gov.dwp.winter_fuel_payment.eligibility.partner_receipt_counts":["is_on_winter_fuel_payment_relevant_benefit"],"gov.dwp.winter_fuel_payment.eligibility.relevant_benefits":["is_on_winter_fuel_payment_relevant_benefit","winter_fuel_payment_eligible"],"gov.dwp.winter_fuel_payment.eligibility.require_benefits":["winter_fuel_payment_eligible"],"gov.dwp.winter_fuel_payment.eligibility.state_pension_age_requirement":["winter_fuel_payment_eligible"],"gov.dwp.winter_fuel_payment.eligibility.taxable_income_test.maximum_taxable_income":["winter_fuel_payment_eligible"],"gov.dwp.winter_fuel_payment.eligibility.taxable_income_test.use_maximum_taxable_income":["winter_fuel_payment_eligible"],"gov.economic_assumptions.yoy_growth.obr.rpi":["plan_1_interest_rate","plan_2_interest_rate","plan_5_interest_rate","postgraduate_interest_rate"],"gov.hmrc.alcohol_duty.high_abv":["beer_duty","cider_duty","other_fermented_duty","sparkling_cider_duty","spirits_duty","wine_duty"],"gov.hmrc.alcohol_duty.sparkling_cider_abv":["sparkling_cider_duty"],"gov.hmrc.alcohol_duty.spirits_abv":["beer_duty","cider_duty","other_fermented_duty","sparkling_cider_duty","spirits_duty","wine_duty"],"gov.hmrc.alcohol_duty.standard_abv":["beer_duty","cider_duty","other_fermented_duty","sparkling_cider_duty","spirits_duty","wine_duty"],"gov.hmrc.alcohol_duty.taxable_abv":["beer_duty","cider_duty","other_fermented_duty","sparkling_cider_duty","spirits_duty","wine_duty"],"gov.hmrc.alcohol_duty.wine_easement_abv":["wine_duty"],"gov.hmrc.alcohol_duty.wine_easement_max_abv":["wine_duty"],"gov.hmrc.alcohol_duty.wine_easement_min_abv":["wine_duty"],"gov.hmrc.business_rates.statistics.revenue.ENGLAND":["baseline_business_rates","business_rates"],"gov.hmrc.business_rates.statistics.revenue.NORTHERN_IRELAND":["baseline_business_rates","business_rates"],"gov.hmrc.business_rates.statistics.revenue.SCOTLAND":["baseline_business_rates","business_rates"],"gov.hmrc.business_rates.statistics.revenue.WALES":["baseline_business_rates","business_rates"],"gov.hmrc.cgt.additional_rate":["capital_gains_tax"],"gov.hmrc.cgt.annual_exempt_amount":["capital_gains_tax"],"gov.hmrc.cgt.badr.lifetime_limit":["capital_gains_tax"],"gov.hmrc.cgt.badr.rate":["capital_gains_tax"],"gov.hmrc.cgt.basic_rate":["capital_gains_tax"],"gov.hmrc.cgt.carried_interest.additional_rate":["capital_gains_tax"],"gov.hmrc.cgt.carried_interest.basic_rate":["capital_gains_tax"],"gov.hmrc.cgt.carried_interest.higher_rate":["capital_gains_tax"],"gov.hmrc.cgt.higher_rate":["capital_gains_tax"],"gov.hmrc.cgt.residential_property.additional_rate":["capital_gains_tax"],"gov.hmrc.cgt.residential_property.basic_rate":["capital_gains_tax"],"gov.hmrc.cgt.residential_property.higher_rate":["capital_gains_tax"],"gov.hmrc.child_benefit.amount.additional":["child_benefit_respective_amount"],"gov.hmrc.child_benefit.amount.eldest":["child_benefit_respective_amount"],"gov.hmrc.child_benefit.eligibility.child_age_limit":["is_child_for_child_benefit","meets_qualifying_young_person_age_condition_for_child_benefit"],"gov.hmrc.child_benefit.eligibility.education_or_training_start_age_limit":["meets_qualifying_young_person_entry_condition_for_child_benefit"],"gov.hmrc.child_benefit.eligibility.qualifying_young_person_age_limit":["meets_qualifying_young_person_age_condition_for_child_benefit"],"gov.hmrc.child_benefit.opt_out_charge_share":["child_benefit"],"gov.hmrc.fuel_duty.lpg":["fuel_duty"],"gov.hmrc.fuel_duty.natural_gas":["fuel_duty"],"gov.hmrc.fuel_duty.petrol_and_diesel":["fuel_duty"],"gov.hmrc.fuel_duty.rural_fuel_duty_relief":["fuel_duty"],"gov.hmrc.income_tax.adjusted_net_income_components":["net_income","uc_income_tax_on_earnings","uc_income_tax_on_trade"],"gov.hmrc.income_tax.allowances.annual_allowance.default":["pension_annual_allowance"],"gov.hmrc.income_tax.allowances.annual_allowance.minimum":["pension_annual_allowance"],"gov.hmrc.income_tax.allowances.annual_allowance.reduction_rate":["pension_annual_allowance"],"gov.hmrc.income_tax.allowances.annual_allowance.taper":["pension_annual_allowance"],"gov.hmrc.income_tax.allowances.dividend_allowance":["dividend_income_tax","taxed_dividend_income"],"gov.hmrc.income_tax.allowances.marriage_allowance.eligible_bands":["meets_marriage_allowance_income_conditions"],"gov.hmrc.income_tax.allowances.marriage_allowance.max":["marriage_allowance"],"gov.hmrc.income_tax.allowances.marriage_allowance.rounding_increment":["marriage_allowance"],"gov.hmrc.income_tax.allowances.married_couples_allowance.deduction_rate":["married_couples_allowance_deduction"],"gov.hmrc.income_tax.allowances.personal_allowance.amount":["carers_allowance_earnings","marriage_allowance","personal_allowance","savings_starter_rate_income","uc_minimum_income_floor_income_tax"],"gov.hmrc.income_tax.allowances.personal_allowance.maximum_ANI":["personal_allowance"],"gov.hmrc.income_tax.allowances.personal_allowance.reduction_rate":["personal_allowance"],"gov.hmrc.income_tax.allowances.personal_savings_allowance.additional":["savings_allowance"],"gov.hmrc.income_tax.allowances.personal_savings_allowance.basic":["savings_allowance"],"gov.hmrc.income_tax.allowances.personal_savings_allowance.higher":["savings_allowance"],"gov.hmrc.income_tax.allowances.property_allowance":["property_allowance_deduction_if_used","property_receipts_within_allowance"],"gov.hmrc.income_tax.allowances.trading_allowance":["trading_allowance_deduction"],"gov.hmrc.income_tax.bases.taxable_self_employment_income_deductions":["taxable_self_employment_income"],"gov.hmrc.income_tax.charges.CB_HITC.phase_out_end":["CB_HITC","child_benefit"],"gov.hmrc.income_tax.charges.CB_HITC.phase_out_start":["CB_HITC","child_benefit"],"gov.hmrc.income_tax.earned_taxable_income_exclusions":["earned_taxable_income","uc_income_tax_on_earnings","uc_income_tax_on_trade"],"gov.hmrc.income_tax.income_tax_additions":["income_tax"],"gov.hmrc.income_tax.income_tax_subtractions":["income_tax","property_finance_cost_relief","uc_income_tax_on_earnings","uc_income_tax_on_trade"],"gov.hmrc.income_tax.rates.dividends":["dividend_income_tax"],"gov.hmrc.income_tax.rates.property.additional":["property_income_tax"],"gov.hmrc.income_tax.rates.property.basic":["property_finance_cost_relief","property_income_tax"],"gov.hmrc.income_tax.rates.property.higher":["property_income_tax"],"gov.hmrc.income_tax.rates.savings.additional":["savings_income_tax"],"gov.hmrc.income_tax.rates.savings.basic":["savings_income_tax"],"gov.hmrc.income_tax.rates.savings.higher":["savings_income_tax"],"gov.hmrc.income_tax.rates.savings_starter_rate.allowance":["savings_starter_rate_income"],"gov.hmrc.income_tax.rates.savings_starter_rate.phase_out":["savings_starter_rate_income"],"gov.hmrc.income_tax.rates.scotland.rates":["carers_allowance_earnings","earned_income_tax","esa_exempt_work_earnings","property_income_tax","tax_band","uc_income_tax_on_earnings","uc_income_tax_on_trade","uc_minimum_income_floor_income_tax"],"gov.hmrc.income_tax.rates.uk":["add_rate_earned_income","add_rate_earned_income_tax","add_rate_savings_income","basic_rate_earned_income","basic_rate_earned_income_tax","basic_rate_savings_income","basic_rate_savings_income_pre_starter","capital_gains_tax","carers_allowance_earnings","earned_income_tax","esa_exempt_work_earnings","gift_aid_grossed_up","higher_rate_earned_income","higher_rate_earned_income_tax","higher_rate_savings_income","personal_pension_contributions_tax","property_income_tax","savings_allowance","tax_band","uc_income_tax_on_earnings","uc_income_tax_on_trade","uc_minimum_income_floor_income_tax"],"gov.hmrc.income_tax.reliefs.pension_contribution.basic_amount":["pension_contributions_relief"],"gov.hmrc.income_tax.reliefs.property_finance_costs.disallowed_share":["deductible_property_finance_costs","property_finance_costs_relievable"],"gov.hmrc.isa.lifetime.charge_free_age":["lifetime_isa_countable_capital"],"gov.hmrc.isa.lifetime.withdrawal_charge":["lifetime_isa_countable_capital"],"gov.hmrc.minimum_wage.apprentice":["minimum_wage"],"gov.hmrc.minimum_wage.non_apprentice":["minimum_wage","uc_minimum_income_floor_gross"],"gov.hmrc.national_insurance.class_1.rates.employee.additional":["esa_exempt_work_earnings","ni_class_1_employee_additional","salary_sacrifice_pension_ni_employee","uc_minimum_income_floor_national_insurance"],"gov.hmrc.national_insurance.class_1.rates.employee.main":["esa_exempt_work_earnings","ni_class_1_employee_primary","salary_sacrifice_pension_ni_employee","uc_minimum_income_floor_national_insurance"],"gov.hmrc.national_insurance.class_1.rates.employer":["adjusted_employer_cost","employer_ni_fixed_employer_cost_change","ni_class_1_employer","salary_sacrifice_pension_ni_employer"],"gov.hmrc.national_insurance.class_1.thresholds.primary_threshold":["esa_exempt_work_earnings","ni_class_1_employee_primary","uc_minimum_income_floor_national_insurance"],"gov.hmrc.national_insurance.class_1.thresholds.secondary_threshold":["adjusted_employer_cost","employer_ni_fixed_employer_cost_change","ni_class_1_employer"],"gov.hmrc.national_insurance.class_1.thresholds.upper_earnings_limit":["esa_exempt_work_earnings","ni_class_1_employee_additional","ni_class_1_employee_primary","salary_sacrifice_pension_ni_employee","uc_minimum_income_floor_national_insurance"],"gov.hmrc.national_insurance.class_2.flat_rate":["carers_allowance_earnings","esa_exempt_work_earnings","ni_class_2","ni_class_4_maximum","uc_minimum_income_floor_national_insurance"],"gov.hmrc.national_insurance.class_2.lower_profits_threshold":["carers_allowance_earnings","esa_exempt_work_earnings","ni_class_2","uc_minimum_income_floor_national_insurance"],"gov.hmrc.national_insurance.class_2.lower_profits_threshold_applies":["carers_allowance_earnings","ni_class_2","uc_minimum_income_floor_national_insurance"],"gov.hmrc.national_insurance.class_2.small_profits_threshold":["carers_allowance_earnings","esa_exempt_work_earnings","ni_class_2","uc_minimum_income_floor_national_insurance"],"gov.hmrc.national_insurance.class_4.annual_maximum.includes_class_2":["ni_class_4","ni_class_4_maximum"],"gov.hmrc.national_insurance.class_4.rates.additional":["ni_class_4","ni_class_4_maximum","uc_minimum_income_floor_national_insurance"],"gov.hmrc.national_insurance.class_4.rates.main":["carers_allowance_earnings","esa_exempt_work_earnings","ni_class_4","ni_class_4_main","ni_class_4_maximum","uc_minimum_income_floor_national_insurance"],"gov.hmrc.national_insurance.class_4.thresholds.lower_profits_limit":["carers_allowance_earnings","esa_exempt_work_earnings","ni_class_4","ni_class_4_main","ni_class_4_maximum","uc_minimum_income_floor_national_insurance"],"gov.hmrc.national_insurance.class_4.thresholds.upper_profits_limit":["carers_allowance_earnings","esa_exempt_work_earnings","ni_class_4","ni_class_4_main","ni_class_4_maximum","uc_minimum_income_floor_national_insurance"],"gov.hmrc.national_insurance.salary_sacrifice_pension_cap":["pension_contributions_via_salary_sacrifice_adjusted","salary_sacrifice_broad_base_haircut","salary_sacrifice_returned_to_income"],"gov.hmrc.pensions.pension_contributions_relief_age_limit":["pension_contributions_relief","uc_individual_earned_income_before_mif"],"gov.hmrc.stamp_duty.abolish":["expected_sdlt"],"gov.hmrc.stamp_duty.non_residential.purchase":["sdlt_on_non_residential_property_transactions"],"gov.hmrc.stamp_duty.non_residential.rent":["sdlt_on_non_residential_property_rent"],"gov.hmrc.stamp_duty.property_sale_rate":["expected_lbtt","expected_ltt","expected_sdlt"],"gov.hmrc.stamp_duty.residential.purchase.additional.min":["sdlt_on_residential_property_transactions"],"gov.hmrc.stamp_duty.residential.purchase.additional.rate":["sdlt_on_residential_property_transactions"],"gov.hmrc.stamp_duty.residential.purchase.main.first.max":["sdlt_on_residential_property_transactions"],"gov.hmrc.stamp_duty.residential.purchase.main.first.rate":["sdlt_on_residential_property_transactions"],"gov.hmrc.stamp_duty.residential.purchase.main.subsequent":["sdlt_on_residential_property_transactions"],"gov.hmrc.stamp_duty.residential.rent":["sdlt_on_residential_property_rent"],"gov.hmrc.stamp_duty.statistics.non_residential.corporate.revenue":["corporate_sdlt"],"gov.hmrc.stamp_duty.statistics.residential.corporate.revenue":["corporate_sdlt"],"gov.hmrc.student_loans.interest_rates.plan_1.boe_margin":["plan_1_interest_rate"],"gov.hmrc.student_loans.interest_rates.plan_2.additional_rate":["plan_2_interest_rate"],"gov.hmrc.student_loans.interest_rates.plan_2.upper_threshold":["plan_2_interest_rate"],"gov.hmrc.student_loans.interest_rates.postgraduate_additional_rate":["postgraduate_interest_rate"],"gov.hmrc.student_loans.postgraduate_repayment_rate":["student_loan_repayment_rate"],"gov.hmrc.student_loans.repayment_rate":["student_loan_repayment_rate"],"gov.hmrc.student_loans.thresholds.plan_1":["student_loan_repayment"],"gov.hmrc.student_loans.thresholds.plan_2":["plan_2_interest_rate","student_loan_repayment"],"gov.hmrc.student_loans.thresholds.plan_4":["student_loan_repayment"],"gov.hmrc.student_loans.thresholds.plan_5":["student_loan_repayment"],"gov.hmrc.student_loans.thresholds.postgraduate":["student_loan_repayment"],"gov.hmrc.tax_free_childcare.age.disability":["tax_free_childcare_child_age_eligible"],"gov.hmrc.tax_free_childcare.age.standard":["tax_free_childcare_child_age_eligible"],"gov.hmrc.tax_free_childcare.carers_leave_qualifies":["tax_free_childcare_regarded_as_in_paid_work"],"gov.hmrc.tax_free_childcare.caring_or_incapacity_benefits":["tax_free_childcare_caring_or_incapacity_benefit"],"gov.hmrc.tax_free_childcare.caring_or_incapacity_benefits_in_payment":["tax_free_childcare_regarded_as_in_paid_work"],"gov.hmrc.tax_free_childcare.contribution.disabled_child":["tax_free_childcare"],"gov.hmrc.tax_free_childcare.contribution.rate":["tax_free_childcare"],"gov.hmrc.tax_free_childcare.contribution.standard_child":["tax_free_childcare"],"gov.hmrc.tax_free_childcare.declaration_periods_per_year":["tax_free_childcare","tax_free_childcare_eligible_declaration_periods"],"gov.hmrc.tax_free_childcare.disqualifying_benefits":["tax_free_childcare_program_eligible"],"gov.hmrc.tax_free_childcare.income.countable_sources":["tax_free_childcare_expected_declaration_period_income"],"gov.hmrc.tax_free_childcare.income.declaration_period_weeks":["tax_free_childcare_expected_declaration_period_income","tax_free_childcare_meets_income_requirements"],"gov.hmrc.tax_free_childcare.income.income_limit":["tax_free_childcare_meets_income_requirements"],"gov.hmrc.tax_free_childcare.minimum_weekly_hours":["tax_free_childcare_meets_income_requirements"],"gov.hmrc.vat.reduced_rate":["baseline_vat","vat"],"gov.hmrc.vat.reduced_rate_share":["reduced_rate_vat_consumption"],"gov.hmrc.vat.standard_rate":["baseline_vat","vat"],"gov.local_authorities.england.council_tax_reduction.pensioners.earnings_disregard.additional":["council_tax_reduction_pensioner_earnings_disregard"],"gov.local_authorities.england.council_tax_reduction.pensioners.earnings_disregard.couple":["council_tax_reduction_pensioner_earnings_disregard"],"gov.local_authorities.england.council_tax_reduction.pensioners.earnings_disregard.lone_parent":["council_tax_reduction_pensioner_earnings_disregard"],"gov.local_authorities.england.council_tax_reduction.pensioners.earnings_disregard.single":["council_tax_reduction_pensioner_earnings_disregard"],"gov.local_authorities.england.council_tax_reduction.pensioners.maximum_support_rate":["simulated_council_tax_reduction_benunit"],"gov.local_authorities.england.council_tax_reduction.pensioners.means_test.capital_limit":["simulated_council_tax_reduction_benunit"],"gov.local_authorities.england.council_tax_reduction.pensioners.means_test.withdrawal_rate":["simulated_council_tax_reduction_benunit"],"gov.local_authorities.kingston_upon_thames.council_tax_reduction.maximum_support_rate":["kingston_upon_thames_council_tax_reduction"],"gov.local_authorities.kingston_upon_thames.council_tax_reduction.means_test.capital_limit":["kingston_upon_thames_council_tax_reduction"],"gov.local_authorities.kingston_upon_thames.council_tax_reduction.means_test.tariff_income_step":["kingston_upon_thames_council_tax_reduction"],"gov.local_authorities.kingston_upon_thames.council_tax_reduction.means_test.tariff_income_threshold":["kingston_upon_thames_council_tax_reduction"],"gov.local_authorities.kingston_upon_thames.council_tax_reduction.means_test.withdrawal_rate":["kingston_upon_thames_council_tax_reduction"],"gov.local_authorities.merton.council_tax_reduction.maximum_support_rate":["merton_council_tax_reduction"],"gov.local_authorities.merton.council_tax_reduction.means_test.capital_limit":["merton_council_tax_reduction"],"gov.local_authorities.merton.council_tax_reduction.means_test.withdrawal_rate":["merton_council_tax_reduction"],"gov.local_authorities.newham.council_tax_reduction.maximum_support_rate":["newham_council_tax_reduction"],"gov.local_authorities.newham.council_tax_reduction.means_test.capital_limit":["newham_council_tax_reduction"],"gov.local_authorities.newham.council_tax_reduction.means_test.withdrawal_rate":["newham_council_tax_reduction"],"gov.local_authorities.oxford.council_tax_reduction.income_band.maximum_support_rate":["oxford_council_tax_reduction"],"gov.local_authorities.oxford.council_tax_reduction.means_test.capital_limit":["oxford_council_tax_reduction"],"gov.local_authorities.oxford.council_tax_reduction.means_test.tariff_income_step":["oxford_council_tax_reduction"],"gov.local_authorities.oxford.council_tax_reduction.means_test.tariff_income_threshold":["oxford_council_tax_reduction"],"gov.local_authorities.scotland.council_tax_reduction.maximum_support_rate":["simulated_council_tax_reduction_benunit"],"gov.local_authorities.scotland.council_tax_reduction.means_test.capital_limit":["simulated_council_tax_reduction_benunit"],"gov.local_authorities.scotland.council_tax_reduction.means_test.withdrawal_rate":["simulated_council_tax_reduction_benunit"],"gov.local_authorities.scotland.council_tax_reduction.pensioners.earnings_disregard.additional":["council_tax_reduction_pensioner_earnings_disregard"],"gov.local_authorities.scotland.council_tax_reduction.pensioners.earnings_disregard.couple":["council_tax_reduction_pensioner_earnings_disregard"],"gov.local_authorities.scotland.council_tax_reduction.pensioners.earnings_disregard.lone_parent":["council_tax_reduction_pensioner_earnings_disregard"],"gov.local_authorities.scotland.council_tax_reduction.pensioners.earnings_disregard.single":["council_tax_reduction_pensioner_earnings_disregard"],"gov.local_authorities.scotland.council_tax_reduction.working_age.young_person_follows_universal_credit":["is_child_or_young_person_for_council_tax_reduction"],"gov.local_authorities.wales.council_tax_reduction.maximum_support_rate":["simulated_council_tax_reduction_benunit"],"gov.local_authorities.wales.council_tax_reduction.means_test.capital_limit":["simulated_council_tax_reduction_benunit"],"gov.local_authorities.wales.council_tax_reduction.means_test.withdrawal_rate":["simulated_council_tax_reduction_benunit"],"gov.local_authorities.wales.council_tax_reduction.pensioners.earnings_disregard.additional":["council_tax_reduction_pensioner_earnings_disregard"],"gov.local_authorities.wales.council_tax_reduction.pensioners.earnings_disregard.couple":["council_tax_reduction_pensioner_earnings_disregard"],"gov.local_authorities.wales.council_tax_reduction.pensioners.earnings_disregard.lone_parent":["council_tax_reduction_pensioner_earnings_disregard"],"gov.local_authorities.wales.council_tax_reduction.pensioners.earnings_disregard.single":["council_tax_reduction_pensioner_earnings_disregard"],"gov.local_authorities.westminster.council_tax_reduction.maximum_support_rate":["westminster_council_tax_reduction"],"gov.local_authorities.westminster.council_tax_reduction.means_test.capital_limit":["westminster_council_tax_reduction"],"gov.local_authorities.westminster.council_tax_reduction.means_test.tariff_income_step":["westminster_council_tax_reduction"],"gov.local_authorities.westminster.council_tax_reduction.means_test.tariff_income_threshold":["westminster_council_tax_reduction"],"gov.local_authorities.westminster.council_tax_reduction.means_test.withdrawal_rate":["westminster_council_tax_reduction"],"gov.revenue_scotland.lbtt.non_residential":["lbtt_on_non_residential_property_transactions"],"gov.revenue_scotland.lbtt.rent":["lbtt_on_non_residential_property_rent","lbtt_on_residential_property_rent"],"gov.revenue_scotland.lbtt.residential.additional_residence_surcharge":["lbtt_on_residential_property_transactions"],"gov.revenue_scotland.lbtt.residential.first_time_buyer_rate":["lbtt_on_residential_property_transactions"],"gov.revenue_scotland.lbtt.residential.rate":["lbtt_on_residential_property_transactions"],"gov.scottish_government.funded_early_learning_childcare.age.max":["scottish_funded_early_learning_childcare_eligible"],"gov.scottish_government.funded_early_learning_childcare.age.min":["scottish_funded_early_learning_childcare_eligible"],"gov.simulation.capital_gains_responses.badr_elasticity":["capital_gains_badr_elasticity"],"gov.simulation.capital_gains_responses.elasticity":["capital_gains_badr_behavioural_response","capital_gains_behavioural_response","capital_gains_elasticity"],"gov.simulation.capital_gains_responses.mtr_elasticity":["capital_gains_badr_behavioural_response","capital_gains_behavioural_response"],"gov.simulation.capital_gains_responses.separate_badr_elasticity":["capital_gains_badr_behavioural_response","capital_gains_badr_elasticity","capital_gains_behavioural_response"],"gov.simulation.labour_supply_responses.bounds.effective_wage_rate_change":["relative_wage_change"],"gov.simulation.labour_supply_responses.bounds.income_change":["relative_income_change"],"gov.simulation.labour_supply_responses.income_elasticity":["employment_income_behavioral_response","income_elasticity_lsr"],"gov.simulation.labour_supply_responses.substitution_elasticity":["employment_income_behavioral_response","substitution_elasticity_lsr"],"gov.simulation.marginal_tax_rate_adults":["cliff_evaluated","marginal_tax_rate","marginal_tax_rate_wrt_employer_cost"],"gov.simulation.marginal_tax_rate_delta":["cliff_gap","marginal_tax_rate","marginal_tax_rate_wrt_employer_cost"],"gov.simulation.microdata_vat_coverage":["baseline_vat","vat"],"gov.simulation.private_school_vat.private_school_fees":["private_school_vat"],"gov.simulation.private_school_vat.private_school_vat_basis":["private_school_vat"],"gov.simulation.uc_deductions.calibration_cap":["uc_deduction_rate"],"gov.simulation.uc_deductions.latent_rate_distribution.AT_10":["uc_has_deduction","uc_latent_deduction_rate"],"gov.simulation.uc_deductions.latent_rate_distribution.AT_15":["uc_has_deduction","uc_latent_deduction_rate"],"gov.simulation.uc_deductions.latent_rate_distribution.AT_20":["uc_has_deduction","uc_latent_deduction_rate"],"gov.simulation.uc_deductions.latent_rate_distribution.AT_25":["uc_has_deduction","uc_latent_deduction_rate"],"gov.simulation.uc_deductions.latent_rate_distribution.AT_5":["uc_has_deduction","uc_latent_deduction_rate"],"gov.simulation.uc_deductions.latent_rate_distribution.FIFTEEN_TO_20":["uc_has_deduction","uc_latent_deduction_rate"],"gov.simulation.uc_deductions.latent_rate_distribution.FIVE_TO_10":["uc_has_deduction","uc_latent_deduction_rate"],"gov.simulation.uc_deductions.latent_rate_distribution.OVER_25":["uc_has_deduction","uc_latent_deduction_rate"],"gov.simulation.uc_deductions.latent_rate_distribution.TEN_TO_15":["uc_has_deduction","uc_latent_deduction_rate"],"gov.simulation.uc_deductions.latent_rate_distribution.TWENTY_TO_25":["uc_has_deduction","uc_latent_deduction_rate"],"gov.simulation.uc_deductions.latent_rate_distribution.UNDER_5":["uc_has_deduction","uc_latent_deduction_rate"],"gov.simulation.uc_deductions.mean_monthly_amount_by_type.ADVANCE":["uc_deduction_rate"],"gov.simulation.uc_deductions.mean_monthly_amount_by_type.GOVERNMENT":["uc_deduction_rate"],"gov.simulation.uc_deductions.mean_monthly_amount_by_type.THIRD_PARTY":["uc_deduction_rate"],"gov.simulation.uc_deductions.region_incidence_factor":["uc_has_deduction","uc_latent_deduction_rate"],"gov.simulation.uc_deductions.type_combination.ADVANCE_AND_GOVERNMENT":["uc_deduction_combination"],"gov.simulation.uc_deductions.type_combination.ADVANCE_AND_THIRD_PARTY":["uc_deduction_combination"],"gov.simulation.uc_deductions.type_combination.ADVANCE_ONLY":["uc_deduction_combination"],"gov.simulation.uc_deductions.type_combination.ALL_THREE":["uc_deduction_combination"],"gov.simulation.uc_deductions.type_combination.GOVERNMENT_ONLY":["uc_deduction_combination"],"gov.simulation.uc_deductions.type_combination.THIRD_PARTY_AND_GOVERNMENT":["uc_deduction_combination"],"gov.simulation.uc_deductions.type_combination.THIRD_PARTY_ONLY":["uc_deduction_combination"],"gov.social_security_scotland.carer_support_payment.min_hours":["carer_support_payment_pre_overlap","partners_care_for_same_severely_disabled_person"],"gov.social_security_scotland.carer_support_payment.rate":["carer_support_payment_pre_overlap"],"gov.social_security_scotland.carer_support_payment.supplement":["scottish_carer_supplement"],"gov.social_security_scotland.pawhp.active":["pawhp_eligible"],"gov.social_security_scotland.pawhp.amount.higher":["pension_age_winter_heating_payment"],"gov.social_security_scotland.pawhp.amount.higher_shared_with_80_or_over":["pension_age_winter_heating_payment"],"gov.social_security_scotland.pawhp.amount.higher_shared_with_under_80":["pension_age_winter_heating_payment"],"gov.social_security_scotland.pawhp.amount.lower":["pension_age_winter_heating_payment"],"gov.social_security_scotland.pawhp.amount.lower_shared":["pension_age_winter_heating_payment"],"gov.social_security_scotland.pawhp.eligibility.higher_age_requirement":["pension_age_winter_heating_payment"],"gov.social_security_scotland.pawhp.eligibility.minimum_tax_credit_award":["is_on_pawhp_relevant_benefit","pawhp_eligible"],"gov.social_security_scotland.pawhp.eligibility.partner_receipt_counts":["is_on_pawhp_relevant_benefit"],"gov.social_security_scotland.pawhp.eligibility.relevant_benefits":["is_on_pawhp_relevant_benefit","pawhp_eligible"],"gov.social_security_scotland.pawhp.eligibility.require_benefits":["pawhp_eligible"],"gov.social_security_scotland.pawhp.eligibility.state_pension_age_requirement":["pawhp_eligible"],"gov.social_security_scotland.scottish_child_payment.amount":["is_scp_eligible","scottish_child_payment"],"gov.social_security_scotland.scottish_child_payment.max_age":["is_scp_eligible_child"],"gov.social_security_scotland.scottish_child_payment.qualifying_benefits.child_tax_credit":["is_scp_eligible"],"gov.social_security_scotland.scottish_child_payment.qualifying_benefits.esa_income":["is_scp_eligible"],"gov.social_security_scotland.scottish_child_payment.qualifying_benefits.income_support":["is_scp_eligible"],"gov.social_security_scotland.scottish_child_payment.qualifying_benefits.jsa_income":["is_scp_eligible"],"gov.social_security_scotland.scottish_child_payment.qualifying_benefits.pension_credit":["is_scp_eligible"],"gov.social_security_scotland.scottish_child_payment.qualifying_benefits.universal_credit":["is_scp_eligible"],"gov.social_security_scotland.scottish_child_payment.qualifying_benefits.working_tax_credit":["is_scp_eligible"],"gov.social_security_scotland.two_child_limit_payment.in_effect":["two_child_limit_payment"],"gov.treasury.cost_of_living_support.disabled.amount":["cost_of_living_support_payment"],"gov.treasury.cost_of_living_support.disabled.qualifying_benefits":["cost_of_living_support_payment"],"gov.treasury.cost_of_living_support.means_tested_households.amount":["cost_of_living_support_payment"],"gov.treasury.cost_of_living_support.means_tested_households.qualifying_benefits":["cost_of_living_support_payment"],"gov.treasury.cost_of_living_support.pensioners.amount":["cost_of_living_support_payment"],"gov.treasury.cost_of_living_support.pensioners.qualifying_benefits":["cost_of_living_support_payment"],"gov.treasury.energy_bills_rebate.council_tax_rebate.amount":["ebr_council_tax_rebate"],"gov.treasury.energy_bills_rebate.council_tax_rebate.bands":["ebr_council_tax_rebate"],"gov.treasury.energy_bills_rebate.energy_bills_credit":["ebr_energy_bills_credit"],"gov.treasury.energy_bills_rebate.energy_bills_credit_monthly":["monthly_ebr_energy_bills_credit"],"gov.treasury.energy_bills_rebate.energy_bills_credit_northern_ireland":["monthly_ebr_energy_bills_credit"],"gov.wra.land_transaction_tax.non_residential":["ltt_on_non_residential_property_transactions"],"gov.wra.land_transaction_tax.rent":["ltt_on_non_residential_property_rent","ltt_on_residential_property_rent"],"gov.wra.land_transaction_tax.residential.higher_rate":["ltt_on_residential_property_transactions"],"gov.wra.land_transaction_tax.residential.primary":["ltt_on_residential_property_transactions"],"household.consumption.alcohol.beer_abv":["beer_abv"],"household.consumption.alcohol.cider_abv":["cider_abv"],"household.consumption.alcohol.other_fermented_abv":["other_fermented_abv"],"household.consumption.alcohol.sparkling_cider_abv":["sparkling_cider_abv"],"household.consumption.alcohol.spirits_abv":["spirits_abv"],"household.consumption.alcohol.wine_abv":["wine_abv"],"household.consumption.carbon.emissions.alcohol_and_tobacco":["carbon_consumption"],"household.consumption.carbon.emissions.clothing_and_footwear":["carbon_consumption"],"household.consumption.carbon.emissions.communication":["carbon_consumption"],"household.consumption.carbon.emissions.education":["carbon_consumption"],"household.consumption.carbon.emissions.food_and_non_alcoholic_beverages":["carbon_consumption"],"household.consumption.carbon.emissions.health":["carbon_consumption"],"household.consumption.carbon.emissions.household_furnishings":["carbon_consumption"],"household.consumption.carbon.emissions.housing_water_and_electricity":["carbon_consumption"],"household.consumption.carbon.emissions.miscellaneous":["carbon_consumption"],"household.consumption.carbon.emissions.recreation":["carbon_consumption"],"household.consumption.carbon.emissions.restaurants_and_hotels":["carbon_consumption"],"household.consumption.carbon.emissions.transport":["carbon_consumption"],"household.consumption.fuel.prices.diesel":["diesel_price"],"household.consumption.fuel.prices.petrol":["petrol_price"],"household.consumption.tobacco.cigarettes_per_pack":["tobacco_duty"],"household.consumption.tobacco.price_per_pack":["cigarette_price_per_pack"],"household.consumption.total_by_category.alcohol_and_tobacco_consumption":["carbon_consumption"],"household.consumption.total_by_category.clothing_and_footwear_consumption":["carbon_consumption"],"household.consumption.total_by_category.communication_consumption":["carbon_consumption"],"household.consumption.total_by_category.education_consumption":["carbon_consumption"],"household.consumption.total_by_category.food_and_non_alcoholic_beverages_consumption":["carbon_consumption"],"household.consumption.total_by_category.health_consumption":["carbon_consumption"],"household.consumption.total_by_category.household_furnishings_consumption":["carbon_consumption"],"household.consumption.total_by_category.housing_water_and_electricity_consumption":["carbon_consumption"],"household.consumption.total_by_category.miscellaneous_consumption":["carbon_consumption"],"household.consumption.total_by_category.recreation_consumption":["carbon_consumption"],"household.consumption.total_by_category.restaurants_and_hotels_consumption":["carbon_consumption"],"household.consumption.total_by_category.transport_consumption":["carbon_consumption"],"household.demographic.benefit_unit.presumed_child.age_limit":["is_claimant_or_partner"],"household.demographic.benefit_unit.presumed_child.minimum_age_gap":["is_claimant_or_partner"],"household.demographic.equiv.ahc.child_over_14":["household_equivalisation_ahc"],"household.demographic.equiv.ahc.child_under_14":["household_equivalisation_ahc"],"household.demographic.equiv.ahc.first_adult":["household_equivalisation_ahc"],"household.demographic.equiv.ahc.second_adult":["household_equivalisation_ahc"],"household.demographic.equiv.bhc.child_over_14":["household_equivalisation_bhc"],"household.demographic.equiv.bhc.child_under_14":["household_equivalisation_bhc"],"household.demographic.equiv.bhc.first_adult":["household_equivalisation_bhc"],"household.demographic.equiv.bhc.second_adult":["household_equivalisation_bhc"],"household.demographic.equiv.child_age_threshold":["is_hbai_child_aged_14_or_over","is_hbai_child_under_14"],"household.demographic.hbai.dependent_child.age_limit":["is_hbai_dependent_child"],"household.demographic.hbai.dependent_child.young_person_age_limit":["is_hbai_dependent_child"],"household.poverty.absolute_poverty_threshold_ahc":["in_deep_poverty_ahc","poverty_line_ahc","poverty_threshold_ahc"],"household.poverty.absolute_poverty_threshold_bhc":["in_deep_poverty_bhc","poverty_line","poverty_line_bhc","poverty_threshold_bhc"],"household.poverty.exclude_non_hbai_income":["baseline_hbai_excluded_income"],"household.wealth.land.intensity.property_wealth_by_region.EAST_MIDLANDS":["household_land_value"],"household.wealth.land.intensity.property_wealth_by_region.EAST_OF_ENGLAND":["household_land_value"],"household.wealth.land.intensity.property_wealth_by_region.LONDON":["household_land_value"],"household.wealth.land.intensity.property_wealth_by_region.NORTHERN_IRELAND":["household_land_value"],"household.wealth.land.intensity.property_wealth_by_region.NORTH_EAST":["household_land_value"],"household.wealth.land.intensity.property_wealth_by_region.NORTH_WEST":["household_land_value"],"household.wealth.land.intensity.property_wealth_by_region.SCOTLAND":["household_land_value"],"household.wealth.land.intensity.property_wealth_by_region.SOUTH_EAST":["household_land_value"],"household.wealth.land.intensity.property_wealth_by_region.SOUTH_WEST":["household_land_value"],"household.wealth.land.intensity.property_wealth_by_region.UNKNOWN":["household_land_value"],"household.wealth.land.intensity.property_wealth_by_region.WALES":["household_land_value"],"household.wealth.land.intensity.property_wealth_by_region.WEST_MIDLANDS":["household_land_value"],"household.wealth.land.intensity.property_wealth_by_region.YORKSHIRE":["household_land_value"],"household.wealth.national_balance_sheet.household.financial_net_worth":["shareholding"]},"consumers":{"CB_HITC":["capped_mcad","child_benefit_less_tax_charge","income_tax"],"CTC_child_element":["CTC_maximum_rate"],"CTC_disabled_child_element":["CTC_maximum_rate"],"CTC_family_element":["CTC_maximum_rate"],"CTC_maximum_rate":["child_tax_credit_pre_minimum","tax_credits_reduction"],"CTC_severely_disabled_child_element":["CTC_maximum_rate"],"LHA_allowed_bedrooms":["LHA_category"],"LHA_cap":["housing_benefit_entitlement"],"LHA_category":["BRMA_LHA_rate","uc_LHA_cap","uncapped_BRMA_LHA_rate"],"LHA_eligible":["housing_benefit_eligible","housing_benefit_entitlement"],"LVT":["gov_tax","hbai_household_net_income","household_tax","pre_budget_change_household_tax"],"WTC_basic_element":["WTC_maximum_rate"],"WTC_childcare_element":["WTC_maximum_rate","childcare_grant_eligible"],"WTC_couple_element":["WTC_maximum_rate"],"WTC_disabled_element":["WTC_maximum_rate"],"WTC_lone_parent_element":["WTC_maximum_rate"],"WTC_maximum_rate":["child_tax_credit_pre_minimum","tax_credits_reduction","working_tax_credit_pre_minimum"],"WTC_severely_disabled_element":["WTC_maximum_rate"],"WTC_worker_element":["WTC_maximum_rate"],"aa_category":["attendance_allowance","is_severely_disabled_for_benefits"],"access_fund":["student_payments"],"add_rate_earned_income":["add_rate_earned_income_tax"],"add_rate_savings_income":["savings_income_tax","taxed_savings_income"],"additional_minimum_guarantee":["minimum_guarantee"],"additional_residential_property_purchased":["lbtt_on_residential_property_transactions","ltt_on_residential_property_transactions","sdlt_on_residential_property_transactions"],"additional_state_pension":["overlapping_state_pension","state_pension"],"adjusted_net_income":["CB_HITC","child_benefit","extended_childcare_entitlement_meets_income_requirements","extended_childcare_entitlement_work_condition","is_higher_earner","personal_allowance","tax_free_childcare_meets_income_requirements"],"adult_dependants_grant":["gov_spending","hbai_benefits","household_benefits"],"adult_dependants_grant_adult_eligible":["adult_dependants_grant_eligible"],"adult_dependants_grant_adult_receives_student_finance":["adult_dependants_grant_eligible"],"adult_dependants_grant_course_eligible":["adult_dependants_grant_eligible"],"adult_dependants_grant_eligible":["adult_dependants_grant"],"adult_dependants_grant_has_other_adult_dependant":["adult_dependants_grant_adult_eligible"],"adult_dependants_grant_household_income":["adult_dependants_grant_eligible"],"adult_dependants_grant_other_adult_income":["adult_dependants_grant_adult_eligible"],"adult_dependants_grant_receives_postgraduate_loan":["adult_dependants_grant_eligible"],"adult_ema":["student_payments"],"adult_index":["cliff_evaluated","maintenance_loan_has_sponsor","maintenance_loan_sponsor_income","marginal_tax_rate","marginal_tax_rate_wrt_employer_cost"],"adult_index_cg":["marginal_tax_rate_on_capital_gains"],"afcs":["gov_spending","hbai_benefits","hbai_household_net_income","household_benefits","is_benefit_cap_exempt_health_disability","pre_budget_change_household_benefits"],"afcs_reported":["afcs"],"age":["LHA_allowed_bedrooms","adult_dependants_grant_adult_eligible","adult_index","age_18_64","age_over_64","age_under_18","bi_maximum","birth_year","bursary_fund_16_to_19_age_eligible","care_to_learn_eligible","child_benefit_child_index","child_index","child_minimum_guarantee_addition","childcare_grant_child_eligible","council_tax_reduction_individual_non_dep_deduction_eligible","council_tax_reduction_liable_person","current_education","date_of_birth","eldest_adult_age","eldest_child_age","eldest_claimant_or_partner_age","extended_childcare_entitlement_qualifying_child","extended_childcare_entitlement_total_per_child","has_attained_state_pension_credit_qualifying_age","has_mixed_age_couple_pension_credit_saving","has_non_dependant_for_severe_disability_premium","has_own_esa_award","household_bus_fare_age_weight","housing_benefit_LHA_allowed_bedrooms","housing_benefit_has_non_dependant","housing_benefit_individual_non_dep_deduction_eligible","housing_benefit_meals_deduction","housing_benefit_severe_disability_premium_applies","is_CTC_child_limit_exempt","is_WTC_eligible","is_adult","is_benefit_cap_exempt_health_disability","is_benunit_eldest_child","is_benunit_head","is_cared_for_by_carer_benefit_recipient","is_child","is_child_for_child_benefit","is_child_for_child_tax_credit","is_child_for_pension_credit","is_child_for_universal_credit","is_child_for_working_tax_credit_childcare_element","is_child_receiving_extended_childcare","is_child_receiving_targeted_childcare","is_child_receiving_universal_childcare","is_claimant_or_partner","is_counted_resident_for_severe_disability_addition","is_hbai_child_aged_14_or_over","is_hbai_child_under_14","is_hbai_dependent_child","is_higher_earner","is_household_head","is_lha_shared_accommodation_rate_specified_renter","is_of_compulsory_school_age","is_older_child","is_on_income_based_jsa","is_on_income_related_esa","is_on_income_support","is_on_pension_credit","is_resolved_household_head","is_responsible_for_child_or_young_person_for_uc_or_housing_benefit","is_scp_eligible_child","is_uc_assessed_claimant","is_young_child","lha_renter_has_non_dependant","lifetime_isa_countable_capital","maintenance_loan","maintenance_loan_eligible","maintenance_loan_has_sponsor","maintenance_loan_household_income","maintenance_loan_in_higher_education","maintenance_loan_sponsor_income","meets_housing_benefit_additional_earnings_disregard_conditions","meets_qualifying_young_person_age_condition_for_child_benefit","meets_qualifying_young_person_age_condition_for_child_tax_credit","meets_qualifying_young_person_age_condition_for_pension_credit","meets_qualifying_young_person_age_condition_for_universal_credit","meets_qualifying_young_person_entry_condition_for_child_benefit","meets_qualifying_young_person_entry_condition_for_child_tax_credit","meets_qualifying_young_person_entry_condition_for_pension_credit","meets_qualifying_young_person_entry_condition_for_universal_credit","meets_qualifying_young_person_terminal_date_condition_for_universal_credit","meets_savings_credit_age_requirement","meets_uc_minimum_age_condition","minimum_wage","minimum_wage_category","months_since_last_birthday","months_since_state_pension_age","num_relevant_children_for_housing_benefit_childcare","over_16","pawhp_eligible","pension_age_winter_heating_payment","pension_contributions_relief","person_bus_fare_spending","scottish_funded_early_learning_childcare_eligible","state_pension_age","state_pension_credit_qualifying_age","targeted_childcare_entitlement","tax_free_childcare_child_age_eligible","tv_licence_discount","uc_child_index","uc_individual_earned_income_before_mif","uc_individual_non_dep_deduction_eligible","uc_is_child_born_before_child_limit","uc_is_responsible_carer","uc_minimum_income_floor_gross","uc_standard_allowance_claimant_type","uc_youngest_child_age","universal_childcare_entitlement","universal_childcare_entitlement_eligible","winter_fuel_payment","winter_fuel_payment_eligible","youngest_adult_age","youngest_child_age","youngest_child_age_for_legacy_benefits","youngest_claimant_or_partner_age"],"age_started_or_accepted_current_education_or_training":["meets_qualifying_young_person_entry_condition_for_child_benefit","meets_qualifying_young_person_entry_condition_for_child_tax_credit","meets_qualifying_young_person_entry_condition_for_pension_credit","meets_qualifying_young_person_entry_condition_for_universal_credit"],"age_under_18":["adult_index","adult_index_cg","is_hbai_dependent_child"],"alcohol_and_tobacco_consumption":["carbon_consumption","consumption"],"alcohol_duty":["gov_tax","household_tax"],"allowances":["capital_gains_tax","non_savings_income_after_allowances","received_allowances_dividend_income","received_allowances_earned_income","received_allowances_savings_income","savings_allowance","tax_band"],"armed_forces_independence_payment":["cost_of_living_support_payment","council_tax_reduction_applicant_has_non_dep_exemption","housing_benefit_severe_disability_premium_applies","is_benefit_cap_exempt_health_disability","is_severely_disabled_for_benefits","is_severely_disabled_for_carers_allowance","maintenance_loan_entitled_to_benefits","receives_severe_disability_addition_qualifying_benefit","receives_severe_disability_premium_qualifying_benefit"],"attendance_allowance":["cost_of_living_support_payment","council_tax_reduction_applicant_has_non_dep_exemption","gov_spending","hbai_benefits","hbai_household_net_income","household_benefits","housing_benefit_severe_disability_premium_applies","is_benefit_cap_exempt_health_disability","is_lha_shared_accommodation_rate_specified_renter","is_severely_disabled_for_benefits","is_severely_disabled_for_carers_allowance","pre_budget_change_household_benefits","receives_severe_disability_addition_qualifying_benefit","receives_severe_disability_premium_qualifying_benefit","uc_non_dep_deduction_exempt"],"attends_private_school":["private_school_vat"],"baseline_hbai_excluded_income":["hbai_excluded_income_change"],"baseline_vat":["vat_change"],"basic_income":["council_tax_reduction_applicable_income","gov_spending","household_benefits","housing_benefit_applicable_income","pre_budget_change_household_benefits"],"basic_rate_earned_income":["basic_rate_earned_income_tax"],"basic_rate_savings_income":["savings_income_tax","taxed_savings_income"],"basic_rate_savings_income_pre_starter":["savings_starter_rate_income"],"basic_state_pension":["overlapping_state_pension","state_pension"],"beer_abv":["beer_duty"],"beer_draught_share":["beer_duty"],"beer_duty":["alcohol_duty"],"beer_litres":["beer_duty"],"benefit_cap":["benefit_cap_reduction"],"benefit_cap_reduction":["housing_benefit","uc_deductions","uc_has_deduction","universal_credit"],"benefits_premiums":["housing_benefit_applicable_amount"],"benunit_contains_household_head":["is_liable_for_household_rent","is_non_dependant_of_household_head","pays_rent_to_householder","personal_rent","share_of_household_rent","uc_non_dependants_counted"],"benunit_has_carer":["uc_carer_element"],"benunit_is_rent_liable":["housing_benefit_individual_non_dep_deduction_eligible","housing_benefit_shares_accommodation","is_non_dependant_of_household_head","uc_individual_non_dep_deduction_eligible","uc_non_dep_receives_pension_credit"],"benunit_is_renting":["LHA_eligible","maintenance_loan_household_income","maintenance_loan_living_arrangement"],"benunit_rent":["LHA_cap","benunit_is_rent_liable","housing_benefit_entitlement","uc_LHA_cap","uc_housing_costs_element"],"benunit_reported_capital":["pension_credit_reported_capital","uc_reported_capital"],"benunit_tenure_type":["benunit_is_renting","in_social_housing","uc_housing_costs_element"],"bi_household_phaseout":["bi_phaseout"],"bi_individual_phaseout":["bi_household_phaseout","bi_phaseout"],"bi_maximum":["basic_income","bi_household_phaseout","bi_individual_phaseout"],"bi_phaseout":["basic_income"],"blind_persons_allowance":["allowances","esa_exempt_work_earnings","property_finance_costs_relieved"],"brma":["BRMA_LHA_rate","housing_benefit_LHA_rate","uc_LHA_cap","uncapped_BRMA_LHA_rate"],"bsp":["gov_spending","hbai_benefits","hbai_household_net_income","household_benefits","pre_budget_change_household_benefits"],"bsp_reported":["bsp"],"bursary_fund_16_to_19":["gov_spending","hbai_benefits","household_benefits"],"bursary_fund_16_to_19_age_eligible":["bursary_fund_16_to_19_vulnerable_group_eligible"],"bursary_fund_16_to_19_in_care_or_care_leaver":["bursary_fund_16_to_19_vulnerable_group_eligible"],"bursary_fund_16_to_19_in_qualifying_education":["bursary_fund_16_to_19_vulnerable_group_eligible"],"bursary_fund_16_to_19_receives_uc_or_esa_in_own_right":["bursary_fund_16_to_19_vulnerable_group_eligible"],"bursary_fund_16_to_19_receives_uc_or_is_in_own_right":["bursary_fund_16_to_19_vulnerable_group_eligible"],"bursary_fund_16_to_19_self_supporting":["bursary_fund_16_to_19_vulnerable_group_eligible"],"bursary_fund_16_to_19_vulnerable_group_eligible":["bursary_fund_16_to_19"],"bus_fare_spending_reported":["person_bus_fare_spending"],"bus_in_london_trips":["local_bus_trips"],"bus_subsidy_spending":["dft_subsidy_spending"],"business_rates":["corporate_tax_incidence","gov_tax","household_tax","pre_budget_change_household_tax"],"capital_allowances":["ni_class_4_profits_before_losses","taxable_self_employment_income","trading_allowance_deduction"],"capital_gains":["capital_gains_tax","household_market_income","marginal_tax_rate_on_capital_gains"],"capital_gains_badr":["capital_gains_tax"],"capital_gains_badr_behavioural_response":["capital_gains_tax","marginal_tax_rate_on_capital_gains"],"capital_gains_before_response":["adult_index_cg","capital_gains","capital_gains_tax","relative_capital_gains_mtr_change","relative_capital_gains_retention_rate_change","relative_income_change","relative_wage_change"],"capital_gains_behavioural_response":["capital_gains","capital_gains_tax","marginal_tax_rate_on_capital_gains"],"capital_gains_carried_interest":["capital_gains_tax"],"capital_gains_elasticity":["capital_gains_badr_elasticity"],"capital_gains_residential_property":["capital_gains_tax"],"capital_gains_tax":["gov_tax","household_tax","pre_budget_change_household_tax"],"capped_mcad":["income_tax","property_finance_cost_relief","uc_income_tax_on_earnings","uc_income_tax_on_trade"],"car_co2_emissions":["car_vehicle_excise_duty"],"car_engine_size":["car_vehicle_excise_duty"],"car_first_registration_date":["car_vehicle_excise_duty"],"car_fuel_type":["car_vehicle_excise_duty"],"car_is_ved_exempt":["car_vehicle_excise_duty"],"car_list_price":["car_vehicle_excise_duty"],"car_vehicle_excise_duty":["vehicle_excise_duty"],"carbon_consumption":["carbon_tax"],"carbon_tax":["gov_tax","household_tax","pre_budget_change_household_tax"],"care_hours":["carer_support_payment_pre_overlap","carers_allowance_pre_overlap","is_carer_for_benefits","partners_care_for_same_severely_disabled_person"],"care_to_learn":["gov_spending","household_benefits"],"care_to_learn_eligible":["care_to_learn"],"care_to_learn_qualifying_child":["care_to_learn_eligible"],"carer_minimum_guarantee_addition":["additional_minimum_guarantee"],"carer_premium":["pension_age_benefits_premiums","working_age_benefits_premiums"],"carer_support_payment":["gov_spending","hbai_benefits","hbai_household_net_income","household_benefits","housing_benefit_applicable_income","pension_credit_income","pre_budget_change_household_benefits","receives_carer_support_payment","scottish_carer_supplement","social_security_income","tax_free_childcare_regarded_as_in_paid_work","uc_unearned_carer_support_payment"],"carer_support_payment_overlapping_benefits":["carer_support_payment"],"carer_support_payment_pre_overlap":["carer_support_payment","council_tax_reduction_applicable_income","is_entitled_to_carer_benefit"],"carers_allowance":["council_tax_reduction_applicable_income","gov_spending","hbai_benefits","hbai_household_net_income","household_benefits","housing_benefit_applicable_income","pension_credit_income","pre_budget_change_household_benefits","receives_carers_allowance","social_security_income","tax_free_childcare_regarded_as_in_paid_work","uc_unearned_income"],"carers_allowance_earnings":["is_gainfully_employed_for_carers_allowance"],"carers_allowance_overlapping_benefits":["carers_allowance"],"carers_allowance_pre_overlap":["carers_allowance","is_entitled_to_carer_benefit"],"carers_allowance_reported":["carer_support_payment_pre_overlap","carers_allowance_pre_overlap","is_carer_for_benefits","partners_care_for_same_severely_disabled_person"],"charitable_investment_gifts":["allowances","property_finance_costs_relieved"],"child_benefit":["CB_HITC","benefit_cap_reduction","child_benefit_less_tax_charge","council_tax_reduction_applicable_income","gov_spending","hbai_benefits","hbai_household_net_income","household_benefits","housing_benefit_applicable_income","oxford_council_tax_reduction","pre_budget_change_household_benefits"],"child_benefit_child_index":["child_benefit_respective_amount"],"child_benefit_entitlement":["child_benefit"],"child_benefit_opts_out":["child_benefit"],"child_benefit_respective_amount":["child_benefit_entitlement"],"child_ema":["student_payments"],"child_index":["is_eldest_child"],"child_minimum_guarantee_addition":["additional_minimum_guarantee"],"child_tax_credit":["benefit_cap_reduction","ctc_child_limit_affected","gov_spending","hbai_benefits","hbai_household_net_income","household_benefits","is_scp_eligible","meets_child_tax_credit_criteria_for_targeted_childcare_entitlement","pre_budget_change_household_benefits","tax_free_childcare_program_eligible"],"child_tax_credit_pre_minimum":["ctc_entitlement"],"child_tax_credit_reported":["claims_all_entitled_benefits","claims_legacy_benefits","is_CTC_eligible","legacy_benefits_closed","pawhp_eligible","tax_credit_award","winter_fuel_payment_eligible","would_claim_CTC"],"childcare_expenses":["housing_benefit_applicable_income_childcare_element","tax_free_childcare","uc_childcare_element","weekly_childcare_expenses"],"childcare_grant":["gov_spending","hbai_benefits","household_benefits"],"childcare_grant_child_eligible":["childcare_grant_eligible_children"],"childcare_grant_child_has_special_educational_needs":["childcare_grant_child_eligible"],"childcare_grant_eligible":["childcare_grant"],"childcare_grant_eligible_children":["childcare_grant_eligible"],"childcare_grant_full_time_student":["childcare_grant_eligible"],"childcare_grant_household_income":["childcare_grant_eligible"],"childcare_grant_provider_is_nanny":["childcare_grant_uses_qualifying_provider"],"childcare_grant_receives_nhs_childcare_support":["childcare_grant_eligible"],"childcare_grant_receives_postgraduate_loan":["childcare_grant_eligible"],"childcare_grant_student_finance_eligible":["childcare_grant_eligible"],"childcare_grant_uses_qualifying_provider":["childcare_grant_eligible"],"cider_abv":["cider_duty"],"cider_draught_share":["cider_duty"],"cider_duty":["alcohol_duty"],"cider_litres":["cider_duty"],"cigarette_price_per_pack":["tobacco_duty"],"cigarettes_per_week":["tobacco_duty"],"cigars_grams_per_week":["tobacco_duty"],"claimant_or_partner_esa_income":["council_tax_reduction_applicable_income","council_tax_reduction_relevant_income_based_benefit","extended_childcare_entitlement_limited_capability_or_specified_benefit","housing_benefit_applicable_income","in_receipt_of_income_support_jsa_ib_or_esa_ir","is_on_income_related_esa","is_scp_eligible","targeted_childcare_entitlement_eligible","tax_credits_applicable_income"],"claimant_or_partner_jsa_income":["council_tax_reduction_applicable_income","council_tax_reduction_relevant_income_based_benefit","housing_benefit_applicable_income","in_receipt_of_income_support_jsa_ib_or_esa_ir","is_on_income_based_jsa","is_scp_eligible","targeted_childcare_entitlement_eligible","tax_credits_applicable_income"],"claims_all_entitled_benefits":["would_claim_CTC","would_claim_IS","would_claim_WTC","would_claim_council_tax_reduction","would_claim_housing_benefit"],"claims_legacy_benefits":["is_benefit_cap_exempt_health_disability","is_benefit_cap_single_claimant_rate","is_lha_shared_accommodation_rate_specified_renter"],"claims_uc_at_legacy_closure":["claims_universal_credit","council_tax_reduction_pensioner","is_uc_eligible","left_pension_route_at_legacy_closure"],"claims_universal_credit":["housing_benefit_eligible","is_CTC_eligible","is_benefit_cap_exempt_health_disability","is_benefit_cap_single_claimant_rate","is_lha_shared_accommodation_rate_specified_renter","uc_has_deduction","uc_non_dependants_counted","universal_credit","universal_credit_pre_benefit_cap"],"cliff_gap":["is_on_cliff"],"clothing_and_footwear_consumption":["carbon_consumption","consumption"],"communication_consumption":["carbon_consumption","consumption"],"consumer_debt":["net_wealth"],"consumer_incident_tax_revenue_change":["gov_tax","household_tax"],"consumption":["consumer_incident_tax_revenue_change","consumption_shareholding","full_rate_vat_consumption","reduced_rate_vat_consumption"],"corporate_incident_tax_revenue_change":["gov_tax","household_tax"],"corporate_land_value":["LVT","land_value"],"corporate_sdlt":["corporate_tax_incidence","expected_sdlt","gov_tax","household_tax","pre_budget_change_household_tax"],"corporate_sector_wealth":["corporate_land_value","shareholding"],"corporate_tax_incidence":["hbai_excluded_income"],"corporate_wealth":["corporate_sector_wealth","esa_income_assessable_capital","household_uc_pool_company_holdings","housing_benefit_assessable_capital","income_support_assessable_capital","jsa_income_assessable_capital","pension_credit_assessable_capital","total_wealth","uc_assessable_capital"],"cost_of_living_support_payment":["gov_spending","hbai_benefits","hbai_household_net_income","household_benefits","pre_budget_change_household_benefits"],"council_tax":["council_tax_less_benefit","council_tax_reduction_maximum_eligible_liability","gov_tax","hbai_household_net_income","household_tax","pre_budget_change_household_tax"],"council_tax_band":["ebr_council_tax_rebate"],"council_tax_benefit":["council_tax_reduction","gov_spending","hbai_household_net_income","household_benefits","pre_budget_change_household_benefits"],"council_tax_benefit_reported":["council_tax_benefit","would_claim_council_tax_reduction"],"council_tax_reduction":["council_tax_less_benefit"],"council_tax_reduction_applicable_amount":["kingston_upon_thames_council_tax_reduction","merton_council_tax_reduction","newham_council_tax_reduction","simulated_council_tax_reduction_benunit","westminster_council_tax_reduction"],"council_tax_reduction_applicable_income":["kingston_upon_thames_council_tax_reduction","merton_council_tax_reduction","newham_council_tax_reduction","oxford_council_tax_reduction","simulated_council_tax_reduction_benunit","westminster_council_tax_reduction"],"council_tax_reduction_applicant_has_non_dep_exemption":["kingston_upon_thames_council_tax_reduction_non_dep_deductions","merton_council_tax_reduction_non_dep_deductions","newham_council_tax_reduction_non_dep_deductions","oxford_council_tax_reduction_non_dep_deductions","westminster_council_tax_reduction_non_dep_deductions"],"council_tax_reduction_assessable_capital":["simulated_council_tax_reduction_benunit"],"council_tax_reduction_claimant_benunit":["council_tax_benefit","council_tax_reduction_household_has_simulated_claim","council_tax_reduction_individual_non_dep_deduction_eligible","kingston_upon_thames_council_tax_reduction","merton_council_tax_reduction","newham_council_tax_reduction","oxford_council_tax_reduction","simulated_council_tax_reduction_benunit","westminster_council_tax_reduction"],"council_tax_reduction_claims_are_joint":["council_tax_reduction_claimant_benunit"],"council_tax_reduction_head_applies_alone":["council_tax_reduction_pensioner","is_council_tax_reduction_applicant_or_partner"],"council_tax_reduction_household_has_simulated_claim":["council_tax_benefit"],"council_tax_reduction_individual_non_dep_deduction":["council_tax_reduction_non_dep_deductions"],"council_tax_reduction_individual_non_dep_deduction_eligible":["council_tax_reduction_individual_non_dep_deduction","kingston_upon_thames_council_tax_reduction_individual_non_dep_deduction","merton_council_tax_reduction_individual_non_dep_deduction","newham_council_tax_reduction_individual_non_dep_deduction","oxford_council_tax_reduction_individual_non_dep_deduction","westminster_council_tax_reduction_individual_non_dep_deduction"],"council_tax_reduction_joint_liability_share":["council_tax_benefit","council_tax_reduction_non_dep_deductions","kingston_upon_thames_council_tax_reduction","kingston_upon_thames_council_tax_reduction_non_dep_deductions","merton_council_tax_reduction","merton_council_tax_reduction_non_dep_deductions","newham_council_tax_reduction","newham_council_tax_reduction_non_dep_deductions","oxford_council_tax_reduction","oxford_council_tax_reduction_non_dep_deductions","simulated_council_tax_reduction_benunit","westminster_council_tax_reduction","westminster_council_tax_reduction_non_dep_deductions"],"council_tax_reduction_liable_person":["council_tax_benefit","council_tax_reduction_claimant_benunit","council_tax_reduction_head_applies_alone","council_tax_reduction_joint_liability_share","is_council_tax_reduction_applicant_or_partner"],"council_tax_reduction_maximum_eligible_liability":["council_tax_benefit","kingston_upon_thames_council_tax_reduction","merton_council_tax_reduction","newham_council_tax_reduction","oxford_council_tax_reduction","simulated_council_tax_reduction_benunit","westminster_council_tax_reduction"],"council_tax_reduction_non_dep_deductions":["simulated_council_tax_reduction_benunit"],"council_tax_reduction_pensioner":["council_tax_reduction_applicable_amount","council_tax_reduction_pensioner_earnings_disregard","council_tax_reduction_scheme_supported","is_child_or_young_person_for_council_tax_reduction","kingston_upon_thames_council_tax_reduction","merton_council_tax_reduction","newham_council_tax_reduction","oxford_council_tax_reduction","simulated_council_tax_reduction_benunit","westminster_council_tax_reduction"],"council_tax_reduction_pensioner_earnings_disregard":["council_tax_reduction_applicable_income"],"council_tax_reduction_relevant_income_based_benefit":["council_tax_reduction_pensioner","housing_benefit_pension_age_regulations_apply","kingston_upon_thames_council_tax_reduction","merton_council_tax_reduction","newham_council_tax_reduction","oxford_council_tax_reduction","westminster_council_tax_reduction"],"council_tax_reduction_scheme_supported":["council_tax_benefit","council_tax_reduction_household_has_simulated_claim"],"country":["adult_dependants_grant_eligible","bursary_fund_16_to_19_vulnerable_group_eligible","care_to_learn_eligible","carer_support_payment_pre_overlap","carers_allowance_pre_overlap","childcare_grant_eligible","council_tax_reduction_pensioner","council_tax_reduction_pensioner_earnings_disregard","council_tax_reduction_scheme_supported","extended_childcare_entitlement_qualifying_child","housing_benefit_on_passporting_benefit","is_child_or_young_person_for_council_tax_reduction","is_scp_eligible","kingston_upon_thames_council_tax_reduction","lbtt_liable","ltt_liable","maintenance_loan_in_england_system","merton_council_tax_reduction","monthly_ebr_energy_bills_credit","newham_council_tax_reduction","oxford_council_tax_reduction","parents_learning_allowance_eligible","partners_care_for_same_severely_disabled_person","pawhp_eligible","pays_scottish_income_tax","receives_severe_disability_premium_qualifying_benefit","scottish_funded_early_learning_childcare_eligible","sdlt_liable","simulated_council_tax_reduction_benunit","targeted_childcare_entitlement_eligible","travel_grant_eligible","two_child_limit_payment","universal_childcare_entitlement_eligible","westminster_council_tax_reduction","winter_fuel_payment_eligible"],"covenanted_payments":["allowances"],"ctc_entitlement":["child_tax_credit"],"cumulative_non_residential_rent":["lbtt_on_non_residential_property_rent","ltt_on_non_residential_property_rent","sdlt_on_non_residential_property_rent"],"cumulative_residential_rent":["lbtt_on_residential_property_rent","ltt_on_residential_property_rent","sdlt_on_residential_property_rent"],"current_education":["bursary_fund_16_to_19_in_qualifying_education","care_to_learn_eligible","council_tax_benefit","is_in_non_advanced_education","maintenance_loan_in_higher_education"],"date_of_birth":["birth_year","child_minimum_guarantee_addition","has_attained_state_pension_credit_qualifying_age","has_mixed_age_couple_pension_credit_saving","is_CTC_child_limit_exempt","meets_savings_credit_age_requirement","months_since_state_pension_age","state_pension_age","state_pension_credit_qualifying_age","uc_child_index","uc_is_child_born_before_child_limit"],"deductible_property_finance_costs":["property_allowance_deduction_if_used","taxable_property_income","uses_property_allowance"],"deep_poverty_gap":["in_deep_poverty"],"deep_poverty_line":["deep_poverty_gap"],"deficiency_relief":["taxable_dividend_income"],"dfe_education_spending":["gov_spending","household_benefits"],"dft_subsidy_spending":["gov_spending","household_benefits"],"diesel_litres":["fuel_duty"],"diesel_price":["diesel_litres"],"diesel_spending":["diesel_litres"],"disability_basic_income":["gov_spending","household_benefits","pre_budget_change_household_benefits"],"disability_premium":["maintenance_loan_entitled_to_benefits","working_age_benefits_premiums"],"disabled_students_allowance":["gov_spending","hbai_benefits","household_benefits"],"disabled_students_allowance_course_eligible":["disabled_students_allowance_eligible"],"disabled_students_allowance_eligible":["disabled_students_allowance"],"disabled_students_allowance_eligible_expenses":["disabled_students_allowance_eligible"],"disabled_students_allowance_has_qualifying_condition":["disabled_students_allowance_eligible"],"disabled_students_allowance_receives_equivalent_support":["disabled_students_allowance_eligible"],"dividend_income":["capital_income","hbai_household_net_income","household_market_income","housing_benefit_net_earnings","market_income","tax_credits_current_year_income","taxable_dividend_income","total_income"],"dividend_income_tax":["income_tax","income_tax_pre_charges"],"dla":["bursary_fund_16_to_19_vulnerable_group_eligible","child_minimum_guarantee_addition","cost_of_living_support_payment","disability_basic_income","gov_spending","hbai_benefits","hbai_household_net_income","household_benefits","is_benefit_cap_exempt_health_disability","pre_budget_change_household_benefits"],"dla_m":["dla","maintenance_loan_entitled_to_benefits"],"dla_m_category":["dla_m"],"dla_sc":["council_tax_reduction_applicant_has_non_dep_exemption","dla","is_enhanced_disabled_for_benefits","is_severely_disabled_for_benefits","maintenance_loan_entitled_to_benefits"],"dla_sc_category":["dla_sc","dla_sc_middle_plus","receives_highest_dla_sc"],"dla_sc_middle_plus":["housing_benefit_severe_disability_premium_applies","is_lha_shared_accommodation_rate_specified_renter","is_severely_disabled_for_carers_allowance","receives_severe_disability_addition_qualifying_benefit","receives_severe_disability_premium_qualifying_benefit","uc_non_dep_deduction_exempt"],"domestic_energy_consumption":["monthly_domestic_energy_consumption"],"domestic_rates":["gov_tax","hbai_household_net_income","household_tax","pre_budget_change_household_tax"],"earned_income_tax":["income_tax","income_tax_pre_charges"],"earned_taxable_income":["add_rate_earned_income","basic_rate_earned_income","earned_income_tax","higher_rate_earned_income","non_savings_taxable_income","uc_income_tax_on_earnings","uc_income_tax_on_trade"],"ebr_council_tax_rebate":["energy_bills_rebate"],"ebr_energy_bills_credit":["energy_bills_rebate"],"ebr_energy_bills_credit_eligible":["monthly_ebr_energy_bills_credit"],"education_consumption":["carbon_consumption","consumption"],"education_grants":["student_payments"],"eldest_child_age":["is_benunit_eldest_child"],"eldest_claimant_or_partner_age":["council_tax_reduction_applicable_amount","housing_benefit_applicable_amount","housing_benefit_specified_or_temporary_accommodation_disregard","income_support_applicable_amount","is_WTC_eligible","is_housing_benefit_young_individual"],"employee_pension_contributions":["carers_allowance_earnings","esa_exempt_work_earnings","hbai_household_net_income","pension_contributions","pension_contributions_for_annual_allowance"],"employee_pension_contributions_reported":["employee_pension_contributions"],"employer_cost":["marginal_tax_rate_wrt_employer_cost"],"employer_ni_fixed_employer_cost_change":["employment_income"],"employer_ni_response_capital_incidence":["household_tax"],"employer_ni_response_consumer_incidence":["household_tax"],"employer_pension_contributions":["adjusted_employer_cost","baseline_employer_cost","employer_cost","employer_ni_fixed_employer_cost_change","pension_contributions_for_annual_allowance"],"employment_benefits":["housing_benefit_net_earnings","housing_benefit_specified_or_temporary_accommodation_disregard","taxable_employment_income"],"employment_deductions":["esa_exempt_work_earnings","taxable_employment_income"],"employment_expenses":["employment_deductions"],"employment_income":["adjusted_employer_cost","carers_allowance_earnings","council_tax_reduction_applicable_income","earned_income","employer_cost","esa_exempt_work_earnings","extended_childcare_entitlement_meets_income_requirements","hbai_household_net_income","household_market_income","housing_benefit_applicable_income","housing_benefit_net_earnings","housing_benefit_specified_or_temporary_accommodation_disregard","in_work","income_support_applicable_income","marginal_tax_rate","marginal_tax_rate_wrt_employer_cost","market_income","ni_class_1_income","pension_contributions_relief","pension_credit_earnings","salary_sacrifice_pension_ni_employee","tax_credits_current_year_income","tax_free_childcare_expected_declaration_period_income","taxable_employment_income","total_income","uc_individual_earned_income_before_mif"],"employment_income_before_lsr":["baseline_employer_cost","employer_ni_fixed_employer_cost_change","employment_income","income_elasticity_lsr","pension_contributions_via_salary_sacrifice_from_pay","substitution_elasticity_lsr"],"employment_income_behavioral_response":["baseline_employer_cost","employer_ni_fixed_employer_cost_change","employment_income"],"energy_bills_rebate":["gov_spending","household_benefits","pre_budget_change_household_benefits"],"enhanced_disability_premium":["working_age_benefits_premiums"],"epg_subsidy":["gov_spending","household_benefits","pre_budget_change_household_benefits"],"equiv_hbai_household_net_income":["household_income_decile","in_deep_poverty_bhc","in_poverty_bhc","in_relative_poverty_bhc"],"equiv_hbai_household_net_income_ahc":["in_deep_poverty_ahc","in_poverty_ahc","in_relative_poverty_ahc"],"esa_contrib":["benefit_cap_reduction","carer_support_payment_overlapping_benefits","carers_allowance_overlapping_benefits","council_tax_reduction_applicable_income","esa","extended_childcare_entitlement_limited_capability_or_specified_benefit","gov_spending","has_own_esa_award","hbai_benefits","hbai_household_net_income","household_benefits","housing_benefit_applicable_income","income_support_eligible","is_benefit_cap_exempt_health_disability","pension_credit_income","pre_budget_change_household_benefits","savings_credit_income","tax_free_childcare_caring_or_incapacity_benefit","tax_free_childcare_regarded_as_in_paid_work","uc_unearned_income"],"esa_contrib_reported":["bursary_fund_16_to_19_receives_uc_or_esa_in_own_right","esa_contrib","social_security_income"],"esa_exempt_work_earnings":["esa_income_claimant_remunerative_work"],"esa_includes_support_component":["is_benefit_cap_exempt_health_disability","uc_limited_capability_for_WRA"],"esa_income":["benefit_cap_reduction","claimant_or_partner_esa_income","cost_of_living_support_payment","esa","gov_spending","has_own_esa_award","hbai_benefits","hbai_household_net_income","household_benefits","income_support_eligible","is_benefit_cap_exempt_health_disability","is_on_income_related_esa","pre_budget_change_household_benefits"],"esa_income_assessable_capital":["esa_income_eligible","esa_income_tariff_income","is_on_income_related_esa"],"esa_income_claimant_remunerative_work":["esa_income_eligible","is_on_income_related_esa"],"esa_income_eligible":["benefit_cap_reduction","claimant_or_partner_esa_income","esa_income","income_support_eligible","is_benefit_cap_exempt_health_disability","is_on_income_related_esa"],"esa_income_remunerative_work_hours":["esa_income_claimant_remunerative_work","esa_income_eligible"],"esa_income_reported":["benefit_cap_reduction","bursary_fund_16_to_19_receives_uc_or_esa_in_own_right","claimant_or_partner_esa_income","claims_all_entitled_benefits","claims_legacy_benefits","esa_income","esa_income_assessable_capital","esa_income_eligible","has_mixed_age_couple_pension_credit_saving","has_own_esa_award","income_support_eligible","is_benefit_cap_exempt_health_disability","is_on_income_related_esa","pawhp_eligible","winter_fuel_payment_eligible"],"esa_income_tariff_income":["benefit_cap_reduction","claimant_or_partner_esa_income","esa_income","income_support_eligible","is_benefit_cap_exempt_health_disability","is_on_income_related_esa"],"expected_lbtt":["gov_tax","household_tax","pre_budget_change_household_tax"],"expected_ltt":["gov_tax","household_tax","pre_budget_change_household_tax"],"expected_sdlt":["gov_tax","household_tax","pre_budget_change_household_tax"],"extended_childcare_entitlement":["gov_spending","household_benefits","is_child_receiving_extended_childcare"],"extended_childcare_entitlement_eligible":["extended_childcare_entitlement","extended_childcare_entitlement_per_child","extended_childcare_entitlement_total_per_child"],"extended_childcare_entitlement_limited_capability_or_specified_benefit":["extended_childcare_entitlement_work_condition"],"extended_childcare_entitlement_meets_income_requirements":["extended_childcare_entitlement_work_condition"],"extended_childcare_entitlement_per_child":["extended_childcare_entitlement","is_child_receiving_extended_childcare"],"extended_childcare_entitlement_qualifying_child":["extended_childcare_entitlement_eligible","extended_childcare_entitlement_total_per_child","is_child_receiving_extended_childcare"],"extended_childcare_entitlement_total_per_child":["extended_childcare_entitlement_per_child","targeted_childcare_entitlement","universal_childcare_entitlement"],"extended_childcare_entitlement_work_condition":["extended_childcare_entitlement_eligible"],"external_child_payments":["hbai_household_net_income"],"food_and_non_alcoholic_beverages_consumption":["carbon_consumption","consumption"],"free_school_fruit_veg":["hbai_household_net_income"],"free_school_meals":["hbai_household_net_income"],"free_school_milk":["hbai_household_net_income"],"free_tv_licence_value":["hbai_household_net_income"],"fuel_duty":["gov_tax","household_tax","pre_budget_change_household_tax"],"full_rate_vat_consumption":["baseline_vat","vat"],"full_rate_vat_expenditure_rate":["full_rate_vat_consumption"],"gender":["is_female","is_male"],"gift_aid":["gift_aid_grossed_up"],"gift_aid_grossed_up":["add_rate_earned_income","add_rate_savings_income","adjusted_net_income","basic_rate_earned_income","basic_rate_savings_income","basic_rate_savings_income_pre_starter","capital_gains_tax","dividend_income_tax","earned_income_tax","higher_rate_earned_income","higher_rate_savings_income","property_income_tax","savings_allowance","tax_band","uc_income_tax_on_earnings","uc_income_tax_on_trade"],"gov_spending":["gov_balance"],"gov_tax":["gov_balance"],"guarantee_credit":["in_receipt_of_guarantee_credit","in_receipt_of_savings_credit_only","pension_credit_entitlement","targeted_childcare_entitlement_eligible"],"hand_rolling_tobacco_grams_per_week":["tobacco_duty"],"has_attained_state_pension_credit_qualifying_age":["council_tax_reduction_pensioner","has_mixed_age_couple_pension_credit_saving","housing_benefit_pension_age_regulations_apply","income_support_eligible","is_mixed_age_couple","is_on_pension_credit","is_uc_eligible","meets_pension_credit_age_conditions","pension_age_severe_disability_premium","pension_credit_assessable_capital","uc_member_of_couple_claims_as_single_person","uc_work_related_group_apart_from_earnings","winter_fuel_payment_eligible"],"has_mixed_age_couple_pension_credit_saving":["meets_pension_credit_age_conditions"],"has_non_dependant_for_severe_disability_premium":["severe_disability_premium"],"has_own_esa_award":["esa_includes_support_component","uc_limited_capability_for_WRA"],"hbai_excluded_income":["baseline_hbai_excluded_income","hbai_excluded_income_change"],"hbai_household_net_income":["deep_poverty_gap","equiv_hbai_household_net_income","hbai_household_net_income_ahc","poverty_gap","poverty_gap_bhc","real_hbai_household_net_income"],"hbai_household_net_income_ahc":["equiv_hbai_household_net_income_ahc","poverty_gap_ahc","real_hbai_household_net_income_ahc"],"health_consumption":["carbon_consumption","consumption"],"healthy_start_vouchers":["gov_spending","hbai_benefits","hbai_household_net_income","household_benefits"],"heated_tobacco_grams_per_week":["tobacco_duty"],"high_value_council_tax_surcharge":["gov_tax","household_tax"],"higher_rate_earned_income":["higher_rate_earned_income_tax"],"higher_rate_savings_income":["savings_income_tax","taxed_savings_income"],"hours_worked":["in_work","uc_is_responsible_carer","weekly_hours"],"household_benefits":["household_gross_income","household_net_income","household_net_income_ahc"],"household_benefits_individual_non_dep_deduction":["housing_benefit_non_dep_deductions"],"household_bus_fare_age_weight":["person_bus_fare_spending"],"household_count_people":["household_income_decile","household_wealth_decile","in_relative_poverty_ahc","in_relative_poverty_bhc"],"household_equivalisation_ahc":["equiv_hbai_household_net_income_ahc","poverty_line_ahc"],"household_equivalisation_bhc":["equiv_hbai_household_net_income","equiv_household_net_income","poverty_line","poverty_line_bhc","pre_budget_change_ons_household_income_decile"],"household_furnishings_consumption":["carbon_consumption","consumption"],"household_income_decile":["income_decile"],"household_land_value":["LVT","land_value"],"household_market_income":["household_gross_income","household_net_income","household_net_income_ahc","pre_budget_change_household_net_income"],"household_net_income":["equiv_household_net_income","marginal_tax_rate","marginal_tax_rate_on_capital_gains","marginal_tax_rate_wrt_employer_cost","real_household_net_income","relative_income_change"],"household_net_income_ahc":["real_household_net_income_ahc"],"household_owns_tv":["free_tv_licence_value","tv_licence"],"household_tax":["household_net_income","household_net_income_ahc"],"household_uc_pool_company_holdings":["uc_assessable_capital"],"household_uc_reported_capital":["uc_assessable_capital"],"household_uc_unreported_claimants":["uc_assessable_capital"],"household_weight":["carbon_tax","corporate_land_value","household_income_decile","household_wealth_decile","in_relative_poverty_ahc","in_relative_poverty_bhc","person_weight","pre_budget_change_ons_household_income_decile"],"housing_benefit":["cost_of_living_support_payment","gov_spending","hbai_benefits","hbai_household_net_income","household_benefits","pre_budget_change_household_benefits"],"housing_benefit_LHA_allowed_bedrooms":["housing_benefit_LHA_category"],"housing_benefit_LHA_category":["housing_benefit_LHA_rate"],"housing_benefit_LHA_rate":["LHA_cap"],"housing_benefit_applicable_amount":["housing_benefit_entitlement"],"housing_benefit_applicable_income":["housing_benefit_entitlement"],"housing_benefit_applicable_income_childcare_element":["housing_benefit_applicable_income","housing_benefit_applicable_income_disregard","housing_benefit_savings_credit_only_income"],"housing_benefit_applicable_income_disregard":["housing_benefit_applicable_income","housing_benefit_savings_credit_only_income"],"housing_benefit_assessable_capital":["housing_benefit_eligible","housing_benefit_tariff_income"],"housing_benefit_board_and_attendance_determination":["LHA_cap"],"housing_benefit_eligible":["housing_benefit_applicable_amount","housing_benefit_pre_benefit_cap"],"housing_benefit_entitlement":["housing_benefit_pre_benefit_cap"],"housing_benefit_has_non_dependant":["housing_benefit_LHA_category"],"housing_benefit_individual_non_dep_deduction_eligible":["household_benefits_individual_non_dep_deduction"],"housing_benefit_meals_deduction":["LHA_cap","housing_benefit_entitlement"],"housing_benefit_net_earnings":["council_tax_reduction_pensioner_earnings_disregard","housing_benefit_applicable_income_disregard"],"housing_benefit_non_dep_deductions":["housing_benefit_entitlement"],"housing_benefit_on_passporting_benefit":["housing_benefit_applicable_income","housing_benefit_applicable_income_disregard","housing_benefit_assessable_capital"],"housing_benefit_pension_age_regulations_apply":["benefits_premiums","housing_benefit_applicable_amount","housing_benefit_applicable_income","housing_benefit_assessable_capital","housing_benefit_eligible","housing_benefit_specified_or_temporary_accommodation_disregard","housing_benefit_tariff_income","is_benefit_cap_exempt_other"],"housing_benefit_pre_benefit_cap":["benefit_cap_reduction","housing_benefit"],"housing_benefit_reported":["claims_all_entitled_benefits","claims_legacy_benefits","has_mixed_age_couple_pension_credit_saving","housing_benefit_eligible","would_claim_housing_benefit"],"housing_benefit_savings_credit_only_income":["housing_benefit_applicable_income"],"housing_benefit_severe_disability_premium_applies":["housing_benefit_LHA_category"],"housing_benefit_shares_accommodation":["housing_benefit_LHA_category"],"housing_benefit_specified_or_temporary_accommodation_disregard":["housing_benefit_applicable_income_disregard"],"housing_benefit_tariff_income":["housing_benefit_applicable_income"],"housing_costs":["household_net_income_ahc"],"housing_water_and_electricity_consumption":["carbon_consumption","consumption"],"iidb":["gov_spending","hbai_benefits","hbai_household_net_income","household_benefits","is_benefit_cap_exempt_health_disability","pre_budget_change_household_benefits","uc_unearned_income"],"iidb_reported":["iidb"],"in_FE":["council_tax_benefit"],"in_HE":["council_tax_benefit","council_tax_reduction_claimant_benunit","council_tax_reduction_joint_liability_share","maintenance_loan_has_sponsor","maintenance_loan_in_higher_education","maintenance_loan_sponsor_income"],"in_receipt_of_guarantee_credit":["council_tax_reduction_applicable_income","council_tax_reduction_assessable_capital","housing_benefit_applicable_income","housing_benefit_assessable_capital","housing_benefit_tariff_income"],"in_receipt_of_income_support_jsa_ib_or_esa_ir":["housing_benefit_on_passporting_benefit"],"in_receipt_of_savings_credit_only":["council_tax_reduction_applicable_income","council_tax_reduction_assessable_capital","housing_benefit_applicable_income","housing_benefit_assessable_capital","housing_benefit_tariff_income"],"in_rural_fuel_duty_relief_area":["fuel_duty"],"in_social_housing":["LHA_eligible","housing_benefit_eligible"],"in_specified_or_temporary_accommodation":["housing_benefit_specified_or_temporary_accommodation_disregard"],"in_work":["extended_childcare_entitlement_work_condition","tax_free_childcare_treated_as_in_work","uc_childcare_work_condition"],"incapacity_benefit":["benefit_cap_reduction","carer_support_payment_overlapping_benefits","carers_allowance_overlapping_benefits","extended_childcare_entitlement_limited_capability_or_specified_benefit","gov_spending","hbai_benefits","hbai_household_net_income","household_benefits","pre_budget_change_household_benefits","social_security_income","tax_free_childcare_caring_or_incapacity_benefit","tax_free_childcare_regarded_as_in_paid_work"],"incapacity_benefit_reported":["incapacity_benefit"],"income_support":["benefit_cap_reduction","cost_of_living_support_payment","council_tax_reduction_applicable_income","council_tax_reduction_relevant_income_based_benefit","gov_spending","hbai_benefits","hbai_household_net_income","household_benefits","housing_benefit_applicable_income","in_receipt_of_income_support_jsa_ib_or_esa_ir","is_on_income_support","is_scp_eligible","pre_budget_change_household_benefits","targeted_childcare_entitlement_eligible","tax_credits_applicable_income"],"income_support_applicable_amount":["income_support_entitlement"],"income_support_applicable_income":["income_support_entitlement"],"income_support_assessable_capital":["income_support_eligible","income_support_tariff_income"],"income_support_eligible":["income_support_entitlement"],"income_support_remunerative_work_hours":["income_support_eligible"],"income_support_reported":["bursary_fund_16_to_19_receives_uc_or_is_in_own_right","claims_all_entitled_benefits","claims_legacy_benefits","has_mixed_age_couple_pension_credit_saving","income_support_eligible","is_on_income_support","legacy_benefits_closed","pawhp_eligible","winter_fuel_payment_eligible","would_claim_IS"],"income_support_tariff_income":["income_support_applicable_income"],"income_tax":["council_tax_reduction_applicable_income","gov_tax","hbai_household_net_income","household_tax","housing_benefit_applicable_income","housing_benefit_net_earnings","income_support_applicable_income","pension_credit_income","post_tax_income","pre_budget_change_household_tax","tax"],"income_tax_pre_charges":["capped_mcad","property_finance_cost_relief"],"individual_savings_account_interest_income":["tax_free_savings_income"],"inflation_adjustment":["real_hbai_household_net_income","real_hbai_household_net_income_ahc","real_household_net_income","real_household_net_income_ahc"],"is_CTC_child_limit_exempt":["CTC_child_element","ctc_child_limit_affected"],"is_CTC_eligible":["CTC_disabled_child_element","CTC_family_element","CTC_severely_disabled_child_element","ctc_entitlement"],"is_SP_age":["additional_state_pension","bi_maximum","is_WA_adult","is_hbai_pensioner","is_hbai_working_age_adult","ni_liable","pawhp_eligible","state_pension_type","winter_fuel_payment_eligible"],"is_WTC_eligible":["WTC_basic_element","WTC_childcare_element","WTC_couple_element","WTC_disabled_element","WTC_lone_parent_element","WTC_severely_disabled_element","WTC_worker_element","wtc_entitlement"],"is_adult":["benunit_count_adults","eldest_adult_age","family_type","is_WA_adult","num_adults","num_disabled_adults","num_enhanced_disabled_adults","num_severely_disabled_adults","youngest_adult_age"],"is_apprentice":["bursary_fund_16_to_19_in_qualifying_education","care_to_learn_eligible","is_in_non_advanced_education","minimum_wage","minimum_wage_category"],"is_before_universal_credit_qualifying_young_person_terminal_date":["meets_qualifying_young_person_terminal_date_condition_for_universal_credit"],"is_benefit_cap_exempt":["benefit_cap"],"is_benefit_cap_exempt_earnings":["is_benefit_cap_exempt"],"is_benefit_cap_exempt_health_disability":["is_benefit_cap_exempt"],"is_benefit_cap_exempt_other":["is_benefit_cap_exempt"],"is_benefit_cap_single_claimant_rate":["benefit_cap"],"is_benunit_head":["council_tax_benefit","council_tax_reduction","has_own_esa_award","household_num_benunits","household_uc_reported_capital","is_benefit_cap_exempt_health_disability","is_claimant_or_partner","is_hbai_dependent_child","is_on_income_based_jsa","is_on_income_related_esa","is_on_income_support","is_on_pension_credit","kingston_upon_thames_council_tax_reduction_non_dep_deductions","merton_council_tax_reduction_non_dep_deductions","newham_council_tax_reduction_non_dep_deductions","oxford_council_tax_reduction_non_dep_deductions","pawhp_eligible","personal_rent","westminster_council_tax_reduction_non_dep_deductions","winter_fuel_payment_eligible"],"is_blind":["council_tax_reduction_applicant_has_non_dep_exemption","disabled_students_allowance_has_qualifying_condition","has_non_dependant_for_severe_disability_premium","housing_benefit_severe_disability_premium_applies","is_child_for_working_tax_credit_childcare_element","is_counted_resident_for_severe_disability_addition","num_relevant_children_for_housing_benefit_childcare","severe_disability_minimum_guarantee_addition","severe_disability_premium","tax_free_childcare","tax_free_childcare_child_age_eligible","tv_licence_discount"],"is_cared_for_by_carer_benefit_recipient":["severe_disability_minimum_guarantee_addition","severe_disability_premium"],"is_carer_for_benefits":["esa_income_eligible","income_support_eligible","is_benefit_cap_exempt_health_disability","meets_uc_minimum_age_condition","num_carers","receives_uc_carer_element","uc_unable_to_provide_childcare","uc_work_related_group_apart_from_earnings"],"is_child":["benunit_count_children","child_index","eldest_child_age","family_type","is_benunit_eldest_child","num_children","num_disabled_children","num_enhanced_disabled_children","num_severely_disabled_children","youngest_child_age"],"is_child_for_child_benefit":["income_support_eligible","is_child_or_qualifying_young_person_for_child_benefit","youngest_child_age_for_legacy_benefits"],"is_child_for_child_tax_credit":["is_child_or_qualifying_young_person_for_child_tax_credit"],"is_child_for_pension_credit":["is_child_or_qualifying_young_person_for_pension_credit"],"is_child_for_universal_credit":["is_child_or_qualifying_young_person_for_universal_credit","meets_uc_minimum_age_condition","uc_youngest_child_age"],"is_child_or_qualifying_young_person_for_child_benefit":["care_to_learn_qualifying_child","child_benefit_child_index","child_benefit_respective_amount","has_non_dependant_for_severe_disability_premium","is_child_or_young_person_for_legacy_benefits"],"is_child_or_qualifying_young_person_for_child_tax_credit":["CTC_child_element","CTC_disabled_child_element","ctc_child_limit_affected","is_CTC_eligible","is_responsible_for_child_or_qualifying_young_person_for_child_tax_credit","tax_credits_current_year_income"],"is_child_or_qualifying_young_person_for_pension_credit":["child_minimum_guarantee_addition"],"is_child_or_qualifying_young_person_for_universal_credit":["is_benefit_cap_exempt_health_disability","is_child_or_young_person_for_council_tax_reduction","is_responsible_for_child_or_qualifying_young_person_for_universal_credit","lha_renter_has_non_dependant","uc_child_index","uc_individual_disabled_child_element","uc_individual_severely_disabled_child_element","uc_is_child_born_before_child_limit","uc_is_child_limit_affected"],"is_child_or_young_person_for_council_tax_reduction":["council_tax_reduction_applicable_income","is_responsible_for_child_or_young_person_for_council_tax_reduction"],"is_child_or_young_person_for_legacy_benefits":["council_tax_reduction_applicable_income","housing_benefit_applicable_income","housing_benefit_has_non_dependant","housing_benefit_severe_disability_premium_applies","income_support_applicable_income","is_benefit_cap_exempt_health_disability","is_child_or_young_person_for_council_tax_reduction","is_responsible_for_child_or_young_person_for_legacy_benefits","lha_renter_has_non_dependant","meets_housing_benefit_additional_earnings_disregard_conditions","num_relevant_children_for_housing_benefit_childcare","youngest_child_age_for_legacy_benefits"],"is_claimant_or_partner":["WTC_severely_disabled_element","benefit_cap_reduction","carer_minimum_guarantee_addition","carer_premium","claimant_or_partner_esa_income","claimant_or_partner_jsa_income","council_tax_reduction_applicable_income","council_tax_reduction_head_applies_alone","council_tax_reduction_liable_person","eldest_claimant_or_partner_age","esa_income_assessable_capital","esa_income_eligible","extended_childcare_entitlement_eligible","extended_childcare_entitlement_work_condition","has_mixed_age_couple_pension_credit_saving","has_non_dependant_for_severe_disability_premium","has_own_esa_award","housing_benefit_LHA_allowed_bedrooms","housing_benefit_applicable_income","housing_benefit_assessable_capital","housing_benefit_has_non_dependant","housing_benefit_net_earnings","housing_benefit_pension_age_regulations_apply","housing_benefit_severe_disability_premium_applies","housing_benefit_specified_or_temporary_accommodation_disregard","income_support_applicable_income","income_support_assessable_capital","income_support_eligible","is_WTC_eligible","is_benefit_cap_exempt_health_disability","is_benefit_cap_single_claimant_rate","is_cared_for_by_carer_benefit_recipient","is_child_for_working_tax_credit_childcare_element","is_child_or_qualifying_young_person_for_child_benefit","is_child_or_qualifying_young_person_for_child_tax_credit","is_child_or_qualifying_young_person_for_pension_credit","is_child_or_young_person_for_council_tax_reduction","is_child_or_young_person_for_legacy_benefits","is_council_tax_reduction_applicant_or_partner","is_dependent_child_for_student_support","is_lha_shared_accommodation_rate_specified_renter","is_liable_for_household_rent","is_mixed_age_couple","is_on_income_based_jsa","is_on_income_related_esa","is_on_income_support","is_on_pawhp_relevant_benefit","is_on_pension_credit","is_on_universal_credit","is_on_winter_fuel_payment_relevant_benefit","is_responsible_for_child_or_qualifying_young_person_for_child_tax_credit","is_responsible_for_child_or_young_person_for_uc_or_housing_benefit","is_savings_credit_eligible","is_uc_claimant","jsa_income_assessable_capital","jsa_income_eligible","lha_renter_has_non_dependant","maintenance_loan_entitled_to_benefits","marital_status","marriage_allowance","meets_housing_benefit_additional_earnings_disregard_conditions","meets_pension_credit_age_conditions","meets_severe_disability_addition_residence_condition","num_disabled_claimants_or_partners_for_legacy_benefits","num_enhanced_disabled_claimants_or_partners_for_legacy_benefits","partners_care_for_same_severely_disabled_person","partners_unused_personal_allowance","pawhp_eligible","pension_age_severe_disability_premium","pension_age_winter_heating_payment","pension_credit_assessable_capital","pension_credit_earnings","pension_credit_income","relation_type","savings_credit_income","severe_disability_minimum_guarantee_addition","severe_disability_premium","tax_credit_award","tax_credits_current_year_income","tax_free_childcare_regarded_as_in_paid_work","tax_free_childcare_work_condition","winter_fuel_payment","winter_fuel_payment_eligible","would_claim_IS","youngest_claimant_or_partner_age"],"is_council_tax_reduction_applicant_or_partner":["council_tax_reduction_applicable_income","council_tax_reduction_applicant_has_non_dep_exemption","council_tax_reduction_pensioner"],"is_council_tax_reduction_lone_parent":["council_tax_reduction_applicable_amount"],"is_counted_resident_for_severe_disability_addition":["meets_severe_disability_addition_residence_condition"],"is_couple":["adult_dependants_grant_adult_eligible","council_tax_reduction_applicable_amount","council_tax_reduction_pensioner_earnings_disregard","disability_premium","enhanced_disability_premium","housing_benefit_applicable_amount","housing_benefit_applicable_income_disregard","housing_benefit_specified_or_temporary_accommodation_disregard","income_support_applicable_income","is_WTC_eligible","is_benefit_cap_single_claimant_rate","is_lha_shared_accommodation_rate_specified_renter","is_married","maintenance_loan_household_income","maintenance_loan_living_arrangement","meets_housing_benefit_additional_earnings_disregard_conditions","severe_disability_minimum_guarantee_addition","severe_disability_premium"],"is_dependent_child_for_student_support":["childcare_grant_child_eligible","parents_learning_allowance_dependent_children"],"is_disabled_for_benefits":["CTC_disabled_child_element","disabled_students_allowance_has_qualifying_condition","is_WTC_eligible","is_child_for_working_tax_credit_childcare_element","meets_housing_benefit_additional_earnings_disregard_conditions","num_disabled_adults","num_disabled_children","num_disabled_claimants_or_partners_for_legacy_benefits","num_relevant_children_for_housing_benefit_childcare","tax_free_childcare","tax_free_childcare_child_age_eligible","uc_individual_disabled_child_element","uc_limited_capability_for_WRA","uc_limited_capability_for_work"],"is_engaged_in_owned_company_trade":["uc_company_capital"],"is_enhanced_disabled_for_benefits":["num_enhanced_disabled_adults","num_enhanced_disabled_children","num_enhanced_disabled_claimants_or_partners_for_legacy_benefits"],"is_entitled_to_carer_benefit":["carer_minimum_guarantee_addition","carer_premium","extended_childcare_entitlement_limited_capability_or_specified_benefit","is_benefit_cap_exempt_health_disability","is_carer_for_benefits","partners_care_for_same_severely_disabled_person","tax_free_childcare_caring_or_incapacity_benefit"],"is_gainfully_employed_for_carers_allowance":["carers_allowance_pre_overlap"],"is_guarantee_credit_eligible":["guarantee_credit","is_pension_credit_eligible"],"is_hbai_adult":["household_equivalisation_ahc","household_equivalisation_bhc","is_claimant_or_partner","is_hbai_pensioner","is_hbai_working_age_adult"],"is_hbai_child_aged_14_or_over":["household_equivalisation_ahc","household_equivalisation_bhc"],"is_hbai_child_under_14":["household_equivalisation_ahc","household_equivalisation_bhc"],"is_hbai_dependent_child":["hbai_person_type","is_hbai_adult","is_hbai_child_aged_14_or_over","is_hbai_child_under_14"],"is_hbai_working_age_adult":["hbai_person_type"],"is_higher_earner":["CB_HITC"],"is_household_head":["is_resolved_household_head"],"is_housing_benefit_young_individual":["housing_benefit_LHA_category"],"is_in_approved_training":["is_hbai_dependent_child","meets_qualifying_young_person_education_or_training_condition_for_child_benefit","meets_qualifying_young_person_education_or_training_condition_for_child_tax_credit","meets_qualifying_young_person_education_or_training_condition_for_pension_credit","meets_qualifying_young_person_education_or_training_condition_for_universal_credit"],"is_in_non_advanced_education":["is_hbai_dependent_child","meets_qualifying_young_person_education_or_training_condition_for_child_benefit","meets_qualifying_young_person_education_or_training_condition_for_child_tax_credit","meets_qualifying_young_person_education_or_training_condition_for_pension_credit","meets_qualifying_young_person_education_or_training_condition_for_universal_credit"],"is_lha_shared_accommodation_rate_specified_renter":["LHA_category"],"is_liable_for_household_rent":["housing_benefit_LHA_allowed_bedrooms","housing_benefit_has_non_dependant","housing_benefit_severe_disability_premium_applies","share_of_household_rent","uc_non_dependants_counted"],"is_lone_parent":["council_tax_reduction_pensioner_earnings_disregard","housing_benefit_applicable_amount","housing_benefit_applicable_income_disregard","housing_benefit_specified_or_temporary_accommodation_disregard","income_support_applicable_income","income_support_eligible","meets_housing_benefit_additional_earnings_disregard_conditions"],"is_looked_after_by_local_authority":["extended_childcare_entitlement_qualifying_child","income_support_eligible","is_benefit_cap_exempt_health_disability","is_child_for_working_tax_credit_childcare_element","is_child_or_qualifying_young_person_for_child_tax_credit","is_child_or_qualifying_young_person_for_pension_credit","is_child_or_qualifying_young_person_for_universal_credit","is_child_or_young_person_for_legacy_benefits","tax_free_childcare_qualifying_child","uc_youngest_child_age"],"is_male":["LHA_allowed_bedrooms","housing_benefit_LHA_allowed_bedrooms","state_pension_age"],"is_married":["marital_status"],"is_mixed_age_couple":["has_mixed_age_couple_pension_credit_saving","legacy_benefits_closed","meets_pension_credit_age_conditions"],"is_non_dependant_of_household_head":["LHA_allowed_bedrooms","housing_benefit_has_non_dependant","housing_benefit_non_dep_deductions","housing_benefit_severe_disability_premium_applies","lha_renter_has_non_dependant","uc_non_dep_deductions"],"is_of_compulsory_school_age":["universal_childcare_entitlement_eligible"],"is_on_income_based_jsa":["is_on_pawhp_relevant_benefit","is_on_winter_fuel_payment_relevant_benefit","pawhp_eligible","winter_fuel_payment_eligible"],"is_on_income_related_esa":["is_on_pawhp_relevant_benefit","is_on_winter_fuel_payment_relevant_benefit","maintenance_loan_entitled_to_benefits","pawhp_eligible","winter_fuel_payment_eligible"],"is_on_income_support":["is_on_pawhp_relevant_benefit","is_on_winter_fuel_payment_relevant_benefit","pawhp_eligible","winter_fuel_payment_eligible"],"is_on_pawhp_relevant_benefit":["pawhp_eligible","pension_age_winter_heating_payment"],"is_on_pension_credit":["is_on_pawhp_relevant_benefit","is_on_winter_fuel_payment_relevant_benefit","pawhp_eligible","winter_fuel_payment_eligible"],"is_on_universal_credit":["is_on_pawhp_relevant_benefit","is_on_winter_fuel_payment_relevant_benefit","pawhp_eligible","winter_fuel_payment_eligible"],"is_on_winter_fuel_payment_relevant_benefit":["winter_fuel_payment","winter_fuel_payment_eligible"],"is_parent":["care_to_learn_eligible","care_to_learn_qualifying_child","childcare_grant_eligible","is_claimant_or_partner","is_hbai_dependent_child","maintenance_loan_entitled_to_benefits","maintenance_loan_household_income","maintenance_loan_living_arrangement","parents_learning_allowance_eligible","tax_free_childcare_eligible","tax_free_childcare_qualifying_child"],"is_pension_credit_eligible":["guarantee_credit","in_receipt_of_guarantee_credit","in_receipt_of_savings_credit_only","pension_credit_entitlement"],"is_qualifying_young_person_for_child_benefit":["is_benefit_cap_exempt_health_disability","is_child_or_qualifying_young_person_for_child_benefit"],"is_qualifying_young_person_for_child_tax_credit":["is_child_or_qualifying_young_person_for_child_tax_credit"],"is_qualifying_young_person_for_pension_credit":["is_child_or_qualifying_young_person_for_pension_credit","is_counted_resident_for_severe_disability_addition"],"is_qualifying_young_person_for_universal_credit":["is_benefit_cap_exempt_health_disability","is_child_or_qualifying_young_person_for_universal_credit"],"is_resolved_household_head":["benunit_contains_household_head","council_tax_reduction_head_applies_alone","council_tax_reduction_liable_person","is_council_tax_reduction_applicant_or_partner","maintenance_loan_household_income","maintenance_loan_living_arrangement","personal_rent"],"is_responsible_for_child_or_qualifying_young_person_for_child_tax_credit":["is_WTC_eligible"],"is_responsible_for_child_or_qualifying_young_person_for_universal_credit":["is_responsible_for_child_or_young_person_for_uc_or_housing_benefit","is_uc_work_allowance_eligible"],"is_responsible_for_child_or_young_person_for_council_tax_reduction":["is_council_tax_reduction_lone_parent"],"is_responsible_for_child_or_young_person_for_legacy_benefits":["income_support_applicable_amount","is_lone_parent","is_responsible_for_child_or_young_person_for_uc_or_housing_benefit","is_single_person"],"is_responsible_for_child_or_young_person_for_uc_or_housing_benefit":["is_benefit_cap_single_claimant_rate","is_lha_shared_accommodation_rate_specified_renter"],"is_savings_credit_eligible":["is_pension_credit_eligible","savings_credit"],"is_scp_eligible":["scottish_child_payment"],"is_scp_eligible_child":["is_scp_eligible"],"is_severely_disabled_for_benefits":["WTC_severely_disabled_element","num_severely_disabled_adults","num_severely_disabled_children","uc_individual_severely_disabled_child_element"],"is_severely_disabled_for_carers_allowance":["is_cared_for_by_carer_benefit_recipient"],"is_shared_accommodation":["housing_benefit_shares_accommodation"],"is_single":["disability_premium","enhanced_disability_premium","income_support_applicable_amount","income_support_eligible","is_WTC_eligible","is_council_tax_reduction_lone_parent","is_lone_parent","is_single_person"],"is_single_person":["housing_benefit_applicable_amount","income_support_applicable_income","is_housing_benefit_young_individual"],"is_uc_assessed_claimant":["benefit_cap_reduction","is_benefit_cap_exempt_earnings","is_benefit_cap_exempt_health_disability","is_benefit_cap_single_claimant_rate","is_uc_single_or_joint_claimant","uc_childcare_work_condition","uc_earned_income","uc_individual_earned_income","uc_is_ineligible_partner","uc_is_responsible_carer","uc_member_of_couple_claims_as_single_person","uc_minimum_income_floor_gross","uc_unearned_income","uc_work_related_group_apart_from_earnings","uc_youngest_child_age"],"is_uc_claimant":["household_uc_pool_company_holdings","household_uc_unreported_claimants","is_responsible_for_child_or_qualifying_young_person_for_universal_credit","is_uc_assessed_claimant","meets_uc_minimum_age_condition","uc_assessable_capital","uc_child_index","uc_individual_disabled_child_element","uc_individual_severely_disabled_child_element","uc_is_child_limit_affected"],"is_uc_eligible":["uc_income_reduction","uc_maximum_amount","uc_non_dependants_counted","uc_tariff_income"],"is_uc_entitled":["council_tax_reduction_pensioner","housing_benefit_on_passporting_benefit","housing_benefit_pension_age_regulations_apply","left_pension_route_at_legacy_closure"],"is_uc_single_or_joint_claimant":["is_uc_eligible","uc_childcare_work_condition","uc_member_of_couple_claims_as_single_person","uc_standard_allowance_claimant_type"],"is_uc_work_allowance_eligible":["uc_work_allowance"],"jsa_contrib":["benefit_cap_reduction","carer_support_payment_overlapping_benefits","carers_allowance_overlapping_benefits","council_tax_reduction_applicable_income","gov_spending","hbai_benefits","hbai_household_net_income","household_benefits","housing_benefit_applicable_income","income_support_eligible","jsa","pension_credit_income","pre_budget_change_household_benefits","savings_credit_income","uc_unearned_income"],"jsa_contrib_reported":["jsa_contrib","social_security_income"],"jsa_income":["benefit_cap_reduction","claimant_or_partner_jsa_income","cost_of_living_support_payment","gov_spending","hbai_benefits","hbai_household_net_income","household_benefits","income_support_eligible","is_on_income_based_jsa","jsa","pre_budget_change_household_benefits"],"jsa_income_assessable_capital":["is_on_income_based_jsa","jsa_income_eligible","jsa_income_tariff_income"],"jsa_income_eligible":["is_on_income_based_jsa"],"jsa_income_reported":["benefit_cap_reduction","claimant_or_partner_jsa_income","claims_all_entitled_benefits","claims_legacy_benefits","has_mixed_age_couple_pension_credit_saving","income_support_eligible","is_on_income_based_jsa","jsa_income_assessable_capital","jsa_income_eligible","legacy_benefits_closed","pawhp_eligible","winter_fuel_payment_eligible"],"jsa_income_tariff_income":["is_on_income_based_jsa"],"jsa_remunerative_work_hours":["is_on_income_based_jsa","jsa_income_eligible"],"kingston_upon_thames_council_tax_reduction":["simulated_council_tax_reduction_benunit"],"kingston_upon_thames_council_tax_reduction_individual_non_dep_deduction":["kingston_upon_thames_council_tax_reduction_non_dep_deductions"],"kingston_upon_thames_council_tax_reduction_non_dep_deductions":["kingston_upon_thames_council_tax_reduction"],"land_and_buildings_transaction_tax":["expected_lbtt"],"land_transaction_tax":["expected_ltt"],"land_value":["LVT"],"lbtt_liable":["land_and_buildings_transaction_tax"],"lbtt_on_non_residential_property_rent":["lbtt_on_rent"],"lbtt_on_non_residential_property_transactions":["lbtt_on_transactions"],"lbtt_on_rent":["land_and_buildings_transaction_tax"],"lbtt_on_residential_property_rent":["lbtt_on_rent"],"lbtt_on_residential_property_transactions":["lbtt_on_transactions"],"lbtt_on_transactions":["land_and_buildings_transaction_tax"],"left_pension_route_at_legacy_closure":["housing_benefit_eligible","is_pension_credit_eligible"],"legacy_benefits_closed":["claims_uc_at_legacy_closure","esa_income_eligible","housing_benefit_eligible","is_CTC_eligible","is_WTC_eligible","is_on_income_based_jsa","is_on_income_related_esa","jsa_income_eligible","left_pension_route_at_legacy_closure"],"lha_renter_has_non_dependant":["is_lha_shared_accommodation_rate_specified_renter"],"liable_for_share_of_household_rent":["council_tax_reduction_claims_are_joint","council_tax_reduction_individual_non_dep_deduction_eligible","council_tax_reduction_liable_person","housing_benefit_shares_accommodation","is_liable_for_household_rent"],"lifetime_isa_balance":["has_lifetime_isa","household_lifetime_isa_balance","lifetime_isa_countable_capital"],"lifetime_isa_countable_capital":["esa_income_assessable_capital","housing_benefit_assessable_capital","income_support_assessable_capital","jsa_income_assessable_capital","pension_credit_assessable_capital","uc_assessable_capital"],"local_authority":["council_tax_reduction_scheme_supported","kingston_upon_thames_council_tax_reduction","merton_council_tax_reduction","newham_council_tax_reduction","oxford_council_tax_reduction","westminster_council_tax_reduction"],"loss_relief":["taxable_self_employment_income"],"lpg_kg":["fuel_duty"],"ltt_liable":["land_transaction_tax","ltt_on_non_residential_property_transactions"],"ltt_on_non_residential_property_rent":["ltt_on_rent"],"ltt_on_non_residential_property_transactions":["ltt_on_transactions"],"ltt_on_rent":["land_transaction_tax"],"ltt_on_residential_property_rent":["ltt_on_rent"],"ltt_on_residential_property_transactions":["ltt_on_transactions"],"ltt_on_transactions":["land_transaction_tax"],"main_residence_value":["main_residential_property_purchased","non_primary_residence_wealth_tax","residential_property_value"],"main_residential_property_purchased":["lbtt_on_residential_property_transactions","ltt_on_residential_property_transactions","sdlt_on_residential_property_transactions"],"main_residential_property_purchased_is_first_home":["lbtt_on_residential_property_transactions","sdlt_on_residential_property_transactions"],"maintenance_expenses":["hbai_household_net_income","market_income"],"maintenance_income":["hbai_household_net_income","household_market_income","market_income"],"maintenance_loan_candidate_benunit_income":["maintenance_loan_sponsor_income"],"maintenance_loan_eligible":["childcare_grant_student_finance_eligible","maintenance_loan","travel_grant_income_assessed_support"],"maintenance_loan_entitled_to_benefits":["maintenance_loan"],"maintenance_loan_has_sponsor":["maintenance_loan_household_income","maintenance_loan_living_arrangement"],"maintenance_loan_household_income":["adult_dependants_grant_household_income","childcare_grant_household_income","maintenance_loan","parents_learning_allowance_household_income","travel_grant_household_income"],"maintenance_loan_in_england_system":["disabled_students_allowance_eligible","maintenance_loan_eligible"],"maintenance_loan_in_higher_education":["adult_dependants_grant_adult_receives_student_finance","adult_dependants_grant_course_eligible","disabled_students_allowance_course_eligible","maintenance_loan_eligible","maintenance_loan_has_sponsor","maintenance_loan_household_income","maintenance_loan_living_arrangement","maintenance_loan_sponsor_income","parents_learning_allowance_course_eligible"],"maintenance_loan_living_arrangement":["maintenance_loan"],"maintenance_loan_sponsor_income":["maintenance_loan_household_income"],"marginal_tax_rate":["cliff_gap","relative_wage_change"],"marginal_tax_rate_on_capital_gains":["relative_capital_gains_mtr_change","relative_capital_gains_retention_rate_change"],"marital_status":["marriage_allowance"],"marriage_allowance":["earned_taxable_income"],"married_couples_allowance":["married_couples_allowance_deduction"],"married_couples_allowance_deduction":["capped_mcad","esa_exempt_work_earnings"],"maternity_allowance":["carer_support_payment_overlapping_benefits","carers_allowance_overlapping_benefits","council_tax_reduction_applicable_income","gov_spending","hbai_benefits","hbai_household_net_income","household_benefits","housing_benefit_applicable_income","pre_budget_change_household_benefits","tax_free_childcare_treated_as_in_work","uc_childcare_treated_as_in_paid_work","uc_unearned_income"],"maternity_allowance_reported":["maternity_allowance"],"max_free_entitlement_hours_used":["extended_childcare_entitlement_total_per_child","targeted_childcare_entitlement","universal_childcare_entitlement"],"maximum_extended_childcare_hours_usage":["extended_childcare_entitlement_total_per_child"],"meals_included_in_rent":["housing_benefit_meals_deduction"],"meets_housing_benefit_additional_earnings_disregard_conditions":["council_tax_reduction_pensioner_earnings_disregard","housing_benefit_applicable_income_disregard"],"meets_marriage_allowance_income_conditions":["marriage_allowance"],"meets_pension_credit_age_conditions":["housing_benefit_eligible","income_support_eligible","is_pension_credit_eligible","is_uc_eligible","left_pension_route_at_legacy_closure","legacy_benefits_closed"],"meets_qualifying_young_person_age_condition_for_child_benefit":["is_qualifying_young_person_for_child_benefit"],"meets_qualifying_young_person_age_condition_for_child_tax_credit":["is_qualifying_young_person_for_child_tax_credit"],"meets_qualifying_young_person_age_condition_for_pension_credit":["is_qualifying_young_person_for_pension_credit"],"meets_qualifying_young_person_age_condition_for_universal_credit":["is_qualifying_young_person_for_universal_credit"],"meets_qualifying_young_person_education_or_training_condition_for_child_benefit":["is_qualifying_young_person_for_child_benefit"],"meets_qualifying_young_person_education_or_training_condition_for_child_tax_credit":["is_qualifying_young_person_for_child_tax_credit"],"meets_qualifying_young_person_education_or_training_condition_for_pension_credit":["is_qualifying_young_person_for_pension_credit"],"meets_qualifying_young_person_education_or_training_condition_for_universal_credit":["is_qualifying_young_person_for_universal_credit"],"meets_qualifying_young_person_entry_condition_for_child_benefit":["is_qualifying_young_person_for_child_benefit"],"meets_qualifying_young_person_entry_condition_for_child_tax_credit":["is_qualifying_young_person_for_child_tax_credit"],"meets_qualifying_young_person_entry_condition_for_pension_credit":["is_qualifying_young_person_for_pension_credit"],"meets_qualifying_young_person_entry_condition_for_universal_credit":["is_qualifying_young_person_for_universal_credit"],"meets_qualifying_young_person_terminal_date_condition_for_universal_credit":["is_qualifying_young_person_for_universal_credit"],"meets_savings_credit_age_requirement":["is_savings_credit_eligible"],"meets_severe_disability_addition_residence_condition":["severe_disability_minimum_guarantee_addition"],"meets_uc_minimum_age_condition":["is_uc_eligible","uc_is_ineligible_partner","uc_member_of_couple_claims_as_single_person"],"meets_universal_credit_criteria_for_targeted_childcare_entitlement":["targeted_childcare_entitlement_eligible"],"merton_council_tax_reduction":["simulated_council_tax_reduction_benunit"],"merton_council_tax_reduction_individual_non_dep_deduction":["merton_council_tax_reduction_non_dep_deductions"],"merton_council_tax_reduction_non_dep_deductions":["merton_council_tax_reduction"],"minimum_guarantee":["guarantee_credit","is_guarantee_credit_eligible","savings_credit"],"minimum_wage":["extended_childcare_entitlement_meets_income_requirements","tax_free_childcare_meets_income_requirements"],"miscellaneous_consumption":["carbon_consumption","consumption"],"miscellaneous_income":["hbai_household_net_income","household_market_income","market_income","tax_credits_current_year_income","taxable_miscellaneous_income"],"monthly_domestic_energy_consumption":["monthly_epg_consumption_level","monthly_epg_subsidy"],"monthly_ebr_energy_bills_credit":["ebr_energy_bills_credit"],"monthly_epg_consumption_level":["monthly_epg_subsidy"],"monthly_epg_subsidy":["epg_subsidy"],"months_since_last_birthday":["birth_year","child_minimum_guarantee_addition","date_of_birth","has_attained_state_pension_credit_qualifying_age","has_mixed_age_couple_pension_credit_saving","is_CTC_child_limit_exempt","meets_savings_credit_age_requirement","months_since_state_pension_age","state_pension_age","state_pension_credit_qualifying_age","uc_child_index","uc_is_child_born_before_child_limit"],"months_since_state_pension_age":["is_SP_age","meets_savings_credit_age_requirement","ni_class_4_liable","state_pension_type"],"mortgage":["housing_costs"],"mortgage_capital_repayment":["mortgage"],"mortgage_debt":["net_wealth"],"mortgage_interest_repayment":["hbai_household_net_income_ahc","mortgage"],"national_insurance":["council_tax_reduction_applicable_income","gov_tax","hbai_household_net_income","household_tax","housing_benefit_applicable_income","income_support_applicable_income","pension_credit_income","post_tax_income","pre_budget_change_household_tax","tax","total_national_insurance"],"natural_gas_kg":["fuel_duty"],"net_income":["adjusted_net_income","capital_gains_tax","earned_taxable_income","maintenance_loan_candidate_benunit_income","maintenance_loan_household_income","non_savings_income_after_allowances","pension_annual_allowance","plan_2_interest_rate","property_finance_costs_relieved","received_allowances_earned_income","savings_allowance","student_loan_repayment","tax_band","uc_income_tax_on_earnings","uc_income_tax_on_trade","unused_personal_allowance"],"new_state_pension":["overlapping_state_pension","state_pension"],"newham_council_tax_reduction":["simulated_council_tax_reduction_benunit"],"newham_council_tax_reduction_individual_non_dep_deduction":["newham_council_tax_reduction_non_dep_deductions"],"newham_council_tax_reduction_non_dep_deductions":["newham_council_tax_reduction"],"nhs_a_and_e_spending":["nhs_spending"],"nhs_admitted_patient_spending":["nhs_spending"],"nhs_outpatient_spending":["nhs_spending"],"nhs_spending":["gov_spending","household_benefits"],"ni_class_1_employee":["carers_allowance_earnings","housing_benefit_net_earnings","national_insurance","ni_class_4","ni_employee","uc_national_insurance_on_earnings"],"ni_class_1_employee_additional":["ni_class_1_employee"],"ni_class_1_employee_primary":["ni_class_1_employee","ni_class_4_maximum"],"ni_class_1_employer":["ni_employer","total_national_insurance"],"ni_class_1_income":["ni_class_1_employee_additional","ni_class_1_employee_primary","ni_class_1_employer"],"ni_class_1_secondary_liable":["ni_class_1_employer"],"ni_class_2":["housing_benefit_net_earnings","national_insurance","ni_class_4","ni_class_4_maximum","ni_self_employed","uc_national_insurance_on_earnings","uc_national_insurance_on_trade"],"ni_class_3":["national_insurance"],"ni_class_4":["housing_benefit_net_earnings","national_insurance","ni_self_employed","uc_national_insurance_on_earnings","uc_national_insurance_on_trade"],"ni_class_4_liable":["esa_exempt_work_earnings","ni_class_4","ni_class_4_main","uc_minimum_income_floor_national_insurance"],"ni_class_4_loss_relief":["ni_class_4_losses_carried_forward","ni_class_4_profits"],"ni_class_4_losses_brought_forward":["ni_class_4_loss_relief","ni_class_4_losses_carried_forward"],"ni_class_4_maximum":["ni_class_4"],"ni_class_4_profits":["ni_class_2","ni_class_4","ni_class_4_main","ni_class_4_maximum"],"ni_class_4_profits_before_losses":["ni_class_4_loss_relief","ni_class_4_profits"],"ni_class_4_trading_loss":["ni_class_4_loss_relief","ni_class_4_losses_carried_forward"],"ni_employer":["employer_cost","gov_tax"],"ni_liable":["esa_exempt_work_earnings","ni_class_1_employee","ni_class_2","uc_minimum_income_floor_national_insurance"],"non_primary_residence_wealth_tax":["gov_tax","household_tax","pre_budget_change_household_tax"],"non_residential_property_purchased":["lbtt_on_non_residential_property_transactions","ltt_on_non_residential_property_transactions","sdlt_on_non_residential_property_transactions"],"non_residential_property_value":["esa_income_assessable_capital","housing_benefit_assessable_capital","income_support_assessable_capital","jsa_income_assessable_capital","pension_credit_assessable_capital","property_wealth","uc_assessable_capital"],"non_residential_rent":["lbtt_on_non_residential_property_rent","ltt_on_non_residential_property_rent","sdlt_on_non_residential_property_rent"],"non_savings_income_after_allowances":["property_income_tax","taxable_property_income_after_allowances"],"non_savings_taxable_income":["add_rate_savings_income","basic_rate_savings_income","basic_rate_savings_income_pre_starter","dividend_income_tax","higher_rate_savings_income","savings_starter_rate_income","taxed_income"],"num_carers":["benunit_has_carer"],"num_disabled_claimants_or_partners_for_legacy_benefits":["disability_premium"],"num_enhanced_disabled_claimants_or_partners_for_legacy_benefits":["enhanced_disability_premium"],"num_relevant_children_for_housing_benefit_childcare":["housing_benefit_applicable_income_childcare_element"],"num_vehicles":["owns_vehicle"],"other_deductions":["allowances","property_finance_costs_relieved"],"other_fermented_abv":["other_fermented_duty"],"other_fermented_draught_share":["other_fermented_duty"],"other_fermented_duty":["alcohol_duty"],"other_fermented_litres":["other_fermented_duty"],"other_investment_income":["taxable_savings_interest_income"],"other_local_bus_trips":["local_bus_trips"],"other_public_spending_budget_change":["gov_spending"],"other_residential_property_value":["additional_residential_property_purchased","esa_income_assessable_capital","housing_benefit_assessable_capital","income_support_assessable_capital","jsa_income_assessable_capital","pension_credit_assessable_capital","residential_property_value","uc_assessable_capital"],"other_tax_credits":["income_tax","property_finance_cost_relief","uc_income_tax_on_earnings","uc_income_tax_on_trade"],"other_tobacco_grams_per_week":["tobacco_duty"],"over_16":["ni_class_1_secondary_liable","ni_class_4_liable","ni_liable","tax_free_childcare_work_condition"],"overlapping_state_pension":["carer_support_payment_overlapping_benefits","carers_allowance_overlapping_benefits"],"owned_company_capital":["uc_company_capital"],"owned_company_carries_on_property_business":["uc_company_owner_treatment_applies"],"owned_company_carries_on_trade":["uc_company_capital","uc_company_gainful_self_employment","uc_company_owner_treatment_applies","uc_company_self_employed_earnings"],"owned_company_holding_value":["uc_company_holding_disregard"],"owned_company_income_share":["uc_company_self_employed_earnings"],"owned_company_intermediary_earnings_chapter":["uc_company_intermediary_exclusion_applies"],"owned_company_intermediary_earnings_from_main_employment":["uc_company_intermediary_exclusion_applies"],"owned_company_is_main_employment":["uc_company_capital","uc_company_gainful_self_employment"],"owned_company_trade_assets":["uc_company_capital"],"owned_land":["esa_income_assessable_capital","household_land_value","housing_benefit_assessable_capital","income_support_assessable_capital","jsa_income_assessable_capital","pension_credit_assessable_capital"],"oxford_council_tax_reduction":["simulated_council_tax_reduction_benunit"],"oxford_council_tax_reduction_individual_non_dep_deduction":["oxford_council_tax_reduction_non_dep_deductions"],"oxford_council_tax_reduction_non_dep_deductions":["oxford_council_tax_reduction"],"parents_learning_allowance":["gov_spending","hbai_benefits","household_benefits"],"parents_learning_allowance_course_eligible":["parents_learning_allowance_eligible"],"parents_learning_allowance_dependent_children":["parents_learning_allowance_eligible"],"parents_learning_allowance_eligible":["parents_learning_allowance"],"parents_learning_allowance_household_income":["parents_learning_allowance_eligible"],"partners_care_for_same_severely_disabled_person":["carer_premium"],"partners_unused_personal_allowance":["marriage_allowance"],"pawhp":["gov_spending","hbai_benefits","hbai_household_net_income","household_benefits"],"pawhp_eligible":["pension_age_winter_heating_payment"],"pays_rent_to_householder":["benunit_tenure_type","council_tax_reduction_individual_non_dep_deduction_eligible","housing_benefit_shares_accommodation"],"pays_scottish_income_tax":["carers_allowance_earnings","earned_income_tax","esa_exempt_work_earnings","property_income_tax","tax_band","uc_income_tax_on_earnings","uc_income_tax_on_trade","uc_minimum_income_floor_income_tax"],"pension_age_benefits_premiums":["benefits_premiums","council_tax_reduction_applicable_amount"],"pension_age_severe_disability_premium":["pension_age_benefits_premiums"],"pension_age_winter_heating_payment":["pawhp"],"pension_annual_allowance":["pension_contributions_relief","personal_pension_contributions_tax"],"pension_contributions":["carers_allowance_earnings","council_tax_reduction_applicable_income","household_net_income","housing_benefit_applicable_income","housing_benefit_net_earnings","income_support_applicable_income","pension_contributions_relief","pension_credit_income","uc_individual_earned_income_before_mif"],"pension_contributions_for_annual_allowance":["personal_pension_contributions_tax"],"pension_contributions_relief":["allowances","capital_gains_tax"],"pension_contributions_via_salary_sacrifice":["pension_contributions_via_salary_sacrifice_from_pay"],"pension_contributions_via_salary_sacrifice_adjusted":["pension_contributions_for_annual_allowance"],"pension_contributions_via_salary_sacrifice_from_pay":["pension_contributions_via_salary_sacrifice_adjusted","salary_sacrifice_returned_to_income"],"pension_credit":["cost_of_living_support_payment","council_tax_reduction_applicable_income","gov_spending","hbai_benefits","hbai_household_net_income","household_benefits","housing_benefit_savings_credit_only_income","in_receipt_of_savings_credit_only","is_on_pension_credit","is_scp_eligible","pre_budget_change_household_benefits","tax_credits_applicable_income","tv_licence_discount","uc_non_dep_receives_pension_credit"],"pension_credit_assessable_capital":["council_tax_reduction_assessable_capital","housing_benefit_assessable_capital","pension_credit_deemed_income"],"pension_credit_deemed_income":["pension_credit_income"],"pension_credit_earnings":["pension_credit_income"],"pension_credit_entitlement":["pension_credit"],"pension_credit_income":["council_tax_reduction_applicable_income","guarantee_credit","housing_benefit_savings_credit_only_income","is_guarantee_credit_eligible","savings_credit","savings_credit_income"],"pension_credit_reported":["has_mixed_age_couple_pension_credit_saving","is_on_pension_credit","legacy_benefits_closed","pawhp_eligible","winter_fuel_payment_eligible"],"pension_credit_reported_capital":["pension_credit_assessable_capital"],"person_bus_fare_spending":["bus_fare_spending"],"person_id":["is_benunit_eldest_child"],"person_weight":["benunit_weight"],"personal_allowance":["allowances","esa_exempt_work_earnings","property_finance_costs_relieved","unused_personal_allowance"],"personal_pension_contributions":["capital_gains_tax","esa_exempt_work_earnings","hbai_household_net_income","pension_contributions","pension_contributions_for_annual_allowance"],"personal_pension_contributions_tax":["income_tax"],"personal_rent":["benunit_rent","family_rent"],"petrol_litres":["fuel_duty"],"petrol_price":["petrol_litres"],"petrol_spending":["petrol_litres"],"pip":["bursary_fund_16_to_19_vulnerable_group_eligible","child_minimum_guarantee_addition","cost_of_living_support_payment","disability_basic_income","gov_spending","hbai_benefits","hbai_household_net_income","household_benefits","is_benefit_cap_exempt_health_disability","pre_budget_change_household_benefits"],"pip_dl":["council_tax_reduction_applicant_has_non_dep_exemption","housing_benefit_severe_disability_premium_applies","is_lha_shared_accommodation_rate_specified_renter","is_severely_disabled_for_benefits","is_severely_disabled_for_carers_allowance","maintenance_loan_entitled_to_benefits","pip","receives_severe_disability_addition_qualifying_benefit","receives_severe_disability_premium_qualifying_benefit","uc_non_dep_deduction_exempt"],"pip_dl_category":["pip_dl","receives_enhanced_pip_dl"],"pip_m":["maintenance_loan_entitled_to_benefits","pip"],"pip_m_category":["pip_m"],"plan_1_interest_rate":["plan_4_interest_rate","student_loan_interest_rate"],"plan_2_interest_rate":["student_loan_interest_rate"],"plan_4_interest_rate":["student_loan_interest_rate"],"plan_5_interest_rate":["student_loan_interest_rate"],"postgraduate_interest_rate":["student_loan_interest_rate"],"poverty_gap":["in_poverty"],"poverty_line":["deep_poverty_line","poverty_gap"],"poverty_line_ahc":["poverty_gap_ahc"],"poverty_line_bhc":["poverty_gap_bhc"],"poverty_threshold_ahc":["in_poverty_ahc"],"poverty_threshold_bhc":["in_poverty_bhc"],"pre_budget_change_household_benefits":["pre_budget_change_household_net_income"],"pre_budget_change_household_net_income":["pre_budget_change_ons_household_income_decile"],"pre_budget_change_household_tax":["pre_budget_change_household_net_income"],"private_pension_income":["council_tax_reduction_applicable_income","earned_income","hbai_household_net_income","household_market_income","housing_benefit_applicable_income","housing_benefit_net_earnings","income_support_applicable_income","market_income","pension_credit_income","tax_credits_current_year_income","taxable_pension_income","total_income","total_pension_income","uc_unearned_income"],"private_pension_wealth":["corporate_sector_wealth","total_wealth"],"private_school_vat":["gov_tax","household_tax"],"private_transfer_income":["hbai_household_net_income","household_market_income","market_income"],"property_allowable_expenses":["property_allowance_deduction_if_used"],"property_allowance_deduction":["taxable_property_income"],"property_allowance_deduction_if_used":["property_allowance_deduction","uses_property_allowance"],"property_finance_cost_relief":["income_tax","uc_income_tax_on_earnings","uc_income_tax_on_trade"],"property_finance_costs":["deductible_property_finance_costs","property_finance_costs_relievable","property_income_after_finance_costs"],"property_finance_costs_brought_forward":["property_finance_costs_carried_forward","property_finance_costs_relievable"],"property_finance_costs_relievable":["property_finance_costs_carried_forward","property_finance_costs_relieved","uses_property_allowance"],"property_finance_costs_relieved":["property_finance_cost_relief","property_finance_costs_carried_forward"],"property_income":["hbai_household_net_income","household_market_income","housing_benefit_net_earnings","market_income","property_allowable_expenses","property_allowance_deduction_if_used","property_income_after_finance_costs","property_receipts_within_allowance","taxable_property_income","total_income","uses_property_allowance"],"property_income_after_finance_costs":["council_tax_reduction_applicable_income","housing_benefit_applicable_income","income_support_applicable_income","pension_credit_income","tax_credits_current_year_income"],"property_income_tax":["income_tax","income_tax_pre_charges","uc_income_tax_on_earnings","uc_income_tax_on_trade"],"property_purchased":["additional_residential_property_purchased","main_residential_property_purchased","non_residential_property_purchased"],"property_receipts_within_allowance":["property_allowance_deduction_if_used"],"property_rental_income":["property_allowable_expenses","property_allowance_deduction_if_used","property_receipts_within_allowance"],"property_wealth":["household_land_value","total_wealth"],"rail_subsidy_spending":["dft_subsidy_spending"],"rail_usage":["rail_subsidy_spending"],"received_allowances_dividend_income":["dividend_income_tax","received_allowances","taxed_dividend_income"],"received_allowances_earned_income":["earned_taxable_income","received_allowances","received_allowances_dividend_income","received_allowances_savings_income"],"received_allowances_savings_income":["add_rate_savings_income","basic_rate_savings_income","basic_rate_savings_income_pre_starter","dividend_income_tax","higher_rate_savings_income","received_allowances","received_allowances_dividend_income","savings_starter_rate_income"],"receives_benefits_in_own_right":["is_benefit_cap_exempt_health_disability","is_qualifying_young_person_for_child_benefit","is_qualifying_young_person_for_child_tax_credit","is_qualifying_young_person_for_pension_credit","is_qualifying_young_person_for_universal_credit"],"receives_carer_benefit":["is_cared_for_by_carer_benefit_recipient","is_carer_for_benefits","is_entitled_to_carer_benefit","tax_free_childcare_regarded_as_in_paid_work","uc_non_dep_deduction_exempt"],"receives_carer_support_payment":["receives_carer_benefit"],"receives_carers_allowance":["receives_carer_benefit"],"receives_enhanced_pip_dl":["child_minimum_guarantee_addition"],"receives_highest_dla_sc":["child_minimum_guarantee_addition"],"receives_limited_capability_for_work_credits":["extended_childcare_entitlement_limited_capability_or_specified_benefit","tax_free_childcare_caring_or_incapacity_benefit","tax_free_childcare_regarded_as_in_paid_work"],"receives_severe_disability_addition_qualifying_benefit":["is_counted_resident_for_severe_disability_addition","severe_disability_minimum_guarantee_addition"],"receives_severe_disability_premium_qualifying_benefit":["has_non_dependant_for_severe_disability_premium","severe_disability_premium"],"receives_uc_carer_element":["extended_childcare_entitlement_limited_capability_or_specified_benefit"],"recreation_consumption":["carbon_consumption","consumption"],"reduced_rate_vat_consumption":["baseline_vat","vat"],"region":["benefit_cap","benunit_region","country","household_land_value","maintenance_loan_living_arrangement","uc_has_deduction","uc_latent_deduction_rate"],"relation_type":["is_couple","is_savings_credit_eligible","is_single","savings_credit","standard_minimum_guarantee"],"relative_income_change":["income_elasticity_lsr"],"relative_wage_change":["substitution_elasticity_lsr"],"rent":["hbai_household_net_income_ahc","housing_costs","lbtt_on_residential_property_rent","ltt_on_residential_property_rent","personal_rent","sdlt_on_residential_property_rent"],"rent_paid_as_boarder":["pays_rent_to_householder","personal_rent"],"rent_paid_as_lodger":["pays_rent_to_householder","personal_rent"],"residential_property_value":["property_wealth"],"restaurants_and_hotels_consumption":["carbon_consumption","consumption"],"salary_sacrifice_broad_base_haircut":["employment_income"],"salary_sacrifice_returned_to_income":["employee_pension_contributions","employment_income","salary_sacrifice_pension_ni_employee","salary_sacrifice_pension_ni_employer"],"savings":["council_tax_reduction_assessable_capital","esa_income_assessable_capital","housing_benefit_assessable_capital","income_support_assessable_capital","jsa_income_assessable_capital","kingston_upon_thames_council_tax_reduction","merton_council_tax_reduction","newham_council_tax_reduction","oxford_council_tax_reduction","pension_credit_assessable_capital","total_wealth","uc_assessable_capital","westminster_council_tax_reduction"],"savings_allowance":["add_rate_savings_income","basic_rate_savings_income","higher_rate_savings_income"],"savings_credit":["in_receipt_of_savings_credit_only","pension_credit_entitlement"],"savings_credit_income":["is_savings_credit_eligible","savings_credit"],"savings_income_tax":["income_tax","income_tax_pre_charges"],"savings_interest_income":["capital_income","hbai_household_net_income","household_market_income","housing_benefit_net_earnings","market_income","tax_credits_current_year_income","taxable_savings_interest_income","total_income"],"savings_starter_rate_income":["add_rate_savings_income","basic_rate_savings_income","higher_rate_savings_income"],"scottish_carer_supplement":["gov_spending","hbai_benefits","hbai_household_net_income","household_benefits","pre_budget_change_household_benefits","social_security_income"],"scottish_child_payment":["gov_spending","hbai_household_net_income","household_benefits"],"scottish_funded_early_learning_childcare_start_date_reached":["scottish_funded_early_learning_childcare_eligible"],"sda":["benefit_cap_reduction","carer_support_payment_overlapping_benefits","carers_allowance_overlapping_benefits","extended_childcare_entitlement_limited_capability_or_specified_benefit","gov_spending","hbai_benefits","hbai_household_net_income","household_benefits","pre_budget_change_household_benefits","tax_free_childcare_caring_or_incapacity_benefit","tax_free_childcare_regarded_as_in_paid_work"],"sda_reported":["sda"],"sdlt_liable":["stamp_duty_land_tax"],"sdlt_on_non_residential_property_rent":["sdlt_on_rent"],"sdlt_on_non_residential_property_transactions":["sdlt_on_transactions"],"sdlt_on_rent":["stamp_duty_land_tax"],"sdlt_on_residential_property_rent":["sdlt_on_rent"],"sdlt_on_residential_property_transactions":["sdlt_on_transactions"],"sdlt_on_transactions":["stamp_duty_land_tax"],"self_employment_gross_receipts":["trading_allowance_deduction"],"self_employment_income":["carers_allowance_earnings","council_tax_reduction_applicable_income","earned_income","esa_exempt_work_earnings","extended_childcare_entitlement_meets_income_requirements","hbai_household_net_income","household_market_income","housing_benefit_applicable_income","housing_benefit_net_earnings","housing_benefit_specified_or_temporary_accommodation_disregard","in_work","income_support_applicable_income","market_income","ni_class_4_profits_before_losses","pension_contributions_relief","pension_credit_earnings","tax_credits_current_year_income","tax_free_childcare_expected_declaration_period_income","taxable_self_employment_income","total_income","trading_allowance_deduction","uc_individual_earned_income_before_mif","uc_is_in_gainful_self_employment"],"severe_disability_minimum_guarantee_addition":["additional_minimum_guarantee"],"severe_disability_premium":["maintenance_loan_entitled_to_benefits","pension_age_severe_disability_premium","working_age_benefits_premiums"],"share_of_household_rent":["housing_benefit_non_dep_deductions","personal_rent"],"shareholding":["baseline_business_rates","business_rates","carbon_tax","corporate_incident_tax_revenue_change","corporate_sdlt"],"simulated_council_tax_reduction_benunit":["council_tax_benefit"],"social_security_income":["housing_benefit_net_earnings","income_support_applicable_income","tax_credits_current_year_income","taxable_social_security_income","total_income"],"sparkling_cider_abv":["sparkling_cider_duty"],"sparkling_cider_draught_share":["sparkling_cider_duty"],"sparkling_cider_duty":["alcohol_duty"],"sparkling_cider_litres":["sparkling_cider_duty"],"spirits_abv":["spirits_duty"],"spirits_draught_share":["spirits_duty"],"spirits_duty":["alcohol_duty"],"spirits_litres":["spirits_duty"],"ssmg":["council_tax_reduction_applicable_income","gov_spending","hbai_benefits","hbai_household_net_income","household_benefits","housing_benefit_applicable_income","pre_budget_change_household_benefits"],"ssmg_reported":["ssmg"],"stamp_duty_land_tax":["expected_sdlt"],"standard_minimum_guarantee":["minimum_guarantee","savings_credit"],"stands_as_sole_owner_or_partner_of_company":["uc_company_owner_treatment_applies"],"state_pension":["council_tax_reduction_applicable_income","gov_spending","hbai_benefits","hbai_household_net_income","household_benefits","housing_benefit_applicable_income","overlapping_state_pension","pension_credit_income","pre_budget_change_household_benefits","social_security_income","total_pension_income","uc_unearned_income"],"state_pension_age":["months_since_state_pension_age"],"state_pension_credit_qualifying_age":["has_attained_state_pension_credit_qualifying_age"],"state_pension_reported":["additional_state_pension","basic_state_pension","new_state_pension"],"state_pension_type":["additional_state_pension","basic_state_pension","new_state_pension","overlapping_state_pension"],"statutory_maternity_pay":["adjusted_employer_cost","baseline_employer_cost","council_tax_reduction_applicable_income","employer_cost","employer_ni_fixed_employer_cost_change","employment_benefits","gov_spending","hbai_benefits","hbai_household_net_income","household_benefits","housing_benefit_applicable_income","ni_class_1_income","pre_budget_change_household_benefits","tax_free_childcare_treated_as_in_work","uc_childcare_treated_as_in_paid_work","uc_individual_earned_income_before_mif"],"statutory_paternity_pay":["adjusted_employer_cost","baseline_employer_cost","employer_cost","employer_ni_fixed_employer_cost_change","gov_spending","hbai_benefits","hbai_household_net_income","household_benefits","ni_class_1_income","tax_free_childcare_treated_as_in_work","uc_childcare_treated_as_in_paid_work","uc_individual_earned_income_before_mif"],"statutory_sick_pay":["adjusted_employer_cost","baseline_employer_cost","council_tax_reduction_applicable_income","employer_cost","employer_ni_fixed_employer_cost_change","employment_benefits","gov_spending","hbai_benefits","hbai_household_net_income","household_benefits","housing_benefit_applicable_income","ni_class_1_income","pre_budget_change_household_benefits","tax_free_childcare_treated_as_in_work","uc_childcare_treated_as_in_paid_work","uc_individual_earned_income_before_mif"],"structural_insurance_payments":["hbai_household_net_income_ahc"],"student_loan_balance":["net_wealth","student_loan_repayment"],"student_loan_plan":["has_student_loan","student_loan_interest_rate","student_loan_repayment","student_loan_repayment_rate"],"student_loan_repayment":["student_loan_repayments"],"student_loan_repayment_rate":["student_loan_repayment"],"student_loan_repayments":["gov_tax","hbai_household_net_income","household_tax"],"targeted_childcare_entitlement":["extended_childcare_entitlement_per_child","gov_spending","household_benefits","is_child_receiving_targeted_childcare"],"targeted_childcare_entitlement_eligible":["targeted_childcare_entitlement"],"tax":["benunit_tax","tax_modelling"],"tax_band":["meets_marriage_allowance_income_conditions"],"tax_credit_award":["is_on_pawhp_relevant_benefit","is_on_winter_fuel_payment_relevant_benefit","pawhp_eligible","winter_fuel_payment_eligible"],"tax_credits":["council_tax_reduction_applicable_income","ctc_entitlement","housing_benefit_applicable_income","tax_credit_award"],"tax_credits_applicable_income":["tax_credits_reduction"],"tax_credits_current_year_income":["meets_child_tax_credit_criteria_for_targeted_childcare_entitlement","meets_working_tax_credit_criteria_for_targeted_childcare_entitlement","tax_credits_applicable_income"],"tax_credits_reduction":["child_tax_credit_pre_minimum","working_tax_credit_pre_minimum"],"tax_free_childcare":["childcare_grant_eligible","gov_spending","hbai_benefits","hbai_household_net_income","household_benefits","is_child_receiving_tax_free_childcare"],"tax_free_childcare_caring_or_incapacity_benefit":["tax_free_childcare_regarded_as_in_paid_work"],"tax_free_childcare_child_age_eligible":["tax_free_childcare_qualifying_child"],"tax_free_childcare_eligible":["tax_free_childcare","tax_free_childcare_eligible_declaration_periods"],"tax_free_childcare_eligible_declaration_periods":["tax_free_childcare"],"tax_free_childcare_expected_declaration_period_income":["tax_free_childcare_meets_income_requirements"],"tax_free_childcare_meets_income_requirements":["tax_free_childcare_eligible"],"tax_free_childcare_meets_uk_connection":["tax_free_childcare_program_eligible"],"tax_free_childcare_on_adoption_leave":["tax_free_childcare_treated_as_in_work"],"tax_free_childcare_on_carers_leave":["tax_free_childcare_regarded_as_in_paid_work"],"tax_free_childcare_on_qualifying_leave":["tax_free_childcare_treated_as_in_work"],"tax_free_childcare_on_shared_parental_leave":["tax_free_childcare_treated_as_in_work"],"tax_free_childcare_program_eligible":["tax_free_childcare_eligible"],"tax_free_childcare_qualifying_child":["is_child_receiving_tax_free_childcare","tax_free_childcare","tax_free_childcare_eligible"],"tax_free_childcare_regarded_as_in_paid_work":["tax_free_childcare_meets_income_requirements","tax_free_childcare_work_condition"],"tax_free_childcare_self_employment_start_up_period":["tax_free_childcare_meets_income_requirements"],"tax_free_childcare_spend_routed_share":["tax_free_childcare"],"tax_free_childcare_treated_as_in_work":["tax_free_childcare_regarded_as_in_paid_work","tax_free_childcare_work_condition"],"tax_free_childcare_uses_qualifying_provider":["tax_free_childcare"],"tax_free_childcare_work_condition":["tax_free_childcare_eligible"],"tax_free_savings_income":["taxable_savings_interest_income"],"tax_reported":["tax_modelling"],"taxable_dividend_income":["dividend_income_tax","earned_taxable_income","net_income","non_savings_income_after_allowances","property_finance_costs_relieved","received_allowances_dividend_income","received_allowances_earned_income","taxed_dividend_income","uc_income_tax_on_earnings","uc_income_tax_on_trade"],"taxable_employment_income":["net_income","uc_income_tax_on_earnings","uc_income_tax_on_trade"],"taxable_miscellaneous_income":["housing_benefit_net_earnings","net_income","total_income","uc_income_tax_on_earnings","uc_income_tax_on_trade","uc_individual_earned_income_before_mif"],"taxable_pension_income":["net_income"],"taxable_property_income":["earned_taxable_income","net_income","property_finance_costs_relieved","taxable_property_income_after_allowances","uc_income_tax_on_earnings","uc_income_tax_on_trade"],"taxable_property_income_after_allowances":["non_savings_taxable_income","property_income_tax"],"taxable_savings_interest_income":["add_rate_savings_income","basic_rate_savings_income","basic_rate_savings_income_pre_starter","dividend_income_tax","earned_taxable_income","higher_rate_savings_income","net_income","non_savings_income_after_allowances","property_finance_costs_relieved","received_allowances_earned_income","received_allowances_savings_income","savings_starter_rate_income","uc_income_tax_on_earnings","uc_income_tax_on_trade"],"taxable_self_employment_income":["net_income","uc_income_tax_on_earnings","uc_income_tax_on_trade"],"taxable_social_security_income":["net_income"],"taxed_dividend_income":["taxed_income"],"taxed_income":["personal_pension_contributions_tax"],"taxed_savings_income":["taxed_income"],"tenure_type":["benunit_tenure_type","is_renting","ons_tenure_type"],"tobacco_duty":["gov_tax","household_tax"],"total_income":["bi_household_phaseout","bi_individual_phaseout","household_benefits_individual_non_dep_deduction","housing_benefit_net_earnings","post_tax_income","winter_fuel_payment_eligible"],"total_wealth":["household_wealth_decile","net_wealth","non_primary_residence_wealth_tax","wealth_tax"],"trading_allowance_deduction":["ni_class_4_profits_before_losses","taxable_self_employment_income"],"trading_loss":["loss_relief"],"transport_consumption":["carbon_consumption","consumption"],"travel_grant":["gov_spending","hbai_benefits","household_benefits"],"travel_grant_abroad_placement":["travel_grant_eligible"],"travel_grant_clinical_placement":["travel_grant_eligible"],"travel_grant_eligible":["travel_grant"],"travel_grant_eligible_expenses":["travel_grant_eligible"],"travel_grant_income_assessed_support":["travel_grant_eligible"],"travel_grant_receives_means_tested_nhs_bursary":["travel_grant_eligible"],"tv_licence":["gov_tax","household_tax","pre_budget_change_household_tax"],"tv_licence_discount":["free_tv_licence_value","tv_licence"],"two_child_limit_payment":["gov_spending","household_benefits"],"uc_LCWRA_element":["is_benefit_cap_exempt_health_disability","uc_disability_elements"],"uc_LHA_cap":["uc_housing_costs_element"],"uc_assessable_capital":["is_uc_eligible","kingston_upon_thames_council_tax_reduction","merton_council_tax_reduction","newham_council_tax_reduction","uc_tariff_income","westminster_council_tax_reduction"],"uc_carer_element":["is_benefit_cap_exempt_health_disability","receives_uc_carer_element","uc_maximum_amount"],"uc_child_element":["uc_maximum_amount"],"uc_child_index":["uc_individual_child_element"],"uc_childcare_element":["childcare_grant_eligible","uc_maximum_amount"],"uc_childcare_element_claimed":["uc_childcare_element"],"uc_childcare_element_eligible_children":["uc_maximum_childcare_element_amount"],"uc_childcare_treated_as_in_paid_work":["uc_childcare_work_condition"],"uc_childcare_work_condition":["uc_childcare_element_claimed"],"uc_company_capital":["uc_assessable_capital"],"uc_company_gainful_self_employment":["uc_is_in_gainful_self_employment"],"uc_company_holding_disregard":["household_uc_pool_company_holdings","uc_assessable_capital"],"uc_company_intermediary_exclusion_applies":["uc_company_owner_treatment_applies"],"uc_company_owner_treatment_applies":["uc_company_capital","uc_company_gainful_self_employment","uc_company_holding_disregard","uc_company_self_employed_earnings"],"uc_company_self_employed_earnings":["uc_individual_earned_income_before_mif"],"uc_deduction_combination":["uc_deduction_rate"],"uc_deduction_random_draw":["uc_has_deduction","uc_latent_deduction_rate"],"uc_deduction_rate":["uc_deductions"],"uc_deduction_type_random_draw":["uc_deduction_combination"],"uc_deductions":["universal_credit"],"uc_disability_elements":["uc_maximum_amount"],"uc_earned_income":["kingston_upon_thames_council_tax_reduction","meets_universal_credit_criteria_for_targeted_childcare_entitlement","merton_council_tax_reduction","newham_council_tax_reduction","uc_income_reduction","westminster_council_tax_reduction"],"uc_expected_hours":["uc_minimum_income_floor_gross"],"uc_has_deduction":["uc_deduction_combination","uc_latent_deduction_rate"],"uc_has_offer_of_paid_work_starting_by_end_of_next_assessment_period":["uc_childcare_work_condition"],"uc_housing_costs_element":["uc_maximum_amount","uc_work_allowance"],"uc_income_reduction":["universal_credit_pre_benefit_cap"],"uc_income_tax_on_earnings":["uc_income_tax_on_trade","uc_individual_earned_income_before_mif"],"uc_income_tax_on_trade":["uc_individual_earned_income_before_mif"],"uc_individual_child_element":["uc_child_element","uc_childcare_element_eligible_children","uc_is_child_limit_affected"],"uc_individual_disabled_child_element":["uc_disability_elements"],"uc_individual_earned_income":["uc_earned_income"],"uc_individual_earned_income_before_mif":["is_benefit_cap_exempt_earnings","uc_individual_earned_income"],"uc_individual_non_dep_deduction":["uc_non_dep_deductions"],"uc_individual_non_dep_deduction_eligible":["uc_individual_non_dep_deduction"],"uc_individual_severely_disabled_child_element":["uc_disability_elements"],"uc_is_adopter_in_first_year":["uc_work_related_group_apart_from_earnings"],"uc_is_child_born_before_child_limit":["uc_individual_child_element"],"uc_is_child_limit_affected":["two_child_limit_payment"],"uc_is_foster_parent_or_new_friend_or_family_carer":["uc_work_related_group_apart_from_earnings"],"uc_is_in_gainful_self_employment":["uc_mif_applies"],"uc_is_in_pregnancy_or_post_confinement_period":["uc_work_related_group_apart_from_earnings"],"uc_is_in_startup_period":["uc_mif_applies"],"uc_is_ineligible_partner":["is_benefit_cap_exempt_health_disability","is_lha_shared_accommodation_rate_specified_renter","is_on_universal_credit","is_uc_single_or_joint_claimant","uc_is_responsible_carer","uc_member_of_couple_claims_as_single_person","uc_minimum_income_floor_gross","uc_work_related_group_apart_from_earnings"],"uc_is_responsible_carer":["uc_expected_hours","uc_work_related_group_apart_from_earnings"],"uc_is_responsible_foster_parent_of_child_under_one":["uc_work_related_group_apart_from_earnings"],"uc_is_student_with_no_work_related_requirements":["uc_work_related_group_apart_from_earnings"],"uc_is_temporarily_absent_from_claimant_household":["uc_unable_to_provide_childcare"],"uc_latent_deduction_rate":["uc_deduction_rate"],"uc_limited_capability_for_WRA":["disability_basic_income","extended_childcare_entitlement_limited_capability_or_specified_benefit","is_benefit_cap_exempt_health_disability","uc_limited_capability_for_work","uc_work_related_group_apart_from_earnings"],"uc_limited_capability_for_work":["is_uc_work_allowance_eligible","meets_uc_minimum_age_condition","uc_unable_to_provide_childcare","uc_work_related_group_apart_from_earnings"],"uc_maximum_amount":["kingston_upon_thames_council_tax_reduction","merton_council_tax_reduction","newham_council_tax_reduction","uc_income_reduction","universal_credit_pre_benefit_cap","westminster_council_tax_reduction"],"uc_maximum_childcare_element_amount":["uc_childcare_element"],"uc_member_of_couple_claims_as_single_person":["is_benefit_cap_exempt_health_disability","is_benefit_cap_single_claimant_rate","is_lha_shared_accommodation_rate_specified_renter"],"uc_mif_applies":["uc_individual_earned_income"],"uc_minimum_income_floor":["uc_individual_earned_income"],"uc_minimum_income_floor_gross":["uc_minimum_income_floor","uc_minimum_income_floor_income_tax","uc_minimum_income_floor_national_insurance"],"uc_minimum_income_floor_income_tax":["uc_minimum_income_floor"],"uc_minimum_income_floor_national_insurance":["uc_minimum_income_floor"],"uc_national_insurance_on_earnings":["uc_individual_earned_income_before_mif","uc_national_insurance_on_trade"],"uc_national_insurance_on_trade":["uc_individual_earned_income_before_mif"],"uc_non_dep_deduction_exempt":["uc_individual_non_dep_deduction_eligible"],"uc_non_dep_deductions":["uc_housing_costs_element"],"uc_non_dep_receives_pension_credit":["uc_non_dep_deduction_exempt"],"uc_non_dependants_counted":["LHA_allowed_bedrooms","lha_renter_has_non_dependant","uc_non_dep_deductions"],"uc_reported_capital":["household_uc_pool_company_holdings","household_uc_reported_capital","household_uc_unreported_claimants","uc_assessable_capital"],"uc_standard_allowance":["uc_deductions","uc_maximum_amount","universal_credit"],"uc_standard_allowance_claimant_type":["uc_standard_allowance"],"uc_tariff_income":["uc_unearned_income"],"uc_unable_to_provide_childcare":["uc_childcare_work_condition"],"uc_unearned_carer_support_payment":["uc_unearned_income"],"uc_unearned_income":["kingston_upon_thames_council_tax_reduction","merton_council_tax_reduction","newham_council_tax_reduction","uc_income_reduction","westminster_council_tax_reduction"],"uc_work_allowance":["uc_earned_income"],"uc_work_related_group_apart_from_earnings":["uc_mif_applies","uc_minimum_income_floor_gross"],"uc_youngest_child_age":["uc_expected_hours","uc_is_responsible_carer","uc_work_related_group_apart_from_earnings"],"universal_childcare_entitlement":["extended_childcare_entitlement_per_child","gov_spending","household_benefits","is_child_receiving_universal_childcare"],"universal_childcare_entitlement_eligible":["universal_childcare_entitlement"],"universal_credit":["cost_of_living_support_payment","council_tax_reduction_applicable_income","disability_basic_income","gov_spending","hbai_benefits","hbai_household_net_income","household_benefits","is_on_universal_credit","is_scp_eligible","kingston_upon_thames_council_tax_reduction","kingston_upon_thames_council_tax_reduction_non_dep_deductions","meets_universal_credit_criteria_for_targeted_childcare_entitlement","merton_council_tax_reduction","merton_council_tax_reduction_non_dep_deductions","newham_council_tax_reduction","oxford_council_tax_reduction","pre_budget_change_household_benefits","receives_uc_carer_element","uc_is_child_limit_affected","westminster_council_tax_reduction"],"universal_credit_pre_benefit_cap":["benefit_cap_reduction","is_benefit_cap_exempt_health_disability","is_benefit_cap_single_claimant_rate","is_uc_entitled","tax_free_childcare_program_eligible","uc_deductions","uc_has_deduction","universal_credit"],"universal_credit_reported":["bursary_fund_16_to_19_receives_uc_or_esa_in_own_right","bursary_fund_16_to_19_receives_uc_or_is_in_own_right","claims_all_entitled_benefits","has_mixed_age_couple_pension_credit_saving","is_on_universal_credit","meets_pension_credit_age_conditions","pawhp_eligible","winter_fuel_payment_eligible"],"unused_personal_allowance":["partners_unused_personal_allowance"],"uses_property_allowance":["property_allowance_deduction","property_finance_costs_carried_forward","property_finance_costs_relieved"],"vat":["gov_tax","vat_change"],"vat_change":["household_tax","pre_budget_change_household_tax"],"vehicle_excise_duty":["gov_tax","household_tax"],"water_and_sewerage_charges":["hbai_household_net_income_ahc","housing_costs"],"wealth_tax":["gov_tax","household_tax","pre_budget_change_household_tax"],"weekly_hours":["benunit_weekly_hours","esa_income_remunerative_work_hours","income_support_remunerative_work_hours","is_WTC_eligible","jsa_remunerative_work_hours","meets_housing_benefit_additional_earnings_disregard_conditions"],"westminster_council_tax_reduction":["simulated_council_tax_reduction_benunit"],"westminster_council_tax_reduction_individual_non_dep_deduction":["westminster_council_tax_reduction_non_dep_deductions"],"westminster_council_tax_reduction_non_dep_deductions":["westminster_council_tax_reduction"],"wine_abv":["wine_duty"],"wine_draught_share":["wine_duty"],"wine_duty":["alcohol_duty"],"wine_litres":["wine_duty"],"winter_fuel_allowance":["cost_of_living_support_payment","gov_spending","hbai_benefits","hbai_household_net_income","household_benefits"],"winter_fuel_payment":["winter_fuel_allowance"],"winter_fuel_payment_eligible":["winter_fuel_payment"],"working_age_benefits_premiums":["benefits_premiums","council_tax_reduction_applicable_amount","income_support_applicable_amount"],"working_tax_credit":["gov_spending","hbai_benefits","hbai_household_net_income","household_benefits","is_benefit_cap_exempt_health_disability","is_scp_eligible","meets_child_tax_credit_criteria_for_targeted_childcare_entitlement","meets_working_tax_credit_criteria_for_targeted_childcare_entitlement","pension_credit_income","pre_budget_change_household_benefits","tax_free_childcare_program_eligible"],"working_tax_credit_reported":["claims_all_entitled_benefits","claims_legacy_benefits","council_tax_reduction_pensioner","is_WTC_eligible","is_uc_eligible","legacy_benefits_closed","pawhp_eligible","tax_credit_award","winter_fuel_payment_eligible","would_claim_WTC"],"would_claim_CTC":["child_tax_credit","child_tax_credit_pre_minimum"],"would_claim_IS":["income_support","income_support_assessable_capital"],"would_claim_WTC":["working_tax_credit","working_tax_credit_pre_minimum"],"would_claim_adult_dependants_grant":["adult_dependants_grant_eligible"],"would_claim_bursary_fund_16_to_19":["bursary_fund_16_to_19_vulnerable_group_eligible"],"would_claim_care_to_learn":["care_to_learn_eligible"],"would_claim_carers_allowance":["carer_support_payment_pre_overlap","carers_allowance_pre_overlap","is_carer_for_benefits","partners_care_for_same_severely_disabled_person"],"would_claim_child_benefit":["child_benefit"],"would_claim_childcare_grant":["childcare_grant_eligible"],"would_claim_council_tax_reduction":["kingston_upon_thames_council_tax_reduction","merton_council_tax_reduction","newham_council_tax_reduction","oxford_council_tax_reduction","simulated_council_tax_reduction_benunit","westminster_council_tax_reduction"],"would_claim_disabled_students_allowance":["disabled_students_allowance_eligible"],"would_claim_extended_childcare":["extended_childcare_entitlement_eligible"],"would_claim_housing_benefit":["housing_benefit","housing_benefit_pre_benefit_cap"],"would_claim_marriage_allowance":["marriage_allowance"],"would_claim_parents_learning_allowance":["parents_learning_allowance_eligible"],"would_claim_pc":["in_receipt_of_guarantee_credit","in_receipt_of_savings_credit_only","income_support_eligible","pension_credit"],"would_claim_scp":["scottish_child_payment"],"would_claim_targeted_childcare":["targeted_childcare_entitlement"],"would_claim_tfc":["tax_free_childcare_eligible"],"would_claim_travel_grant":["travel_grant_eligible"],"would_claim_uc":["claims_universal_credit"],"would_claim_uc_at_legacy_closure":["claims_uc_at_legacy_closure"],"would_claim_uc_childcare":["uc_childcare_element_claimed"],"would_claim_universal_childcare":["universal_childcare_entitlement"],"would_evade_tv_licence_fee":["free_tv_licence_value","tv_licence"],"wtc_entitlement":["working_tax_credit"],"youngest_child_age_for_legacy_benefits":["income_support_eligible"],"youngest_claimant_or_partner_age":["income_support_applicable_amount","is_WTC_eligible"]}} diff --git a/app/src/libs/flagship/parameterDependencies.ts b/app/src/libs/flagship/parameterDependencies.ts index 2fed365bb..5d6a6c2e9 100644 --- a/app/src/libs/flagship/parameterDependencies.ts +++ b/app/src/libs/flagship/parameterDependencies.ts @@ -1,16 +1,18 @@ /** * Parameter → variable dependency map, traced from the model. * - * `app/scripts/build-parameter-dependency-map.py` runs policyengine-us with - * core's FullTracer and records which variables read each parameter path - * and which variables consume each variable. This module answers the - * question the validation layer needs: given a reform's parameter paths, - * which model variables does it move, and how far downstream? Depth is the - * validation "ring": 0–1 is the primary variable, 2–4 the mechanism it - * feeds, deeper is incidental. + * `app/scripts/build-parameter-dependency-map.py` runs a country model + * (policyengine-us, or policyengine-uk) with core's FullTracer and records + * which variables read each parameter path and which variables consume + * each variable. This module answers the question the validation layer + * needs: given a reform's parameter paths, which model variables does it + * move, and how far downstream? Depth is the validation "ring": 0–1 is the + * primary variable, 2–4 the mechanism it feeds, deeper is incidental. The + * household section reads the same map upstream, for the inputs a reform + * makes worth filling in. * - * The JSON is loaded lazily — it is a few hundred kilobytes and only the - * validation surfaces need it. + * Each country's JSON is loaded lazily: the US map is over a megabyte and + * only the validation and household surfaces need one. */ export interface ParameterDependencyMap { @@ -124,26 +126,42 @@ export function variablesReachedByPaths( ); } +/** The countries with a traced map, each loaded only when first asked for. */ +const MAP_LOADERS: Record Promise<{ default: unknown }>> = { + us: () => import('@/data/flagship/parameterDependencies.json'), + uk: () => import('@/data/flagship/parameterDependencies.uk.json'), +}; + /** - * Whether a country has a traced map. The map is traced from - * policyengine-us only, so another country's reform paths would match - * US variables: such a country gets no map at all. + * Whether a country has a traced map. Each map is traced from its own + * country's model, so another country's reform paths never match it: a + * country without its own map gets none at all. */ export function hasParameterDependencies(countryId: string): boolean { - return countryId === 'us'; + return countryId in MAP_LOADERS; } -let cached: Promise | null = null; +const cached = new Map>(); -/** The traced map for policyengine-us, loaded once per session. */ -export function loadParameterDependencies(): Promise { - if (!cached) { - cached = import('@/data/flagship/parameterDependencies.json').then( - (module) => module.default as ParameterDependencyMap - ); - cached.catch(() => { - cached = null; +/** + * A country's traced map, loaded once per session. Without a country it is + * the US map, which the validation surfaces (calibration, scorecard, track + * record) read. + */ +export function loadParameterDependencies( + countryId: string = 'us' +): Promise { + const loader = MAP_LOADERS[countryId]; + if (!loader) { + return Promise.reject(new Error(`No traced parameter map for ${countryId}.`)); + } + let map = cached.get(countryId); + if (!map) { + map = loader().then((module) => module.default as ParameterDependencyMap); + cached.set(countryId, map); + map.catch(() => { + cached.delete(countryId); }); } - return cached; + return map; } diff --git a/app/src/tests/fixtures/components/flagship/report/householdSuggestionMocks.ts b/app/src/tests/fixtures/components/flagship/report/householdSuggestionMocks.ts new file mode 100644 index 000000000..871ef7f68 --- /dev/null +++ b/app/src/tests/fixtures/components/flagship/report/householdSuggestionMocks.ts @@ -0,0 +1,46 @@ +import type { VariableInfo } from '@/utils/VariableResolver'; + +/** Universal Credit's child element: a UK reform's parameter. */ +export const UK_CHILD_ELEMENT_PATH = 'gov.dwp.universal_credit.elements.child.amount'; + +/** The Child Tax Credit's base amount: a US reform's parameter. */ +export const US_CTC_BASE_PATH = 'gov.irs.credits.ctc.amount.base'; + +function ukInput(name: string, entity: string, documentation?: string): VariableInfo { + return { + name, + label: name.replaceAll('_', ' '), + entity, + valueType: 'float', + defaultValue: 0, + isInputVariable: true, + hiddenInput: false, + // The UK model files no input under a module. + moduleName: '', + documentation, + }; +} + +/** + * UK inputs as the model's metadata lists them: some a reader describes a + * household with, and one only the microdata sets (a public-spending + * imputation), which the household section never suggests. + */ +export const UK_INPUT_VARIABLES: VariableInfo[] = [ + ukInput('age', 'person'), + ukInput('employment_income', 'person'), + ukInput('childcare_expenses', 'person'), + ukInput('is_disabled_for_benefits', 'person'), + ukInput('rent', 'household'), + ukInput('region', 'household'), + ukInput('dfe_education_spending', 'person'), +]; + +export const UK_HOUSEHOLD_INPUT_NAMES = new Set( + UK_INPUT_VARIABLES.filter((variable) => variable.name !== 'dfe_education_spending').map( + (variable) => variable.name + ) +); + +/** An input only the microdata sets, which the UK map reaches from the child element. */ +export const UK_MICRODATA_ONLY_INPUT = 'dfe_education_spending'; diff --git a/app/src/tests/unit/components/flagship/report/HouseholdImpactSuggestions.test.tsx b/app/src/tests/unit/components/flagship/report/HouseholdImpactSuggestions.test.tsx new file mode 100644 index 000000000..f89ad425d --- /dev/null +++ b/app/src/tests/unit/components/flagship/report/HouseholdImpactSuggestions.test.tsx @@ -0,0 +1,76 @@ +import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; +import { render, screen, userEvent, waitFor } from '@test-utils'; +import { beforeEach, describe, expect, test, vi } from 'vitest'; +import HouseholdImpactSection from '@/components/flagship/report/household/HouseholdImpactSection'; +import { + UK_CHILD_ELEMENT_PATH, + UK_INPUT_VARIABLES, + UK_MICRODATA_ONLY_INPUT, +} from '@/tests/fixtures/components/flagship/report/householdSuggestionMocks'; +import { + BASELINE_POLICY_ID, + HOUSEHOLD_YEAR, + REFORM_POLICY_ID, +} from '@/tests/fixtures/libs/flagship/householdRunMocks'; + +// The model's inputs, as its metadata lists them. +vi.mock('@/utils/VariableResolver', async (importOriginal) => ({ + ...(await importOriginal()), + getInputVariables: () => UK_INPUT_VARIABLES, +})); +// The household builder, tested on its own: a stand-in shows the inputs it is asked to lead with. +vi.mock('@/components/household/HouseholdBuilderForm', () => ({ + default: ({ suggestedVariables }: { suggestedVariables?: string[] }) => ( +
+ ), +})); +vi.mock('@/utils/HouseholdValidation', () => ({ + HouseholdValidation: { isReadyForSimulation: () => ({ isValid: true, errors: [] }) }, +})); + +function renderSection(countryId: string, reformPaths: string[]) { + const queryClient = new QueryClient({ defaultOptions: { queries: { retry: false } } }); + return render( + + + , + countryId + ); +} + +const suggestedInputs = () => + (screen.getByRole('generic', { name: 'Household builder' }).getAttribute('data-suggested') ?? '') + .split(' ') + .filter(Boolean); + +describe('HouseholdImpactSection suggestions', () => { + beforeEach(() => { + vi.clearAllMocks(); + }); + + test("given a UK reform to Universal Credit's child element then the inputs it reads are suggested", async () => { + const user = userEvent.setup(); + renderSection('uk', [UK_CHILD_ELEMENT_PATH]); + + await user.click(screen.getByRole('button', { name: 'Add a household' })); + + await waitFor(() => expect(suggestedInputs()).toContain('childcare_expenses')); + expect(suggestedInputs()).toContain('age'); + }); + + test('given a UK reform then an input only the microdata sets is never suggested', async () => { + const user = userEvent.setup(); + renderSection('uk', [UK_CHILD_ELEMENT_PATH]); + + await user.click(screen.getByRole('button', { name: 'Add a household' })); + + await waitFor(() => expect(suggestedInputs()).toContain('age')); + expect(suggestedInputs()).not.toContain(UK_MICRODATA_ONLY_INPUT); + }); +}); diff --git a/app/src/tests/unit/libs/flagship/householdSuggestions.test.ts b/app/src/tests/unit/libs/flagship/householdSuggestions.test.ts index 15cc1f033..511f11c79 100644 --- a/app/src/tests/unit/libs/flagship/householdSuggestions.test.ts +++ b/app/src/tests/unit/libs/flagship/householdSuggestions.test.ts @@ -1,6 +1,13 @@ import { describe, expect, test } from 'vitest'; import { suggestedHouseholdInputs } from '@/libs/flagship/householdSuggestions'; -import type { ParameterDependencyMap } from '@/libs/flagship/parameterDependencies'; +import { + loadParameterDependencies, + type ParameterDependencyMap, +} from '@/libs/flagship/parameterDependencies'; +import { + UK_CHILD_ELEMENT_PATH, + UK_HOUSEHOLD_INPUT_NAMES, +} from '@/tests/fixtures/components/flagship/report/householdSuggestionMocks'; const MAP = { generatedAt: '', @@ -83,3 +90,21 @@ describe('suggestedHouseholdInputs', () => { ).toEqual(['childcare_expenses']); }); }); + +describe('suggestedHouseholdInputs for the UK', () => { + test("given a change to Universal Credit's child element then a child's age and childcare lead", async () => { + const map = await loadParameterDependencies('uk'); + + const suggested = suggestedHouseholdInputs( + [UK_CHILD_ELEMENT_PATH], + map, + UK_HOUSEHOLD_INPUT_NAMES, + undefined, + new Set(), + 'uk' + ); + + expect(suggested).toContain('age'); + expect(suggested).toContain('childcare_expenses'); + }); +}); diff --git a/app/src/tests/unit/libs/flagship/parameterDependencies.test.ts b/app/src/tests/unit/libs/flagship/parameterDependencies.test.ts index a045746d4..e8b38244c 100644 --- a/app/src/tests/unit/libs/flagship/parameterDependencies.test.ts +++ b/app/src/tests/unit/libs/flagship/parameterDependencies.test.ts @@ -1,5 +1,7 @@ import { describe, expect, test } from 'vitest'; import { + hasParameterDependencies, + loadParameterDependencies, normalizeParameterPath, ParameterDependencyMap, readersOfPath, @@ -86,3 +88,26 @@ describe('variablesReachedByPaths', () => { expect(variablesReachedByPaths([STANDARD_DEDUCTION_PATH], map)).toEqual([]); }); }); + +describe('each country has its own traced map', () => { + test.each(['us', 'uk'])('given %s then it has a traced map', (countryId) => { + expect(hasParameterDependencies(countryId)).toBe(true); + }); + + test('given a country without a traced model then it has none', () => { + expect(hasParameterDependencies('ca')).toBe(false); + }); + + test("given the UK then the map is traced from policyengine-uk, with the UK's parameters", async () => { + const map = await loadParameterDependencies('uk'); + + expect(map.model.package).toBe('policyengine-uk'); + expect(readersOfPath('gov.dwp.universal_credit.elements.child.amount', map)).toContain( + 'uc_individual_child_element' + ); + }); + + test('given no country then the US map loads, as the validation surfaces read it', async () => { + expect((await loadParameterDependencies()).model.package).toBe('policyengine-us'); + }); +}); From e50ee92ae585ef1825c54640c3035b6ae29ea08e Mon Sep 17 00:00:00 2001 From: Anthony Volk <14987227+anth-volk@users.noreply.github.com> Date: Tue, 20 Oct 2026 01:45:58 +0400 Subject: [PATCH 5/7] v3 UK households: acceptance checks from issues #358 and #562 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Tests only: the section already sends UK households as built and runs them in the UK, so these check that behavior against the two issues rather than drive a change. Each was confirmed to fail when the section sent a new household instead of the built one, or ran a UK household against the US API. - #358: the issue's household (an adult earning £100, a dependant aged 10 earning £10, one benefit unit, a BRMA, region and local authority naming different places) is sent as described and its result shows. The v1 API once failed on it; run locally, policyengine-uk 2.130.1 (the version the .py bundle 6.7.5 pins) calculates it for 2025 and 2026. - #562: a couple and a child share one benefit unit and one household; an input set on the benefit unit is sent on the benefit unit; the household runs under the report's two policies and reads in pounds. Saving and reusing a household, #562's second item, belongs to the standalone household report. Co-Authored-By: Claude Opus 5.5 --- .../libs/flagship/householdRunMocks.ts | 41 +++++ .../report/UKHouseholdAcceptance.test.tsx | 141 ++++++++++++++++++ 2 files changed, 182 insertions(+) create mode 100644 app/src/tests/unit/components/flagship/report/UKHouseholdAcceptance.test.tsx diff --git a/app/src/tests/fixtures/libs/flagship/householdRunMocks.ts b/app/src/tests/fixtures/libs/flagship/householdRunMocks.ts index 81ddddea7..c906a43b6 100644 --- a/app/src/tests/fixtures/libs/flagship/householdRunMocks.ts +++ b/app/src/tests/fixtures/libs/flagship/householdRunMocks.ts @@ -258,3 +258,44 @@ export const UK_FAMILY_REFORM_RESULT = ukHouseholdResult({ universalCredit: 20511.06, childBenefit: 2337.4, }); + +/** + * Issue #358's UK household, in the report's year: an adult earning £100 + * and a dependant aged 10 earning £10, in one benefit unit, with a BRMA, + * region and local authority that name different places. The v1 API once + * failed to calculate it; policyengine-uk 2.130.1 calculates it. + */ +export const ISSUE_358_HOUSEHOLD = Household.fromV1CreationPayload({ + country_id: 'uk', + data: { + people: { + you: { age: at(40), employment_income: at(100) }, + 'your first dependent': { age: at(10), employment_income: at(10) }, + }, + benunits: { 'your benefit unit': { members: ['you', 'your first dependent'] } }, + households: { + 'your household': { + members: ['you', 'your first dependent'], + brma: at('AYLESBURY'), + region: at('NORTH_EAST'), + local_authority: at('ABERDEENSHIRE'), + }, + }, + }, +}); + +/** + * Issue #562's UK household: a couple and a child, built with the + * household builder's own controls, with an input set on the benefit unit + * (it opts out of Child Benefit) rather than on a person or the household. + */ +export const UK_COUPLE_WITH_BENEFIT_UNIT_INPUT = Household.starter('uk', HOUSEHOLD_YEAR) + .withBuilderMaritalStatus(HOUSEHOLD_YEAR, 'married') + .withBuilderChildCount(HOUSEHOLD_YEAR, 1) + .setGroupVariableAtYear( + 'benunits', + 'your benefit unit', + 'child_benefit_opts_out', + HOUSEHOLD_YEAR, + true + ); diff --git a/app/src/tests/unit/components/flagship/report/UKHouseholdAcceptance.test.tsx b/app/src/tests/unit/components/flagship/report/UKHouseholdAcceptance.test.tsx new file mode 100644 index 000000000..8a28af42f --- /dev/null +++ b/app/src/tests/unit/components/flagship/report/UKHouseholdAcceptance.test.tsx @@ -0,0 +1,141 @@ +import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; +import { render, screen, userEvent, waitFor, within } from '@test-utils'; +import { beforeEach, describe, expect, test, vi } from 'vitest'; +import HouseholdImpactSection from '@/components/flagship/report/household/HouseholdImpactSection'; +import type { Household } from '@/models/Household'; +import { + BASELINE_POLICY_ID, + calculationResponse, + CREATED_HOUSEHOLD_ID, + HOUSEHOLD_YEAR, + ISSUE_358_HOUSEHOLD, + REFORM_POLICY_ID, + UK_BASELINE_RESULT, + UK_COUPLE_WITH_BENEFIT_UNIT_INPUT, + UK_REFORM_RESULT, +} from '@/tests/fixtures/libs/flagship/householdRunMocks'; + +/** + * Acceptance checks for UK households in v3's report section, from issues + * #358 (a UK household the v1 API once failed to calculate) and #562 (the + * UK household checklist: several people, an input on the benefit unit, + * the report's policies, the whole run). Saving and reusing a household + * (#562's second item) belongs to the standalone household report. + */ + +const mockCreateHousehold = vi.fn(); +const mockFetchHouseholdCalculation = vi.fn(); + +vi.mock('@/api/household', () => ({ + createHousehold: (...args: unknown[]) => mockCreateHousehold(...args), +})); +vi.mock('@/api/householdCalculation', () => ({ + fetchHouseholdCalculationWithBundle: async (...args: unknown[]) => + calculationResponse(await mockFetchHouseholdCalculation(...args)), +})); +// The household builder, tested on its own: a stand-in hands the section a +// household the builder can make, as its onChange does. +vi.mock('@/components/household/HouseholdBuilderForm', async () => { + const fixtures = await import('@/tests/fixtures/libs/flagship/householdRunMocks'); + return { + default: ({ onChange }: { onChange: (household: Household) => void }) => ( +
+ + +
+ ), + }; +}); +vi.mock('@/utils/HouseholdValidation', () => ({ + HouseholdValidation: { isReadyForSimulation: () => ({ isValid: true, errors: [] }) }, +})); + +async function calculateUKHousehold(describe: string) { + const user = userEvent.setup(); + const queryClient = new QueryClient({ defaultOptions: { queries: { retry: false } } }); + render( + + + , + 'uk' + ); + await user.click(screen.getByRole('button', { name: 'Add a household' })); + await user.click(screen.getByRole('button', { name: describe })); + await user.click(screen.getByRole('button', { name: 'Calculate' })); + await waitFor(() => expect(mockCreateHousehold).toHaveBeenCalledTimes(1)); + return mockCreateHousehold.mock.calls[0][0]; +} + +describe('UK households in the report section (issues #358 and #562)', () => { + beforeEach(() => { + vi.clearAllMocks(); + mockCreateHousehold.mockResolvedValue({ result: { household_id: CREATED_HOUSEHOLD_ID } }); + mockFetchHouseholdCalculation.mockImplementation( + async (_country: string, _household: string, policyId: string) => + policyId === BASELINE_POLICY_ID ? UK_BASELINE_RESULT : UK_REFORM_RESULT + ); + }); + + test("given issue 358's household then it is sent as described, and its result shows", async () => { + const sent = await calculateUKHousehold("Describe issue 358's household"); + + expect(sent).toEqual(ISSUE_358_HOUSEHOLD.toV1CreationPayload()); + expect(sent.data.benunits['your benefit unit'].members).toEqual([ + 'you', + 'your first dependent', + ]); + expect(sent.data.households['your household']).toMatchObject({ + brma: { [HOUSEHOLD_YEAR]: 'AYLESBURY' }, + region: { [HOUSEHOLD_YEAR]: 'NORTH_EAST' }, + local_authority: { [HOUSEHOLD_YEAR]: 'ABERDEENSHIRE' }, + }); + const result = await screen.findByRole('region', { name: 'Household impact' }); + expect( + within(result).getByRole('group', { name: 'Change in annual net income' }) + ).toHaveTextContent('+£500'); + }); + + test('given a couple and a child then all three share one benefit unit and one household', async () => { + const sent = await calculateUKHousehold('Describe a couple with a child'); + + const everyone = ['you', 'your partner', 'your first dependent']; + expect(Object.keys(sent.data.people)).toEqual(everyone); + expect(sent.data.benunits['your benefit unit'].members).toEqual(everyone); + expect(sent.data.households['your household'].members).toEqual(everyone); + }); + + test('given an input on the benefit unit then it is sent on the benefit unit', async () => { + const sent = await calculateUKHousehold('Describe a couple with a child'); + + expect(sent).toEqual(UK_COUPLE_WITH_BENEFIT_UNIT_INPUT.toV1CreationPayload()); + expect(sent.data.benunits['your benefit unit'].child_benefit_opts_out).toEqual({ + [HOUSEHOLD_YEAR]: true, + }); + expect(sent.data.households['your household'].child_benefit_opts_out).toBeUndefined(); + }); + + test("given a UK household then it runs under the report's two policies, in pounds", async () => { + await calculateUKHousehold('Describe a couple with a child'); + + await waitFor(() => + expect(mockFetchHouseholdCalculation.mock.calls).toEqual([ + ['uk', String(CREATED_HOUSEHOLD_ID), BASELINE_POLICY_ID], + ['uk', String(CREATED_HOUSEHOLD_ID), REFORM_POLICY_ID], + ]) + ); + const result = await screen.findByRole('region', { name: 'Household impact' }); + expect(within(result).getByRole('table', { name: 'Taxes and benefits' })).toHaveTextContent( + 'Income Tax' + ); + expect(result).not.toHaveTextContent('$'); + }); +}); From e05fa6d3ec7e52800e43f815c0cf0f33dab874cc Mon Sep 17 00:00:00 2001 From: Anthony Volk <14987227+anth-volk@users.noreply.github.com> Date: Tue, 20 Oct 2026 17:05:48 +0400 Subject: [PATCH 6/7] v3 household tests and comments: name the Public API, and result rows Comments and test names added for v3 households called the Public API "the v1 API", and called the taxes and benefits a result lists its "lines". They now say "the Public API" and "rows"; the fixture COUNTRY_WITHOUT_HOUSEHOLD_LINES is now COUNTRY_WITHOUT_HOUSEHOLD_RESULT_ROWS. Wording and naming only, so no test could fail first. The affected tests (householdRun.test.ts, UKHouseholdAcceptance.test.tsx) pass. Co-Authored-By: Claude Opus 5.5 --- app/src/libs/flagship/householdRun.ts | 6 +++++- .../tests/fixtures/libs/flagship/householdRunMocks.ts | 10 +++++----- .../flagship/report/UKHouseholdAcceptance.test.tsx | 2 +- app/src/tests/unit/libs/flagship/householdRun.test.ts | 8 ++++---- 4 files changed, 15 insertions(+), 11 deletions(-) diff --git a/app/src/libs/flagship/householdRun.ts b/app/src/libs/flagship/householdRun.ts index 2df3f3bb0..3edc6f49f 100644 --- a/app/src/libs/flagship/householdRun.ts +++ b/app/src/libs/flagship/householdRun.ts @@ -212,7 +212,11 @@ const LINES: Partial< uk: { components: UK_COMPONENTS, programs: UK_PROGRAMS }, }; -/** A country's lines; another country has none, and is never read as the US. */ +/** + * The rows a country's result lists (its `LINES` entry: parts of net + * income and programs). A country without an entry has none, and is never + * read as the US. + */ function linesFor(countryId: string) { const lines = LINES[countryId as CountryId]; if (!lines) { diff --git a/app/src/tests/fixtures/libs/flagship/householdRunMocks.ts b/app/src/tests/fixtures/libs/flagship/householdRunMocks.ts index c906a43b6..541de1254 100644 --- a/app/src/tests/fixtures/libs/flagship/householdRunMocks.ts +++ b/app/src/tests/fixtures/libs/flagship/householdRunMocks.ts @@ -25,7 +25,7 @@ export const REFORM_RUN_BUNDLE: PolicyEngineBundle = { /** The SPM settings a US calculation response echoes. */ export const NATIONAL_SPM_CONFIG: SPMSelection = { geography_kind: 'national' }; -/** One policy's calculation as the v1 API answers it: the result and how it was made. */ +/** One policy's calculation as the Public API's v1 household route answers it: the result and how it was made. */ export function calculationResponse( result: HouseholdCalculationData, provenance: Omit = {} @@ -33,10 +33,10 @@ export function calculationResponse( return { result, policyengine_bundle: null, ...provenance }; } -/** A country without household result lines in v3. */ -export const COUNTRY_WITHOUT_HOUSEHOLD_LINES = 'ca'; +/** A country whose household results v3 does not list (no rows of taxes and benefits). */ +export const COUNTRY_WITHOUT_HOUSEHOLD_RESULT_ROWS = 'ca'; -/** A married couple with two children, as the household builder sends it to the v1 API. */ +/** A married couple with two children, as the household builder sends it to the Public API. */ export const US_COUPLE_WITH_CHILDREN_PAYLOAD = Household.starter('us', HOUSEHOLD_YEAR) .withBuilderMaritalStatus(HOUSEHOLD_YEAR, 'married') .withBuilderChildCount(HOUSEHOLD_YEAR, 2) @@ -262,7 +262,7 @@ export const UK_FAMILY_REFORM_RESULT = ukHouseholdResult({ /** * Issue #358's UK household, in the report's year: an adult earning £100 * and a dependant aged 10 earning £10, in one benefit unit, with a BRMA, - * region and local authority that name different places. The v1 API once + * region and local authority that name different places. The Public API once * failed to calculate it; policyengine-uk 2.130.1 calculates it. */ export const ISSUE_358_HOUSEHOLD = Household.fromV1CreationPayload({ diff --git a/app/src/tests/unit/components/flagship/report/UKHouseholdAcceptance.test.tsx b/app/src/tests/unit/components/flagship/report/UKHouseholdAcceptance.test.tsx index 8a28af42f..025b66f39 100644 --- a/app/src/tests/unit/components/flagship/report/UKHouseholdAcceptance.test.tsx +++ b/app/src/tests/unit/components/flagship/report/UKHouseholdAcceptance.test.tsx @@ -17,7 +17,7 @@ import { /** * Acceptance checks for UK households in v3's report section, from issues - * #358 (a UK household the v1 API once failed to calculate) and #562 (the + * #358 (a UK household the Public API once failed to calculate) and #562 (the * UK household checklist: several people, an input on the benefit unit, * the report's policies, the whole run). Saving and reusing a household * (#562's second item) belongs to the standalone household report. diff --git a/app/src/tests/unit/libs/flagship/householdRun.test.ts b/app/src/tests/unit/libs/flagship/householdRun.test.ts index 66441ddad..1161627ad 100644 --- a/app/src/tests/unit/libs/flagship/householdRun.test.ts +++ b/app/src/tests/unit/libs/flagship/householdRun.test.ts @@ -11,7 +11,7 @@ import { BASELINE_RESULT, BASELINE_RUN_BUNDLE, calculationResponse, - COUNTRY_WITHOUT_HOUSEHOLD_LINES, + COUNTRY_WITHOUT_HOUSEHOLD_RESULT_ROWS, CREATED_HOUSEHOLD_ID, HOUSEHOLD_YEAR, householdResult, @@ -174,15 +174,15 @@ describe('compareHouseholds', () => { expect(() => compareHouseholds(missing, BASELINE_RESULT, HOUSEHOLD_YEAR, 'us')).toThrow(); }); - test('given a country without household result lines then the comparison fails, not reads as the US', () => { + test('given a country without household result rows then the comparison fails, not reads as the US', () => { expect(() => compareHouseholds( BASELINE_RESULT, REFORM_RESULT, HOUSEHOLD_YEAR, - COUNTRY_WITHOUT_HOUSEHOLD_LINES + COUNTRY_WITHOUT_HOUSEHOLD_RESULT_ROWS ) - ).toThrow(`Household results are not available for ${COUNTRY_WITHOUT_HOUSEHOLD_LINES}.`); + ).toThrow(`Household results are not available for ${COUNTRY_WITHOUT_HOUSEHOLD_RESULT_ROWS}.`); }); }); From aee676651ecfc8ee14665acc0df38609cde8fb57 Mon Sep 17 00:00:00 2001 From: Anthony Volk <14987227+anth-volk@users.noreply.github.com> Date: Tue, 20 Oct 2026 17:07:49 +0400 Subject: [PATCH 7/7] Parameter maps: every caller names its country loadParameterDependencies still defaulted to the US map when called without a country, the implicit US default this PR removes elsewhere. The country is now required: the four validation callers (scorecard matches, calibration matches, reform readers and scorecard comparisons) ask for the US map by name. Their comments no longer say the dependency map is US-only, as a UK map now exists; they say the validation data is the US model's, so only the US map is read. Test first: parameterDependencies.test.ts asks for a map without a country and expects a rejection, with a @ts-expect-error. Before the change the call resolved the US map, and tsc reported the directive as unused; both now pass. Co-Authored-By: Claude Opus 5.5 --- app/src/components/flagship/ScorecardComparisons.tsx | 5 +++-- app/src/components/flagship/ValidationPanel.tsx | 12 +++++++----- app/src/libs/flagship/calibrationMatching.ts | 2 +- app/src/libs/flagship/modelValidation.ts | 2 +- app/src/libs/flagship/parameterDependencies.ts | 11 +++++------ .../unit/libs/flagship/parameterDependencies.test.ts | 11 +++++++++-- 6 files changed, 26 insertions(+), 17 deletions(-) diff --git a/app/src/components/flagship/ScorecardComparisons.tsx b/app/src/components/flagship/ScorecardComparisons.tsx index 70eea4e86..92d189a4d 100644 --- a/app/src/components/flagship/ScorecardComparisons.tsx +++ b/app/src/components/flagship/ScorecardComparisons.tsx @@ -706,10 +706,11 @@ async function fetchScorecardComparisons( signal: AbortSignal ): Promise { let variables: string[] = []; - // The committed dependency map is US-only. Never use it for another country. + // The scorecard is the US model's: only the US dependency map is read, and + // never for another country. if (countryId === 'us') { try { - variables = variablesReachedByPaths(paths, await loadParameterDependencies()).map( + variables = variablesReachedByPaths(paths, await loadParameterDependencies('us')).map( (entry) => entry.variable ); } catch { diff --git a/app/src/components/flagship/ValidationPanel.tsx b/app/src/components/flagship/ValidationPanel.tsx index 0a9a6491a..a94939937 100644 --- a/app/src/components/flagship/ValidationPanel.tsx +++ b/app/src/components/flagship/ValidationPanel.tsx @@ -258,8 +258,9 @@ export function trackRecordPrograms(trackRecord: ModelTrackRecord): string[] | n * at page level, not inside a tab panel, so the request runs in * parallel with the rest of the report instead of starting on tab * click (inactive tab panels are unmounted). The track record is the - * US model's (its dependency map and comparison table are US-only), so - * another country gets an empty one, and an unknown country waits. + * US model's (it reads the US dependency map, and its comparison table + * is US-only), so another country gets an empty one, and an unknown + * country waits. */ export function useModelTrackRecord( paths: string[], @@ -352,8 +353,9 @@ const NO_READERS: Record = {}; /** * The variables that read each reform path directly, from the traced - * dependency map: `undefined` while it loads. The map is US-only, so - * another country, or a map that fails to load, matches on the paths alone. + * dependency map: `undefined` while it loads. Only the US map is read here, + * as the validation data is the US model's, so another country, or a map + * that fails to load, matches on the paths alone. */ export function useReformReaders( countryId: string, @@ -368,7 +370,7 @@ export function useReformReaders( } const request = JSON.parse(requestKey) as { paths: string[] }; let cancelled = false; - loadParameterDependencies() + loadParameterDependencies('us') .then((map) => Object.fromEntries(request.paths.map((path) => [path, readersOfPath(path, map)])) ) diff --git a/app/src/libs/flagship/calibrationMatching.ts b/app/src/libs/flagship/calibrationMatching.ts index f4ce07f9e..b4b3aa845 100644 --- a/app/src/libs/flagship/calibrationMatching.ts +++ b/app/src/libs/flagship/calibrationMatching.ts @@ -436,7 +436,7 @@ export async function calibrationMatchesForPaths( ): Promise { let map; try { - map = await loadParameterDependencies(); + map = await loadParameterDependencies('us'); } catch { return null; } diff --git a/app/src/libs/flagship/modelValidation.ts b/app/src/libs/flagship/modelValidation.ts index c4d827d4f..2aae9b5bc 100644 --- a/app/src/libs/flagship/modelValidation.ts +++ b/app/src/libs/flagship/modelValidation.ts @@ -203,7 +203,7 @@ export async function scorecardMatchesForPaths( ): Promise { let map; try { - map = await loadParameterDependencies(); + map = await loadParameterDependencies('us'); } catch { return null; } diff --git a/app/src/libs/flagship/parameterDependencies.ts b/app/src/libs/flagship/parameterDependencies.ts index 5d6a6c2e9..c6e877bdc 100644 --- a/app/src/libs/flagship/parameterDependencies.ts +++ b/app/src/libs/flagship/parameterDependencies.ts @@ -144,13 +144,12 @@ export function hasParameterDependencies(countryId: string): boolean { const cached = new Map>(); /** - * A country's traced map, loaded once per session. Without a country it is - * the US map, which the validation surfaces (calibration, scorecard, track - * record) read. + * A country's traced map, loaded once per session. Every caller names its + * country, so none is given the US map by default: the validation surfaces + * (calibration, scorecard, track record) ask for the US map, as their data + * is the US model's. */ -export function loadParameterDependencies( - countryId: string = 'us' -): Promise { +export function loadParameterDependencies(countryId: string): Promise { const loader = MAP_LOADERS[countryId]; if (!loader) { return Promise.reject(new Error(`No traced parameter map for ${countryId}.`)); diff --git a/app/src/tests/unit/libs/flagship/parameterDependencies.test.ts b/app/src/tests/unit/libs/flagship/parameterDependencies.test.ts index e8b38244c..91fd3ebec 100644 --- a/app/src/tests/unit/libs/flagship/parameterDependencies.test.ts +++ b/app/src/tests/unit/libs/flagship/parameterDependencies.test.ts @@ -107,7 +107,14 @@ describe('each country has its own traced map', () => { ); }); - test('given no country then the US map loads, as the validation surfaces read it', async () => { - expect((await loadParameterDependencies()).model.package).toBe('policyengine-us'); + test('given the US then the map is traced from policyengine-us, as the validation surfaces read it', async () => { + expect((await loadParameterDependencies('us')).model.package).toBe('policyengine-us'); + }); + + test('given no country then no map loads, so no caller is given the US map by default', async () => { + // @ts-expect-error Every caller names its country. + await expect(loadParameterDependencies()).rejects.toThrow( + 'No traced parameter map for undefined.' + ); }); });