@@ -79,9 +79,84 @@ export const AD_PROMO_REFERRAL_PROGRAM = 'placements_launch_2026'
7979 */
8080export const AD_PLACEMENT_COLLECTION_RETENTION_DAYS = 180
8181
82+ /**
83+ * Advertiser trust score / derived credit line (COD-268).
84+ *
85+ * The line is expressed as DAYS OF OBSERVED BURN, not as a raw multiple of a
86+ * 30-day total. Collection is nightly (plus a $100 threshold sweep), so the
87+ * only question the line has to answer is "how many days of this advertiser's
88+ * spend are we willing to have outstanding between sweeps". Three days covers
89+ * a weekend plus one failed retry; ten days is the most we extend to anybody
90+ * on payment history alone, and it is still an order of magnitude under the
91+ * global ceiling for a large spender.
92+ */
93+ export const AD_CREDIT_LINE_WINDOW_DAYS = 30
94+ export const AD_CREDIT_LINE_MIN_DAYS = 3
95+ export const AD_CREDIT_LINE_MAX_DAYS = 10
96+
97+ /**
98+ * The absolute per-advertiser cap on a DERIVED line. An operator may hand-set
99+ * a higher floor; nothing computed here may exceed this on its own.
100+ */
101+ export const AD_CREDIT_LINE_CEILING_CENTS = 500_000
102+
103+ /** No growth at all before the account has this much settled history. */
104+ export const AD_CREDIT_LINE_MIN_ACCOUNT_AGE_DAYS = 14
105+ export const AD_CREDIT_LINE_MIN_SUCCESSFUL_COLLECTIONS = 3
106+
107+ /**
108+ * Per-run move limits. Growth may at most double the live line (or add one
109+ * default line, whichever is larger, so a $0 line is not permanently stuck at
110+ * zero); a decrease may take at most 25% in one run, matching the repricer's
111+ * clamp. The dispute cut is deliberately EXEMPT from the decrease clamp.
112+ */
113+ export const AD_CREDIT_LINE_MAX_GROWTH_BPS = 10_000
114+ export const AD_CREDIT_LINE_MIN_GROWTH_STEP_CENTS =
115+ AD_POSTPAID_DEFAULT_CREDIT_LINE_CENTS
116+ export const AD_CREDIT_LINE_MAX_DECREASE_BPS = 2_500
117+
82118/** Direct placements never sell below one dollar per billable click. */
83119export const AD_PLACEMENT_CPC_FLOOR_CENTS = 100
84120
121+ /**
122+ * An operator-set floor exemption for ONE campaign
123+ * (`ad_placement_campaign.cpc_floor_override_cents`). It may only lower the
124+ * rate-card floor, and never to zero -- a zero price looks like a working
125+ * integration while billing nothing.
126+ */
127+ export function isValidPlacementCpcFloorOverride (
128+ value : unknown ,
129+ ) : value is number {
130+ return (
131+ Number . isInteger ( value ) &&
132+ ( value as number ) >= 1 &&
133+ ( value as number ) <= AD_PLACEMENT_CPC_FLOOR_CENTS
134+ )
135+ }
136+
137+ /**
138+ * The floor that actually binds a campaign.
139+ *
140+ * Anything other than a valid exemption resolves to the global floor, so an
141+ * out-of-range or malformed value fails SAFE (it raises the floor back to $1)
142+ * rather than opening it.
143+ *
144+ * This lives beside the constant, and not next to any one of its callers,
145+ * because four separate layers have to agree on it -- the admission
146+ * validators, the `/r/` click-recording guard, the reprice clamp, and the
147+ * table CHECK. Two of those are in `packages/internal` and two in
148+ * `freebuff/web`, and a second copy of this predicate is exactly how the
149+ * price a campaign serves at drifts from the price an automatic run will
150+ * clamp it to.
151+ */
152+ export function effectivePlacementCpcFloorCents (
153+ overrideCents : unknown ,
154+ ) : number {
155+ return isValidPlacementCpcFloorOverride ( overrideCents )
156+ ? overrideCents
157+ : AD_PLACEMENT_CPC_FLOOR_CENTS
158+ }
159+
85160/** A single automatic reprice may move at most 25% in either direction. */
86161export const AD_PLACEMENT_CPC_REPRICE_MAX_MOVE_BPS = 2_500
87162
0 commit comments