Host the FRB/US model on the PolicyEngine Macro MCP server#57
Merged
Conversation
FRB/US was local-only. It is now baked into the Modal image and exposed as three MCP tools plus three CLI commands, taking the hosted tool surface from 10 to 13. New tools (mirroring the obr_shock / list_reform_variables / model_summary surface): - frbus_shock(var, shock, start, periods, horizon, policy_rule, variables, name) — solves an add-factored baseline that reproduces LONGBASE to machine precision, then the shocked model, returning per-quarter deviations for xgdp, lur, picxfe, pcpi and rff plus any requested extras. - frbus_list_variables() — the shockable levers with their units. - frbus_summary() — model metadata and validation provenance. CLI: pe-macro frbus-shock / frbus-variables / frbus-summary. policy_rule is exposed because the answer materially depends on it: 'inertial_taylor' (default), 'taylor', or 'fixed_funds_rate' (rff exogenized, no endogenous monetary offset, so fiscal multipliers are larger). Two silent-wrong-answer traps are made loud rather than plausible: - Each policy rule reads its OWN add-error. Shocking rffintay_aerr under a non-inertial rule converges and returns exactly zero everywhere, which reads as "monetary policy does nothing". It now raises and names the right lever. A backstop warning covers any other all-zero solve. - FRB/US equations mix levels, rates and log-differences, so `<var>_aerr` inherits its own equation's units. egfe_aerr is log points of quarterly growth, not billions of dollars; a dollar-sized shock diverges the solver. Units are documented per lever and a divergence is reported as a units error. SCOPE: score_reform deliberately REFUSES model='frbus'. No mapping exists today from a PolicyEngine US reform to FRB/US fiscal levers, so anything it returned would be a plausible-looking wrong number. The error names frbus_shock as the supported entry point, and the docstrings say so. Image: us-frb-model is baked in at the same absolute path as the other two repos and pip install -e'd, since model.xml and LONGBASE.TXT live in vendor/ and are not package data — a wheel install imports but has no model to run. Only those two files (4.9MB) are needed at runtime, so the vendor .zip archives (which duplicate their own unpacked contents), the EViews-era frbus_package, the pyfrbus reference implementation and its docs, the EViews database, HISTDATA, tests/ and scripts/ are excluded: 251MB -> 5.2MB. The github-source branch prunes equivalently and asserts both files survive, so a bad exclusion fails the BUILD rather than the first production request. Also excludes **/.venv from all three repo copies: a developed checkout carries its own virtualenv (213MB in us-frb-model), which add_local_dir would otherwise copy into the image, shadowing container site-packages with laptop-built wheels. Tests (tests/test_frbus.py, 22 tests) gate what a broken deployment would break: the model and data files resolve after pruning, the tracking invariant holds to the model repo's published 1e-8 gate, a 100bp rffintay_aerr shock reproduces the documented signs and magnitudes, and the fixed-funds-rate rule amplifies a demand shock relative to the Taylor rule. Magnitudes are asserted with wide bands against VALIDATION.md rather than exact floats, so a LONGBASE re-vintage does not break the build while a sign flip or a decoupled lever does. Verified locally against both a full checkout and a pruned copy matching the image exclusions: identical results (xgdp trough -0.5512% in 2027Q4, lur peak +0.2584pp, rff impact +1.0001pp), matching VALIDATION.md. Measured latency: ~3s cold, ~0.5s warm (the compiled model and its baseline are cached per policy rule); list/summary are instant. Importing mcp_server stays fast and does not import frbus. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
FRB/US was local-only. This bakes it into the Modal image and exposes it as three MCP tools plus three CLI commands, taking the hosted tool surface from 10 to 13.
Tools added
frbus_shock(var, shock, start="2026Q1", periods=1, horizon=20, policy_rule="inertial_taylor", variables=None, name=None) -> dictfrbus_list_variables() -> list[dict]frbus_summary() -> dictCLI mirrors:
pe-macro frbus-shock/frbus-variables/frbus-summary.frbus_shocksolves an add-factored baseline that reproduces LONGBASE to machine precision, then the shocked model, and returns per-quarter deviations forxgdp,lur,picxfe,pcpi,rffplus any requested extras, with apeaksblock and per-series units.policy_ruleis exposed because the answer materially depends on it:inertial_taylor(default),taylor, orfixed_funds_rate(rff exogenized — no endogenous monetary offset, so fiscal multipliers are larger).Two silent-wrong-answer traps made loud
Both are the same failure mode as the OBR emulator's
investment_closuretrap, and get the same treatment:rffintay_aerrunder a non-inertial rule converges and returns exactly zero everywhere — which reads as "monetary policy does nothing". It now raises and names the right lever, with a backstop warning for any other all-zero solve.<var>_aerrinherits its own equation's units.egfe_aerris in log points of quarterly growth, not billions of dollars; a dollar-sized shock diverges the solver. Units are documented per lever, and a divergence surfaces as a units error rather than a raw solver traceback.Scope: no reform bridge, deliberately
score_reformrefusesmodel='frbus'. There is no mapping today from a PolicyEngine US reform to FRB/US fiscal levers, so anything it returned would be a plausible-looking wrong number. The error namesfrbus_shockas the supported entry point; the docstrings andfrbus_summary().reform_bridgesay the same.Image
us-frb-modelis baked in at the same absolute path as the other two repos andpip install -e'd —model.xmlandLONGBASE.TXTlive in the repo'svendor/and are not package data, so a wheel install imports fine but has no model to run.Only those two files (4.9MB) are needed at runtime. Excluded: the vendor
.ziparchives (which duplicate their own unpacked contents), the EViews-erafrbus_package, the pyfrbus reference implementation and its docs, the EViews database,HISTDATA.TXT,tests/andscripts/. 251MB -> 5.2MB. TheMACROMOD_IMAGE_SOURCE=githubbranch prunes equivalently and then asserts both files survive, so a bad exclusion fails the build rather than the first production request.Also excludes
**/.venvfrom all three repo copies: a developed checkout carries its own virtualenv (213MB inus-frb-model), whichadd_local_dirwould otherwise copy into the image, shadowing container site-packages with laptop-built wheels.Measured latency (laptop)
frbus_shockcold (first in process)init_trac+ 0.2-0.5s solve)frbus_shockwarm (cached baseline)frbus_list_variablesfrbus_summaryfrbusimportAgainst the 600s Modal timeout that is ~200x headroom.
_FRBUS_BASELINE_CACHEholds the compiled model and its baseline per(policy_rule, start, end). The COST PROFILE block inmodal_app.pyis updated with memory/CPU implications and why FRB/US is hostable where OG-UK is not (bounded linear-time simulation vs an unbounded nested fixed-point steady-state search).Verification
Exercised end to end in a scratch venv against both a full checkout and a pruned copy matching the image exclusions — identical results, matching
VALIDATION.mdexactly:Tracking invariant after
init_trac: 5.6e-17.import policyengine_macro.mcp_serverstays fast (~1.4s) and does not importfrbus— the lazy-import property is preserved.Tests
tests/test_frbus.py, 22 tests, following the existing fast/slow marker layout. The slow ones are the deployment gates: model and data files resolve after pruning, the tracking invariant holds to the model repo's published 1e-8 gate, the 100bp shock reproduces the documented signs and magnitudes, andfixed_funds_rateamplifies a demand shock relative to the Taylor rule (which would fail if the rule switch were silently ignored). Magnitudes use wide bands againstVALIDATION.mdrather than exact floats, so a LONGBASE re-vintage does not break the build while a sign flip or decoupled lever does.One pre-existing failure,
test_core.py::test_summary_parses, is unrelated — it needsboe_var, which is absent from my scratch venv; it fails identically on a cleanmain.GOLDEN_TOOL_COUNTgoes 10 -> 13 intests/tool_surface.py; the remote-deployment test picks this up automatically.Not touched: any site
.html,style.css,sitemap.xmlorvercel.json— a separate pass updates the site copy once this is live. Nomodal deployrun; CI deploys on merge.🤖 Generated with Claude Code