Skip to content

Reforms: place picker, and bill reports that say what each bill changed - #1244

Merged
PavelMakarchuk merged 15 commits into
mainfrom
feat/reforms-polish
Oct 13, 2026
Merged

PavelMakarchuk merged 15 commits into
mainfrom
feat/reforms-polish

Conversation

@PavelMakarchuk

@PavelMakarchuk PavelMakarchuk commented Oct 7, 2026 •

Copy link
Copy Markdown
Contributor

Summary

v3 (flagship) Reforms tab and bill reports. No v2 files change: every changed module is used only by the flagship pages.

Reforms tab

  • The place filter uses the shared ScopePicker and shows a bill count for each place. The "Georgia · Analyzed" place-and-status labels are gone.
  • Dashboards, tools, and blog posts without a reform are no longer listed as bills: 94 tracker entries become 77.

Bill report

  • Policy changes table in the Overview, not in the cover: Change (name, explanation, bill section), Before, After, Start and End. On narrow screens the columns fold under the name.
  • Before comes from what the bill was scored against. In order:
    1. The tracker's write-up.
    2. Its stored baseline_params, added in Store the baseline each bill is scored against (baseline_params) state-legislative-tracker#223 and filled for 75 of 78 bills.
    3. The law in the bill's run year.
  • An enacted bill reads against the tracker's baseline. For example, GA HB 463 now shows 5.09% → 4.99%, where it showed 4.99% → 4.99%.
  • No automatic runs. Opening a bill or any of its tabs starts no calculation. A Load full results button starts it.
  • Stored districts. The Districts tab maps the tracker's stored district results (72 bills) until the full results load. The Overview's district card now follows the report's scope.
  • Smaller fixes:
    • Placeholders, not raw parameter paths, while metadata loads.
    • The poverty chart shows the change only, not the rates before and after.
    • Booleans read true/false, with a switch in the adjust panel.
    • The adjust panel shows each parameter's full name, a Build-style value box, and "was …" beside it.

Reading a bill's reform (these change full-run results)

  • Every dated value is sent to the API, not only the first one.
  • A bill that starts after this year runs in its first year. 18 bills start in 2027.
  • Tracker scale paths (rates.brackets[7].rate) map to the model's (rates[7].rate), so 552 rows find their metadata.
  • Tracker run settings (_use_reform, _skip_params) are not sent as parameters. A model change turned on by name gets its in_effect switch.
  • A year-only period ("2026") starts on January 1. "Already law" checks each dated value.

Build

  • The "N unchanged parameters are left out of the report" note is gone.

This branch also merges the latest main, including the indexing feature (#1243).

Test plan

  • tsc, ESLint and Prettier are clean.
  • Full Vitest: 4,194 passed, 10 skipped.
  • On localhost:
    • GA HB 463, NY A05435, VA HB 979 (runs in 2027), CA AB 1690 (all ten years sent), SC H.3492 and KS HB 2620 (stored district map, no API run).
    • Desktop and phone widths, with no horizontal overflow.

Known API issue, not in this PR: budget.households from the sim API is the sum of squared weights (PolicyEngine/policyengine-sim-api#767). The "average change per household" headline is about 10⁴ too small until that fix ships.

🤖 Generated with Claude Code

Reforms tab
- The place filter is the shared ScopePicker, with a bill count per place;
  the "Georgia · Analyzed" style place-and-status labels are gone.

Bill report
- The policy changes move from the cover into a "Policy changes" card in
  the overview, a row each: name, what it does, and before → after.
- Before → after comes from what the bill was scored against: the
  tracker's write-up (reform_impacts.provisions), its stored baseline
  values (baseline_params, read in a separate query so the feed loads
  without the column), or the law in the bill's run year. An enacted
  bill reads against the tracker's baseline, since today's values
  include it, and never says "current law".

Reading a bill's reform
- Every dated value is kept and sent to the API; only the first was
  sent before, applied from this year on.
- A bill that starts after this year runs in its first year (18 bills
  start in 2027), and reads against that year's law, not today's.
- Tracker scale paths (rates.brackets[7].rate) map to the model's
  (rates[7].rate), so 552 rows find their metadata.
- Tracker run settings (_use_reform, _skip_params) are not sent as
  parameters; a model change turned on by name gets its in_effect switch.
- A year-only period ("2026") starts on Jan 1.
- "Already law" checks each dated value against the law over its dates.

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

vercel Bot commented Oct 7, 2026 •

Copy link
Copy Markdown

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

Project Deployment Actions Updated
policyengine-calculator-next Ready Ready Preview Oct 12, 2026 9:50pm UTC
policyengine-website Ready Ready Preview Oct 12, 2026 9:50pm UTC

Request Review

Opening a bill report created its policy and started the society-wide
run straight away, and every tab waited on it. The page now opens on the
tracker's stored estimates; sections that need the full results offer
"Calculate full results", and only that click starts the run, for that
bill.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The tracker's research table also files dashboards (OBBBA Household
Explorer, ACA-Calc, ...), a tool (MyFriendBen), and blog posts. The feed
listed all of them as bills. It now keeps bills, and blog posts that
carry a reform to score (UT SB 60, SC H.3492); 94 entries become 77.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Whether a bill's full results exist is unknown until the page asks:
another reader may have run it, and then the API returns them at once.
The box now says the results are not loaded, that the page shows the
tracker's stored estimates, and that a first run takes several minutes;
the button reads "Load full results".

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The stored-estimates chart "Poverty rate, before and after" showed the
current-law and with-bill rates side by side; it is now "Poverty rate
change", one bar each for all people and children with the relative
change. The poverty tile on the Reforms bill detail drops its
"16.9% → 14.5%" line and keeps the change.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Until the model's metadata arrives, a bill's provisions have no names or
units, so the Policy changes card, the Validation list, and the Adjust
parameters panel showed raw paths and bare numbers
("gov.states.ga.tax.income.main.flat_rate: 0.0509 → 0.0499") before
the formatted rows. They now show placeholder rows until the metadata
loads. The tracker's own write-up needs no metadata and shows at once.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The Policy changes card is now a table: Change (name, what it does, the
bill section), Before, and After. An unknown before reads "—". Below
the small breakpoint the Before and After columns fold into a
"before → after" line under the name, so the table never scrolls on a
phone.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
PavelMakarchuk and others added 5 commits October 12, 2026 10:24
The table gains Start and End columns. A parameter's dates are its first
dated value's start to its last one's end ("No end date" for 2100-12-31);
an undated value runs from this year on. A tracker row takes the dates
of the parameter it names (its "{filing_status}" placeholder matches
every status), or the bill's when all provisions share one range, and
"—" otherwise. Below the medium breakpoint the dates fold into a line
under the name.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Yes/no parameters showed as "off → on" in the report's adjust panel,
the policy changes table, and the Validation list. They now read
"false → true" (formatValue, which only the v3 pages use), and the
adjust panel edits them with a switch labelled true or false instead of
an on/off button.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Each row led with a compact path cut off with an ellipsis ("… → Sc →
H3492 → SC H.3492 …") and read "false → [switch] true", the switch
between two values. A row now shows the parameter's name in full,
wrapping, with its place in the tree on hover, then "Before" and
"After" lines, the editor on the After line. The remove button and the
editor are named after the parameter, not its path. The report table
and the panel share reportProvisionName.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Unchanged parameters still stay out of the run; the header no longer
says so. "Nothing is changed yet" stays for a draft with no changes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The Before and After lines go. Each row shows the editor, with what the
value was in small type beside it when the two differ, as Build shows
changed values. Numbers use Build's box, so a rate reads 4.99 % and an
amount $ 1,750 rather than 0.0499 and 1750; yes/no values keep the
switch.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The tracker stores congressional-district results for 72 of 78 bills,
but the Districts tab drew its map only from the full results, so until
"Load full results" it showed nothing, and the overview called districts
"not available for this report's scope".

- fetchTrackerBillDistricts reads one bill's district_impacts as its
  report opens ("KS-1" → "KS-01", avgBenefit, winner and loser shares),
  so the Reforms feed stays light.
- DistrictImpactCard takes districts directly and the views to offer;
  the stored map leaves out "Relative", which the tracker does not store.
- The Districts tab shows the stored map under the full-results box
  until the full results replace it.
- The overview's district card reads the report's scope (nationwide or
  a state), not whether the run's policies exist yet.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
PavelMakarchuk and others added 2 commits October 12, 2026 17:47
Reading fetchMock.mock.calls[0][0] needs the mock to take the URL; with
no parameters its call tuple is empty and tsc rejects the index.

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

This branch was successfully deployed

2 active deployments
Preview – policyengine-calculator-next — 73c12618 Deployed Oct 12, 2026 by vercel[bot]
Preview – policyengine-website — 73c12618 Deployed Oct 12, 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