# Changelog of FINRA BrokerCheck Scraper (`devilscrapes/finra-brokercheck-scraper`) Actor

- **URL**: https://apify.com/devilscrapes/finra-brokercheck-scraper/changelog.md
- **Full Actor documentation**: https://apify.com/devilscrapes/finra-brokercheck-scraper.md

## Changelog — finra-brokercheck-scraper

### 0.1 — SHELVED-gate fix pass

- **Bare `useApifyProxy` fixed.** `proxyConfiguration` (default + prefill in
  `.actor/input_schema.json`, default in `src/models.py`, and the QA fixture)
  now names `apifyProxyGroups: ["BUYPROXIES94952"]` and pins
  `apifyProxyCountry: "US"` instead of a bare `{"useApifyProxy": true}`,
  which silently resolves to a random-country DATACENTER exit
  (`reference-bare-useapifyproxy-is-datacenter`).
- **A whole-run zero-row outcome now SUCCEEDS, loudly.** When every query
  answered (`http_ok > 0`) but no broker matched, `RunStats.matched_nothing()`
  is true and `main.py` sets an explicit status message telling the customer to
  check the CRD or the spelling. It deliberately does NOT call `Actor.fail()`:
  FINRA answered correctly, so failing would bill `actor-start` and then hand
  the customer a FAILED run for valid input — and every such run would land in
  `publicActorRunStats30Days` as our failure, the pattern that got vrbo
  delisted. Our own "a SUCCEEDED run with 0 rows scores 100% on every
  dashboard" problem is real but is a MONITORING problem, caught by deep runs
  and the field-fill audit, not by failing a customer's legitimate query.
  `TransportFailureError`/REQ-7 still fails loud when NOTHING answered, which
  is the genuine fault case. `main.py` catches the shared `RunFailureError`
  base.
- **The 0-row shipped-prefill defect investigated, not reproduced.** The
  2026-09-19 finding (`docs/specs/finra-brokercheck-scraper/notes.md`)
  claimed run `dTWAgCsoPf6DgFkP0` (the Actor's own prefill) SUCCEEDED with 0
  rows. Pulling that run's own record from `/v2/actor-runs/{id}` shows
  `statusMessage: "... emitted 6 row(s)."`, `chargedEventCounts.result-emitted:
  6`, and a 6-item dataset — it does not match the finding. A fresh local
  `apify run` against the live FINRA endpoint with the exact shipped prefill
  also returns 6 rows today. No code change reproduces or explains a 0-row
  outcome for this input; see notes.md for the full writeup.
- Added regression tests: `test_shipped_prefill_produces_rows_regression`
  (drives the actual `.actor/input_schema.json` prefill end-to-end against
  recorded fixtures) and `test_zero_hits_across_whole_run_raises_zero_rows_error`
  / `test_one_success_prevents_transport_failure_but_zero_rows_still_raises`
  (assert the new guard fires, and only the new guard — not REQ-7 — for a
  mixed transport-fail + genuine-zero-match run).
- Fixed a handful of pre-existing `pyright` `reportOptionalMemberAccess` /
  `reportArgumentType` findings in `tests/test_client.py` and
  `tests/test_parser.py` (missing `is not None` narrowing) so `pyright` is
  clean — unrelated to the three SHELVED defects but blocking the gate.

### 0.0 — Scaffold

- Actor skeleton created (`actor-scaffolder`): `.actor/` config
  (actor.json, input\_schema.json, dataset\_schema.json,
  output\_schema.json, pay\_per\_event.json, Dockerfile), `src/` entry
  points (`__init__.py`, `__main__.py`, `main.py`), README skeleton,
  and a boot-only placeholder dataset row.
- Real FINRA BrokerCheck search/detail dispatch, disclosure merging,
  and dataset mapping are **not implemented yet** — see
  `docs/specs/finra-brokercheck-scraper/` for the spec/design/tasks
  driving the remaining T02-T13 work (`models.py`, `client.py`,
  `parser.py`, `scraper.py`, the real `main.py` wiring, and the
  README/icon finalization).
