Skip to content

Model-repo review round: correct what the site could not support - #174

Merged
vahid-ahmadi merged 6 commits into
mainfrom
fix/model-repo-review-round-one
Aug 12, 2026
Merged

Model-repo review round: correct what the site could not support#174
vahid-ahmadi merged 6 commits into
mainfrom
fix/model-repo-review-round-one

Conversation

@vahid-ahmadi

Copy link
Copy Markdown
Contributor

Fresh independent reviews of the model repositories (boe-svar, frb-us, us-hank, define-uk) and of the site's validation pages and examples. The model-side fixes are merged upstream and re-pinned here.

Headline corrections:

  • boe-svar FEVD now compares on the paper's own definition (posterior mean of the per-draw group share of total variance, four quarters). UK GDP 37.4% vs ~40% is a match; UK CPI 42.3% vs ~50% is about 8pp short. The previous match came from renormalising a sum of medians.
  • Forecast skill: 64 Diebold–Mariano tests per benchmark, none clearing a 10% false-discovery rate once adjusted together. The Bank Rate p = 0.018 was the smallest of the 64.
  • Published-spec evaluation: the rolling evaluation had estimated without the Covid dummies every published fan carries. Under the published spec UK GDP goes from worse-than-naive to level with it.
  • Fan bands: widening factors were measured on the no-dummy model and applied to dummied fans; regenerated from the production-spec coverage run.
  • DEFINE: the 1.78 multiplier is no longer presented as comparable to IMF/OBR multipliers; the pinned-defect count corrected from thirty-five to thirteen; an unidentifiable citation dropped.
  • us-hank: a test count that described another repo removed from four surfaces.
  • models/index.html: a dead copy button fixed by lifting the handler duplicated on fifteen pages into reveal.js.

Upstream: PolicyEngine/boe-var-model#13, PolicyEngine/us-hank-model#3, PolicyEngine/us-frb-model#8, PolicyEngine/define-uk-model#12 and #13.

🤖 Generated with Claude Code

vahid-ahmadi and others added 4 commits August 12, 2026 15:09
Three model-repo reviews and two recovered page audits. The findings that
were verifiable and mine to fix.

Two published commands could not run. /connect's dynamic-scoring recipe gave
`pe-macro og-score --json > og.json` and `pe-macro dynamic-score --og-payload
og.json`; --reform is required=True on both, so each exits 2 with "Missing
option '--reform'" before doing anything. Confirmed by running them. core.py's
own error text has carried the correct two-step form all along; the page was
the only place that dropped it.

The site's name for a model was rejected by the site's own API. Every page
says psl-og; get_status("psl-og") raised, and the error listed only registry
keys, so nothing connected the two. site_id was added to render one name per
model but the alias was one-directional. Lookups now resolve site names, the
error offers both vocabularies, and the returned model_id is the registry key
so a caller who passed a site name learns the contract id. Pinned by a test.

/connect claimed "no PolicyEngine account and no API key" beside a UK CLI
example that needs a HUGGING_FACE_TOKEN for a private dataset. The claim is
true of the hosted route and false of that example. Three other pages
document the token; the page carrying the example did not. Both now scoped
and stated.

It also said the hosted server "points you to the local CLI" for
score_reform(model='og'). dynamic_reform_impact does return the local recipe;
model='og' returns an import error pointing at an install the registry
documents as unusable in-process. Reworded to what actually happens.

FRB/US: the headline was the weakest evidence in the repo, presented as the
strongest. A review proved the tracking invariant is tautological by running
it on randomly scrambled data — every accounting identity destroyed — where
it still passes at 6.7e-9, because init_trac defines add-factors as minus the
residuals at the input, so re-solving is the identity on any input. 282 of
284 equations have bit-exactly zero residual before Newton runs. models/ now
leads with the real evidence, agreement with the Fed's own pyfrbus across all
284 variables at ~1e-8 — the Board's two releases differ from each other by
1.3e-8 — and the residual chart's tautological bar is relabelled "identity —
not evidence" with the scrambled-data result in its note, instead of being
plotted as the shortest bar beside genuine cross-implementation residuals.

And one of mine: replacing "Seven model classes" left "Seven models, side by
side, side by side." in an h2. The earlier attempt at the same line had also
silently failed on a literal apostrophe rather than the entity.

Twelve gates, 1107 site tests, 275 integration tests.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…the one described

The FRB/US "fixed funds rate" fiscal experiment was not pegged. A review
found the year-two multiplier of 0.99 could not be reproduced by running the
model, which returns 0.90, and the cause is not a definitional difference or
a stale artifact: results.json regenerates bit-identically, so the artifact
faithfully encodes a bad experiment.

run_experiments.py flipped dmpintay to 0 and dmpex to 1 after init_trac, and
only on the shocked frame, then took deviations against the inertial-Taylor
baseline. Tracking had already absorbed the wedge between the rule's own
value and the actual funds rate into the rff add-factor, so it kept being
subtracted: the "pegged" rate settled 0.07-0.12pp below its own rfffix
target. That is an unintended monetary easing stacked on the fiscal
stimulus, and it inflated the multiplier.

The tell needed no external comparison — a pegged run whose funds rate moves
is self-evidently not pegged. It now takes its own pegged baseline, tracked
under the peg, and asserts max |drift| < 1e-10, so a peg that is not a peg
fails loudly instead of returning a plausible number. Three independent
correct implementations agree at 0.904.

Regenerated, and the site corrected in five places across four pages: the
year-two pegged multiplier is 0.90, and it sits below the 1.1-1.2 cross-model
accommodation range rather than just below it. Year one under the inertial
Taylor rule is unaffected at 0.72 — no switches were flipped post-tracking
there, so only the pegged run was wrong.

The script also hardcoded one developer's home directory, so nobody else
could regenerate these figures — which is how a bad experiment stayed
committed. It now resolves from US_FRB_MODEL or a default checkout and fails
with a clear message rather than a stack trace.

Twelve gates, 1107 tests.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Two classes of defect found by the site and model-repo reviews.

**A dead button on the catalog page.** `models/index.html#score` is the
target of fifteen "how to score a reform" links from across the site, and
it renders a copy button. The handler had been pasted by hand into
fourteen pages plus a variant inside /connect's own IIFE, and was missing
here — the button looked live and did nothing. Lifted the one handler
into `reveal.js`, where it is delegated from the document, and removed
all fifteen copies. Two tests keep it honest: a page that renders the
button must load the file, and no page may rebind it (two listeners on
one button is two clipboard writes per click).

**A test count nobody can keep true.** Four surfaces published the size
of the us-hank suite as a fact about another repo. It was "18" while that
repo had 24 test functions; an earlier pass here changed it to "47",
which was also wrong — the true committed figure is 24, and in-flight
work takes it to 43. A number that lives in this repo and describes a
different one drifts on every commit over there, and the page said "an
47-test replication gate", which is what a mechanical replace looks like.
Removed the count from all four surfaces and from the assertion pinning
it; what matters — that steady-state targets, market clearing and shock
responses are gated — is unchanged and still stated.

Also from this round: the us-hank status on `forecasts/us` said "research
prototype" (that is psl-og's registry status), `frb-us` — the id the site
prints — fell through to the bare enum error instead of its written
refusal, the HANK productivity shock documented 0.01 as "~1%" when
steady-state Z = 0.468 makes it ~2.1%, and the six /economy topic pages
carried a breadcrumb through /economy/topics, a redirect source rather
than a page.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
… quoting one of 64 p-values as a result

Fresh reviews of the model repositories found the site publishing four
things it cannot support. All four model repos are re-pinned to the
merged fixes.

**The FEVD replication was measuring the wrong quantity.** The paper's
Figure 4 "decomposes the mean of the sum of the decomposition", with the
note attributing the gap to 100% to the unidentified shocks, and its text
says the identified shocks explain only "around 80%". So its ~40% / ~50%
are posterior means of shares of *total* variance. This site summed
per-shock posterior *medians* and renormalised them to 100% — and those
medians sum to about 0.62 for GDP and 0.71 for CPI, so the renormalisation
inflated every identified share by roughly a third. It also read the
decomposition one column late, since column h holds the (h+1)-step
variance. On the paper's own definition: UK GDP 37.4% against ~40%, which
is a match, and UK CPI **42.3% against ~50%, about 8pp short**. The 49.5%
that matched was an artefact of the renormalisation. Both are published,
with the 68% band (roughly ±14pp) that makes the shortfall unresolvable
at this sample size.

**"Bank Rate is the only defensible forecasting claim" rested on the
smallest of 64 p-values.** The evaluation runs 64 variable×horizon
Diebold–Mariano tests per benchmark and had always noted it needed a
multiplicity adjustment without supplying one. Adjusted together
(Benjamini–Hochberg), the minimum q against a drifting random walk is
0.36. **Nothing clears a 10% false-discovery rate, on any variable at any
horizon.** Also corrected: the ex-Covid 0.77 and the p = 0.38–0.67 range
were quoted inside a drift-benchmark paragraph but belong to the weaker
no-change benchmark; against drift they are 1.21 and 0.33–0.43.

**The forecast evaluation scored a model this site does not publish.**
Every fan here is estimated with six Covid dummies; the rolling
evaluation had always left them out, so 2020Q2 sat in the likelihood as
an ordinary observation. Under the published specification UK GDP against
drift goes 1.06 → 0.99 at h=1 and 1.12 → 0.95 at h=8 — level with naive
rather than worse, and still not better. CPI barely moves, so that
weakness is not a Covid artefact.

**The published fan bands were calibrated on a different model.** The
same no-dummy problem reached the widening factors in
`band_calibration.json`: measured without dummies, applied to fans that
have them, in the same direction at every horizon. UK GDP's 68% factor at
one quarter should be 0.86, not 0.64 — the fan was being narrowed by 36%
where the model actually shown wants 14%. Regenerated from the
production-spec coverage run, with the ±6.7pp standard error recorded so
four decimals are not read as four decimals of precision.

On DEFINE: the multiplier of 1.78 was set beside IMF and OBR multipliers
as if comparable. It is a cumulative ratio to 2040 against short-horizon
benchmarks, its denominator is endogenous and moves the wrong way (social
benefits fall when unemployment does, biasing the ratio up), and a
demand-led closure with Kaldor–Verdoorn productivity implies above 1 over
fifteen years anyway. Now stated as upper-leaning, with the unidentifiable
"Batini et al. 2021" citation dropped rather than left as a bare name.
Two pages said "thirty-five manual defects are pinned in tests"; thirteen
are. The Table 4 growth gate is ±0.31pp against an observed −0.30pp miss,
which is a pass by 0.01pp and now says so. And `make_comparison.py`
pointed at a developer's home directory, so the figure could not be
regenerated by anyone else — which is how a superseded statistic stayed in
the committed artifact.

Merged upstream and re-pinned: boe-var-model#13, us-hank-model#3,
us-frb-model#8, define-uk-model#12.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@vercel

vercel Bot commented Aug 12, 2026

Copy link
Copy Markdown

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

Project Deployment Actions Updated (UTC)
macromod Ready Ready Preview Aug 12, 2026 2:47pm

Request Review

…hecks that cannot fail

forecasts/score.py --check caught the fan charts left stale by the
regenerated band_calibration.json — which is what that gate is for. The
GDP fan is visibly wider at short horizons now: the applied 68% factor at
one quarter goes 0.64 to 0.86.

Also on svar/validation: the forecast-revision adding-up identity sat as
a row in a table captioned 'this replication against Brignone & Piffer,
check by check', where a check that holds by construction reads as a
fifth agreement with the Bank. And the reading guide called the gated
sign and zero restrictions 'real evidence' — they are imposed by the
identification scheme and cannot break, so that gate protects the
software, not a claim about the economy.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…ying one silently

CI caught svar_summary() serving an empty FEVD table: _parse_md_table
returns [] when it cannot find its heading, the summary is assembled
without checking, and the upstream heading gained '(4-quarter-ahead
forecast error)' when the off-by-one was fixed. Matching a substring
rather than most of the heading, plus a test that asserts the table is
non-empty, so the next rename fails loudly instead of publishing nothing.

The summary now carries both FEVD tables and says which is which. The
renormalised sum-of-medians is kept for continuity; the per-draw group
share with its posterior mean and bands is the statistic the paper's
~40% / ~50% refer to, and a caller comparing to the paper needs that one.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@vahid-ahmadi
vahid-ahmadi merged commit d63bb3f into main Aug 12, 2026
7 checks passed
@vahid-ahmadi
vahid-ahmadi deleted the fix/model-repo-review-round-one branch August 12, 2026 14:48
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