Initial build, per the Gate 1 approved plan (design doc 2026-08-17, revision 2 of 2026-08-18).
- One-step input: page URL / Ad Library URL / advertiser name; runs apify/facebook-ads-scraper
as a sub-run billed natively to the buyer, explicit resultsLimit always set, wait-capped with
partial-dataset handling. datasetId chaining (accepts run IDs) and direct mediaUrls kept.
- Meta ads dataset adapter: nested snapshot walk (videos, images, cards, extras), video-wins,
carousel first card as carousel-card, summary rows skipped, unclassifiable rows carry the
snapshot keys seen (shape-drift diagnosability), whitelisted sanitized metadata passthrough.
- Identity and dedupe on adArchiveID (signed URLs are unstable); duplicates analyzed once,
charged once, reference rows pushed.
- Image branch: hardened download with an image Accept header, magic-byte media_type sniffing
(WebP under jpg URLs is real), ffprobe dimension gate, reject-only oversizes.
- Ad taxonomy teardown (hook, offer framing, CTA placement, production style, on-screen text,
adScore, whyItWorks) with the inherited parse discipline: enums pinned, free text sanitized
and capped, measured fields never model-overwritten. vision-parse-failed records are NOT
charged.
- Synthesis brief: one text pass over capped excerpts, 5-creative / 30 percent evidence gate,
429 halve-and-retry, link-stripped outputs, charged only when produced, budget-reserved.
- Charging: four events (start $0.01, video $0.04, image $0.02, brief $0.15); joint row-order
admission gate from SDK headroom (no price literals) with an overflow tail re-admitted as
failures free budget; restart readback paginated to exhaustion and keyed on delivered
creative rows only; unpriced-actor degrade inherited.
- Keyless preview: fetches real ads, measures structure for 3, hard-clamps the upstream fetch,
charges nothing per creative, and the summary carries the exact paid-run upgrade input.
- Run summary row on every run: analyzed/failed/duplicate/unclassifiable counts, charge
counts, upstream run report, page confirmation for advertiserName guesses.
- Drift test extended 3-way at the repo root; download Accept header parameterized across all
three actors in one commit.