Foundation Ads

  • Area: Foundation
  • Path: foundation/ads
  • Kind: Ad serving + monetization (RFC-001)

Role in the stack

koder-ads is the monetization engine for products/horizontal/play/engine (Koder Play). It runs decide() per ad slot — match user/slot features against the line-item inventory, rank by bid × CTR × pacing × brand_safety, return the winner. Plus revenue ledger, super chat, memberships.

Deployed as koder-ads-server (axum, default 0.0.0.0:7900); RUST_LOG controls tracing; /metrics exposed for Prometheus.

Substrate

  • Inventory: campaign → line_item → creative, in-memory v0.1; production swap to data/kdb kdb-record.
  • CTR predictor (ADS-): CtrPredictor trait. v0.1 ships ConstantCtr (= v0 default 0.03) and LogisticCtr (8-feature in-process logistic regression with online SGD). Production points at ai/runtime via HTTP adapter.
  • Pacing (ADS-): pacing_factor() for EvenFrontLoadedAsap. Returns multiplier in [0, 2] per line item; wired into decide_with_predictor().
  • Revenue ledger: RevenueLedger records impressions per PricingModel { Cpm, Cpv, Cpc } and tracks per-creator share (default 55% creator).

Key features

  • [x] Decision engine with targeting + brand-safety + flight check.
  • [x] Pluggable CTR predictor (constant + logistic) (ADS-).
  • [x] Pacing factor — Even / FrontLoaded / Asap (ADS-).
  • [x] Revenue ledger with creator-share split.
  • [x] Super chat + tiered memberships.
  • [x] SCTE-35 ad-cue insertion (DASH MPD + HLS).
  • [x] HTTP API + Prometheus + tracing.
  • [x] Bench harness with SLO baseline (ADS-).
  • [x] FrequencyCap enforcement — per-(user, line_item, day) counter (ADS-).
  • [x] record_with_campaign + spent_for_campaign — pacing reads campaign spend O(1) (ADS-).
  • [x] Per-tenant rate limit on /v1/decide (ADS-).
  • [x] Input validation on impression events (ADS-).
  • [x] Pacing-factor histogram + inventory-size gauge + freq-cap drops counter (ADS-, ADS-).
  • [x] #[instrument] on decide_with_predictor (ADS-).
  • [x] AdsModerationGate trait — drop slots from blocked channels (ADS-).
  • [x] AdsEventSink trait — AuctionWon / NoFill / Impression / BalancePayout events (ADS-).

SLO targets

  • p99 decide()100 ms at 10k line items.
  • CTR prediction inference ≤ 5 ms.
  • Brier ≤ 0.05 on holdout (calibration).

Bench numbers: decide @ 10k = 6.7 ms (15× under SLO); LogisticCtr inference = 26 ns; pacing_factor = 6 ns; revenue.record = 190 ns. See services/foundation/ads/bench/baseline.json.

Interfaces

  • HTTP: POST /v1/decide, POST /v1/impressions, GET /v1/balances/{creator}, POST /v1/superchat, POST /v1/memberships, GET /healthz, GET /metrics.
  • Library: koder_ads::{decide, decide_with_predictor, ConstantCtr, LogisticCtr, pacing_factor, RevenueLedger, SuperChat, MembershipStore}.