Port the CGT structure, salary sacrifice, and student loan stages onto the UK spine at FRS 2024-25 - #740
Conversation
79f5993 to
d70ea39
Compare
…loans Five manifest stages between the SPI channel and the certified pair (roster 21 -> 26, both manifest projections): cgt_incidence_clone (clone_records equal mass split w/2 + Advani-Summers prior amounts on the oldest adult, identity-keyed), cgt_band_donors (270 = 30 x 9 HMRC Table 2.1a bands at band-exact never-zero weights, seed 1), hmrc_cgt_gains_spine (the merged #560 Table 3 redraw reused unchanged on the spine path; the certified-line wrapper and national-driver injection stay untouched until seed 42, + conversion to the 5.4m staging target, identity-keyed seed 2024), and student_loans (cohort rules at calibration year 2025 + PLAN_5- first top-up to SLC liable stocks, identity-keyed seed 42; PLAN_4 never imputed, documented). Thirteen operation kinds registered; five committed cited resources (Table 2.1a with publisher-ODS sha pin, A&S CAGE WP 465 distribution with the row-30 anomaly documented, HMRC 7.7m salary-sacrifice anchor with the 0.70 staging ratio, SLC Table 6a liable stocks flagged chronicle_candidate, donor support bounds recorded as inapplicable-at-terminal for review); per-stage reviewed-constants drift asserts and executed-effect receipts per the #730/#684 two-arm rule, now documented at the spi_spine reviewed-constants block; StagePlan gains explicit declared rewrites; family coverage closes the capital_gains and student_loan_plan producers; student_loan_plan enum-domain gate (BRMA generalization); export surface gains household_is_cgt_band_donor; spine driver wires --cgt-ods and harvests every new seed into the build sidecar. Closes #684. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…car evidence e8_identity_receipt in tools/verify_uk_identity_stability.py receipts the clone-pair structure, recomputes the band-donor selection from the committed resources in original and permuted row order, and recomputes student_loan_plan in full against the stored column; the A&S priors, the Table 3 redraw draws, and the salary-sacrifice QRF and conversion are scoped to twin-build determinism. The spine driver persists the four E8 transforms' executed-effect receipts into the build sidecar as stage_evidence (#730/#684 two-arm rule, arm 2). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ed-world CGT asserts, stage-bound mass receipts Five findings from the pre-push adversarial round, all dispositioned: 1. Gate-battery cross-shard triplet re-pinned in both mirrors from the live producer over the post-#733/#735 union (policy 5cb072a0, gates c5123517, fingerprint 23cf63b6) - the rebase had left main's pre-E8-gate values. 2. The Advani-Summers percentile-69 p95 corrected 15,190 -> 151,900, verified against CAGE WP 465 Table A1 (p. 39); all 61 rows checked value-for-value, single mismatch confirmed as the incumbent's dropped digit - fix-and-sign replaces replicate-and-document. The prior-draw loader now fails closed on any non-monotone quantile row. 3. Salary-sacrifice and student-loan receipts gain expected-vs-realized fields (expected mass = rate x pool, realization deviation), quantifying the Bernoulli realization the port-faithful mechanism accepts. 4. The CGT spine drift assert now binds every operation's full declared parameter mapping closed-world (extra keys rejected), not a subset. 5. Salary-sacrifice and student-loans declare stage-named mass-conservation reasons in both manifests (schema extended), emit matching MassChangeRecords, and the regenerated coverage manifest binds each family to its own receipt instead of the generic fallback (pre-E8 families keep the fallback - follow-up noted). Bundle spec sha re-pinned (17c820bc) for the manifest edits; gate triplet unchanged by them. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
b83e334 to
45faff0
Compare
Adversarial review (2026-08-22)A Codex adversarial round on the rebased branch returned 3 high + 2 medium findings, all dispositioned before this push (one CI round): (1) the cross-shard gate-battery triplet re-pinned from the live producer — the rebase had kept main's pre-E8-gate values; (2) the A&S row-30 correction above; (3) expected-vs-realized fields added to the salsac and per-plan receipts (measured: salsac +2.7%, PLAN_5 −1.4%, PLAN_2 exactly 0 — pool-saturated and deterministic), with the Bernoulli top-up mechanism itself kept port-faithful; (4) the CGT spine drift assert extended to closed-world full-mapping equality per operation (extra keys rejected); (5) salary-sacrifice and student-loans now declare stage-named mass-conservation reasons in both manifests, emit matching MassChangeRecords, and the coverage manifest binds each E8 family to its own receipt (the pre-E8 families' generic fallback is a noted follow-up). Licensed twins rebuilt at the disposition commit: payload-identical, identity receipt PASS, all screens unchanged. Implemented by Codex under |
Fixes the nondeterministic main-CI red first seen on the FRS 2024-25 retarget merge run (test_reform_materialization_builds_one_engine_system _per_family asserting 0 > 1000): variable-module names are keyed by id(system), so in a warm suite process CPython can hand a fresh CountryTaxBenefitSystem a dead prior system's recycled address, re-registering its ~5,600 modules under already-existing names and zeroing the measured delta. No in-process counting survives id recycling, so the measurement now runs end-to-end in a subprocess whose import state is virgin by construction; the pytest test asserts on the child's outcome and surfaces its output on failure. Not an E8 surface - fixed-and-signed in the passing PR per the standing precedent (the WAS bridge-donor pin fix rode the retarget PR the same way). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Main-CI red addressed in this PR (
|
…tinct CGT receipt identities Two findings from the pre-merge adversarial round, both dispositioned: 1. Closed-world coverage was only on the spine amounts stage. Every E8 stage assert now binds the full declared operation sequence and each operation's complete parameter payload (extra keys, missing keys, value drift, and extra or reordered operations all fail by name) via a shared ordered-sequence helper; the donor stage's previously-unbound propensity declaration is covered, with mutation tests for propensity, extra keys, and extra operations on all four stages. 2. The certified and spine CGT families shared one mass-conservation reason, so a single record satisfied both. The reused runtime gains an additive mass_change_reason parameter (certified default unchanged); the spine projection declares and emits its own spine-specific reason in both manifests, and the coverage generator now rejects duplicate stage-declared reasons outright. The five pre-E8 families sharing the generic fallback are a standing follow-up, unchanged here. Bundle spec sha re-pinned (1f163cbf) for the manifest edit; gate triplet unmoved. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Second adversarial round dispositioned (
|
Closes #684. Workstream E8 of the UK-migration master epic #665, child of #145; rebased onto main at 2aa9679 after #733 merged (digest pins re-derived over the post-#733/#735 union). Targets FRS 2024-25 throughout: build period 2024, calibration year 2025 from the release object, donor arithmetic at the Table 2.1a 2023-24-provisional surface.
What moved
Five manifest stages insert contiguously between
hmrc_spi_income_spineand the certified pair (roster 21 → 26, both manifest projections, certified pair pinned at[-2:]):cgt_incidence_clone— every household (FRS and SPI-synthetic) doubles via the new genericclone_recordsop: originals no-gains, clones has-gains (household_is_capital_gains_clone), equal mass split w/2 at importance kind with the exact-total bit-correction discipline,MassChangeRecorddeclared_factor 1.0. The clone household's oldest adult (16+, person_id tiebreak) draws a prior amount from the Advani–Summers percentile surface (linear spline, ext=0, negative draws kept as loss-makers) at an identity-keyed uniform (seed 0). The prior exists because the merged redraw selects gainers ascapital_gains > 0, ranks largest-first, and caps the sub-AEA remainder — the prior supplies the gainer set, ordering, sub-AEA survivors, and pass-through losses, exactly as the certified artifact feeds the stage today.cgt_band_donors— 270 = 30 × 9 donor households (household_is_cgt_band_donor), seeded draw (seed 1) over id-sorted candidates p ∝ A&S incidence at the oldest adult's income, bands positional, initial weights = published band taxpayers / 30 (2,633.33 … 66.67) — never zero (the 18× CI-blowup rationale carried in-manifest); band mean gain on the donor's oldest adult; adds exactly 275,000 weighted taxpayers.hmrc_cgt_gains_spine— the merged Impute capital gains amounts from the published joint distribution #560/Wire the capital gains family required-at-build with its fence in-manifest #676 Table 3 amounts redraw reused unchanged on the spine path (same ODS pin, seed_base 552 mixed with build period, fencecalibration_permitted: false/ 76 facts per UK capital gains: imputed distribution has no top tail, missing 55% of CGT #552). The certified-line wrappercgt_source_stages.jsonand the national-driver injection stay untouched until Assemble the microcosm-built UK spine: whole-spine parity and swap acceptance #686 — the E7 spine-vs-certified naming precedent.salary_sacrifice— weighted QRF (seed 42) trained on the FRS survey channel's asked subset only (216 yes / 3,743 no at 2024-25; clones, donors, SPI rows excluded from training), predictions clamp ≥ 0, asked rows byte-preserved; thenconvert_donors_to_target_stock: shortfall vs the declared 5.4m staging target, donor pool = employee-pension contributors without SS, rate = min(0.5, shortfall/pool mass), identity-keyed selection (seed 2024), full pension moved and source zeroed, headcount receipt into the build sidecar.student_loans— cohort rules at calibration year 2025 (start year = year − age + 18; repayers → PLAN_1 < 2012 ≤ PLAN_2 < 2023 ≤ PLAN_5, not country-gated), thentop_up_to_stockPLAN_5 before PLAN_2 against the SLC liable stocks (10,000 / 8,940,000 at 2025), eligibility England ∧ TERTIARY ∧ age band ∧ cohort band, identity-keyed per-plan salts (seed 42). PLAN_4 never imputed — documented UK-specific gap (the FRS cannot identify the Scottish product; no Scottish liable stock exists).Supporting surfaces: 13 op kinds registered (the 7 existing CGT kinds + 6 new);
StagePlangains explicit declaredrewrites(one-producer check stands otherwise);mass_change_semanticson family coverage so the donor stage's intentional mass increase is validated, not exempted; family coverage closes thecapital_gainsandstudent_loan_planproducers;student_loan_planenum-domain gate (the BRMA evaluator generalized); export surface gainshousehold_is_cgt_band_donor; spine driver wires--cgt-ods, harvests every new seed, and persists the four stages' executed-effect receipts as sidecarstage_evidence.Committed cited resources
hmrc_cgt_size_bands.json— all 13 Table 2.1a rows (the ≥ £12,300 filter stays an op parameter); publisher ODS sha-pinned (69645611…b22491, 10,658 B, retrieved 2026-08-21, content-verified against the extraction) withmapped_build_period: 2024/period_mapping: latest_published_tax_yearper the Retarget the UK build to FRS 2024-25: re-pin raw vintages, regenerate parity instruments, re-measure gate baselines #723 convention.advani_summers_capital_gains_distribution.json— the 61-band incidence + percentile surface, byte-faithful to the incumbent CSV. Citation established (the incumbent had none): Advani & Summers (May 2020), "Capital Gains and UK Inequality", CAGE WP 465 — corroborated: the paper's "~15% of the top 1% have gains" = p99 0.1508; "next percentile 7%" = p98 0.0710. Row 30's p95 is corrected 15,190 → 151,900, verified against WP 465 Table A1 (p. 39) — all 61 rows were checked value-for-value against the paper and the dropped digit was the single mismatch (fix-and-sign; the incumbent's value fabricated loss-makers for band-69 draws above q≈0.962). The prior-draw loader now fails closed on any non-monotone quantile row.salary_sacrifice_anchor.json— the HMRC 7.7m total-users anchor (3.3m above / 4.3m below £2k), the documented 0.7013 staging ratio, and the 5.4m derived stage target.slc_liable_stocks.json— the full Table 6a liable + above-threshold series 2025–2030,chronicle_candidate: true, values equal to the chronicle packageslc-student-loan-borrower-forecasts-england-2025(period note: chronicle stores AY opening year 2024 = our calendar 2025). Consumed as a stage-internal anchor: calibration moves weights and cannot create the ~5m below-threshold plan-holders the FRS never observes — the stage creates the support; calibration later binds the chronicle facts against it.cgt_band_donor_support_bounds.json— published-band intervals, deliberately not wired into the terminal support gate: post-redraw amounts move within Table 3's bands, so the Table 2.1a bounds would be wrong at the terminal surface; the resource documents the inapplicability (see adjudications).Licensed acceptance (all green; evidence
data/ukds/acceptance/e8/)twin_payload_compare.json, exit 0) on the full spine roster; the sidecar-evidence driver patch verified payload-inert against the same artifact.e8_identity_receiptPASS: clone-pair structure, donor selection recomputed from the committed resources in original and permuted row order,student_loan_planrecomputed in full — all match the stored artifact.capital_gains0.233684 vs 0.23375 (−0.00007 — the structure-determined share reproduces);student_loan_plancloses at 1.0;pension_contributions_via_salary_sacrifice0.0796 vs 0.0831 (within tolerance — the E8-pending divergence from Retarget the UK build to FRS 2024-25: re-pin raw vintages, regenerate parity instruments, re-measure gate baselines #733's screen closes);employee_pension_contributions−0.0488 beyond ±0.02, signed below.Signed differences
total_income; carrier rule 16+ (FRS adult convention, in-manifest) vs the engine's 18+is_adult— divergent only for households headed by a 16–17-year-old.Corrections (recorded on #684 at implementation start)
The 780-donor figure was the 2023-artifact era; at 2024-25 it is 270 = 30 × 9 (and the incumbent's own history went 2,700 → 270, never 780). The "5.4m OBR anchor" is a deliberate ~70% staging fraction of HMRC's 7.7m anchor (the
obr/naming is a misattribution). The torch blend is deterministic — the drop stands on the torch dependency and its loss bug (clone half modeled as (1−s)·s·w in the loss vs (1−s)·w applied).Two-arm verification (#730/#684 rule)
Every declared parameter carries a drift assert binding the manifest to reviewed code constants (negative-tested per parameter), and an executed-effect receipt: clone mass split → half-mass evidence + identity receipt; donor count/bands/weights → recomputed invariants + per-band sidecar receipt; conversion target/cap → headcount receipt (cap_bound flag); cohort rules/stocks → per-plan receipts; seeds → twin-build determinism (the standing absence statement). The rule itself is documented at the
spi_spinereviewed-constants block.UK-specificity note
UK-specific: the Table 2.1a band surface, the A&S incidence table, the SLC plan rules and PLAN_4 gap, the salsac SALSAC-domain semantics. Generic:
clone_records,stack_band_donor_households,top_up_to_stock,convert_donors_to_target_stock, the enum-domain gate generalization,rewrites, andmass_change_semantics.For María's adjudication
🤖 Generated with Claude Code