Skip to content

Finance backfill - #2315

Open
J-C-L wants to merge 15 commits into
codeforboston:mainfrom
J-C-L:finance-backfill
Open

J-C-L wants to merge 15 commits into
codeforboston:mainfrom
J-C-L:finance-backfill

Conversation

@J-C-L

@J-C-L J-C-L commented Oct 27, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

This is the bulk of the work for backfilling campaign finance data for legislators. (Issue: #2118)
Major changes:

  • Member matching and finance scraping are now scoped per court.
  • There are new backfill scripts for member matching (OCPF IDs with member codes) and finance scraping
  • There is a new script to script set a member mappings by hand, for cases not automatically matched, and the manual matches always win.
  • Script input is validated with zod and gives clear errors.

Other changes:

  • Renamed matchOcpfMembersV2 to matchOcpfMembers.
  • The finance scrape now warns on OCPF record types it doesn't classify.
  • Entries added to generalCourts (in constants.ts) for 189 (2015-16), 190 (2017-18), 191 (2019-20).

Checklist

  • [N/A] On the frontend, I've made my strings translate-able.
  • [N/A] If I've added shared components, I've added a storybook story.
  • [N/A] I've made pages responsive and look good on mobile.
  • [N/A] If I've added new Firestore queries, I've added any new required indexes to firestore.indexes.json (Please do not only create indexes through the Firebase Web UI, even though the error messages may reccommend it - indexes created this way may be obliterated by subsequent deploys)

Steps to test/reproduce

Locally (on emulator):

  1. Confirm the current-court path still works unchanged for member matching and finance scraping:
  1. Test backfillOcpfMemberMapping against a historical court:
  • Run: yarn firebase-admin run-script backfillOcpfMemberMapping --env local --courts=192
  • Confirm console output prints matched/unmatched/ambiguous with names.
  • Confirm in Firestore:
    /generalCourts/192/ocpfMemberMappingConfig/ exists with ocpfMemberMapping and ocpfMemberMappingFlags
  • Can run with verbose and see additional terminal logs output:
    yarn firebase-admin run-script backfillOcpfMemberMapping --env local --courts 192 --verbose
  • Test multi-court + bad input together. Confirm it fails with explanation of bad input
    Ex: yarn firebase-admin run-script backfillOcpfMemberMapping --env local --courts 193,192xxx
  • Test an obviously bogus court: Confirm output shows “Court 999 failed: Error: No members found for court 999. Nothing written."
    Ex: yarn firebase-admin run-script backfillOcpfMemberMapping --env local --courts 999
  1. Test new script for manual fixing.
  • First confirm that member AMS2 is listed in /generalCourts/192/ocpfMemberMappingConfig/ocpfMemberMappingFlags
  • Run yarn firebase-admin run-script setOcpfMemberMapping --env local --court 192 --memberCode AMS2 --cpfId 16980
  • Confirm member AMS2 is now in /generalCourts/192/ocpfMemberMappingConfig/ocpfMemberMapping with “manual: true”, and removed from/generalCourts/192/ocpfMemberMappingConfig/ocpfMemberMappingFlags
  • Re-run yarn firebase-admin run-script backfillOcpfMemberMapping --env local --courts=192
  • Confirm that member AMS2 is still listed in ocpfMemberMapping and is not in ocpfMemberMappingFlags
  1. Test backfillOcpfFinance against a historical court
  • Run yarn firebase-admin run-script backfillOcpfFinance --env local --courts=192
  • Confirm in Firestore /generalCourts/192/membersFinance docs exist
  • Confirm finance tab populates on website:
    http://localhost:3000/legislators/192/AMS2#finance
  • Test the fail-fast guard:
    Run yarn firebase-admin run-script backfillOcpfFinance --env local --courts=999
    Confirm output shows: Court 999 failed: Error: No general court entry for court 999. Nothing written.
    Confirm court 999 is not written into Firestore
  • Test multi-court:
    Run yarn firebase-admin run-script backfillOcpfFinance --env local --courts=192,193
    Confirm both courts run and the succeeded/failed summary lists both.
  • Test bad input:
    Run yarn firebase-admin run-script backfillOcpfFinance --env local --courts=192,193,abc
    Confirm that for non numeric, whole set fails with: --courts (item 3): Expected number, received nan
    Run yarn firebase-admin run-script backfillOcpfFinance --env local --courts=192,193,999
    Confirm that for one bad court, rest will run, output includes a summary of which succeeded and which failed
  1. Test that we see a warning for an unknown OCPF record type
    *Run yarn firebase-admin run-script backfillOcpfFinance --env local --courts=192
  • Confirm output includes: Warning logged: Unclassified OCPF record type — no amount counted; classify it in accumulateItem
    Note: This proves the defensive logging is working.
    Later, when we want to perfect the data, we need to look into these types and classify them in REPORT_TYPE_HANDLING/KNOWN_IGNORED_RECORD_TYPE_IDS.

J-C-L and others added 15 commits October 27, 2026 14:50
Report types already logged a warning when unrecognized, defaulting to
a safe itemsOnly treatment. Record types fell through to a silent
default with no distinction between deliberately-ignored codes (205,
220) and a genuinely new one — this makes that failure mode loud too.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Pulls the matching logic out of the matchOcpfMembers HTTP handler into
a reusable, court-parameterized function so the upcoming backfill
script can match historical courts too. Active-filers-only filtering
now applies only to the current court; historical courts drop it
since a legislator who served years ago has likely closed their OCPF
committee by now.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Extracts runOcpfFinanceScrape into scrapeFinanceForCourt(court, options),
deriving YEARS per-call from generalCourts instead of a module-level
constant tied to the current court. Adds generalCourts entries for
189-191 so historical courts can be targeted. The two existing
triggers are unaffected — both still just call
scrapeFinanceForCourt(currentGeneralCourt, ...).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…SON summary

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

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…mpty mapping docs

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…in the finance backfill

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

vercel Bot commented Oct 27, 2026 •

Copy link
Copy Markdown

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

Project Deployment Actions Updated
maple-dev Ready Ready Preview Oct 27, 2026 9:40pm UTC

Request Review

This branch was successfully deployed

1 active deployment
Preview – maple-dev — 6777f1bc Deployed Oct 27, 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