@@ -3543,34 +3543,51 @@ def webhook(payload: WebhookPayload):
35433543 # ─────────────────────────────────────────────
35443544 try :
35453545 if getattr (settings , "WINRATE_UPGRADE_ENABLED" , False ) and getattr (settings , "REQUIRE_CONFIRMATION" , False ):
3546- # Build confirmation key: prefer explicit signal_id; fallback to hashed logging id + signal
3547- if payload .signal_id :
3548- conf_key = f"{ payload .signal_id } |{ sig_for_dedupe } "
3549- else :
3550- # signal_id_for_logging may be None here; use fallback hash if needed
3551- payload_hash = _hash_payload (payload .model_dump ())
3552- fallback_id = f"hash_{ payload_hash } "
3553- conf_key = f"{ fallback_id } |{ sig_for_dedupe } "
3546+ # Build a stable confirmation key using market/token + direction + signal_id
3547+ try :
3548+ now_ts = int (time .time ())
3549+ slot = current_slot_start (now_ts )
3550+ slug = slug_for_slot (slot )
3551+ try :
3552+ market = fetch_market_by_slug (slug )
3553+ except Exception :
3554+ market = None
3555+ up_token , down_token = resolve_up_down_tokens (market ) if market else (None , None )
3556+ token_or_market = up_token or slug or "unknown_market"
3557+ sig_id = payload .signal_id or signal_id_for_logging or "no-signal-id"
3558+ conf_key = f"{ token_or_market } :{ sig_for_dedupe } :{ sig_id } "
35543559
3555- confirmed , _ = _confirmation_store .pop_if_confirmed (
3556- conf_key ,
3557- delay = getattr (settings , "CONFIRMATION_DELAY_SECONDS" , 60 ),
3558- ttl = getattr (settings , "CONFIRMATION_TTL_SECONDS" , 180 ),
3559- )
3560- if not confirmed :
3561- # mark pending (idempotent)
3562- _confirmation_store .mark_pending (conf_key , {"first_seen" : time .time (), "request_id" : request_id })
3563- logger .info (f"[{ request_id } ] confirmation_pending: key={ conf_key } " )
3564- return {
3565- "ok" : True ,
3566- "status" : "pending_confirmation" ,
3567- "reason" : "confirmation_pending" ,
3568- "message" : "Signal stored, waiting for confirmation" ,
3569- "confirmation_key" : conf_key ,
3570- "mode" : get_trading_mode_str (),
3571- }
3572- else :
3573- logger .info (f"[{ request_id } ] confirmation_passed: key={ conf_key } " )
3560+ # Use new high-level handle API (returns pending/expired/confirmed)
3561+ result = _confirmation_store .handle (
3562+ conf_key ,
3563+ delay = getattr (settings , "CONFIRMATION_DELAY_SECONDS" , 60 ),
3564+ ttl = getattr (settings , "CONFIRMATION_TTL_SECONDS" , 180 ),
3565+ payload = {"first_seen" : time .time (), "request_id" : request_id },
3566+ )
3567+ status = result .get ("status" )
3568+ if status == "pending" :
3569+ logger .info (f"[{ request_id } ] confirmation_pending: key={ conf_key } delay={ getattr (settings , 'CONFIRMATION_DELAY_SECONDS' , 60 )} s ttl={ getattr (settings , 'CONFIRMATION_TTL_SECONDS' , 180 )} s" )
3570+ return {
3571+ "status" : "pending_confirmation" ,
3572+ "signal_id" : sig_id ,
3573+ "signal" : sig_for_dedupe ,
3574+ "key" : conf_key ,
3575+ "delay_seconds" : getattr (settings , "CONFIRMATION_DELAY_SECONDS" , 60 ),
3576+ "ttl_seconds" : getattr (settings , "CONFIRMATION_TTL_SECONDS" , 180 ),
3577+ }
3578+ if status == "expired" :
3579+ logger .info (f"[{ request_id } ] confirmation_expired: key={ conf_key } " )
3580+ return {
3581+ "status" : "pending_confirmation" ,
3582+ "signal_id" : sig_id ,
3583+ "signal" : sig_for_dedupe ,
3584+ "key" : conf_key ,
3585+ }
3586+ # confirmed -> continue pipeline
3587+ if status == "confirmed" :
3588+ logger .info (f"[{ request_id } ] confirmation_passed: key={ conf_key } " )
3589+ except Exception :
3590+ logger .exception (f"[{ request_id } ] confirmation_store error, continuing without confirmation" )
35743591 except Exception :
35753592 # Fail-safe: if confirmation store has issues, continue processing (do not block pipeline)
35763593 logger .exception (f"[{ request_id } ] confirmation_store error, continuing without confirmation" )
0 commit comments