Change-detection over the FDA approval and clearance stream: new drug approvals (Drugs@FDA), device 510(k) clearances and PMA approvals, unified into one normalized approval record (regulator, applicant, product, date, pathway). Filter by applicant, endpoint or date. Keyless, CC0.
README — dropped the scaffold-era "in progress / landing incrementally" status block for a
launch-ready (v0.1), unpublished note; resolved the two forward-pointers (COMPLIANCE.md and
docs/PRICING.md now exist and are linked, not "lands in a later slice"); retitled the maintenance
section (no longer "carried into slice 2"). No product-surface change — inputs/outputs/pricing model
are as built in slices 1–3.
docs/PRICING.md — pricing model + reasoning, mirroring openfda-enforcement/docs/PRICING.md:
single PPE event approval-returned charged once per approval pushed; _noData/_error never
charged; rejected alternatives (per-run flat, per-endpoint tiers, per-CU); price-band framing with
the actual $/eventDEFERRED to owner (working target ≈ $0.001/record noted, not set). No live
price, no pricingInfos — publish/monetization gate untouched.
docs/LISTING.md — Store-listing draft mirroring openfda-enforcement/docs/LISTING.md, adapted
to the cross-silo approvals product (title/short+full description, tags, SEO keywords, example input,
publish-asset checklist, and the standing "don't surface churn caveats in customer copy" note).
No source touched; offline.node --test green (59 pass, 0 fail); node --check src/*.js clean.
0.1 — 2026-07-10 — slices 4–5: offline test suite + COMPLIANCE.md
slice 4 — test/ offline suite (59 node:test cases): drives the full pure pipeline over
drug/510k/pma fixtures with an injected fetchImpl (no network) — normalize/merge, date-window
trim, applicant + product-code filters, seen-set new-only, projection, max-results cap, retry/backoff
and the 25k-skip truncation ceiling.
slice 5 — COMPLIANCE.md: CC0 1.0 PERMITTED verdict (evidence 2026-07-10) mirroring
openfda-enforcement/COMPLIANCE.md, adapted to the three approval endpoints; adds the two-date-
semantics table (drug compact YYYYMMDD vs device ISO decision_date) and a no-endorsement section.
0.1 — 2026-07-10 — slice 3: filters.js + main.js
filters.js — implemented the pure, order-preserving, null-tolerant filter layer:
dedupeById (collapse duplicate approvalId, keep first; id-less kept as-is), filterByDateWindow
(trim records whose surfaced approvalDate predates/exceeds the window — drops stale drug approvals
the coarse server-side AP filter lets through; device records already in-window; null dates kept),
filterByApplicant (case-insensitive substring competitor-watch — the headline filter),
filterByProductCode (device-only 3-letter product-code narrowing; drug approvals pass through per
input_schema), filterNewOnly, applyFieldProjection (narrow to requested keys, always preserving
endpoint + isNew), applyMaxResults (0 = uncapped).
Design change vs the slice-1 stub:filterNewOnly now takes a seen-set of approvalIds
(KV SEEN), not a per-endpoint date high-water-mark. Approvals are terminal events with stable
unique ids; a seen-set can't miss two approvals sharing the same max date across consecutive runs
(a boundary bug the date-HWM had) and matches the shipped openfda-enforcement watermark for fleet
consistency. No change-detection pass (approvals don't mutate like recalls).
main.js — Actor entry wiring the API + filter layers: read input → select endpoints (default
all 3) → resolve a bounded date window (trailing 30-day default — wider than enforcement's 7 since
approvals are lower-frequency; approvedSince ignored under monitorNewOnly) → per-endpoint
fetchAllApprovals → normalizeApprovals → merge → dedupe → applicant/product-code filters →
filterNewOnly (only under monitorNewOnly) → projection → cap → push one item/approval, charging
one approval-returned PPE event each, attaching attribution (DISCLAIMER) + isNew + fetchedAt.
_noData/_error control records are pushed but never charged; SEEN is persisted only after a
pass that was neither charge-limited nor maxResults-truncated (so undelivered ids re-fetch).
Verified offline (no network):node --check clean on all src/*.js; a mocked-fetchImpl
smoke harness driving the full pipeline over drug/510k/pma fixtures — merge→normalize (4 unified
approvals), date-window trim of an out-of-window drug approval, applicant substring, device-only
product-code, dedupe, seen-set new-only (2nd run → 0), maxResults cap+truncation flag, and
projection — all green (temp harness cleaned, not committed).
Filled every openfda.js stub: toCompactDate/parseOpenFdaDate (dual-format — compact
YYYYMMDD drug dates + ISO decision_date), derivePathway (NDA/ANDA/BLA from
application_number prefix; 510k/PMA per endpoint), buildApprovalUrl (drug adds
submissions.submission_status:AP, sort=<date>:desc, limit≤1000 / skip≤25000, optional
api_key), fetchJson (courtesy UA, retry/backoff on 5xx/429, injectable fetchImpl/sleep;
404 non-retryable), isNoMatchesError (zero-match 404 → no-data green), fetchAllApprovals
(skip-paging under the 25k ceiling, honors maxResults), normalizeApprovals (3 schemas → one
flat approval w/ endpoint-appropriate approvalId + unified pathway).
Verified offline:node --check + mocked-fetchImpl smoke green across all 3 endpoints.
0.1 — 2026-07-10 — slice 1: scaffold
Scaffolded from the shipped openfda-enforcement / sec-edgar-monitor reference implementations
(structure, patterns, PPE model). Actor #6 of the offline BUILD_QUEUE.md (§6 openFDA Approvals).
Same API base as the shipped §2 openFDA Enforcement Actor (api.fda.gov); distinct product = the
approval/clearance stream, not recalls.
Fetch-based Apify Actor (no browser): apify@^3.2.6 only, apify/actor-node:20 base, 256–512 MB.
main.js (Actor entry, approval-returned PPE — impl slice 3).
Cross-silo normalization is the moat: three endpoints with two date semantics and three dedupe
keys (k_number / pma_number+supplement_number / application_number+submission) fold into one
comparable approval record with a unified pathway (NDA/ANDA/BLA/510k/PMA).
License: openFDA is CC0 1.0 Universal public domain — copy/modify/redistribute commercially
without permission; no key or attribution required. A courtesy DISCLAIMER (no FDA endorsement;
not a substitute for the official Drugs@FDA / 510(k) / PMA registers) is emitted on every record.
robots.txt (api.fda.gov/robots.txt) is HTTP 404 — nothing disallowed. (Full compliance record in
COMPLIANCE.md, slice 5.)
README.md documents the intended product surface + output approval shape + the courtesy
disclaimer; CHANGELOG.md (this file).
Verified offline: all src/*.jsnode --check clean; .actor/*.json + package.json valid
JSON (no network).