refuses it rather than guessing. UK only: no US bridge exists, so a
US reform is scored statically.
+
Or drive it directly, without the microsimulation
+
+ The bridge is one way in, not the only one. You can shock the
+ model's own exogenous variables directly, in model units, with no
+ PolicyEngine reform involved — useful when what you have is a
+ macro assumption rather than a statutory change, or when the reform
+ is not household-borne. list_reform_variables returns
+ the levers and the caveat attached to each.
+
+
# £5bn/year more government consumption, 12 quarters
+pe-macro obr-shock --var CGG --shock 1250 --periods 12
+
+# or in Python, with no PolicyEngine dependency at all
+from obr_macro import run_reform
+df = run_reform(name="spending", var="CGG", shock=1250, periods=12)
+
+ Levers: CGG (government consumption, £m/qtr),
+ TCPRO (corporation tax rate), CGIPS
+ (public investment — dead, do not use),
+ HHDI_ADDFACTOR (a costing you produced yourself), and
+ the R / RX monetary and exchange-rate
+ assumptions. Read each one's caveat first: only two of them carry
+ behaviour, and two do not work at
+ all.
+
every join in the suite →this join on the landing page →
diff --git a/obr/methodology/index.html b/obr/methodology/index.html
index 62ad0aa..08f658b 100644
--- a/obr/methodology/index.html
+++ b/obr/methodology/index.html
@@ -107,25 +107,25 @@
Transpile, solve, swap the closure.
click to expand
@@ -145,18 +145,18 @@
What comes out
click to expand
@@ -176,25 +176,25 @@
Why it matters
click to expand
@@ -214,21 +214,21 @@
Runtime
click to expand
@@ -251,23 +251,23 @@
Horizon limits
click to expand
@@ -287,23 +287,23 @@
Shock against an identical baseline
click to expand
diff --git a/obr/validation/index.html b/obr/validation/index.html
index 2be9225..e65b6cd 100644
--- a/obr/validation/index.html
+++ b/obr/validation/index.html
@@ -81,10 +81,9 @@
How far to trust it, and where it stops.
- Five steps: what the three configurations score, the anchored fit
- against the OBR's own forecast, the one independent test, what the
- equations do free-running with no OBR judgement, and the limits that
- follow. The panel alongside carries the figures each step refers to.
+ What the three configurations score, the anchored fit, the one
+ independent test, what the equations do free-running, and the limits
+ that follow. The panel alongside carries the figures.
@@ -96,8 +95,8 @@
How far to trust it, and where it stops.
Excellent anchored. Weak free-running. Both published.
- Three configurations, three levels of trust. Errors are MAPE (mean
- absolute percentage error) against the published EFO path.
+ Three configurations, three levels of trust. Errors are MAPE against
+ the published EFO path.
@@ -130,17 +129,17 @@
How far to trust it, and where it stops.
Anchored
Add-factors matched to the March 2026 EFO. Every reform score uses it.
-
GDP 0.15% MAPE, consumption 0.25%, 2025Q1–2027Q4. GDP holds to 0.29% out to 2031Q1; anchored unemployment is unreliable beyond 2027Q4. CI hard-gates the tolerance, finiteness, the expenditure identity to 0.5% of GDP, and sign invariants.
+
GDP 0.15%, consumption 0.25% (2025Q1–2027Q4); 0.29% out to 2031Q1. Unemployment unreliable past 2027Q4. CI gates tolerance, finiteness, the expenditure identity and signs.
Held add-factors
-
Fitted 2024Q1–2025Q4, held flat to 2027Q4, scored over 2026Q1–2027Q4. Initialised at the EFO values it is scored against, and its fitting window contains OBR-forecast quarters — so it partly encodes “agree with the OBR”.
-
GDP 0.37%, consumption 0.33%; 6 of 8 computed in band. The working paper’s 2.2% / 3.6% is the same window on the November 2025 vintage.
+
Fitted 2024Q1–2025Q4, held flat, scored 2026Q1–2027Q4. Initialised at the EFO values it is scored against, and its fitting window contains OBR-forecast quarters — so it partly encodes “agree with the OBR”.
+
GDP 0.37%, consumption 0.33%; 6 of 8 in band. The paper’s 2.2% / 3.6% is the same window on the November 2025 vintage.
Free-running
De-seeded, add-factors off — raw structural dynamics, no OBR judgement.
-
Weak, and reported as such. GDP 4.48%, consumption 7.49%, household income 6.27%, business investment 15.73%, company profits 63.29%. The model contracts while the EFO grows.
+
Weak, and reported as such. GDP 4.48%, consumption 7.49%, household income 6.27%, business investment 15.73%, company profits 63.29% — the model contracts while the EFO grows.
@@ -170,9 +169,8 @@
How far to trust it, and where it stops.
Anchored GDP and consumption are one test, not two:
- the deviation is identical in £m in all twelve quarters, because
- every other term in the demand identity is exogenous or pinned. The
- independent test is the HMRC costing below.
+ the £m deviation is identical in all twelve quarters, because every
+ other term in the demand identity is exogenous or pinned.
-
Free-running against the March 2026 EFO baseline, real GDP is 4.48% MAPE and consumption 7.49%, with company profits 63.29% off and 6 of 11 computed variables in band. The anchored fit — GDP 0.15%, consumption 0.25% — is one test, not two: every other expenditure component is exogenous or pinned, so the anchored GDP error is the consumption error to the pound. And one of the four fiscal levers contains behaviour: government consumption is a pure accounting identity (impact multiplier 1.0000 at any shock size, against the OBR's 0.6 decaying to zero), government investment is dead with a wrong-signed GDP residue, corporation tax converges only slowly (a 12-quarter run reaches ~40% of its plateau), and only the household-tax route responds on impact. Validation →
-
diff --git a/style.css b/style.css
index 1df7534..7e02463 100644
--- a/style.css
+++ b/style.css
@@ -2953,6 +2953,14 @@ td.vc-warn, th.vc-warn { color: var(--brand-warning); font-weight: 600; }
border-bottom: 1px solid var(--line-soft);
}
@media (min-width: 720px) { .vmet-strip { grid-template-columns: repeat(4, 1fr); } }
+/* Inside a scrollytelling column the 4-up strip has ~560px, not the full band
+ width, and it needs ~660px: the viewport media query above cannot see that,
+ so the fourth stat was being clipped (overflow-x is visible here, so it did
+ not even scroll). Two-up fits and keeps the stats legible. */
+.scrolly-steps .vmet-strip { grid-template-columns: repeat(2, 1fr); }
+@media (min-width: 1500px) {
+ .scrolly-steps .vmet-strip { grid-template-columns: repeat(4, 1fr); }
+}
.vmet-stat {
padding: 22px 4px 20px;