@@ -50,6 +50,11 @@ export const ADS_FIRST_PARTY_IMPRESSION_RECORDED_EVENT =
5050 * opaque click/event identifiers never leave the request handler. */
5151export const ADS_EXTERNAL_CONVERSION_POSTBACK_EVENT =
5252 'ads.external_conversion_postback' as const
53+ /** Browser-side Imprezia decisions. The route deliberately reports only
54+ * bounded serving dimensions: request/content/creative identifiers, URLs, and
55+ * raw provider errors never enter this event. */
56+ export const ADS_IMPREZIA_FETCH_COMPLETED_EVENT =
57+ 'ads.imprezia_fetch_completed' as const
5358
5459type AxiomOnlyFieldType = 'string' | 'number' | 'boolean'
5560type AxiomOnlyFieldSchema = Record < string , AxiomOnlyFieldType >
@@ -164,6 +169,90 @@ const ADS_FETCH_COMPLETED_FIELDS = {
164169 yield_live_evidence_status : 'string' ,
165170} as const satisfies AxiomOnlyFieldSchema
166171
172+ const ADS_IMPREZIA_FETCH_COMPLETED_FIELDS = {
173+ outcome : 'string' ,
174+ selection_reason : 'string' ,
175+ experiment_arm : 'string' ,
176+ surface : 'string' ,
177+ ad_count : 'number' ,
178+ duration_ms : 'number' ,
179+ test_mode : 'boolean' ,
180+ failure_class : 'string' ,
181+ } as const satisfies AxiomOnlyFieldSchema
182+
183+ const ADS_IMPREZIA_FETCH_OUTCOMES = [
184+ 'fill' ,
185+ 'no_fill' ,
186+ 'timeout' ,
187+ 'provider_error' ,
188+ 'not_configured' ,
189+ 'not_eligible' ,
190+ ] as const
191+ const ADS_IMPREZIA_SELECTION_REASONS = [ 'primary' , 'fallback' ] as const
192+ const ADS_IMPREZIA_EXPERIMENT_ARMS = [
193+ 'imprezia_forced' ,
194+ 'imprezia_first' ,
195+ 'control' ,
196+ ] as const
197+ const ADS_IMPREZIA_BROWSER_SURFACES = [
198+ 'freebuff_web_chat' ,
199+ 'chat_assistant' ,
200+ ] as const
201+ const ADS_IMPREZIA_FAILURE_CLASSES = [
202+ 'missing_api_key' ,
203+ 'missing_user_agent' ,
204+ 'invalid_source_url' ,
205+ 'provider_timeout' ,
206+ 'provider_failure' ,
207+ 'client_exception' ,
208+ ] as const
209+ const ADS_IMPREZIA_MAX_DURATION_MS = 60_000
210+
211+ function sanitizeImpreziaFetchCompletedFields (
212+ record : Record < string , unknown > ,
213+ ) : AxiomOnlyLogEvent [ 'data' ] | null {
214+ const data = sanitizeAllowlistedFields (
215+ record ,
216+ ADS_IMPREZIA_FETCH_COMPLETED_FIELDS ,
217+ )
218+ const outcome = data . outcome
219+ const selectionReason = data . selection_reason
220+ const experimentArm = data . experiment_arm
221+ const surface = data . surface
222+ const adCount = data . ad_count
223+ const durationMs = data . duration_ms
224+ const testMode = data . test_mode
225+ const failureClass = data . failure_class
226+
227+ if (
228+ ! ADS_IMPREZIA_FETCH_OUTCOMES . includes (
229+ outcome as ( typeof ADS_IMPREZIA_FETCH_OUTCOMES ) [ number ] ,
230+ ) ||
231+ ! ADS_IMPREZIA_SELECTION_REASONS . includes (
232+ selectionReason as ( typeof ADS_IMPREZIA_SELECTION_REASONS ) [ number ] ,
233+ ) ||
234+ ! ADS_IMPREZIA_EXPERIMENT_ARMS . includes (
235+ experimentArm as ( typeof ADS_IMPREZIA_EXPERIMENT_ARMS ) [ number ] ,
236+ ) ||
237+ ! ADS_IMPREZIA_BROWSER_SURFACES . includes (
238+ surface as ( typeof ADS_IMPREZIA_BROWSER_SURFACES ) [ number ] ,
239+ ) ||
240+ ( adCount !== 0 && adCount !== 1 ) ||
241+ ( outcome === 'fill' ? adCount !== 1 : adCount !== 0 ) ||
242+ typeof durationMs !== 'number' ||
243+ durationMs < 0 ||
244+ durationMs > ADS_IMPREZIA_MAX_DURATION_MS ||
245+ typeof testMode !== 'boolean' ||
246+ ( failureClass !== undefined &&
247+ ! ADS_IMPREZIA_FAILURE_CLASSES . includes (
248+ failureClass as ( typeof ADS_IMPREZIA_FAILURE_CLASSES ) [ number ] ,
249+ ) )
250+ ) {
251+ return null
252+ }
253+ return data
254+ }
255+
167256/**
168257 * First-party inventory selection is operational telemetry only. In
169258 * particular, campaign/creative/placement arrays and user/session IDs stay
@@ -314,6 +403,7 @@ export type AxiomOnlyLogEvent = {
314403 | typeof ADS_FIRST_PARTY_CLICK_RECORDED_EVENT
315404 | typeof ADS_FIRST_PARTY_IMPRESSION_RECORDED_EVENT
316405 | typeof ADS_EXTERNAL_CONVERSION_POSTBACK_EVENT
406+ | typeof ADS_IMPREZIA_FETCH_COMPLETED_EVENT
317407 data : Record < string , string | number | boolean >
318408}
319409
@@ -378,6 +468,10 @@ export function getAxiomOnlyLogEvent(
378468 data : sanitizeAllowlistedFields ( record , ADS_FETCH_COMPLETED_FIELDS ) ,
379469 }
380470 }
471+ if ( eventName === ADS_IMPREZIA_FETCH_COMPLETED_EVENT ) {
472+ const data = sanitizeImpreziaFetchCompletedFields ( record )
473+ return data ? { event : eventName , data } : null
474+ }
381475 if ( eventName === ADS_FIRST_PARTY_DECISION_EVENT ) {
382476 return {
383477 event : eventName ,
0 commit comments