Skip to content

Policy experiments: past UK measures on the modern population - #210

Merged
MaxGhenis merged 33 commits into
mainfrom
uk-policy-experiments
Oct 23, 2026
Merged

MaxGhenis merged 33 commits into
mainfrom
uk-policy-experiments

Conversation

@MaxGhenis

@MaxGhenis MaxGhenis commented Oct 21, 2026 •

Copy link
Copy Markdown
Contributor

WIP. Basis: cos d1817 (Max, 21 Oct 2026): run historical UK Budgets on the newest Microcosm population as policy experiments to catch model bugs.

These are policy experiments on the modern population, not replays, and not PolicyEngine's costing of any past event. The certified replay path is untouched: compute_uk_event.refuse_unexecutable still refuses every historical registry.

Design note

Full design: docs/uk_replay/POLICY_EXPERIMENTS.md. Running findings: docs/uk_replay/EXPERIMENTS.md. Evidence for the claims below: docs/uk_replay/evidence/policy_experiments/.

  • Registry flag. None is added; the historical registries are not edited. An experiment spec data/uk/experiments/<event>.json (kind uk_modern_population_policy_experiments) binds its registry by SHA-256 and reads its source rows for the OBR side. The execution: requires_event_population block keeps refusing replays.

  • What an experiment is. One registry measure restated as a parameter change on modern law, as either reversal_on_modern_law (modern law contains the measure, so restore the pre-measure policy and keep later changes) or forward_on_modern_law (modern law lacks it, so apply it). The replay's orientation rule applies: positive means a gain to the Exchequer.

  • Output location. results/uk/experiments/<population>/<event>/: per experiment-year artifacts, MODERN_LAW_<year>.json, EXPERIMENT_MANIFEST.json, FINDINGS.json, FINDINGS.md. Nothing is written under results/uk/events, results/uk/replays or the variant index, and a property test checks that for any output path.

  • Populations are not variants. data/uk/experiments/populations.json (status experiment_population, ids exp-…) has the variant's identity shape, so the replay's environment checks apply. It is never added to replay_variants.json and never sealed. A test checks that no replay reader (the DB build, the namespace scan, the results-PR builder, workflows) names the experiment namespace.

  • Labels. Every experiment-year artifact, EXPERIMENT_MANIFEST.json, FINDINGS.json and SUMMARY.json carries label: modern_population_sensitivity (PLAN.md's name for this question), is_replay: false and "Policy experiment on the modern population: not a replay or a costing of ." Specs carry the label and the sentence; MODERN_LAW files carry the label and is_replay; RUN_LOG files are timings and carry none. All of them live only under the experiment namespaces.

  • Runs. Each run reuses compute_uk_event.run_sim: the policyengine.py managed microsimulation, the dataset SHA-256 before and after, the dataset year set, and every touched parameter read back from the simulation's processed tree. Runs execute on Modal (pipeline/modal_uk_experiment.py) with network blocked, holding one of the replay's two shared simulation slots.

  • Which constructions count as anomalous (classify, a pure function):

    Code Severity Condition
    crash investigate alternate world raised
    reform_not_applied investigate processed parameter ≠ construction intent
    construction_noop note modern law already equals the pre-measure world (superseded, or missing from this engine's law)
    inert investigate (OBR ≥ £20m) / check a parameter changed but the effect is under £1m
    sign_mismatch investigate OBR ≥ £20m and PE the opposite sign, ≥ £5m and ≥ 10%
    magnitude_outside_10x / _3x investigate / check scaled ratio outside [1/10, 10] / [1/3, 3]
    obr_zero_pe_moves note OBR < £1m, PE ≥ £100m
    mirror_mismatch investigate mirrored experiments (same reform, opposite constructions) are not exact negatives
    modern_law_differs investigate a touched parameter's processed current-law value differs from the one the construction assumed (assumes_modern)

    Magnitude flags apply only when magnitude_check is scaled, the expected value is at least £100m, and the mapped heads hold at least half the OBR's costing.

  • OBR scaling. For each head group, scale = PE modern baseline / OBR event-vintage forecast of that head, where PE's variables cover the whole head (income_tax with Income tax, the four NICs classes with NICs, capital_gains_tax with CGT). Otherwise scale = OBR newest forecast / OBR event-vintage forecast. The forecasts are rows of the OBR Historical official forecasts database (Spring 2026), extracted with cell references into data/uk/experiments/obr_head_forecasts.json and cross-checked value for value against the March 2025 edition that the vintage locks name. The scaling is a bug screen, not a vintage comparison, which is why the bands are wide and every flag needs a diagnosis.

Status (23 Oct, 14:00Z)

Bank. 43 experiments across 19 events, from Budget 2010 to Autumn Statement 2022, built by pipeline/uk_experiment_specs.py with every counterfactual's arithmetic and source.

  • Events with a registry (AB2021, SS2022, AS2022) bind it. Older events bind the inventory (Scope the vintage-faithful replay of 32 OBR-costed fiscal events #158).
  • Events whose costing window ends before 2024 compare with their last costing year, scaled to the run year (carried_from_fy).
  • Uprating counterfactuals use scale: each named parameter's own processed modern value times a factor, so every later uprating of the engine it runs on is kept.
  • Every value a reform sets states the current law it is written against, for every year the experiment can run (assumes_modern), or is set outright with a reason (set_outright); validate_spec refuses anything else. An engine whose processed value differs gets modern_law_differs, on any population.

Populations.

  • certified_pair: policyengine.py 6.10.0 with policyengine-uk 2.132.6 on the interim Microcosm cut, probed on Modal (data years 2024–2032).
  • model_swap: pe-uk 2.143.0 on the same cut. Against the certified pair on the same data, it separates model changes from data. It is valid only where the data carries the newer model's inputs: three variables 2.132.6 computed are dataset inputs by 2.143.0, and the interim cut has none of them (model_swap_input_gaps).

Findings (full log in docs/uk_replay/EXPERIMENTS.md):

  • Bug filed: PolicyEngine/policyengine-uk#2551. Setting the statutory Marriage Allowance rate switches on the CPS expanded-MA reform, which keeps 10% and extends it to higher-rate taxpayers. Removing the allowance therefore lowered income tax by £0.23bn. Reproduced on synthetic couples on 2.143.0 (script and output in the evidence folder). Fixed upstream by PolicyEngine/policyengine-uk#2553, first released in 2.148.2. On 2.148.2 the same couples behave as the statute says.
  • pe-uk 2.132.6 currency gaps, all fixed upstream and confirmed by the swap or the new detector:
    • dividend bands at £37,500 and £150,000 until April 2026 (fixed in 2.139.4): modern_law_differs on the Budget 2018 and Spring Budget 2021 freezes and the additional-rate threshold;
    • no Growth Plan SDLT relief, and no Autumn Budget 2024 +2pp on additional dwellings (both fixed in 2.141.8, 4044d6ccf): the surcharge reversal removes 1pp, not 3pp, on 2.132.6;
    • additional-dwelling purchases overstated (#2238, fixed in 2.134.1); from then the purchase is a dataset input that the interim cut lacks, so the surcharge is inert on the swap until the pre-Budget cut (microcosm#1308).
  • Diagnosed, not bugs: Budget 2017's Class 4 rise (the OBR's costing is net of incorporation); Budget 2016's trading allowance (neither data line carries gross receipts); Budget 2012's 45p (a behavioural costing); construction_noop notes on measures modern law supersedes.
  • Clean otherwise: every other experiment returns the OBR's sign, and every magnitude-checked ratio is inside the 3x band. That includes the HSCL and its reversal (exact negatives across containers), the 20% and 19% basic-rate pair, the UC taper, the double lock, and the two-child limit.
  • The population. The income tax base is 0.94–0.98 of the OBR's March 2026 forecast, and NICs 1.01–1.05.

Answers to the first review (Opus 5.5, at bb445279; ~/reviews/uk-policy-experiments/review-out-opus.md): the four construction findings are corrected and rerun, modern_law_differs added, findings refuses a run on another spec, adopt checks before copying, committed findings and summaries regenerate byte for byte in a test, containment refuses any checkout's replay roots, and the PR's claims have evidence files. The SS2022 primary-threshold path has more than one defensible reading; the choice is logged and both experiments are sign only.

Answers to the second review (Opus 5.5, at 767a695e; ~/reviews/uk-policy-experiments/review-out-opus-r2.md):

  • B1, the swap's model changes. The seven undiagnosed swap rows are diagnosed: VAT grossing (pe-uk#1996, 2.135.7: 0.38 → 0.67 × 0.7, so VAT scales by 0.810 and the rate rise's ratio moves 1.31 → 1.06); the savings starting-rate taper (35f992c6a, #1799, 2.139.2: ratio 0.43 → 0.73); relieved pension contributions in adjusted net income (1dbc88172, 2.134.8); and the Growth Plan first-time-buyer limits (4044d6ccf). The two income tax ones have synthetic-household evidence. The log now lists every swap change with its cause.
  • B2, undeclared current law. Every reform value now states its current law: filled from one table that both engines match (at that round, 204 declarations over 144 path-years and 50 parameters; now 207 over 147 and 51), plus values set outright. validate_spec enforces it, so the detector covers the pre-Budget pair too.
  • Smaller fixes: containment is case-insensitive (N1); the threshold hold is a stated convention (N2); the lower profits limit is 52 × the weekly threshold (N3); claim wording and prose-only claims (N4, N5); lint (N6); a comment's arithmetic (N7).

Answers to the third review (GPT-6.1 Sol, at 575f4cc8; ~/reviews/uk-policy-experiments/review-out-r3.md):

  • Blocking: the Growth Plan SDLT relief has three legs. Both constructions set only the main scale. They now also set the additional-dwellings first band to £250,000 (Temporary Relief Act 2023 s. 1(3)) and the lease-rent nil-rate band to £250,000 (s. 1(4)). Synthetic checks are in the evidence folder: a £200,000 additional dwelling moves from £6,000 to £7,500 when the relief is removed in 2024-25, and from £11,500 to £10,000 when it is kept in 2025-26. Neither engine has the lease leg itself, which is now recorded on policyengine-uk#2332.
  • Found while fixing it: brackets that share a threshold add their rates in policyengine. So the first attempt's zero-width band taxed additional dwellings above £250,000 at 13%. validate_spec now refuses shared thresholds among the brackets a reform sets; a collision with a bracket the reform leaves alone needs the engine's schedule and shows in the effect.
  • Smaller fixes: the citations, case-insensitive repository containment, a crash keeping modern_law_differs, lint, the narrowed label claim, and the declaration count (now 207 declarations over 147 distinct path-years and 51 parameters).

Reruns. All 17 events whose specs changed in round 2 were rerun on both populations and adopted. Autumn Statement 2022 was rerun again for the SDLT correction and adopted. Every flag on either population and every model-swap change is diagnosed, and the experiment tests pass (130). Every committed run is on the current spec, every flag on either population and every model-swap change is diagnosed, and the experiment tests pass (127).

Results pipeline.

  • PE_UK_PRIVATE_HF_READ_TOKEN reads populace-uk-private: a scratch workflow's HEAD requests got 302 on the Microcosm file and 200 on its release manifest, against 401 without a token (run link in the evidence folder).
  • 6.10.0's qualification lost its runner at the same AB2025 step in both attempts (47fe63f4, dfc9d655), and 6.10.1's first attempt (201e753c) also ended run_artifact_failed, though its run job left no log to say where. Run the UK replay's year workers that fit the runner's memory, and log memory around each event #218 measures, on Modal, 10.2 GiB for one worker over the whole of AB2025 and 18.5 GiB for two on Microcosm, against 9.3 GiB for two on the enhanced FRS, so two Microcosm workers exceed the 16 GB hosted runner. It carries the fix and the retries.

Invariants (property-tested, tests/test_uk_policy_experiment.py)

  1. Orientation: reversal and forward give exact negatives, and spending negates tax.
  2. A total is the exact (math.fsum) sum of its head groups.
  3. The mapped and unmapped OBR values sum to the registry's FY rows, in Decimal.
  4. classify is pure and invariant under joint negation and joint positive scaling above the floors. A ratio further from 1 than a flagged one is also flagged. crash, inert and construction_noop exclude the sign and magnitude codes.
  5. No output path resolves into a replay root of this checkout or any other.
  6. Mirrors return exact negatives (checked on real runs).
  7. Every committed FINDINGS and SUMMARY file regenerates byte for byte from the committed artifacts, and findings refuses a run on another spec.
  8. Where a model swap and its certified pair differ on the current law of a parameter a construction sets, the construction declares the law it assumes or sets the parameter outright.

Plan

  • Harness, specs, scaling bases, tests
  • Modal probe → population records (certified pair and model swap)
  • AS2022, SS2022, AB2021 and 16 older events on the interim pair; model swap in progress
  • Diagnose anomalies; pe-uk#2551 filed and handed to the UK hub
  • Opus review of bb445279; its findings answered
  • Reruns of the six changed events on both populations
  • Round 2 (Opus 5.5 at 767a695e); its findings answered
  • Reruns of the 17 changed events on both populations
  • Round 3 (GPT-6.1 Sol at 575f4cc8); its findings answered
  • Autumn Statement 2022 rerun on both populations
  • Rounds 4 and 5 (GPT-6.1 Sol at 9b15c476 and 378b8496); their findings answered
  • Pre-Budget pair when published

axiom: n/a: replay and experiment tooling; no policy encoding.

🤖 Generated with Claude Code

MaxGhenis and others added 2 commits October 21, 2026 12:36
Run historical fiscal-event measures as parameter changes on modern law,
on an experiment population, and screen each result against the OBR's
costing for crashes, inert constructions, sign errors and implausible
magnitudes (cos d1817). Experiments are labelled
modern_population_sensitivity, live in their own namespace and are never
replays: the historical registries keep refusing replays.

First constructions: 17 experiments for Autumn Budget 2021, Spring
Statement 2022 and Autumn Statement 2022. The OBR's Historical official
forecasts database supplies the scaling bases.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The Modal probe recorded each engine package's RECORD digest, the packaged
bundle manifest, the runtime release bundle and the dataset's years
(2024-2032).

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

vercel Bot commented Oct 21, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
policyengine-scorecard Ready Ready Preview Oct 23, 2026 1:14pm UTC

Request Review

Events without a registry read their OBR rows from the inventory. Add
the three fuel-duty freezes (forgone RPI uprating from the OBR forecast of
the year), Spring Budget 2021's allowance and threshold freeze and Spending
Review 2020's pension credit uprating. An experiment can name the years it
runs, so a day-weighted parameter keeps whole-fiscal-year windows.

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

A model swap runs a newer policyengine-uk on the same data cut, to catch
current bugs before a cut is built for it and to separate model changes
from data. Mirrors now compare only the head groups both experiments map.
The summary collects findings, mirror checks and each comparable head's
modern base against the OBR's newest forecast.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
An event whose costings end before the population's first year compares
an experiment's named years with one stated costing year, scaled from that
year's event forecast to the run year's base, and records the comparison
year on every row.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
MaxGhenis and others added 3 commits October 21, 2026 12:54
… duty in cash

Fuel duty counterfactuals take the 2022 5p cut in cash: 57.95p x (1 +
forgone RPI) - 5p. Budget 2018's early allowance and threshold rises, its
work-allowance increase and fuel freeze, Autumn Budget 2017's first-time
buyers' relief and fuel freeze, and Budget 2017's withdrawn Class 4 rise
run on the population's years, carried forward from each event's last
costing year.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
36 experiment-years, no investigate-level anomaly; every scaled ratio
between 0.5 and 2.3. The six construction_noop notes are diagnosed:
superseded on modern law, outside the measure's years, or (SDLT 2024-25)
the Growth Plan relief missing from pe-uk 2.132.6, fixed in 2.141.8.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
MaxGhenis and others added 2 commits October 21, 2026 13:27
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… swap

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…2015 and Summer Budget 2015

The two-child limit's removal (sign only: its yield grows until 2035), the
additional-dwellings surcharge's original 3pp, the £1,000 trading and
property allowances, and the 2016 and 2017 fuel-duty freezes, each
carried forward from the event's last costing year.

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

Both clean: no anomaly, scaled ratios 0.54 to 1.46. The Health and Social
Care Levy and its reversal return exact negatives in every year and head
group across separate containers.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
MaxGhenis and others added 2 commits October 21, 2026 13:39
…d Budget 2015

VAT at 17.5%, the child benefit freeze and the high-income charge, the 45p
additional rate, the marriage allowance and the personal savings
allowance, carried forward from each event's last costing year. A head
group may carry a PolicyEngine leg the OBR books under another group's
head (the charge is income tax in PolicyEngine, benefit spending in the
OBR's costing).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
12 experiment-years, no anomaly; both welfare rows move Universal Credit
in the OBR's direction (scaled ratios 0.57 to 1.40).

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

Offsetting mapped heads hid Budget 2017's Class 4 rise from the magnitude
check (mapped share 35% net, 69% by head). It is now flagged, and
diagnosed: the OBR's costing carries an incorporation response; the NICs
leg alone is 1.27 times the OBR's NICs row. Autumn Budget 2017 and Spring
Budget 2021 on the interim pair are clean.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
MaxGhenis and others added 3 commits October 21, 2026 14:29
On pe-uk 2.143.0 the interim cut buys no additional dwellings: from
2.134.1 the purchase price is a dataset input (#2238's fix), which the cut
built for 2.132.6 does not supply, so the surcharge reversal is inert and
SDLT falls from £15.0bn to £8.1bn. Microcosm imputes it from #1308. A
model swap is valid only where the data carries the newer model's inputs.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…p's input gaps

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…10, Budget 2010

All clean but Budget 2012's 45p rate, flagged 39 times the OBR's costing
and diagnosed: the OBR's figure is net of a taxable-income response that
offsets almost all of the static cost.

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

- Constructions state the current law they are written against
  (assumes_modern); an engine whose processed value differs gets
  modern_law_differs (investigate). On pe-uk 2.132.6 that catches the
  additional-dwellings surcharge reversal removing 1pp, not 3pp, and the
  dividend higher-rate threshold at 37,500 in the SB2021 and B2018 freezes.
- SS2022's primary threshold without the alignment follows CPI to April
  2025, then the hold; both experiments are sign only. Budget 2018's work
  allowance keeps the April 2019 uprating. The 30-hour childcare
  construction zeroes the age-4 bracket too.
- findings() refuses a run on another spec; adopt() checks every download
  before copying any; every committed FINDINGS and SUMMARY regenerates byte
  for byte in a test; no output path may enter a replay root of any
  checkout; a test checks the two engines disagree on a touched parameter's
  current law only where the construction says so.
- Evidence files for the Marriage Allowance reproduction, the dataset
  token's access and the missing gross-receipts columns.
- Reruns on both populations for SS2022, B2018, SB2015 and AS2015, and the
  certified pair's SB2021. AS2022 and the swap's SB2021 are still running.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Autumn Statement 2022 rerun on both populations, and Spring Budget 2021
  on the model swap. The certified pair's figures are unchanged. The
  additional-rate threshold gets modern_law_differs on 2.132.6 in 2024-25
  and 2025-26 (dividend band at 150,000), diagnosed with the SB2021 freeze.
- A test checks that wherever the model swap and the certified pair differ on
  a parameter a construction sets that year, the construction declares the
  law it assumes or sets the parameter outright. 248 parameter-years, 21
  differ: 16 declared and 5 set outright, each listed with its reason.
- Findings log and design doc: final ratios, the check, invariants 7 and 8.

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

Answers the second review (Opus 5.5 at 767a695):

- B2: every reform path, in every year an experiment can run, either states
  the current law it is written against (assumes_modern) or is set outright
  with a reason (set_outright, new). validate_spec enforces it, so
  modern_law_differs fires on any population, not only a model swap. The
  builder fills assumes_modern from CURRENT_LAW (204 path-years over 50
  paths, which pe-uk 2.132.6 and 2.143.0 share), cross-checked against its
  own State Pension, guarantee and work-allowance constants.
- B1: the model swap's seven undiagnosed changes are diagnosed: VAT grossing
  (pe-uk#1996, 2.135.7), the savings starting-rate taper (35f992c6a, #1799,
  2.139.2), relieved pension contributions in adjusted net income
  (1dbc88172, 2.134.8) and the Growth Plan first-time-buyer limits
  (4044d6ccf). Synthetic households for the two income tax ones in
  docs/uk_replay/evidence/policy_experiments/swap_mechanisms.py.
- N1 containment compares replay-root segments case-insensitively; N3 the
  lower profits limit is 52 x the weekly threshold; N2 the SS2022 hold is a
  stated convention; N6 lint; N7 the work-allowance comment's arithmetic.

The 17 events whose specs changed are being rerun on both populations, so
their committed findings do not regenerate until the reruns are adopted.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Every committed run is on the current spec again: the 17 events whose
  specs gained declared current law were rerun on Modal on the certified
  pair and the model swap and adopted. Effects are unchanged apart from
  Spring Statement 2022's lower profits limit (52 x the weekly threshold).
  Both summaries have no undiagnosed row.
- Findings log: every model-swap change with its cause; the VAT and
  savings allowance ratios on 2.143.0; unbacked lag claims cut.
- Design doc: the current-law rule as validate_spec enforces it.
- Evidence: column_check.py (names only) and the swap-mechanism outputs.

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

- The two Growth Plan SDLT constructions set all three legs of the
  Stamp Duty Land Tax (Temporary Relief) Act 2023 s. 1: the main scale, the
  additional-dwellings first band to £250,000 (s. 1(3)) and the lease-rent
  nil-rate band to £250,000 (s. 1(4)). Keeping the relief merges the
  additional-dwellings bands at the current-law 5% rate, stated in the
  experiment's own assumes_modern. Synthetic checks on 2.143.0 and 2.132.6
  in the evidence folder.
- validate_spec refuses two brackets of one scale at the same threshold:
  policyengine adds the rates of brackets that share a threshold, which is
  how a first attempt here taxed every additional dwelling above £250,000
  at 13%.
- Citations: the Temporary Relief Act 2023, Finance Act 2023 s. 6(4) and
  s. 7(3)-(4). Containment treats a cased spelling of the checkout as the
  repository; a crash keeps modern_law_differs; lint.
- Marriage Allowance: fixed upstream in pe-uk 2.148.2 (#2553), confirmed on
  the synthetic couples. The label claim is narrowed to what each file
  carries; the declaration count is 204 over 144 distinct path-years.

Autumn Statement 2022 is being rerun on both populations, so its committed
findings do not regenerate until the rerun is adopted.

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

- Both populations rerun and adopted. Keeping the relief from 2025-26 now
  returns +£1.34bn on 2.143.0 (scaled ratios 1.33, 0.87, 0.80). On 2.132.6
  it is flagged modern_law_differs: the construction merges the
  additional-dwellings bands at current law's 5%, which that engine lacks.
- Diagnoses: that flag, and the model-swap change it causes (the
  additional-dwellings leg; nil on the swap, whose cut has no
  additional-dwelling purchases). Both summaries have no undiagnosed row.
- Findings log: the corrected ratio row and the swap change.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- test_a_scaled_path_runs_at_its_modern_value_times_its_factor compared
  changes_modern_law with factor != 1.0; production uses a 1e-9 relative
  tolerance, and Hypothesis found factor 1.0000000000000002. The property
  now applies the same tolerance.
- The shared-threshold guard's scope is stated where it is enforced, tested
  and documented: brackets a reform sets. A collision with a bracket it
  leaves alone needs the engine's schedule.
- Findings log: the declaration count at each round (204 over 144 path-years
  and 50 parameters then; 207 over 147 and 51 now).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@MaxGhenis
MaxGhenis marked this pull request as ready for review October 23, 2026 15:52
@MaxGhenis
MaxGhenis merged commit 9d64bf9 into main Oct 23, 2026
13 checks passed
@MaxGhenis

Copy link
Copy Markdown
Contributor Author

Merged by squash at head 378b8496 (merge commit 9d64bf9a).

Reviews. Six rounds, each answered before the next:

  1. Opus 5.5 at bb445279;
  2. Opus 5.5 at 767a695e;
  3. GPT-6.1 Sol at 575f4cc8, which found the blocking Growth Plan SDLT legs;
  4. Sol at 9b15c476;
  5. Sol at 378b8496;
  6. Sol confirmation of the PR body at 378b8496: MERGE-SAFE.

The reports are in ~/reviews/uk-policy-experiments/.

Gates. gh pr checks exits 0 on the latest run (2,455-test suite, DB drift and replay namespace checks). The PR is MERGEABLE (CLEAN), ready, with no changes requested. Separation from replays was rechecked in every round: additions only, with no registry, variant index, DB or workflow change.

Upstream from this work:

Next. The pre-Budget Microcosm cut runs as a new population when it is published. It will carry the fixed engine, so it gives the national Marriage Allowance rerun and the additional-dwellings legs that the interim cut's input gap hides.

🤖 Generated with Claude Code

@MaxGhenis
MaxGhenis deleted the uk-policy-experiments branch October 23, 2026 15:53

This branch was successfully deployed

1 active deployment
Preview — 378b8496 Deployed Oct 23, 2026 by vercel[bot]
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.

1 participant