Ads: autobid by default, paper-money auction, bid history - #253
Merged
Merged
Conversation
Every campaign on the network is self-deal, so serveAd demoted every fill to the free tier and the free tier weighted everything at 1: nobody bid, and the auction, pacing and charge path had never run end to end with real numbers. - `autobid` on ad_campaigns, default true for every row. A pure pacing controller (lib/ads/autobid.ts) recomputes each bid hourly from the worker: behind daily pace raises it, ahead lowers it, capped by what the daily budget covers, held when already well above the market. The bid field is gone from the create form; the edit form shows an Autobid switch and the current bid, with a typed bid only when the switch is off. - The free tier is a paper auction: the same bid-weighted lottery, weighted by the paper bid and gated by a paper daily budget. Every free-tier click records what it would have cost (ad_clicks.paper_cents, campaign paper counters) through a new ad_paper_charge RPC that refuses any billed click. No credit balance is ever debited; the paid tier is untouched. - ad_bids logs every decision with its signals. The campaign page charts bid against impressions, clicks and tracker-attributed visits, with the last decisions and their reasons underneath. GET /api/ads/v1/campaigns/[id] carries the same under stats.bid; PATCH takes `autobid`; a bare bid_credits turns autobid off. CLI: `crawlproof ads bid <ref> auto|<credits>`. Migration 20260913120000_ad_autobid.sql is applied to prod (ref ywcizjsgrcmhgyplldac) and every function was exercised in a rolled-back transaction. The worker seeds every campaign's first bid at boot. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PDJmt1CPi1fAkpD4FXRSHu
ThreatCrush Security Scan39 finding(s) HIGH/CRITICAL: 2 | MEDIUM: 28 | LOW: 9
Snippets are redacted; ThreatCrush never prints matched credential material. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Every campaign on crawlproof.com is self-deal, so every fill books free tier and the free tier weighted every campaign at 1. Nobody bid. This turns bidding on for all 314 campaigns with paper money, so the auction, the pacing and the charge path run end to end with real numbers and no real funds.
autobidcolumn, true for every existing and new campaign.lib/ads/autobid.tsis a pure pacing controller: behind daily pace raises the bid, ahead lowers it, capped so the budget buys at least five clicks, held when already twice the market median. The worker runs it hourly and at boot (runAutobidSweep), so every campaign has a seed bid within a minute of deploy.ad_paper_charge, which refuses any click that billed. Impressions record the winning bid. No credit balance is ever debited; the paid tier andad_charge_clickare untouched.ad_bidslogs every decision with the signals behind it. The campaign page gets a bid vs. clicks chart (impressions as bars, tracker-attributed visits when the destination runs the tracker) and a decision log. The API'sstats.bidcarries the same;crawlproof ads showprints it.PATCH { autobid }; a barebid_creditsturns autobid off.crawlproof ads bid <ref> auto|<credits>.Schema
supabase/migrations/20260913120000_ad_autobid.sqlis already applied to prod (ywcizjsgrcmhgyplldac). All columns are additive with defaults.ad_paper_charge,ad_autobid_activityandad_campaign_bid_historywere each exercised in a rolled-back transaction; the ledger is at zero.Checks
tsc --noEmitclean,vitest run174 files / 2279 tests green,next buildexit 0.tests/ads-autobid.test.ts(controller rules, paper weights, history carry-forward, sweep writes) andtests/ads-autobid-requests.test.ts.🤖 Generated with Claude Code
https://claude.ai/code/session_01PDJmt1CPi1fAkpD4FXRSHu