# Changelog of SEC Form D Scraper — Capital-Raise Leads (`devilscrapes/sec-form-d-leads`) Actor

- **URL**: https://apify.com/devilscrapes/sec-form-d-leads/changelog.md
- **Full Actor documentation**: https://apify.com/devilscrapes/sec-form-d-leads.md

## Changelog

All notable changes to this Actor will be documented in this file.

### \[0.2.0] — 2026-09-22

#### Fixed

- Fixed a fleet-health regression: 30-day customer success rate was 83%
  (5/30 runs FAILED, 3 paying users), on a build that had been live for 27
  of those 30 days. Root cause — `main()` raised `SystemExit(1)` whenever
  the total emitted row count was zero, with no distinction between "the
  EDGAR search completed and genuinely matched nothing" (a customer's
  `query` / `stateFilter` / `minOfferingAmountUsd` combo can legitimately
  match zero Form D filings) and "we never got a real answer." A
  legitimate zero-match search must SUCCEED with zero rows (see
  `ops/os/EMPTY-IS-NOT-A-FAILURE-2026-08-19.md`) — the customer was
  already charged `actor-start` and then told the run FAILED for doing
  exactly what was asked.
- `_run` now returns `RunOutcome(total, any_completed)`. Transport
  failures during EFTS pagination already raised uncaught before this fix
  and still do — `any_completed` only goes `False` in the narrower case
  where real filings were found (`hits_seen > 0`), at least one fetch was
  attempted (`fetch_attempted > 0` — not all amendment-skipped), and
  *every* XML fetch/parse failed (`fetch_failed == fetch_attempted`). Any
  other zero-row outcome (no EFTS hits, all hits excluded by
  `includeAmendments=false`, or hits that fetched fine but were rejected
  by `stateFilter` / `minOfferingAmountUsd`) now finishes SUCCEEDED with a
  status message naming the filters applied.
- Reproduced locally: a narrow `query` + 1-day date window that returns
  zero EFTS hits FAILED (exit 1) before the fix; after the fix it exits 0
  with "No rows emitted — ... produced zero qualifying filings." The
  broad QA fixture (`tests/fixtures/input.qa.json`) still delivers 3 real
  rows unchanged — one row (Auxilium Health, Inc., CIK 0002135544,
  accession 0002135544-26-000002) was spot-checked field-for-field against
  the live `primary_doc.xml` on sec.gov.
- New `tests/test_main.py` — 7 regression tests covering the ambiguous-zero
  distinction (zero EFTS hits, all-amendment hits, post-filter rejection,
  and every-fetch-failure) plus the `main()` success/fail-loud dispatch.
  55 tests green (was 48).

### \[0.1.0] — 2026-05-16

#### Added

- Initial release: SEC EDGAR Form D (Regulation D capital-raise) → structured B2B leads.
- EDGAR Full-Text Search pagination over `forms=D` with `startdt` / `enddt` date range
  and optional free-text `query` filter.
- `primary_doc.xml` deep-fetch per filing — extracts 27 structured fields plus a
  nested list of officers/directors/promoters with names and locations.
- Pydantic v2 `ActorInput` model with default 30-day date window, ISO date
  validation, and `start_date <= end_date` enforcement.
- Pydantic v2 `ResultRow` + nested `RelatedPerson` models — single source of truth
  for `input_schema.json` and `dataset_schema.json`.
- Post-filters: `state_filter` (issuer state) and `min_offering_amount_usd`;
  applied before the per-row PPE charge so users pay only for kept rows.
- Amendment toggle: `include_amendments=false` (default) skips Form D/A entries
  before the XML fetch — saves bandwidth and rate-limit budget.
- XML schema quirks handled: `"Indefinite"` literal offering amounts, `overFiveYears`
  vs `withinFiveYears` year-of-incorporation fork, `yetToOccur` first-sale fork,
  raw `"0"` minimum investment → null.
- EDGAR Fair Access Policy compliance: mandatory User-Agent header on every request;
  0.1 s inter-XML-fetch sleep to stay under 10 req/s/IP.
- Exponential backoff with `Retry-After` for `429` / `503` responses; max 5 attempts.
- Two PPE events: `actor-start` ($0.05), `result-row` ($0.005).
- `curl-cffi` with Chrome 131 TLS impersonation (ADR-0002 house default).
- Apify Proxy support via `BUYPROXIES94952` group (opt-in via `useProxy`).
- 40+ unit tests covering models, parser, client, and the no-`idempotency_key`
  regression for `Actor.charge`.
