megadonors.org

Methodology

This page is generated from config/pipeline.json — the same file the pipeline reads when it computes the numbers. It cannot describe a method the build is not running, because the build fails if the two disagree.

Pro-rata attribution, frozen at the expenditure date

For an independent expenditure made by a committee on a given date:

numerator Sum of the donor's itemized contributions to the committee with date on or before the expenditure date.
denominator Sum of ALL itemized receipts of that committee with date on or before the expenditure date.
ratio numerator ÷ denominator (0.0 where the denominator is zero)
attributed ratio x expenditure amount

The ratio is frozen at the expenditure_date, stored on the row, and never recomputed. Where that date is missing, the dissemination_date is used.

Support and oppose

Support and oppose are carried separately end to end and are never summed at candidate level.

A combined figure would describe a candidate as the object of a single quantity of spending, which misstates what the filings say. Summing is legitimate only at donor level, because there it describes the donor.

The published candidate schema contains no field whose name includes 'total' or 'net'. validate.py asserts this.

Duplicate filings

Schedule E rows where most_recent is false are excluded before attribution.

Independent expenditures reported on a 24- or 48-hour notice are re-reported on the committee's periodic report, and amended filings restate rows that were already filed. Counting every returned row would double-count the same spending. The excluded rows stay in data/raw/ and their count is published on each donor's figures.

This removes duplicate records of one expenditure. It never alters, nets, or reconciles the amounts themselves.

Memo rows

Schedule A rows carrying a memo code are excluded from both the numerator and the denominator.

A memo row itemizes money already counted by another row — an earmarked or bundled contribution broken out for disclosure. The FEC excludes them from a committee's receipt total for exactly this reason. Counting them inflates the denominator, which shrinks every ratio and understates the donor.

The same filter runs on the donor's own contributions. A row filed twice would otherwise inflate the numerator instead.

Itemized receipts are a subset of total receipts, so the itemized share cannot exceed 1. Counting memo rows produced 1.0325 for one committee. That assertion now gates the build.

Naming candidates

Expenditures are rolled up by candidate_id where the filing carries one, and by normalized candidate name where it does not.

The FEC returns Schedule E rows naming a candidate but carrying a null candidate_id, typically for candidates without a registered committee at the time of filing. Keying on candidate_id alone would drop that spending from the published tables without any visible trace.

validate.py asserts that every attributed dollar in the expenditure rows appears in the candidate rollup.

What these numbers are wrong about

Ratios are biased upward

The denominator counts itemized receipts only. Contributions under $200 are not itemized, so the denominator is understated and every ratio is therefore overstated. The gap is measured per committee as receipt_coverage, comparing itemized receipts against the committee totals endpoint. It is disclosed, never corrected.

501(c)(4) spending is structurally invisible

Money routed through a 501(c)(4) is not disclosed to the FEC at donor level and cannot appear here at all. Nothing on this site should be read as a complete account of a donor's political spending. The unattributed share of expenditures is published as a headline figure on every donor page.

Most committee spending is not attributed to any one donor

A donor is attributed the share of a committee's spending that their contributions funded. The remainder was funded by other contributors and is reported as not attributed, not as unknown.

No model writes a figure

No language model writes, edits, or repairs a published figure. Code, parsers, configuration and presentation are fair game. Output is not. If a number is wrong the bug is in the pipeline; the pipeline gets fixed and recomputes.

The only claim this site makes is that you can run the script yourself and get these numbers. An agent with write access to output makes that claim false in a way no reader could detect.

Which jurisdictions are included

A state is admitted only if it meets all four conditions. Every state checked is published in the coverage table with the condition it failed and the date checked.

  1. Itemized contributions to the committee are disclosed.
  2. Itemized independent expenditures name the target candidate with a support or oppose indicator.
  3. Data is available in bulk or via an API, not only through a paginated search form.
  4. Dates are precise enough to stamp the ratio at the expenditure date.

Every jurisdiction checked, and what it failed.

Assertions that gate the build

These run on every build. Any failure stops the deploy, leaving the previously published site in place rather than replacing it with numbers that did not pass.