Repository navigation
Fix v3 bill budget label, reform delete, chart labels and accessibility - #1280
Merged
Merged
Conversation
Each paged read of a tracker table now sends an order on the table's key. Without ORDER BY, Postgres gave the two 1,000-row pages of processed_bills in a different order on each load, so some rows came back twice and others were never read. Those bills lost their stage badge, their bill text link and their place in the stage filter. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Each paged tracker read now names a stable order by the table's key. Without one, page 2 of processed_bills could repeat rows of page 1 and skip others, so bills lost their stage and bill-text link. When two status rows share a bill number, the one with the latest action wins. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
An id with words after the number (hi-sb3125-hd1, nj-a1185-marriage-penalty-elimination, ut-sb60-bill) matched no processed_bills row, so the bill showed no stage. After the id, the join now tries the title's bill number, as the tracker does, and then the id's first part. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The stored budget card on Economic impacts now takes the bill and uses the overview's own wording: "Annual revenue loss" for a federal bill, "Annual state revenue loss" for a state bill, with the amount unsigned next to the loss or gain word, as the overview shows it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Each paged tracker read now names a unique order column (bill_id for processed_bills, id for the rest). Without one, Postgres gave page 2 of processed_bills rows already on page 1, so about 418 of 1,418 status rows were lost on each load, and a different set each time. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Open as draft reform started a national draft for this year, so a bill from 2027 scored no change from Build and a state bill ran nationwide. The draft now opens with the bill's run year and state, as the bill's report and Run impact report do. loadProvisionsIntoDraft takes an opt-in source; without one the draft stays hand-built. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…tage When two processed_bills rows share one normalized bill number (NY "S 4487" and "S04487"), the feed kept whichever row it read last. It now keeps the row with the higher LegiScan bill id, the later bill, so the stage and the bill text link no longer depend on the read order. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The Economic impacts tab labelled every stored budget 'Annual state revenue', so HR 1425's -$225.5bn read as state revenue while the Overview said 'Annual revenue loss'. The stored budget now takes the bill's state and words it as the Overview does. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Delete in the reform detail now opens a confirm dialog that names the reform and says how many of its reports leave the list (they still open from their links). A failed delete or duplicate shows an error, and the error clears when another reform opens. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The tracker's fiscal_note_source was read but never shown, and a note stored as a range without a point estimate lost its link, so 'Within fiscal-note range' cited a note no one could open. The fiscal-note row now takes the stored source as its name, and a note without an estimate is named and linked under the accepted range, or in a row of its own when no range is stored. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… re-run UT SB60's tracker row scores 0.045, the law before the bill, under a Policy changes table of 4.5% to 4.45%, so Load full results showed an $85.0m revenue gain for a rate cut. The bill report now compares the values a run would score with the write-up's 'after' values. When they disagree, the page keeps the tracker's stored estimate and says why the full results are not available. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Recharts' default tick interval hid category labels that crowd, so on a 375px screen the Hispanic bar, the Top 10% share bar and the state tax bar had a value and no name. The report's bar charts and the budget waterfall now show every tick: each label wraps by word to its own slot, the font shrinks until the longest word fits, and the x-axis grows to hold the label with the most lines. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
react-simple-maps gives every district shape tabindex 0, with no name and, here, no focus outline, so a keyboard user pressed Tab hundreds of times to pass the map. The districts now take no focus, and the map reads as one image whose name points to the ranked district lists. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…aders The search input is a combobox whose focus stays in the input while the arrow keys move the highlight, but nothing told a screen reader which row was highlighted, so Enter added a parameter the user had not heard. Each result now has its own id, the input points at the highlighted one with aria-activedescendant (none while a folder is pointed at, the list is out of date or no results show), and it says it filters a list with aria-autocomplete="list". Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…o fix/v3-audit-states-a11y Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…o wip/audit2-security
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
…o wip/audit2-bills
Revert 2e15b9f. The paged processed_bills read and the rule for two status rows under one bill number belong to #1277 (fix/v3-audit-security) only. The feed reads processed_bills without last_action_date again, and the title and id-prefix stage join stays. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The id "sc-income-tax-cut" names no bill number, so only the title's "H. 3492" finds the processed_bills row. The test fails when the title candidate is removed from processedBillFor. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
When two status rows share one bill number (NY "S04487" from LegiScan and "S 4487" from OpenStates), the row with the later last_action_date now wins. On the same day, or with no dates, the row that links to LegiScan wins. The bill id is only a fixed tie-break after that: the OpenStates and Congress monitors hash their ids above 10,000,000, so a higher id does not mean a later bill, and the OpenStates row always won before. The test rows now carry realistic ids for each source. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
billScoresOtherThanWriteUp flagged a bill when any paired provision held
no value near the write-up's "after". Correct bills lost "Load full
results": a filing-status change written with one status's value, a
yearly write-up of a monthly parameter, a step ("+1%") or a percent
stored as a whole number.
The check now needs evidence of a swap: the named provisions together
hold the write-up's "before" value and none of its "after" value. A
signed "after" next to an unsigned "before" is a step and is not checked.
A stored value also reads as a percent the other way (4.45 for "0.0445").
UT SB60 (0.045 for "4.5% → 4.45%") still flags.
changeNamesPath is exported, so the Policy changes table can share it.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The 1,001-bill test now gives every reform_impacts row its baseline params and checks that every bill's provisions carry that baseline. Before, the baselines read could lose its row order and the test still passed; now that read drops the 1,001st bill's baseline and the test fails. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…red helper ReportChanges copied changeNamesPath line by line as namesPath. It now imports the one in billProvisions. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The federal page test passes with the page's state prop removed, since no state already gives the federal words. This test fails then: a Utah bill must read "Annual state revenue loss" on Economic impacts. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The feed maps a null fiscal_note_url to undefined but keeps "". With no estimate, an empty link then gave an "Official fiscal note · No estimate" row with no link and no source. The estimates table now treats a blank link as absent. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The test asserted the draft's year, which draftYear already gave before the fix. It now reads the year the draft runs in, and asserts what the fix changed: the draft opens with source "bill" and no state region. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… no draft The bill report stopped re-running UT SB60, but on the Reforms page "Open as draft reform" still loaded its swapped 0.045 into Build, and a run there scored the same +$85m increase. The bill panel now uses the same check: "Run impact report" and "Open as draft reform" are disabled, and a note says why. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
PavelMakarchuk
changed the base branch from
fix/v3-relevant-comparisons
to
main
October 15, 2026 13:40
# Conflicts: # app/src/api/billFeed.ts # app/src/tests/unit/api/billFeed.test.ts
# Conflicts: # app/src/api/billFeed.ts # app/src/tests/unit/api/billFeed.test.ts
…mp/audit-int # Conflicts: # app/src/components/flagship/report/StoredImpactCharts.tsx # app/src/pages/flagship/BillReport.page.tsx # app/src/tests/unit/components/flagship/report/StoredImpactCharts.test.tsx
anth-volk
added a commit
that referenced
this pull request
Oct 15, 2026
…audit and report re-runs Brought over from main: the v3 audit fixes (#1273, #1274, #1277, #1278, #1280, #1281, #1283, #1284, #1285), run progress from the API, a report that opens from its stored output and records a failed run, a wait for the reform policy, the report year switcher and All years view (#1292), dated edits in the adjust panel (#1294), each country's own draft, and Your reforms' read-only reform detail with a parameters table, "View results", "Re-run" and the delete prompt (#1288), with the other merged fixes (#1289, #1290, #1293, #1295, #1296). How the conflicts were resolved: - Report page: a link is still a saved report's ID, read through the credential-free shared-report route, with the v1 report's number only without accounts. The v1 report it names (the shared row's legacy_report_id) gets main's run lifecycle: stored output, recorded failures, the household guard, the wait for the reform policy (for any link that resolved), the unknown-baseline state and the year switcher. - Reforms page and ReformReports: main's read-only detail, parameters table, delete prompt, View results and Re-run, on this session's stores and session-scoped query keys. "View results", "Open" and "View full impact report" go to reportLink(report), never the v1 report's number. The detail keeps this branch's guards: a reform whose changes did not load cannot run and says so, a reform that changes nothing cannot run, and the run sends what Build would. A record without a year reads it from the API's record. - Build's run bar: still "Save and run", which saves first and runs nothing when the save fails; it now saves only the values that differ from current law, leaves a reused reform (and its name) as it is, and names a budget window's years. A new reform has nothing to save when nothing differs. - Adjust panel: main's dated edits, budget window and unknown-baseline guard on this session's reform store; recompute still waits until a value differs from current law. - draftReform: loadProvisionsIntoDraft takes both the saved reform it edits and main's window and source. - Tests: main's run-hook tests sit beside this branch's store tests; the run bar test that ran a report after a failed save is dropped, as a failed save runs nothing here. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This branch was successfully deployed
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.
Summary
Fixes five reproduced v3 (flagship) problems: a mislabeled federal bill budget, a one-click reform delete, unlabeled chart bars at phone width, 437 unnamed tab stops on the district map, and a parameter search that screen readers could not follow. All changes are in v3 code.
Problems and fixes
1. Federal bill's Economic impacts tab called its revenue "state revenue"
StoredImpactChartsgot onlyimpact, so it always said "Annual state revenue loss" and added a−sign. On/us/report/bill/us-hr1425the Overview said "$225.5bn Annual revenue loss" and Economic impacts said "−$225.5bn Annual state revenue loss".Fix:
StoredImpactChartsnow takes the bill. A newstoredRevenueMetricinlibs/flagship/billMetrics.tsholds the Overview's wording, and both places use it. A federal bill reads "$225.5bn Annual revenue loss"; a state bill keeps "Annual state revenue loss". The amount is unsigned next to the loss or gain word, as in the Overview.2. Deleting a saved reform was one click, with no confirm and a silent failure
Fix: Delete opens a confirm dialog (
DeleteReformDialog, a Radix AlertDialog). It names the reform and says how many of its reports leave the list (they still open from their links). A failed delete or duplicate now shows an error message, and the error clears when another reform opens.3. Report bar charts dropped category labels at phone width
Recharts' default
interval="preserveEnd"hid crowded ticks, so at 375px the Hispanic bar (poverty by race), the middle inequality bar and the middle budget waterfall bar had a value and no name.Fix: a new
getCategoryAxisinflagship/report/charts/barLayout.ts. Withinterval={0}, each label wraps by word to its own slot, the font shrinks until the longest word fits, and the x-axis grows to hold the label with the most lines. Applied to poverty by race, gender and age, deep poverty by gender and age, inequality, and the budget waterfall.4. The district map put every district (437) in the tab order, unnamed and with no focus outline
Fix: each
GeographygetstabIndex={-1}. The map SVG is now onerole="img"with a name that points to the ranked district lists, which carry the values.5. The parameter search combobox did not tell screen readers which result was highlighted
Fix: each result option has its own id (from
useId). The input setsaria-activedescendantto the highlighted option, and sets none while a folder is pointed at, the list is out of date or no results show. The input also setsaria-autocomplete="list".Not done here: the folder header buttons ("Open folder", the breadcrumb and subfolder rows) are still inside
role="listbox". To move them out of the listbox, or to make them options that the arrow keys reach, changes how the results list works for all users. That needs a design decision.Tracker row order: not in this PR
The paged tracker reads with no ORDER BY get their fix only in #1277 (
fix/v3-audit-security). This branch had its own copy of that fix, and a commit on this branch reverts it, soapp/src/api/billFeed.tsdoes not change here.v2 impact
None. Every changed source file is under
components/flagship,pages/flagshiporlibs/flagship. No legacy v2 page, route, shared chart utility or shared hook changes.Tests
Each fix has a test that failed before the fix:
StoredImpactCharts.test.tsxandBillReport.test.tsx: a federal bill reads "Annual revenue loss" with no−, and a state bill keeps "state revenue".Reforms.test.tsx: Delete opens an alertdialog and does not delete yet. Confirm deletes and Cancel keeps the reform. The report count is in the prompt. A failed delete or duplicate shows an error, and the error clears on another reform.CategoryAxisLabels.test.tsx(jsdom at a 300px card with measured text) andbarLayout.test.ts: every bar keeps its label, and long labels wrap.DistrictChoroplethMap.test.tsx: no district path is a tab stop, and the map is one named image.ParameterSearchBox.test.tsx:aria-autocomplete="list", unique option ids, andaria-activedescendantfollows the arrow keys (also in a folder open in place). There is no active option while a folder is hovered or when there are no results.Checks (from
app/):bun run typecheckpasses.eslint --max-warnings 0andprettier --checkpass on the changed files.vitest runon the flagship component, page, lib and api folders passes (1,335 tests). The fullbun run vitestpasses (4,949 passed, 10 skipped).Note: this PR is based on the open #1274 (
fix/v3-relevant-comparisons). Retarget it tomainafter #1274 merges.🤖 Generated with Claude Code