# Money Map — Methodology

**Dataset:** `data/money/money-index.json`
**Build date:** 2026-10-01 · **Cycle covered:** 2023-01-01 → present · **Maintainer:** SiLobbyist data layer

This document describes exactly how the Money Map's campaign-finance figures were
produced, what each field means, and — critically — what the data cannot support.
It is written for a working lobbyist: trust the numbers only as far as this document says you can.

---

## 1. Sources

**Authoritative source:** Cal-Access, the California Secretary of State's campaign
finance and lobbying disclosure system. Every dollar in the Money Map originates
as a filed disclosure (Form 460/461/496/497 family — see §2).

**Access path used for this build:** the public record feed published by
**CalMatters Digital Democracy** (`calmatters.digitaldemocracy.org`), a nonprofit
newsroom database that ingests filed contribution records from the Secretary of
State. Per its published methodology, Digital Democracy pulls records directly
from the SOS and hand-categorizes contributors.

**Why not Cal-Access directly?** At build time (2026-10-01) both direct routes were
unavailable to automated collection:

- `cal-access.sos.ca.gov` (web search) sits behind Incapsula bot mitigation; the
  filing search returns a JavaScript challenge page to non-browser clients.
- The official bulk export (`https://campaignfinance.cdn.sos.ca.gov/dbwebexport.zip`,
  linked from `sos.ca.gov/campaign-lobbying/.../raw-data-campaign-finance-and-lobbying-activity`)
  returned empty `HTTP 200` responses (0 bytes) to automated requests; the documentation
  ZIP on the same host downloaded normally, confirming host-level filtering of the data file.

The Digital Democracy feed exposes the same underlying filed records
(donor name as filed, transaction date, amount, transaction type) and is itself a
public, inspectable source: every legislator entry below links to its source page.

**What this means for traceability:** each figure is traceable to
`(source_url, transaction date, donor name as filed)`. SOS **filing ID numbers**
are not exposed by this feed, so the `filings` array from the original schema is
**omitted by design** — documented in §8. No figure in this dataset is estimated,
rounded beyond cents, or invented.

---

## 2. Filing types behind the figures

California campaign disclosure, in brief (per the SOS Cal-Access table documentation
and FPPC filing schedules):

| Form | What it is | Money Map use |
|---|---|---|
| **Form 460** (Recipient Committee Campaign Statement) | The workhorse: filed by candidate and primarily-formed committees each semi-annual/quarterly/pre-election period. Schedules A (monetary contributions received), C (non-monetary), etc. | Primary source of per-legislator contribution records (`RCPT` table in Cal-Access) |
| **Form 461** (Independent Expenditure Committee & Major Donor Committee Statement) | Filed by committees making independent expenditures and by major donors | Feeds IE records |
| **Form 496** (24-hour Late Independent Expenditure Report) | Filed within 24 hours when an IE of $1,000+ is made in the 90 days before an election | IE spike detection (not separately broken out in this build) |
| **Form 497** (24-hour Late Contribution Report) | Filed within 24 hours for contributions of $1,000+ received in the 90 days before an election | Late-money detection (not separately broken out in this build) |
| **Form 803** (Behested Payment Report) | Filed by the *payor* (not the official) when payments are made at the behest of an elected official — e.g., to a charity or cause the official solicited | **Not in this dataset** — see §7 |

The feed collapses these into transaction types: `Candidate Donations`,
`Independent Expenditures`, `Party Committees`, `Gift`, `Sponsored Travel`.

---

## 3. Record fields (as received)

Each raw record carries:

- `giver.label` / `giver.specific_label` — donor/committee name **as filed**
  (`specific_label` preferred; it preserves the filer's exact text)
- `receiver.label` — the legislator the money is attributed to
- `amount` — dollars and cents, as filed
- `date` — transaction date (`YYYY-MM-DD`) as filed; **empty for IE records** in this feed
- `type` — one of the transaction types above
- `description` — schedule detail, e.g. `Itemized Monetary:`, `Unitemized Monetary:`,
  `Itemized Non-Monetary: <purpose>`

---

## 4. Aggregation and normalization rules

1. **Cycle filter.** Only records with `date >= 2023-01-01` enter legislator totals
   and donor rankings. Records with empty dates are excluded from cycle aggregates
   (this affects IE records in particular — see §7).
2. **"Total raised" definition.** `total_raised` = sum of `Candidate Donations`
   records with monetary descriptions (itemized + unitemized) in-cycle. Excludes
   loans, non-monetary/in-kind contributions, and committee transfers. This matches
   the colloquial "money raised" but is **not** the committee's cash-on-hand.
3. **Donor roll-up.** Contributions are grouped per legislator by **normalized**
   donor name: uppercased, accent-stripped, punctuation removed, common entity
   suffixes (`LLC`, `INC`, `CORP`, `PAC`, `ASSN`, …) stripped for comparison only
   (display always uses the filed name). Distinct dates are collected per
   donor→legislator pair into `filing_dates`.
4. **Unitemized contributions.** California committees report sub-$100 (per-election
   sub-threshold) contributions in aggregate. These buckets are **counted in
   `total_raised` but excluded from donor rankings** — they are not attributable
   donors, and ranking them would mislead.
5. **Top-donor cut.** Top 12 donors per legislator by in-cycle monetary total;
   top 200 donors overall by giving across all legislators in the dataset.
6. **No double counting across legislators.** A donor giving to 5 legislators
   appears once in `donors[]` with per-recipient breakdown; legislator entries
   each show their own slice.
7. **Amendments.** If a committee amends a filing, the feed may carry both the
   original and the amended record. Byte-identical duplicate feed records are
   collapsed to one (conservative deduplication); near-duplicates that differ
   in any field are kept, which can modestly inflate a donor's apparent total.
   Large figures should be verified in Cal-Access before a client sees them.
8. **Vacant seats.** Two seats were vacant at build time (AD-3, SD-10), so the
   dataset covers 118 seated legislators, not 120.

---

## 5. Donor-type labels (heuristic)

Each donor carries a `type` label — `labor`, `corporate`, `trade`, `pac`,
`individual`, `party`, `tribal`, `candidate`, or `other` — assigned by
**heuristic classification from the filed name** (keyword rules, e.g. union
locals → labor, "LLC"/"Inc" → corporate). These are **not official
designations** and are wrong often enough to matter: spot-check before citing,
and the Money Map UI marks every badge as heuristic. The brain never states a
donor's type as fact without that qualifier.

## 6. Lobbyist-client overlap (name-match heuristic)

Donors are flagged `lobbyist_client_overlap` when the normalized donor name
exactly matches a registered lobbyist client name in `data/lobbyists.json`
(1,190 client names). This is a **normalized name-match heuristic**: it catches
"BLUE SHIELD OF CALIFORNIA" → "Blue Shield of California" but misses
DBA/trade-name variants, and a match does **not** establish that the lobbyist
directed the contribution. Absence of a flag proves nothing. Never present a
flag as evidence of coordination, and never make unverified negative claims
about any donor or official.

## 7. What the feed does NOT contain (by design)

- **Independent expenditures:** 60 IE records are included, but the feed
  exposes **no transaction dates and no support/oppose stance** for them.
  Amounts and spenders are real filed figures, but they **cannot be
  cycle-attributed** here and must never be read as support vs. oppose.
  For stance and timing, pull the committee's Form 496/497 filings in
  Cal-Access directly.
- **Behested payments:** FPPC Form 803 data is **not in this feed** — the
  `behested` array is empty by design. Use the SOS/FPPC behested-payments
  search separately. (A separate SOS-sourced behested extract exists in
  `data/money/behested_raw.json` — 4,018 records, 2024–2026 — for a future
  merge; it is not yet wired into the index.)
- **Gifts and travel:** 50 records, cycle-filtered from 2023-01-01. These are
  **personal disclosures** (Form 700 family), not campaign support — the UI
  frames them as influence signal, never as contributions.
- **Filing ID numbers:** not exposed by the feed (see §1). Traceability is via
  `source_url` + transaction date, per legislator.

## 8. What the data cannot support

- Cash-on-hand or burn rate (totals are contributions received, not balances).
- Attribution of motive: a contribution is a filed fact; *why* it was given is
  not in this dataset.
- Cycle attribution for IE records (no dates in feed).
- Support/oppose reading of IE records (no stance in feed).
- Completeness for late-2026 filings: the feed was last updated ~May 2026;
  24-hour reports (Forms 496/497) near the general election lag. Rebuild
  before the election.
- Donor rankings below the top-200 statewide / top-12 per legislator cut
  (long-tail splits from name variants are possible — verify large figures).

## 9. Version history

- **2026-10-01 (v1, current):** CalMatters Digital Democracy feed build —
  118 seated legislators, $221.3M in-cycle filed monetary contributions
  (2023-01-01 → present), top-200 donors, 60 IE records, 50 gift/travel
  records. Raw feed snapshots preserved outside the repo's data tree.
- **2026-10-01 (superseded):** an SOS Power Search build covering 7 of 120
  legislators was produced during a partial SOS outage and then set aside —
  its per-legislator contribution data was too thin, though its complete IE
  (8,047 rows) and behested (4,018 records) extracts are preserved in
  `data/money/ie_raw.json` and `data/money/behested_raw.json` for a future
  merge. The Power Search methodology draft was not kept.
