@@ -3537,6 +3537,43 @@ def webhook(payload: WebhookPayload):
35373537 }
35383538 else :
35393539 logger .info (f"[{ request_id } ] SIGNAL DEDUPE: signal_id={ signal_id } , signal={ sig_for_dedupe } - ACCEPTED" )
3540+ # ─────────────────────────────────────────────
3541+ # CONFIRMATION (Debounce) - run IMMEDIATELY AFTER dedupe acceptance,
3542+ # and BEFORE Session / MQ checks (ensures ordering: SIGNAL ACCEPTED -> confirmation -> Session Gate)
3543+ # ─────────────────────────────────────────────
3544+ try :
3545+ 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 } "
3554+
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 } " )
3574+ except Exception :
3575+ # Fail-safe: if confirmation store has issues, continue processing (do not block pipeline)
3576+ logger .exception (f"[{ request_id } ] confirmation_store error, continuing without confirmation" )
35403577 else :
35413578 logger .warning (f"[{ request_id } ] SIGNAL DEDUPE: signal_id={ signal_id } but invalid signal={ sig_for_dedupe } , skipping dedupe check" )
35423579 else :
@@ -3573,36 +3610,7 @@ def webhook(payload: WebhookPayload):
35733610 f"MODE: { mode } | KIND: { signal_kind } (TradingView signal tracking)"
35743611 )
35753612
3576- # ─────────────────────────────────────────────
3577- # CONFIRMATION (Debounce) - run BEFORE Session / MQ checks
3578- # ─────────────────────────────────────────────
3579- if getattr (settings , "WINRATE_UPGRADE_ENABLED" , False ) and getattr (settings , "REQUIRE_CONFIRMATION" , False ):
3580- # Build confirmation key: prefer explicit signal_id; fallback to hashed logging id + signal
3581- conf_key = None
3582- if payload .signal_id :
3583- conf_key = f"{ payload .signal_id } |{ sig_for_dedupe } "
3584- else :
3585- conf_key = f"{ signal_id_for_logging } |{ sig_for_dedupe } "
3586-
3587- confirmed , _ = _confirmation_store .pop_if_confirmed (
3588- conf_key ,
3589- delay = getattr (settings , "CONFIRMATION_DELAY_SECONDS" , 60 ),
3590- ttl = getattr (settings , "CONFIRMATION_TTL_SECONDS" , 180 ),
3591- )
3592- if not confirmed :
3593- # mark pending (idempotent)
3594- _confirmation_store .mark_pending (conf_key , {"first_seen" : time .time (), "request_id" : request_id })
3595- logger .info (f"[{ request_id } ] confirmation_pending: key={ conf_key } " )
3596- return {
3597- "ok" : True ,
3598- "status" : "pending_confirmation" ,
3599- "reason" : "confirmation_pending" ,
3600- "message" : "Signal stored, waiting for confirmation" ,
3601- "confirmation_key" : conf_key ,
3602- "mode" : get_trading_mode_str (),
3603- }
3604- else :
3605- logger .info (f"[{ request_id } ] confirmation_passed: key={ conf_key } " )
3613+ # (confirmation logic moved to run immediately after dedupe acceptance to ensure correct ordering)
36063614
36073615 # Robustes Parsing und Normalisierung
36083616 # Note: sig_for_dedupe was already parsed above for dedupe check
0 commit comments