Skip to content

UK November event data, PR2: feed re-pin, trading allowance claim status, Scottish council tax and NSND, young people and PIP rows, UC take-up age fit, PIP points, UC limited capability - #1550

Merged
juaristi22 merged 29 commits into
mainfrom
uk-event-data-pr2
Nov 10, 2026

Conversation

@juaristi22

@juaristi22 juaristi22 commented Nov 9, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

PR2 of the plan for the November event data (microcosm#1095). It re-pins the UK feed onto Chronicle main after PolicyEngine/chronicle#423, #424 and #425, which bring PolicyEngine/chronicle#420's facts for the November UK events, and carries the pieces that read them. It stays on policyengine-uk 2.174.1, as main locks it.

Closes #1439 (T1). That issue's last "Done when" item, the national rebuilt and the trading allowance measure rescored on it, follows with PR2's datasets after the merge.

Draft. María signed the PR's texts on 9 November 2026 (see "Rulings and signatures"). Lane P's PIP points stage (P1) and Y1, the admin-linked limited capability status, are in, and María signed their eleven choices the same day. The arm at the signed head and four calibrate-only variants ran on 9 and 10 November (see "Measurement"). On their results María chose on 10 November to bind Y4's two age bands and P2's PIP award split, and to keep S4 held out. She signed the one restated register text the same day.

  • The re-pin to 8045b13 (2,091,616 rows).

    • A row-by-row diff of the two artifacts finds no row dropped and no value moved; 506,321 rows are new.
    • No compiled value moves on either surface: both reference files and both compile-parity receipts are byte-identical. The vendored resources carry the same rows under the new feed identity.
  • Nit 3 (Vahid's review of UK November event data, PR1: full-time education, single ages 16 to 24, Scottish PRIS diagnostics, energy kWh columns #1535): apprentices only outside full-time education.

    • frs_person_draws no longer flags an employee aged 21 to 24 who is in full-time education (is_in_full_time_education). The FRS never codes an apprentice that way.
    • The draw's target is unchanged; only its pool narrows. On 2.174.1 only the s.9B employer NICs relief reads the flag at these ages.
  • T1, microcosm#1439: the trading allowance claim status in three outcomes.

    • trading_allowance_receipts writes trading_allowance_claim_status: CLAIMANT for drawn claimants, NON_CLAIMANT for other traders with a positive profit, UNKNOWN otherwise. self_employment_gross_receipts stays at the engine's zero.
    • The full-relief group (FRS respondents with a profit of £1,000 or less, not drawn claimants) is empty at its share of zero. The five bound SPI self-employment rows count declarers only, so no row moves.
    • The claimant rates are re-fitted on control C2's release to HMRC's figures of about 400,000 gainers at about £380: 0.6364 for profits up to £4,500 and 0.1532 up to £9,000 (from 0.72 and 0.14).
    • tools/measure_uk_trading_allowance_gainers.py judges the rates on the expected gainers, each band's rate times its would-be gainers, against 400,000 within 5%. The release's realised count is reported beside it (María's ruling of 9 November 2026).
  • S4: HMRC's Scottish NSND outturn 2024-25, two held-out diagnostics. These are the revenue (£18,635m, uprated to 2025 by the OBR earnings index) and the taxpayer count (3,036,400, read at 2025 under a reviewed hold, since no pinned index counts taxpayers).

  • S2(a): Scotland's council tax bills levelled.

    • The level is the Scottish Government's 2024-25 liability before council tax reduction: CTAXBASE 2025's Band D equivalents at September 2024, times CTAS 2026's average Band D, over the 32 councils, £3.393bn.
    • One factor at the spine design weights scales the bills. The bound band stock keeps the mix, so no weight moves.
  • Y4: DWP's people on Universal Credit aged 16 to 24, 16 to 21 and 22 to 24.

    • Great Britain, every regime, on the four quarterly points of 2025.
    • 16 to 21 and 22 to 24 bind (María's call of 10 November 2026). 16 to 24, their sum, stays held out as the check on them.
    • The 16 to 17 count never appears alone or by difference.
  • P3: DWP's PIP cases with entitlement, 94 rows. England and Wales are separate rows, each with its total, the awards of each component and age bands; the nine English regions are split by each award. All are single breakdowns. Each country's six award rows bind, the award split (P2, María's call of 10 November 2026); the other 82 stay held out.

  • Y3: ONS's NEET people aged 16 to 24, held out. It is the mean of 2025's four LFS quarters, not seasonally adjusted, on a new quarterly_window_average compile rule.

  • The UC take-up redraw fits young claimants by age (uc_take_up, María's call of 9 November 2026).

    • Y2's flag takes full-time students off UC, and the redraw refilled the single caseload by award band without reading age.
    • Now, within every pool, the drawn units with a claimant or partner aged 16 to 24 claim at one odds ratio against the pool's other drawn units. The ratio is solved so that young claimants and partners come as near DWP's count as the redraw allows.
    • On the first arm it stopped at the low end of its range (see "Measurement"). So, on María's second call of 9 November 2026, a shortfall passed between pools now fills only units with no young claimant or partner. A family type whose shortfall only young units could fill falls short of DWP's count by it, and the receipt records what stays unplaced.
  • P1: PIP points for every recipient (pip_points, María's go of 9 November 2026).

    • policyengine-uk decides a PIP component's rate from pip_dl_points and pip_m_points (8 points standard, 12 enhanced) wherever no category is supplied for the year. The release used to store the categories, which the engine copies into every projected year, so no reform to the thresholds could move anyone.
    • A new late stage draws each recipient's daily living and mobility points within their stored award, by age group. The source is DWP's Pathways to Work evidence pack, chapter 2, Tables 2.9 and 2.10 (England and Wales, end of January 2025; chronicle#420 item 5).
    • The release carries the points instead of the categories, and the spine keeps the categories for VED and the severe disability flag. With unchanged thresholds the engine's categories equal the stored ones for every person, which an engine test checks for 2024 to 2030.
    • Table 2.9's whole percentages add to between 92 and 102 per row as ported (16 to 19 is the 92). The draw uses each row's shares only relative to one another within an award's range, and the receipt records every row's total.
  • Y1: DWP's limited capability status on linked UC claims (uc_limited_capability, María's NS6 ruling of 9 November 2026, which revisits her ruling of 29 October to keep the engine's proxy).

    • policyengine-uk gives limited capability for work and work-related activity to anyone flagged is_disabled_for_benefits (any reported disability benefit or ESA), unless their own ESA award lacks the support component.
    • The FRS 2024-25 links most UC claims to DWP's records, and BENEFITS.UCLCW gives the claim's own status (SN 9563's data dictionary: 0 None, 1 LCFW Group, 2 LCFWRA Group; blank where the claim isn't linked). frs_spine carries it on the UC row's person; the FRS keeps one UC row per claim, couples included.
    • A new engine-backed stage just before uc_take_up stores both flags for everyone: the locked engine's proxy, with DWP's status on linked FRS claims. Unlinked reporters, the take-up redraw's entrants, the legacy-closure movers and every SPI row keep the proxy.
    • On the age-fit arm's spine, the status and the proxy disagree on a substantial share of linked claims in both directions, so Y1 changes who has the LCWRA element more than how many. Before take-up, the model's LCWRA units already sit near DWP's count, so the bound LCWRA row's starting gap looks like a take-up question rather than a flags one.

Measurement

  • Control C2 (0dff7773e: main after PR1 plus the re-pin; review date 2026-11-07; feed 8045b13):
    • all seven terminal gates pass, with 98.7% of 1,514 rows within 10%;
    • its release is identical to main's last national build, every column and every weight.
  • The first arm (this branch's data at cf73a73ad, before the squash; review date 2026-11-09):
    • all seven terminal gates pass. The final loss is 0.00515 (C2 0.00514), with 98.8% of 1,514 rows within 10%.
    • The age fit stopped short, which led to the age-aware gap rule (see "Summary"). At its smallest ratio, young claimants and partners still came to 1.24 times DWP's count at the stage's weights. A replay of the stage on the spine's checkpoint (identical receipt and output) showed why:
      • about half the young claims are units that report UC, which no ratio moves;
      • almost all the rest sat in single award-band pools whose count needed every drawn unit, mostly the £200 to £400 a month bands around the under-25 standard allowance;
      • those pools were full because the shortfall of DWP's high-award single counts passed down to them: the model entitles fewer high-award singles than DWP counts.
    • Held out on its release: Y4's 16 to 24 read 1.28 times DWP's 762,585; Y3 was 2.7% below ONS; England's PIP caseload was 3.9% above DWP's and Wales's 0.4%, with England's cases aged 16 to 34 about 42% above.
  • The arm at the signed head (daa359a0b; a full spine, since P1 and Y1 change stages; review date 2026-11-09):
    • all seven terminal gates pass. The final loss is 0.00515, with 1,497 of 1,514 rows within 10% (98.9%).
    • At the spine: at the spine's design weights, Y4's 16 to 24 row meets DWP's count (1.002 times), so the age-aware rule works. A replay of uc_take_up reproduces the stored receipt. Replayed with and without Y1's flags, it gives 1.2% more Great Britain benefit units claiming with an LCWRA element with them.
    • P1: on the release, the engine's categories from the stored points equal the stored awards for every recipient.
    • T1: 399,300 expected gainers (−0.2%), within the 5% tolerance; the release's own draw gives 379,100.
    • The bound UC rows start lower at the spine's weights than on the first arm (households −11.2% against −6.7%; households with a deduction −15.8% against −11.1%), and end within a point of where they ended there.
    • Held out on the release:
      • Y4's 16 to 24 reads 1.24 times DWP's count, so the solve puts back nearly all that the age-aware rule took off at the spine.
      • Y3's NEET count moves from 2.7% below ONS to 16.2% above. The proxy's count at design weights is the same on both arms, so the move is all weights: the solve refills the bound UC rows through the young people still drawn to claim, mostly NEET.
      • P3: 33 of 94 rows within 10%.
  • Calibrate-only variants on that arm's spine (the same review date; each a local commit on the signed head, never pushed):
    • S4 (both NSND rows bound): both land within 0.3% and all seven gates pass, but five SPI income-band rows cross 10%, four of them Scottish. The solve can't lower Scotland's NSND tax by about 5% while SPI's tax on all income stays bound by band, so it trims Scottish taxpayers in the middle bands. S4 stays held out.
    • P2 (England's and Wales's award split, 12 rows): the 12 rows land within 0.5%. One Scottish SPI row that sits on the 10% line from arm to arm crosses it.
    • Y4 (16 to 21 and 22 to 24): no row crosses 10%, and 16 to 24 lands at −0.1% as their sum. NEET falls to 3.1% above ONS. P3: 36 of 94 within 10%; England's cases aged 20 to 24 go from 37% to 14% above DWP's.
    • Y4 and P2 together (the register this PR now carries):
      • all seven terminal gates pass. The final loss is 0.00513, with 1,510 of 1,528 rows within 10%.
      • All 14 bound rows land within 0.3%, and 16 to 24 lands at +0.1%. NEET is 1.1% above ONS.
      • England's and Wales's PIP totals land (0.0% and −0.1%), since each component's awards sum to the caseload.
      • P3's other 82 rows: their mean absolute error falls from 0.226 on the base arm (0.220 with Y4 alone) to 0.203, but 24 are within 10%, against 27 (29). England's young bands come closer: 16 to 19 is 37% above DWP's (52% on the base arm), 20 to 24 is 7% above (37%) and 30 to 34 is 26% above (37%). With the totals pinned, the older bands slip 1 to 4 points further below than with Y4 alone, so the caseload's age profile still runs young.
      • Elsewhere: two bound ONS population rows (women aged 19, and ages 20 to 29 in the South West) move by 3 to 4 points and stay inside 10%. One SPI income-tax band row that sits on the 10% line crosses it.

Rulings and signatures

María's call of 10 November 2026, on the calibrate-only variants: bind Y4's 16 to 21 and 22 to 24 rows and P2's award split, and keep S4's two rows held out (b835be176; the signature below is 33c273773).

  • The two Y4 parts' exclusions and the twelve award rows' exclusions go: the register holds 135 rows, from 149.
  • Signed by María on 10 November 2026: 16 to 24's restated reason and adjudication. The reason now says the solve binds its two parts and it stays held out as their check; the adjudication records the call. The entry carries approved_on 2026-11-10 and expires 2027-02-10, so the next arm needs a review date from 2026-11-10.

Signed by María on 9 November 2026. The registers carry approved_on 2026-11-09: the exclusions expire 2027-02-09 and the S4 hold 2027-01-09. The arm's review date is the signing day.

  • Nit 3: the restated frs_person_draws eligibility text.
  • T1:
  • S4: the two exclusions and the taxpayer count's reviewed_no_index uprating hold.
  • S2(a):
    • the level's rule;
    • one factor rather than one per band;
    • the September 2024 base;
    • a frame with no Scottish bill keeps its bills.
  • Y4: the three exclusions. Their reason states what the age fit can and can't do. Two go on 10 November, and 16 to 24's is restated (above).
  • P3: the 94 exclusions, of which 82 stay after 10 November.
  • Y3: the exclusion, with two choices within María's rule: not seasonally adjusted, and calendar 2025's quarters.
  • P1 (pip_points):
    • Points within a band: spread evenly over its integers, with the open band (41 and over) at 41.
    • Scotland's and Northern Ireland's recipients use England and Wales's tables.
    • Pension-age recipients take the 60-and-over row, which carries them.
    • The draws are seeded on person_id.
    • The two categories leave the release. This covers their reviewed export exclusions and the coverage manifest's two engine-derived entries, dated 2026-11-09. The manifest tool admits those entries through a reviewed list of inputs the pinned engine derives since the eFRS reference's 2.89.0.
  • Y1 (uc_limited_capability, NS6 revisited):
    • NS6 restated: read UCLCW for linked claims, and keep the proxy elsewhere. The bound LCWRA row's note records it, and no longer says the carer and childcare rows sit on the measure-exclusion register, since neither does.
    • The code mapping: 0 None, 1 LCW, 2 LCWRA; blank means not linked.
    • The joint-claim rule: where the proxy flags no claimant, the status goes to the UC row's person, or to the partner where the UC row's person cares and the partner doesn't, so a carer keeps the carer element.
    • NONE overrides the proxy: a linked claim with no status has no LCW or LCWRA, whatever its disability benefits.
    • Who keeps the proxy: unlinked reporters, the take-up redraw's entrants, the legacy-closure movers and SPI rows. uc_reporter_redraw's award screen, earlier in the spine, still reads the proxy.

Still to come in this PR

  • Review rounds.

Not in this PR

  • P2's original award-mix correction: P3's data put the gap in the age profile, not the award mix, so this PR binds the award split instead.
  • PIP's age profile: it still runs young with the split bound (see "Measurement"), and nothing here corrects it.
  • Y4's split by conditionality regime: it waits for María's mapping of DWP's regimes.
  • P4, binding Scottish ADP and Carer Support Payment spending: a limitation instead. Scottish disability and carer payments (Adult Disability Payment, Carer Support Payment) are not calibrated to Social Security Scotland: the data hold about a third fewer Scottish recipients than its caseload, and binding the spending would stretch those households' weights beyond the build's limit.
  • The policyengine-uk bump.

Derived surfaces

  • Regenerated on the national cut of feed 8045b13:
    • the national target references and membership: 1,697 active references, the 1,599 before plus the 98 new rows (84 still held out after the binds), with no existing reference moved;
    • the national compile-parity receipt, with 98 new ledger-only rows;
    • the release-input coverage manifest;
    • the H2 spine fixture.
  • The local surfaces move only with the re-pin's feed identity.
  • Three new vendored resources come from the pinned feed: scotgov_band_d_liability_facts.json (S2(a)), dwp_uc_people_by_age_facts.json (the age fit) and dwp_pip_points_facts.json (P1).
  • For P1:
    • the coverage manifest's pip_points family, and the two categories as reviewed exclusions (141 required and 4 reviewed of 145 inputs);
    • the H2 fixture's 55th stage;
    • the release contract's committed digests in microcosm-data (the spec's policy, gates manifest and fingerprint, and the release cut's scoped parts), re-pinned on this spec. They also catch up with PR2's earlier commits, whose spec and gates.json edits had left them at main's values.
  • For Y1:
    • the coverage manifest's uc_limited_capability family (still 141 required and 4 reviewed of 145 inputs);
    • the H2 fixture's 56th stage, and UCLCW in its synthetic BENEFITS rows;
    • the release contract's digests, re-pinned again.
  • For the binds: none move. No committed reference, receipt, fixture or digest reads the measure-exclusion register or the contract's parity notes.

Testing

Targeted tests by touched surface at each step, one process per file:

  • The re-pin:
    • 14 direct files: 444 passed;
    • a sweep of 55 engine-free files: 2,481 passed, 11 skipped;
    • H2 parity: passed.
  • Nit 3, T1, S4 and S2(a):
    • 43 engine-free files: 2,433 passed, 10 skipped;
    • 8 engine-tier files: all passed, including T1's claim status (9) and H2 parity.
  • Y4, P3 and Y3:
    • the shared compiler suite: 514 passed;
    • after the regeneration, the 30 files that read the references: all passed.
  • The age fit:
    • 21 engine-free files: 1,243 passed, 1 skipped;
    • H2 parity: passed.
  • The final text corrections:
    • the 19 engine-free files that read the exclusions register, the stage module or the changelog: 1,124 passed, 6 skipped;
    • H2 parity: passed.
  • The age-aware gap rule, at the head: 23 engine-free files that read the stage, the spec or the registers: 1,400 passed, 1 skipped. H2 parity, on the regenerated fixture, passed. On the stage's saved inputs from the arm, the committed code reproduces the replay's result exactly.
  • The signing commit:
    • 32 engine-free files that read the registers, the stage spec, the coverage manifest or the contract digests: 1,894 passed, 6 skipped;
    • H2 parity, on the regenerated fixture: passed.
  • P1, at the head:
    • the full set a stage change reaches, 302 engine-free files (microcosm-build's 274 UK files, the 18 spec-engine files, the gate-battery, coverage and spec files, and microcosm-data's contract test) and 8 engine files: 8,211 passed, 39 skipped and 8 failed of 8,258;
      • two failures were P1's own pins in the engine test_uk_release_input_coverage.py, now restated;
      • two were tests T1 and Nit 3 had left stale, test_uk_pension_age_benefit_targets and test_uk_stochastic_tools, now pinned in e7f8223a3;
      • four fail only on the local machine: test_uk_cgt_projection (the engine is installed there), the two in test_uk_rowwise_build_driver (a temp folder under home prints as ~; they pass outside it) and test_uk_orrery_reconstruction (Orrery's Node package isn't installed locally);
    • the restated and pinned files, rerun: all passed;
    • the 13 other engine files that read the stage list, the registers or the coverage ledger: 117 passed;
    • H2 parity, on the regenerated fixture: passed.
  • CI at a859ac7c9 failed in the engine-free job, in test_uk_release_assembler, on the release contract's stale digests, which 2e0dc5771 re-pins. CI stops at its first failure.
  • Y1, at the head (targeted tests, as María asked: the files Y1's surface reaches):
    • 26 engine-free files (the spine and its carrier, the new stage, the roster and spec files, the export, coverage and contract registers, the LCWRA row's readers, uc_take_up and the concept mapping) and 7 engine files: 1,704 passed, 5 skipped and 2 failed of 1,711;
      • both failures were pins Y1 moves: uc_take_up's preceding stage, and the engine coverage test's required build stages. Restated; the two files rerun pass (34 and 52);
    • the stage's own tests: 6 engine-free, and 2 engine on 2.174.1 (unlinked people keep the engine's proxy exactly, and the LCWRA element follows DWP's status in 2024 and 2025);
    • H2 parity, on the regenerated fixture: passed.
  • The signing commit (daa359a0b): the 13 engine-free and 2 engine files that read the signed texts, the coverage manifest or the contract: 920 passed and 5 skipped of 925. H2 parity, on the regenerated fixture: passed.
  • The binds (b835be176), the files that read the measure-exclusion register or the contract's notes:
    • 26 engine-free files: 1,206 passed, 9 skipped and 1 failed of 1,216. The failure was the register's count pin in test_uk_measure_simulation, now 135; the file reruns pass (65);
    • the 2 engine files that key the target kernels on the register, and test_uk_release_assembler: 38 passed.
  • The signature (33c273773): the 20 engine-free files that read the measure-exclusion register and the 2 engine files above: 1,056 passed, 1 skipped.
  • CI at 33c273773 failed in the engine-free job (3.14) on one test of 22,242: a stage-order pin in test_uk_legacy_closure_take_up, stale since Y1 put uc_limited_capability before uc_take_up. 09add3214 restates it, and the file passes (26).
  • UK trading allowance: store the claim status once policyengine-uk#2765 is released #1439's allowance above £3,000 (e4185628d): a reform to £5,000 in 2028-29 relieves a claimant's 2025 profit by min(profit, £4,000) and a non-claimant's by nothing. T1's engine file passes (11).

Checks:

  • ruff check and ruff format --check are clean on the changed Python files, P1's 24, Y1's 22 and the binds' 3 included.
  • tools/ci_test_plan.py verify passes.
  • The feed-gated tests weren't run locally; CI skips them too.

Disclosure

Figures here are national, Great Britain, England, Wales or Scotland-level aggregates, and one English region's population row, each resting on 30 or more survey households. Statements over several rows include cells on fewer: the twelve bound award rows (Wales's nil cells rest on 10 to 29 households) and the counts and averages over P3's rows (cells on 3 to 29 households among them). No figure rests on fewer than three. They include no unit-record values and quote no SPI-channel rows.

🤖 Generated with Claude Code

juaristi22 and others added 19 commits November 7, 2026 22:57
…425

Chronicle main 8045b13 brings PolicyEngine/chronicle#420's facts for the
November UK events, which PR2 of the November event-data plan reads
(microcosm#1095): the young people batch (#423: ONS NEET, the LFS A06
tables, PAYE RTI by age, ASHE Table 6, HMRC's employer NICs age reliefs,
DWP's UC people by age and conditionality regime), the PIP batch (#424:
Pathways to Work PIP points, PIP cases with entitlement) and the Scottish
batch (#425: HMRC's Scottish income tax outturn statistics 2024-25, the
Scottish Government's social security caseloads and spending). It also
carries what main merged after 6475380: #413's UK area inputs, #415's land
value inputs (VOA's council tax stock of properties 2026, MHCLG's council
tax collection and QRC4 for 2025-26, EPC, land value estimates, dwelling
density, the market value survey, ONS land under buildings) and #421's NRS
data zone dwelling bands (2,091,616 rows in all). The rows stay
chronicle.consumer_fact.v5. A row-by-row diff of the two artifacts finds no
row dropped and no value moved: 506,321 rows are new, and 14,784 NRS data
zone rows change only their record-set spec hash.

No compiled value moves on either surface: both reference files and both
compile-parity receipts are byte-identical. The national membership moves
its feed label and the candidate counts of MHCLG's council tax band stock
by region (VOA's 2026 stock adds candidate facts; no resolution changes),
and the local membership its feed label and the 1,263 DESNZ constituency
keys, whose derived keys hash the feed identity. The 38 vendored resources
and the DESNZ constituency resource carry the same rows under the new feed
identity (the DESNZ resource's 2,526 rows and values match on their source
record ids). The census and the validation register restate the pin, the
coverage manifest the CGT resource's hash, and the H2 fixture moves the
stage contract hashes of the 19 stages that bind vendored resources. The
high-value home stock's feed inputs are unchanged, so it is not rebuilt.

The consumer artifact was built with CPython's cyclic garbage collector
off: the build holds every row in memory (about 50 GB footprint on the
24 GiB Mac), and with the collector on the first run stalled for an hour
in collection passes over a swapped heap. The regeneration's Python steps
ran the same way. The rows are acyclic, so the outputs are the same.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…1535, nit 3)

The FRS's full-time education question never codes an apprentice as in
full-time education, so frs_person_draws no longer flags an employee aged
21 to 24 who has is_in_full_time_education (from frs_education). The
draw's target stays r times everyone aged 21 to 24 at the frame's
weights: only the pool it flags from narrows, and the receipt names the
excluded flag. The stage refuses a frame without the flag, and the graph
node declares it as an input.

On policyengine-uk 2.174.1 the flag at these ages moves only the s.9B
employer NICs relief, so the rest of the engine's is_apprentice readers
are unchanged. The stage's signed eligibility text is restated for
María's signature.

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

trading_allowance_receipts keeps its name and #1428's claimant draw, and
now writes policyengine-uk's trading_allowance_claim_status instead of
encoding the claim in gross receipts, which stay at the engine's zero.
Drawn claimants are CLAIMANT, so a raise to GBP 3,000 relieves exactly
min(profit, GBP 2,000) more. Every other trader with a positive profit
is NON_CLAIMANT. A person with no positive profit is UNKNOWN, and so is
the full-relief group: FRS respondents with a profit of GBP 1,000 or
less, not drawn claimants, whose receipts lie within the allowance. SPI
rows never join the group.

The group's share is María's ruling. It is zero, since M10 found no FRS
surplus over SPI's declarers, so the group is empty. The carrier
trading_allowance_full_relief marks it. The five bound SPI
self-employment rows (Table 3.10 by self-employment band, Table 3.6 by
total income) now count declarers only by filtering on the carrier, so
no row moves while the group is empty. The release keeps the carrier,
so a re-measured row reads the same population.

The spec, schema branch and graph cells follow. The claim status leaves
the signed defaults, and self_employment_gross_receipts is re-signed at
zero. Both new columns join the export allow-list, and the receipts
column leaves it.

tools/measure_uk_trading_allowance_gainers.py measures the raise's
gainers on a release from the claim statuses it stores (on an older
release it makes the stage's draw again on person_build_id, since the
release renumbers person_id). With --fit, it solves the two claimant
rates for HMRC's 400,000 gainers at about GBP 380. Without it, it judges
the rates on the expected gainers, each band's rate times its would-be
gainers, against 400,000 within 5%, with the release's realised count
and the draw's spread beside it (María's ruling of 9 November 2026).
The regeneration of the references, receipts, coverage manifest,
contract digests and H2 follows in its own commit.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…iagnostics (S4)

Two national rows from HMRC's Scottish Income Tax Outturn Statistics
2024-25 join the contract as measured diagnostics for the Scottish
Budget 2027-28 income tax costing:

- hmrc.scottish_income_tax.nsnd_outturn: Table 1's final non-savings,
  non-dividend revenue of Scottish taxpayers, on earned_income_tax +
  property_income_tax over pays_scottish_income_tax, uprated to 2025 by
  the engine's OBR average earnings index;
- hmrc.scottish_income_tax.nsnd_taxpayers: Table 2's All rates count,
  on people taxed at the Scottish rates with earned_income_tax above
  zero, read at 2025 without uprating.

Both select feed 8045b1383's 2024-25 record sets for Scotland. The
taxpayer row pins the layout's all value, since the six rows by marginal
rate share its record set and measure. Two signed exclusions hold both
out of the solve; their approved_on is drafted for María's signature.
The tests pin 542 targets, 480 in registry scope, 297 unmapped
declarations and 51 exclusions. The exclusion names resolve to
committed references once the integration regenerates them.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… (S2(a))

The FRS council tax stage's Scottish bills sum to GBP 3.10bn on the last
release, about 9% below the Scottish Government's own measure of the
2024-25 liability before council tax reduction, while the bound Scottish
band stock already fixes the household mix. So the stage now levels the bills' amounts, not the weights
(S2(a) of the November event-data plan, microcosm#1095).

The measure is the sum over the 32 council areas of CTAXBASE 2025's Band D
equivalent dwellings before council tax reduction at September 2024 (the
middle of 2024-25; dwellings after discounts and exemptions, as the bills
are) times CTAS 2026's average Band D council tax for 2024-25: GBP 3.393bn.
Both tables are vendored from the pinned feed into
scotgov_band_d_liability_facts.json (64 rows), which the stage verifies
against the pin before it reads the raw tab. One factor, the measure over
the Scottish households' derived bills at the spine design weights, scales
every Scottish household's council_tax; bills elsewhere and every weight are
unchanged. The stage receipt records the measure, the stored total, the
factor and the Scottish households' support as a band. A frame with no
Scottish bill to level (a synthetic fixture's) keeps its bills as derived,
and its receipt says so. obr.council_tax_scotland stays a held-out
diagnostic.

The manifest declares the resource artifact, a verify_vendored_fact_resource
operation and the new level_scottish_council_tax operation, which the
operation vocabulary and the sources schema now carry; the closed-world
assert covers all three declarations and the artifact. The synthetic spine
roster and the pinned resource and operation lists follow.

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

T1 stores each trader's trading_allowance_claim_status instead of
#1428's gross receipts, so its claimant rates are re-fitted to HMRC's
policy paper on the raise (about 400,000 taxpayers with a lower bill, by
about GBP 380 on average) on the new encoding before PR2's arm, as María
asked on 6 Nov.

tools/measure_uk_trading_allowance_gainers.py --fit on control C2's
release (0dff777: main after PR1 plus the 8045b13 re-pin; review date
2026-11-07; all seven terminal gates pass) sets every trader outside the
full-relief group to CLAIMANT, runs one simulation pair at 2028 on
policyengine-uk 2.174.1 (the allowance at GBP 3,000 against one held at
GBP 1,000 from 6 April 2027) and solves the two free band rates: 0.6364
for profits up to GBP 4,500 (from 0.72) and 0.1532 from there to
GBP 9,000 (from 0.14). Both lie in the unit interval. The evidence file
holds band aggregates only, each band resting on 30 or more households.

The rates move in the stage module and both copies of the stage's
manifest together; the calibration text names the fit.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Nit 3, T1 and S2(a) change stages and S4 adds two contract rows, so the
surfaces derived from them are regenerated once on the branch head, on
the national cut of the re-pinned feed:

- the national target references and membership: S4's two Scottish rows
  resolve and are active (1,597 to 1,599 active references; no other
  reference moves). The NSND outturn reads HMRC's GBP 18,635m for 2024-25,
  uprated to 2025 by the OBR earnings index; the taxpayer count reads
  3,036,400 as published. ACTIVE_REFERENCE_COUNT follows, and the
  Scotland geography test checks both rows are active;
- the national compile-parity receipt: the two rows enter as ledger-only
  (new targets have no frozen fixture value); nothing else moves;
- the release-input coverage manifest, for the stage manifest's new hash;
- last, the charter-H2 fixture: the frs_council_tax, frs_person_draws and
  trading_allowance_receipts stage payloads and graph nodes, the synthetic
  CGT asset-type facts sized to the frame those stages leave, and the
  normalization note's new string column.

The local census, references, membership and receipt do not move: PR2's
rows are national. The regeneration ran its Python steps with CPython's
cyclic garbage collector off, as the re-pin did; the outputs are the same.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…agnostics (Y4)

Three national rows from DWP's People on Universal Credit by country,
age and conditionality regime (Stat-Xplore UC_Monthly, chronicle#420
item 3) join the contract as measured diagnostics for the young people
work review:

- dwp.uc.people_aged_16_to_24, dwp.uc.people_aged_16_to_21 and
  dwp.uc.people_aged_22_to_24: Great Britain, every regime, DWP's
  single years of age summed at the four quarterly points of 2025 and
  averaged (monthly_window_sum_average, the State Pension by-age
  pattern).

The model counts claimants and partners (is_claimant_or_partner) in
benefit units with positive universal_credit, in the Great Britain
regions. The bands are María's call of 8 Nov: 16 to 17 sits inside
16 to 21, so no row and no difference of rows shows it on its own. The
regime split waits for her regime mapping. Three signed exclusions,
drafted for her signature, hold the rows out of the solve. The tests
pin 545 targets, 483 in registry scope, 300 unmapped declarations and
54 exclusions; the exclusion names resolve to committed references
once the integration regenerates them.

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

DWP's PIP cases with entitlement (Stat-Xplore PIP_Monthly_new,
chronicle#420 item 6) join the contract as 94 measured diagnostics,
the source of P2's award-mix check. There is no England-and-Wales fact,
so England and Wales are separate rows (María's call of 8 Nov):

- per country: every case; each component's standard, enhanced and
  nil award; and age bands from 16 to 19 up to 70 to 74, with 75 and
  over merged. DWP's cube carries no case above 79, so its 75 to 79
  band meets the model's recipients aged 75 and over;
- the nine English regions by each award of each component.

The rows select the country and region cubes by their source tables,
on the four quarter-end points of 2025 (monthly_window_average), under
a new dwp_pip monthly family in SOURCE_MONTH_FAMILIES. The model counts
people with pip above zero by their reported pip_dl_category and
pip_m_category. The breakdowns are single: on the interim arm's release
the award-by-age cross rests on fewer than three survey households in
many Welsh and some English cells, while every single breakdown clears
three once 75 and over is merged.

Ninety-four signed exclusions, drafted for María's signature, hold the
rows out of the solve. The tests pin 639 targets, 577 in registry
scope, 394 unmapped declarations and 148 exclusions; the exclusion
names resolve to committed references once the integration
regenerates them.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
ons.neet.people_aged_16_to_24 joins the contract as a measured
diagnostic for the young people work review: ONS's NEET Table 1
(August 2026, chronicle#420 item 1), UK, aged 16 to 24, not seasonally
adjusted, as the mean of the four LFS quarters inside calendar 2025
(María's call of 8 Nov). The model counts people aged 16 to 24 neither
employed nor self-employed, nor in full-time education (the FRS answer
since Y2), nor in approved training; the FRS records no part-time study
or other training, which ONS counts as education, so the proxy and ONS's
count measure different things. A signed exclusion, drafted for her
signature, holds the row out of the solve.

The compiler gains quarterly_window_average, beside the monthly windows:

- the selector declares period_type quarter and an explicit, unique,
  ordered YYYY-Qn list; the reference takes source_window, an explicit
  period and no operands;
- _resolve_quarterly_window_reference_facts requires one fact per
  declared quarter, of one series and one publication, and the value is
  their sum over the declared count;
- each LFS quarter is its own record set (people_nsa.2025_q1, ...), so
  the series check drops the quarter piece from record-set ids and
  layout values. The drop sits behind strip_quarters on
  _selector_period_invariant_key, which only the quarterly resolver
  sets, so no other series identity moves;
- the source-window period check, the reference metadata
  (ledger_source_quarters and count), the authoring list, the UK hold
  exemption for window operations and the contract's
  allowed_value_operations carry it.

Sixteen engine-free tests cover the mean, the refusals, the declaration
rules and the confinement of the quarter drop. The shared compiler suite
(514), the BE references (156) and the UK compile, holds and reference
tests pass. The tests pin 640 targets, 578 in registry scope, 395
unmapped declarations and 149 exclusions.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
test_uk_measurement_period holds every variable a binding reads as a
filter or condition to a reviewed list: such reads keep the frame's
stored values, so each must be engine-computed or unchanged between the
frame's period and the calibration period (microcosm#1324). PR2's rows
add nine:

- engine-computed at the calibration period, stored by no frame:
  earned_income_tax and pays_scottish_income_tax (S4's Scottish NSND
  rows) and pip (P3, which the engine adds from the award categories);
- stored, and the same in every period: is_claimant_or_partner (Y4, a
  benefit-unit role), is_in_full_time_education and
  is_in_approved_training (Y3, the FRS answers since Y2), pip_dl_category
  and pip_m_category (P3, stored for every projected year) and
  trading_allowance_full_relief (T1's stage flag).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
tools/generate_uk_target_references.py and the national compile-parity
builder on feed 8045b1383's national cut (repin_8045b1383.sh from
"national", the local surfaces, coverage and H2 skipped: the new rows are
national only), at the head of Y4, P3 and Y3:

- target_references.json: 1,697 references, 1,599 plus Y4's 3, P3's 94
  and Y3's 1, all active; no existing reference moves. The allowed
  operations gain quarterly_window_average, and the hierarchy the new
  rows' labels;
- target_reference_membership.json: the 98 rows active on their
  declared geographies; no existing entry or pin moves;
- the national parity receipt: 98 new ledger_only rows (no fixture
  counterpart), none removed.

Every exclusion name now resolves to a committed reference. The tests
pin the new count (ACTIVE_REFERENCE_COUNT 1,697), the operation list,
38 GB UC rows, 120 UC monthly references with Y4's windows, the 94 PIP
references on the four quarter-end points of 2025, and P3's membership
pins. Y4's three rows read DWP's 762,585 people aged 16 to 24, 386,618
aged 16 to 21 and 375,968 aged 22 to 24.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Y2's full-time education flag takes full-time students off Universal Credit,
but uc_take_up refits each family type's award-band pools to DWP's caseloads
without reading age, so it refilled the single caseload with other entitled
singles: claimants and partners aged 16 to 24 stayed well above DWP's count
already at the spine's design weights (María's call of 2026-11-09,
"Age-aware redraw").

The redraw keeps every pool's count. Within each pool, the drawn units with a
claimant or partner aged 16 to 24 (is_claimant_or_partner, at the stored age,
which policyengine-uk carries unchanged to the entitlement year) claim at one
odds ratio against the pool's other drawn units, and the two rates realize the
pool's count together, each in the order of the uniform. The ratio is solved
by bisection on its log over Great Britain, at the stage's household weights,
so that those young claimants and partners in entitled units that claim come
as near DWP's People on Universal Credit aged 16 to 24 as the redraw allows:
every regime, the single years summed in February, May, August and November
2025 and averaged, 762,585, the value the dwp.uc.people_aged_16_to_24
diagnostic compiles. Fixed claims (units that report Universal Credit, and
units moved off or kept on their legacy benefits) and pools whose count needs
more claims than their other drawn units can give keep young units claiming
whatever the ratio, so the count can stay above DWP's; where no ratio reaches
it, the ratio holds at the nearer end and the receipt says why. Without the
age inputs the stage keeps its old path.

The facts are vendored with the tool from the pinned 8045b138 feed into
dwp_uc_people_by_age_facts.json (Great Britain's rows of the four months'
every-regime record sets, 112 rows), with its selection and package entry.
The manifest declares the second artifact, its verify operation and three new
keys on assign_award_band_take_up_residual (young_people, age_targets,
age_fit), which the sources schema carries. The receipt's age_fit block
records DWP's count, the young claimants and partners before and after, and
the ratio, withheld where fewer than three source households carry the drawn
young units. Y4's exclusion reason is restated: the fit brings the 16 to 24
count as near DWP's as the redraw allows, and the rows stay held out as checks
on the fit, on the solve and on the split between 16 to 21 and 22 to 24.

Tests: the count reader and its refusals, the committed count, the fit keeping
the pool's count while meeting DWP's young count on a frame where it can, the
out-of-reach bound, the inputs' refusals and the redraw's plumbing; the pinned
resource lists follow.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The release-input coverage manifest restates the source manifest's digest (25 leaves), and the charter-H2 spine fixture carries uc_take_up's new artifact, verify operation, age keys and notes, with its stage contract hash. The H2 parity test passes on the regenerated fixture.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
María signed PR2's drafted texts on 9 November 2026:

- the 100 measure exclusions (S4's two, Y4's three, P3's 94 and Y3's
  one): approved on 2026-11-09, expiring 2027-02-09, with the signature
  marker dropped from their adjudications;
- S4's reviewed_no_index uprating hold for the Scottish taxpayer count:
  approved on 2026-11-09, expiring 2027-01-09;
- T1's declarer-only notes on the five bound SPI self-employment rows,
  and S2(a)'s level rule in frs_council_tax's notes (sources.yaml and
  source_stages.json in lockstep): "María's signature of 2026-11-09";
- the five changelog fragments that called the dates drafts;
- and the texts with no date to set: Nit 3's restated eligibility, T1's
  full-relief group and its zero share, the restated #1428 filer stance,
  the carrier kept on the export with all five SPI rows filtered, the
  re-fitted claimant rates, and self_employment_gross_receipts re-signed
  at zero. The concepts module keeps its signature marker on that text,
  as it does on every signed text there.

The arm's review date (2026-11-09) is the signing day, so it stays valid
evidence for these registers. The release-input coverage manifest
restates the source manifest's digest, and the charter-H2 fixture carries
frs_council_tax's notes; H2 parity passes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
On the age-fit arm (pr2q-cf73a) the age fit held at its lower bound: the
shortfalls that the single pools from GBP 700 a month up pass to their
neighbours, where DWP's count exceeds every unit they entitle, filled the
single pools around the under-25 standard allowance to every drawn unit,
so young units claimed whatever the ratio. A replay of the stage on the
spine's checkpoint, which reproduced the stored receipt exactly, sized the
alternative, and María adopted it on 9 November 2026, to be tested in the
next arm.

With the age fit's inputs, _pass_unmet_gaps takes each pool's drawn weight
with no claimant or partner aged 16 to 24, and a shortfall passed to
another pool fills only those units: its room is the pool's undrawn
claims plus that weight, less its count. What no pool can take that way
stays unplaced, so the family type's caseload falls short of DWP's count
by it. A pool's own count still draws on all its drawn units, an excess
passes as before, and without the age inputs the stage keeps its old path.
The age_fit receipt records each family type's unplaced shortfall.

On the saved inputs of the arm's stage the young claimants and partners
meet DWP's count, and the single caseload falls short of DWP's at the
stage's weights; the calibration binds single households without children
below the redraw's count, so the solve can close it. The stage's gate
holds each family type no further from DWP's count than before the
redraw, which the singles meet.

The pooling and age-fit rule texts, the stage notes, the module docstring
(which drops an interim figure from a comment) and the changelog follow;
sources.yaml and source_stages.json stay in lockstep. Tests: the gap rule
with and without older weights, and a shortfall left unplaced rather than
drawn from young units. The coverage manifest and the H2 fixture are
regenerated; H2 parity passes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
test_uk_pension_age_benefit_targets expected one filter on Table 3.10's
employment counts by self-employment band. T1 (713a0d0, microcosm#1439)
gave SPI's rows of declarers a second, trading_allowance_full_relief =
false, and this row is one of them. The E4 frame in test_uk_stochastic_tools
lacked is_in_full_time_education, which the apprentice draw reads since
Nit 3 (31b9aa5). The code is unchanged; the tests now pin what it does.

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

policyengine-uk 2.174.1 decides a PIP component's rate from pip_dl_points
and pip_m_points (8 points for the standard rate, 12 for the enhanced)
wherever no category is supplied for the year. The release stored
pip_dl_category and pip_m_category, which the engine copies into every
projected year, so no reform to the thresholds could move anyone (P1 of the
November event-data plan, microcosm#1095; María's go of 9 November 2026).

A new late stage, pip_points, just before trading_allowance_receipts, draws
each recipient's daily living and mobility totals within their stored award
from DWP's Pathways to Work evidence pack, chapter 2, Tables 2.9 and 2.10
(the PIP caseload's points by age group, England and Wales, end of January
2025; chronicle#420 item 5). The tables are vendored from the pinned feed as
dwp_pip_points_facts.json and verified against the pin. Each age group's
distribution spreads a daily living band's share over its integer points,
with the open band at 41, and takes the mobility totals as published;
restricted to the stored award's range, it is inverted by one uniform per
component on person_id. A recipient of one component draws the other's total
below 8, and a person with neither keeps -1. The stage asserts that the
points give back every stored category at the thresholds; its receipt gives
England and Wales's weighted shares by DWP's cells against DWP's, by age
group, with support bands and small cells withheld.

The release drops the two categories (UK_RELEASE_EXPORT_DROPPED_COLUMNS), the
export allow-list carries the points instead, and the categories join the
reviewed export exclusions, in code and gates.json. The coverage manifest
tool restates the categories as engine-derived exclusions. The eFRS
reference's engine (2.89.0) read them as plain inputs, so a reviewed list
admits the inputs the pinned engine derives since the reference, and the
ledger's engine-derived section carries the two entries, dated for María's
signature. The points join through a family of their own. The spec gains the
stage (YAML and JSON in lockstep), the operation kind
assign_pip_points_by_award with its schema branch, the artifact and its
verify operation. The graph, kernels, spine build and H2 fixture tool wire
it, and the roster pins move to 55.

Tests: eight engine-free ones for the reader, the draws, the fallback, the
stage and its closed world; an engine test that policyengine-uk's categories
from the points equal the stored ones in every year from 2024 to 2030, on
thresholds of 8 and 12; and the manifest tool's reviewed list. The coverage
tests' pins, engine-free and engine, restate the categories as engine-derived
and add the stage to the required build stages; the engine one also checks
that the pinned engine derives both categories. For María's signature:
points spread evenly within a band, with the open band at 41; Scotland's and
Northern Ireland's recipients on England and Wales's tables; pension-age
recipients on the 60-and-over row; draws on person_id.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The release-input coverage manifest restates the source manifest's digest,
adds the pip_points family and restates the two PIP categories as reviewed
exclusions (141 required and 4 reviewed of 145 inputs), and the charter-H2
spine fixture carries the 55th stage, its cells and its contract. H2 parity
passes.

The release contract's committed digests in microcosm-data (the spec's
policy, gates manifest and fingerprint, and the release cut's scoped parts)
are re-pinned on this spec. They also catch up with PR2's earlier commits,
whose spec and gates.json edits had left them at main's values; CI's
engine-free job failed on that at a859ac7, in test_uk_release_assembler.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@juaristi22 juaristi22 changed the title UK November event data, PR2: feed re-pin, trading allowance claim status, Scottish council tax and NSND, young people and PIP diagnostics, UC take-up age fit UK November event data, PR2: feed re-pin, trading allowance claim status, Scottish council tax and NSND, young people and PIP diagnostics, UC take-up age fit, PIP points Nov 9, 2026
juaristi22 and others added 2 commits November 9, 2026 19:29
policyengine-uk 2.174.1 gives limited capability for work and work-related
activity to anyone flagged is_disabled_for_benefits (any reported disability
benefit or ESA), unless their own ESA award lacks the support component. The
FRS 2024-25 links most UC claims to DWP's records, and BENEFITS.UCLCW gives
the claim's own status. SN 9563's UKDA data dictionary codes it 0 None, 1
LCFW Group and 2 LCFWRA Group, and it is blank where the claim has no linked
record. This is Y1 of the November event-data plan (microcosm#1095), on
María's NS6 ruling of 9 November 2026, which revisits her ruling of 29
October to keep the proxy.

frs_spine carries the status as frs_uc_lcw_status on the UC row's person,
and the release drops it. The FRS keeps one UC row per claim, couples
included; the carrier refuses a second UC row on a claim, an unknown code,
or a UC row whose person isn't on the spine.

A new engine-backed stage, uc_limited_capability, runs just before
uc_take_up. It asks the locked engine for its proxy, the UC claimant role
and carer status, then stores uc_limited_capability_for_WRA and
uc_limited_capability_for_work for every person. Linked FRS claims take
DWP's status:
- NONE sets every claimant false;
- LCWRA keeps the claimants the proxy flags. If it flags none, both flags
  go to the UC row's person, or to the partner where the UC row's person
  cares and the partner doesn't;
- LCW does the same, with WRA false.
Everyone else keeps the proxy. The receipt counts the linked claims by
status against the proxy, with support bands and small cells withheld with
their partner, and counts each branch of the rule.

The spec gains the stage (YAML and JSON in lockstep) and the operation
kind assign_uc_limited_capability_from_admin_status, with its schema
branch. The graph, kernels, spine build and H2 fixture tool wire it; the
fixture tool's string audit counts the carrier (33 columns), and the
roster pins move to 56. The export allow-list carries both flags, and the
coverage tool gains the stage's family. The bound LCWRA row's note records
the ruling; it no longer says the carer and childcare rows sit on the
measure-exclusion register, since neither does. The synthetic FRS fixtures
carry UCLCW beside UCSTART.

Tests:
- the carrier (three);
- the stage's rule, receipt, refusals and closed world (six);
- two engine tests on 2.174.1: unlinked people keep the engine's own proxy,
  and the LCWRA element follows DWP's status in 2024 and in a 2025 dataset
  holding the stored flags.

For María's signature: the NS6 restatement, the code mapping, the
joint-claim rule, NONE overriding the proxy, and who keeps the proxy.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- The release-input coverage manifest restates the source manifest's digest
  and adds the stage's family. Its counts are unchanged: 141 required and 4
  reviewed of 145 inputs.
- The charter-H2 spine fixture carries the 56th stage, its cells and its
  contract, plus the UCLCW carrier in its synthetic BENEFITS rows, its
  person sources and its normalization note. H2 parity passes.
- microcosm-data's release contract digests (the spec's policy, gates
  manifest and fingerprint, and the release cut's scoped parts) are
  re-pinned on this spec.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@juaristi22 juaristi22 changed the title UK November event data, PR2: feed re-pin, trading allowance claim status, Scottish council tax and NSND, young people and PIP diagnostics, UC take-up age fit, PIP points UK November event data, PR2: feed re-pin, trading allowance claim status, Scottish council tax and NSND, young people and PIP diagnostics, UC take-up age fit, PIP points, UC limited capability Nov 9, 2026
juaristi22 and others added 3 commits November 9, 2026 19:58
María signed P1's five choices and Y1's six on 9 November 2026.

P1:
- points spread evenly within a band, with the open band at 41;
- Scotland's and Northern Ireland's recipients on England and Wales's
  tables;
- pension-age recipients on the 60-and-over row;
- draws on person_id;
- the two categories leaving the release, with their reviewed export
  exclusions and the coverage ledger's two engine-derived entries
  (approved 2026-11-09).

Y1:
- NS6 restated: read UCLCW for linked claims, the proxy elsewhere;
- the code mapping;
- the joint-claim rule;
- NONE overriding the proxy;
- who keeps the proxy;
- the restated LCWRA row note.

The markers go. These texts now record the signature: the two stages'
notes (YAML and JSON) and module docstrings, P1's export exclusion reasons
(code and gates.json), the ledger entries and the coverage tool's copy,
the LCWRA note, and the two changelog fragments. The coverage manifest,
the H2 fixture and microcosm-data's release contract digests are
regenerated for the texts, and H2 parity passes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
María's call of 10 November 2026, after the calibrate-only arms on
pr2q-daa35's spine: bind DWP's people on Universal Credit aged 16 to 21
and 22 to 24 (Y4) and England's and Wales's PIP cases by the award of
each component (P2), and keep S4's two NSND rows held out.

- calibration_measure_exclusions.json drops those 14 entries (149 to
  135), the set the combined variant measured.
- 16 to 24 stays held out as the check on its two parts, since binding
  it as well would weight the same people twice. Its reason no longer
  says the parts stay held out, and its adjudication records the call.
  The restated entry is for María's signature: approved_on 2026-11-10,
  expiring 2027-02-10, so an arm that reads this register needs a review
  date from 2026-11-10.
- The 82 other PIP rows keep their signed exclusions.
- The contract's parity notes on the 14 rows, the PIP cube's comment in
  uc_source_periods and its test, and three changelog fragments now say
  which rows bind.
- test_packaged_exclusions_load pins the register at 135 (was 149), and
  its note now names PR2's rows beside S4's.

No derived surface moves: no committed reference, receipt, fixture or
digest reads the measure-exclusion register or the parity notes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
María signed the restated exclusion for DWP's people on Universal Credit
aged 16 to 24 on 10 November 2026. That covers the reason that keeps the
row held out as the check on its two bound parts, and the adjudication
that records her call of that day. The signature marker goes from the
adjudication, and Y4's changelog fragment now says she signed it.
approved_on stays 2026-11-10, the signing day, and the entry expires
2027-02-10.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@juaristi22 juaristi22 changed the title UK November event data, PR2: feed re-pin, trading allowance claim status, Scottish council tax and NSND, young people and PIP diagnostics, UC take-up age fit, PIP points, UC limited capability UK November event data, PR2: feed re-pin, trading allowance claim status, Scottish council tax and NSND, young people and PIP rows, UC take-up age fit, PIP points, UC limited capability Nov 10, 2026
juaristi22 and others added 3 commits November 10, 2026 10:46
Y1 put uc_limited_capability between uc_capital_coherence and uc_take_up.
The legacy-closure stage's order pin still put the capital check two
stages before it, so CI's engine-free job (3.14) failed at 33c2737.
The pin now names all three stages before it. Y1's targeted run had
missed this file, which reads the stage order from the packaged spec.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
microcosm#1439's "Done when" asks the stage's tests to cover an allowance
above £3,000, the case #1428's receipts encoding mis-scored. On the locked
engine, a reform to £5,000 in 2028-29 relieves a claimant's 2025 profit by
min(profit, £4,000) and a non-claimant's by nothing, for profits of £1,500
and £6,000. The file passes: 11 tests.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Y1 put uc_limited_capability straight after uc_capital_coherence. The
capital check's test of the stages that follow it, none of which writes
a UC report, failed both engine-free jobs at 09add32. The test now
expects Y1's stage first. The 14 test files that name the stages around
Y1's insertion pass locally (605 tests).

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

Copy link
Copy Markdown
Contributor

Review of 8780aa3

I read the code and config changes against the merge of #1535 (dc00d15): the re-pin, Nit 3, T1, S2(a), S4, Y4, P1, Y1 and the take-up age fit. I spot-checked the generated files against the re-pin, and checked the law-facing claims against legislation.gov.uk, policyengine-uk 2.174.1 and HMRC's 2024-25 Scottish outturn release. In a fresh clone I ran the PR's engine-free tests one file at a time: test_uk_pip_points, test_uk_uc_limited_capability, test_uk_frs_council_tax, test_uk_trading_allowance_receipts, test_uk_trading_allowance_gainers_tool, test_uk_apprentice_draw, test_uk_uc_take_up, test_ledger_quarterly_window, test_uk_chronicle_feed, test_uk_uprating_holds and test_uk_legacy_closure_take_up. All passed.

From #1535: all four items are closed. Should 1 was counted, with fewer than three households, and noted in the stage notes. Should 2 was fixed in ab629d689. Nit 4 went into 821c13d. Nit 3 is here at frs_person_draws.py:328, and the stage now refuses a frame without is_in_full_time_education (:303).

Should

  1. A PIP points-threshold reform will also move Scotland's Adult Disability Payment recipients, and Northern Ireland's PIP recipients (uk_runtime/pip_points.py:30-34 and :153-159; frs_spine.py:175-176). frs_spine maps ADP's FRS codes 117 and 118 into pip_dl_reported and pip_m_reported. So Scottish ADP recipients hold pip_*_category, and this stage now gives them points. policyengine-uk 2.174.1 has one threshold for everyone, gov.dwp.pip.*.points_thresholds, and no separate ADP variable. Failure case: a Scottish ADP standard-rate recipient drawn at 8 daily living points loses the award under a reform that raises daily_living.points_thresholds.standard to 9. ADP's thresholds, though, are set by the Disability Assistance for Working Age People (Scotland) Regulations 2022 reg. 8(3) (8 to 11 points limited, 12 or more severely limited), and a DWP reform doesn't change them. NI PIP sits under its own 2016 regulations. Before the stage, the stored categories meant no reform moved anyone, so this is new with P1. Suggested fix: say it in the changelog and stage notes ("a threshold reform reaches ADP and NI recipients too; net them out by country"), and add each country's recipient count to the receipt so users can do that. A region gate on the thresholds would be a policyengine-uk change, not one for this PR.

  2. Scotland's level counts dwellings no FRS household lives in (uk_runtime/frs_council_tax.py:323; changelog.d/1095-uk-scottish-council-tax-level.changed.md:3). The level is CTAXBASE's Band D equivalents times CTAS's Band D, £3.393bn (I recomputed it from scotgov_band_d_liability_facts.json: 2,392,465 Band D equivalents over 32 councils). The vendored rows are CTAXBASE 2025's "Band D equivalents" table, with chargeable dwellings as their entity. gov.scot's "Second homes and empty properties in September 2025" comes from the same council tax base returns. It counts 20,927 second homes and 44,453 empty homes liable for council tax in September 2025, after a fall of 679 and a rise of 915 on the year. That puts September 2024 at about 21,600 and 43,500. The FRS only samples occupied households, so one factor over the FRS bills puts the liability on these dwellings onto households. Failure case: about 65,000 liable dwellings with no FRS household is roughly 2 to 3% of Scotland's chargeable stock. If they pay about an average bill, or more where a premium applies, the factor runs high by about that much, and so does every Scottish household's council_tax. That flows into CTR entitlement and household net income. Suggested fix: take second homes and liable empty dwellings out of the level, from CTAXBASE's own counts by discount or premium class at September 2024. If that can't be done in this PR, record in the stage notes and changelog how much of the roughly 9% gap they could account for.

Nit

  1. The PIP points are totals only, drawn independently by component (pip_points.py:20-27). The stage can score a change to the 8 or 12 thresholds. It can't score a rule that turns on points in one activity, such as needing at least 4 points in one daily living activity, and it loses any link between a person's daily living and mobility points. One sentence in the changelog's scope would stop users reading more into the points than they hold.
  2. Once its parts bind, 16 to 24 carries no new information after the solve (calibration_measure_exclusions.json:546). It lands where they do (+0.1%). The reading that tests the age fit is the one at the spine's design weights (1.002), so it is worth reporting that one on every arm.

Checked and fine

  • Re-pin: chronicle_feed.json moves to 8045b13 (2,091,616 rows). In every vendored resource the 38 4/4 files change only source_commit, fact_row_count, facts_sha256 and manifest_sha256. In desnz_constituency_energy_facts.json only the derived keys and the input hash change, with no value moved. The local membership and census change the same way. No 64753803 remains in the packages or tools.
  • T1 against ITTOIA 2005 Part 7A: full relief applies without an election where relevant income is within the allowance (s. 783AE(1)), and trade profits are then nil (s. 783AF). Partial relief deducts the allowance in place of expenses (s. 783AI(3)). So a CLAIMANT's receipts are their profit plus £1,000, and a reform to £5,000 relieves min(profit, £4,000), as e4185628d tests. The re-fit solves exactly from fit-ctl2-0dff7.json: 0.6364 × 539,000 + 0.1532 × 372,200 = 400,041 gainers, and 0.6364 × £196.8m + 0.1532 × £174.6m = £152.0m, which is £380 a gainer.
  • S4: HMRC's 2024-25 outturn gives £18,635m of NSND liability and 3,036,400 Scottish taxpayers. HMRC defines taxpayers as people with some net NSND liability after reliefs, so the count fits the model's taxpayers.
  • P1 thresholds: PIP Regs 2013 reg. 5(3) and reg. 6(3) set 8 and 12 points. PIP_AWARD_RANGES (pip_points.py:102) matches, and the mobility totals (0, 4, 8, 10 to 24 even) are the sums the descriptors allow. policyengine-uk 2.174.1's utils/pip.py derives the category from the latest points only where no category is supplied, so dropping the categories from the export is what makes the points bite.
  • Y1: the proxy is policyengine-uk 2.174.1's own formula (UC Regs 2013 regs 39 and 40), and is_disabled_for_benefits is a plain input there, so storing both flags drops no formula a reform could reach. The joint-claim choice keeps a carer's carer element, which reg. 29(4) would otherwise bar for a claimant with LCWRA.
  • The age fit: the target is DWP's Great Britain claimants and partners aged 16 to 24, all regimes, averaged over 2025's four quarters. I summed February 2025's single years from the vendored facts: 749,143.

CI at 8780aa3: lint, wheels, installed-emitter, select-countries, integration-uk, engine-uk (3.13) and engine-uk (3.14) pass. engine-free (3.13, 3.14) and engine-us (3.13, 3.14) are still running.

Verdict: the code matches its signed texts and the law I checked. Should 1 and Should 2 are the two to settle before the national is rebuilt on it. Both can be handled with notes if the fixes wait.

🤖 Generated with Claude Code

juaristi22 and others added 2 commits November 10, 2026 13:01
Vahid's review of #1550 (Should 1): policyengine-uk 2.174.1 has one set
of PIP points thresholds, and frs_spine reads Scotland's Adult Disability
Payment (FRS codes 117 and 118) as PIP. So a threshold reform reaches
Scotland's ADP recipients and Northern Ireland's PIP recipients too,
whose awards their own regulations set.

- The pip_points receipt gains recipients_by_country. For England, Wales,
  Scotland and Northern Ireland it gives the rounded records, a support
  band and the weighted count at the stage's weights. The weighted count
  is withheld for a country on fewer than three source households.
  Recipients in a region no country lists are counted apart.
- The P1 changelog says so. It also says (Nit 3) that the points are each
  component's total, drawn independently: they score the 8 and 12
  thresholds, not a rule on one activity's points.
- No frame cell moves, and the stage notes are unchanged.

The 11 test files that read the stage pass (317), with two new tests.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Vahid's review of #1550, Should 1 and Should 2, settled with notes on
María's signature of 10 November 2026:

- A, pip_points. A reform to the points thresholds reaches Scotland's
  ADP recipients, whom the FRS codes as PIP, and Northern Ireland's PIP
  recipients, whose awards their own regulations set. The receipt counts
  each country's recipients for netting them out. The points are each
  component's total, drawn independently: they score the 8 and 12
  thresholds, not a rule on one activity's points. Text A is in the
  stage notes (YAML and JSON) and the module docstring, and the P1
  changelog says it is signed.
- B, frs_council_tax. Scotland's level counts the liability of about
  21,600 second homes and 43,500 liable empty homes in September 2024
  (Scottish Government, Second Homes and Empty Properties in September
  2025), which no FRS household occupies. They are roughly 2 to 3% of
  the chargeable stock, so the factor may carry 2 to 5% of the level
  that belongs to no FRS household. Netting them out needs CTAXBASE's
  counts by class in Chronicle, a follow-up. Text B is in the stage notes
  (YAML and JSON) and the S2(a) changelog.

The release-input coverage manifest restates the source manifest's
digest, and the charter-H2 fixture carries the two stages' notes. The
46 engine-free files that read the spec, the coverage manifest or the
two stages pass (3,266 tests, 20 skipped), and H2 parity passes on the
regenerated fixture.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@juaristi22
juaristi22 marked this pull request as ready for review November 10, 2026 13:39
@juaristi22

Copy link
Copy Markdown
Collaborator Author

Thanks, Vahid.

Should 1 (ADP and NI PIP under a threshold reform): agreed. a0c6d8b34 adds each UK country's recipients to the stage's receipt (rounded records, a support band and the weighted count, withheld below three source households). The P1 changelog now says that a threshold reform reaches Scotland's ADP recipients and Northern Ireland's PIP recipients, whose awards follow their own regulations, and to net them out by country. The stage notes say it too, signed by María (b4250ebe9). A region gate on the thresholds stays a policyengine-uk question.

Should 2 (second homes and empty dwellings in Scotland's level): agreed: the level carries their liability. gov.scot's Second Homes and Empty Properties in September 2025 puts September 2024 at about 21,600 second homes and 43,500 liable empty homes, roughly 2 to 3% of the chargeable stock. The stage notes and the changelog now say how much of the level they could carry, signed by María (b4250ebe9). Netting them out needs CTAXBASE's counts by class in Chronicle, so it follows separately.

Nit 3: the P1 changelog's scope now says the points are each component's total, drawn independently. They score a change to the 8 or 12 thresholds, not a rule on one activity's points, and they keep no link between the components.

Nit 4: agreed. The arm reads take Y4's 16–24 at the spine's design weights beside the release; for the head arm those are 1.002 and +0.1%. We'll report the spine reading on every arm.

🤖 Generated with Claude Code

@vahid-ahmadi

Copy link
Copy Markdown
Contributor

Round 2 at b4250eb

I read a0c6d8b34 and b4250ebe9 against 8780aa3 and María's reply, and re-ran test_uk_pip_points in a fresh clone (9 passed).

  1. Should 1 (ADP and NI under a threshold reform): fixed. The receipt now has recipients_by_country (uk_runtime/pip_points.py:171-186, :523-554, :646), and the changelog says to net them out (changelog.d/1095-uk-pip-points-stage.added.md:18). I checked the counts. They key on recipient, which is any person with a category other than NONE. frs_spine.py:175-176 merges codes 96/97 (PIP) with 117/118 (ADP), so Scotland's row is every Scottish recipient under either code. Northern Ireland has its own key. The 12 region names match frs_spine.py's REGION_MAP (:101-114), and an UNKNOWN region falls into "unassigned" rather than into a country. The weighted count is withheld below three source households, and the new test covers that. One small thing: the counts are at the stage's spine weights. A user netting out at release weights should filter on region in the release, not lift these numbers. A short note in the receipt saying so would help.
  2. Should 2 (second homes and empty dwellings in Scotland's level): partly. Notes only, no code change (changelog.d/1095-uk-scottish-council-tax-level.changed.md:8-11; the frs_council_tax stage notes). The figures are right: about 65,100 liable dwellings is roughly 2.6% of the stock, and up to about 5% once premiums count. But I don't think a dwelling-count correction has to wait for CTAXBASE's class counts in Chronicle. D14f, María's ruling of 2026-10-29, already settles that these dwellings don't belong in main-residence bills. obr.council_tax binds Great Britain's council_tax_less_benefit, Scotland included, scaled by England's chargeable dwellings less mhclg.council_taxbase.second_homes and mhclg.council_taxbase.empty_dwellings (uk/uk_population_targets.json:2932, complement operand at :2968). The note there says "England's share stands for Scotland's and Wales's" as a stated approximation, and says binding the whole line "pushed main-residence bills up". S2(a), though, levels Scottish bills to all chargeable dwellings (frs_council_tax.py:323). So one build now treats the same dwellings two ways. The bound target nets them out, and the Scottish level puts them back into each Scottish household's council_tax. The share's inputs are already in the pinned feed. Only the premium refinement needs class counts, and I found no Scottish second-home concept vendored yet. Suggested fix: scale level.total by the D14f share, stated as the same approximation. Or say in the S2(a) notes why the level departs from D14f. Either way, the "follow-up" should name an issue. Households' council tax on second homes and other property (engine and data) #1423 covers council tax on other property, not this.
  3. Nit 3 (points are totals only): fixed (changelog.d/1095-uk-pip-points-stage.added.md:19; stage notes and the pip_points.py docstring).
  4. Nit 4 (16 to 24 at design weights): accepted. It is a reporting change for the arm reads, so there is no code to check here.

Records: text A sits in sources.yaml, source_stages.json, the parity fixture, the pip_points.py docstring and the P1 changelog. Text B sits in sources.yaml, source_stages.json, the fixture and the S2(a) changelog, all dated 2026-11-10. That matches what the commit message says. The coverage manifest changes only source_manifest_sha256.

CI at b4250eb: lint, wheels, installed-emitter, select-countries, integration-uk, engine-uk (3.13, 3.14), engine-us (3.13, 3.14) and engine-free (3.14) pass. engine-free (3.13) is still pending.

Verdict: Should 1 and both nits are done. Should 2 is the one left. Its notes are accurate, but the D14f share already gives an interim correction, so the deferral needs either that or a reason.

🤖 Generated with Claude Code

@juaristi22

Copy link
Copy Markdown
Collaborator Author

Thanks, Vahid.

1. Should 1: agreed on the note. The counts are at the stage's spine weights; to net ADP and Northern Ireland recipients out at release weights, filter on region in the release. We'll add that line to the receipt in PR3 of the November event-data plan rather than hold this PR for it.

2. Should 2: we'll defer the correction to PR3 of the November event-data plan (#1095), which nets these dwellings out of the level. You're right that D14f already nets them out of obr.council_tax, while S2(a) keeps them for Scotland. We're not applying D14f's share in this PR for three reasons:

  • An unmeasured move. It would lower every Scottish household's council_tax by about 2.6% (up to about 5% with premiums) after the arms that measured S2(a) as signed, so it needs an arm of its own. PR3 has one.
  • England's share for Scotland's. It would layer England's share onto a level that is otherwise Scotland's own. Scotland's counts, and its premiums since April 2024, can differ from England's, and gov.scot warns that its empty-home counts may be overstated. PR3 uses CTAXBASE's own counts by class once they're in Chronicle, with D14f's England share as the interim if they can't be packaged in time.
  • The size meanwhile. On the Great Britain line that obr.council_tax binds, the difference is about 0.2 to 0.4%. The S2(a) notes and changelog already state the dwellings and their size.

3 and 4: thanks.

🤖 Generated with Claude Code

@juaristi22
juaristi22 merged commit bd09f17 into main Nov 10, 2026
12 checks passed
juaristi22 added a commit that referenced this pull request Nov 10, 2026
main moved microcosm-emitter-interface to 0.14.0 (and its floor in
microcosm-build); this branch moved policyengine-uk and the UK side's
policyengine-core. uv.lock merges both, uv lock confirms it unchanged,
and APPROVED_UV_LOCK_SHA256 is that lock's digest.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
juaristi22 added a commit that referenced this pull request Nov 10, 2026
Part of #1095. The fragment still said 26, from before the six columns
microcosm#1550 adds were declared; gates.json declares 32.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
juaristi22 added a commit that referenced this pull request Nov 10, 2026
The UK lock moves on from 2.174.1 to 2.177.7, the newest release, after
#1550 merged (microcosm#1095); policyengine-core stays at 3.34.10, and
uv.lock moves policyengine-uk alone. 2.177.5 to 2.177.7 add no input, so
the concept coverage keeps its 378 inputs and only its version moves.
They change what the build's engine reads return:
- 2.177.5 (PolicyEngine/policyengine-uk#2807): no income-related ESA
  for a claimant who has reached pensionable age, or for a couple that
  would get Pension Credit without it.
- 2.177.6 (PolicyEngine/policyengine-uk#2808): the legacy enhanced
  disability premium for enhanced PIP daily living and armed forces
  independence payment beside the highest DLA care rate, and four
  councils' own working-age CTR lists. The is_enhanced_disabled_for_benefits
  the build stores now reaches only Kingston upon Thames's working-age
  Council Tax Reduction and two deprecated counts.
- 2.177.7 (PolicyEngine/policyengine-uk#2830): the allowances and reliefs
  set against income in the way that gives the least tax.

Every text that cites the locked engine was checked against 2.177.7 and
moves with it; only tax_band's comment changed among the variables they
cite. The approved lock digest, the three pyproject floors, the
engine-core pin test, the version stamps of the uprating pins and the
bonus-sacrifice anchor, the coverage manifest and the changelog follow.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

UK trading allowance: store the claim status once policyengine-uk#2765 is released

2 participants