Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
a3dc800
Estimate society-wide run time by region
PavelMakarchuk Oct 13, 2026
6368204
Validation: the same checks on every report, in one card style
PavelMakarchuk Oct 14, 2026
f5440f3
Report: test validation with a related published score
PavelMakarchuk Oct 14, 2026
19abf25
Validation: scorecard not comparable against a custom baseline
PavelMakarchuk Oct 14, 2026
97c2f41
Reforms: bills read as the tracker names them
PavelMakarchuk Oct 14, 2026
968f6d3
Merge remote-tracking branch 'origin/main' into feat/run-durations-by…
PavelMakarchuk Oct 14, 2026
eea72d9
Report: bill report links to its tracker page
PavelMakarchuk Oct 14, 2026
ee60cdf
Reforms: link the bill tracker home
PavelMakarchuk Oct 14, 2026
d15ca4c
Region estimates: opt-in for v3 only
PavelMakarchuk Oct 14, 2026
8faa5fe
States: shared loading, empty and error states for app v3
PavelMakarchuk Oct 14, 2026
4e823cf
Build: parameter placeholders, and a retry when metadata fails
PavelMakarchuk Oct 14, 2026
f6f1f6d
Build: a search with no match offers to clear it
PavelMakarchuk Oct 14, 2026
56a9cf6
Reforms: card placeholders, retries and empty states
PavelMakarchuk Oct 14, 2026
1177095
Report: not found and failed loads end in a state, not a wait
PavelMakarchuk Oct 14, 2026
3b464c7
Report: a failed budget window retries in place
PavelMakarchuk Oct 14, 2026
e242ff1
Bill report: placeholder, feed failure and metadata retry
PavelMakarchuk Oct 14, 2026
1c7430a
Report: a failed policy does not hold up the run
PavelMakarchuk Oct 14, 2026
beb82e3
Shell: one menu and fingertip controls on a phone
PavelMakarchuk Oct 14, 2026
ab8afcc
Report: side panel is a bottom bar and a drawer on a phone
PavelMakarchuk Oct 14, 2026
c3b4818
Build: reform table, values and pickers fit a phone
PavelMakarchuk Oct 14, 2026
b8c51a1
Reforms: filters and cards fit a phone
PavelMakarchuk Oct 14, 2026
07f25a7
Tracker: one status join, net cost in the budget card, header wraps
PavelMakarchuk Oct 14, 2026
7578da2
UI states: a failed refetch keeps its data; review fixes
PavelMakarchuk Oct 14, 2026
c7c3660
Shell: phone layout only on v3 pages; drawer is a modal
PavelMakarchuk Oct 14, 2026
a1dc931
Report: a spinner while the run starts, not an empty card
PavelMakarchuk Oct 14, 2026
7689406
Merge remote-tracking branch 'origin/main' into m/1269
PavelMakarchuk Oct 14, 2026
5df69d3
Report: drop the old custom-baseline note tests from ReportView
PavelMakarchuk Oct 14, 2026
d026092
Merge branch 'm/1269' into m/1270
PavelMakarchuk Oct 14, 2026
7d32a87
Merge branch 'm/1270' into m/1272
PavelMakarchuk Oct 14, 2026
6d47b65
Merge branch 'm/1272' into m/1268
PavelMakarchuk Oct 14, 2026
682cd52
Report: a bill not in the feed links to its tracker page again
PavelMakarchuk Oct 14, 2026
74f16c9
Reforms: one place name for a bill, from the tracker's rule
PavelMakarchuk Oct 14, 2026
6bd601b
Merge branch 'm/1268' into m/1257
PavelMakarchuk Oct 14, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 16 additions & 4 deletions app/src/api/billFeed.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { CURRENT_YEAR, FOREVER } from '@/constants';
import { CountryId } from '@/libs/countries';
import { trackerBillUrl, trackerPlace, withTrackerTitle } from '@/libs/flagship/billTracker';
import type { ValueInterval } from '@/types/subIngredients/valueInterval';

/**
Expand Down Expand Up @@ -104,6 +105,10 @@ export interface TrackedBill {
/** Two-letter state code for state bills; absent for federal ones. */
state?: string;
title: string;
/**
* The bill's stage in the tracker's words ("In Committee"), or
* "Analyzed" when the tracker follows no stage for it.
*/
status: string;
summary: string;
provisions: TrackedBillProvision[];
Expand All @@ -114,6 +119,8 @@ export interface TrackedBill {
legiscanUrl?: string;
/** The bill's source page (congress.gov / state legislature), when known. */
sourceUrl?: string;
/** The bill's page in the bill tracker. */
trackerUrl?: string;
/** Analysis date (ISO), for newest-first ordering. */
date?: string;
/** Model and data versions behind the stored analysis. */
Expand Down Expand Up @@ -396,7 +403,8 @@ export function changesFromTrackerProvisions(raw: unknown): BillChange[] {

/** Headline numbers from a reform_impacts row, when present and numeric. */
function extractImpacts(impact: any): TrackedBill['impacts'] {
const revenue = impact?.budgetary_impact?.stateRevenueImpact;
// As the tracker reads it: net cost stands in where no revenue change is stored.
const revenue = impact?.budgetary_impact?.stateRevenueImpact ?? impact?.budgetary_impact?.netCost;
const poverty = impact?.poverty_impact?.percentChange;
const result: NonNullable<TrackedBill['impacts']> = {};
if (typeof revenue === 'number' && Number.isFinite(revenue) && revenue !== 0) {
Expand Down Expand Up @@ -559,7 +567,8 @@ function processedBillFor(
*/
export async function fetchTrackerBills(): Promise<TrackedBill[] | null> {
const [research, impacts, processed, validations, baselines] = await Promise.all([
trackerSelect('research', '*'),
// Titled as the tracker shows them: an entry with no title reads as its bill number.
trackerSelect('research', '*').then((rows) => rows?.map(withTrackerTitle) ?? null),
trackerSelect(
'reform_impacts',
'id,reform_params,provisions,computed,budgetary_impact,poverty_impact,child_poverty_impact,winners_losers,decile_impact,policyengine_us_version,dataset_name,dataset_version,computed_at'
Expand Down Expand Up @@ -600,7 +609,7 @@ export async function fetchTrackerBills(): Promise<TrackedBill[] | null> {
return {
id: record.id,
countryId: 'us',
jurisdiction: STATE_NAMES[record.state] ?? record.state ?? 'Federal',
jurisdiction: trackerPlace(record.state, STATE_NAMES),
// The tracker files federal bills under "US", which is not a state.
state:
/^[a-z]{2}$/i.test(record.state ?? '') && record.state.toUpperCase() !== 'US'
Expand All @@ -614,6 +623,7 @@ export async function fetchTrackerBills(): Promise<TrackedBill[] | null> {
keyFindings: Array.isArray(record.key_findings) ? record.key_findings : undefined,
legiscanUrl: processedBill?.legiscan_url ?? undefined,
sourceUrl: record.url ?? undefined,
trackerUrl: trackerBillUrl(record),
date: record.date ?? undefined,
provenance: impact
? {
Expand Down Expand Up @@ -643,7 +653,9 @@ function detectValidationDrift(row: any, impact: any): BillValidation['drift'] {
}
const reasons: string[] = [];
const snapEstimate = snapshot.pe_estimate;
const currentEstimate = impact.budgetary_impact?.stateRevenueImpact;
// The estimate the feed headlines (see extractImpacts).
const currentEstimate =
impact.budgetary_impact?.stateRevenueImpact ?? impact.budgetary_impact?.netCost;
if (
typeof snapEstimate === 'number' &&
typeof currentEstimate === 'number' &&
Expand Down
22 changes: 22 additions & 0 deletions app/src/components/flagship/BillTrackerLink.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { IconExternalLink } from '@tabler/icons-react';
import { colors, typography } from '@/designTokens';

/** A bill's page in the bill tracker, beside the report's other source links. */
export default function BillTrackerLink({ href }: { href: string }) {
return (
<a
href={href}
target="_blank"
rel="noreferrer"
className="tw:inline-flex tw:items-center tw:gap-0.5"
style={{
color: colors.text.secondary,
fontSize: typography.fontSize.xs,
fontFamily: typography.fontFamily.primary,
}}
>
Bill tracker
<IconExternalLink size={11} />
</a>
);
}
Loading
Loading