2929_ORDER_SUBMISSION_UNKNOWN = "SUBMISSION_UNKNOWN"
3030_ORDER_SUBMISSION_TERMINAL = "TERMINAL"
3131_ORDER_CLIENT_ID_PREFIX = "QSL_"
32+ _EARN_METHOD_BY_EFFECT_TYPE = {
33+ "earn_redeem" : "redeem_simple_earn_flexible_product" ,
34+ "earn_subscribe" : "subscribe_simple_earn_flexible_product" ,
35+ }
36+ _EARN_SUCCESS_ID_BY_METHOD = {
37+ "redeem_simple_earn_flexible_product" : "redeemId" ,
38+ "subscribe_simple_earn_flexible_product" : "purchaseId" ,
39+ }
3240_LAST_API_CALL_TS : float = 0.0
3341RUNTIME_EVIDENCE_CONTRACT_VERSION = "qsl.runtime_evidence_aggregate.v1"
3442RECONCILIATION_STATUSES = frozenset ({"MISSING" , "MATCHED" , "MISMATCHED" })
@@ -610,11 +618,15 @@ def _load_order_submission_state(runtime):
610618 if set (record ) != {"state" }:
611619 raise StatePersistenceError ("submission_state_invalid" ) from None
612620 elif status == _ORDER_SUBMISSION_UNKNOWN :
613- if set (record ) != {"state" , "identity_sha256" , "symbol" }:
614- raise StatePersistenceError ("submission_state_invalid" ) from None
615621 if not _is_sha256 (record .get ("identity_sha256" )):
616622 raise StatePersistenceError ("submission_state_invalid" ) from None
617- if not re .fullmatch (r"[A-Z0-9]{3,30}" , str (record .get ("symbol" ) or "" )):
623+ if set (record ) == {"state" , "identity_sha256" , "symbol" }:
624+ if not re .fullmatch (r"[A-Z0-9]{3,30}" , str (record .get ("symbol" ) or "" )):
625+ raise StatePersistenceError ("submission_state_invalid" ) from None
626+ elif set (record ) == {"state" , "identity_sha256" , "method_name" }:
627+ if str (record .get ("method_name" ) or "" ) not in _EARN_SUCCESS_ID_BY_METHOD :
628+ raise StatePersistenceError ("submission_state_invalid" ) from None
629+ else :
618630 raise StatePersistenceError ("submission_state_invalid" ) from None
619631 else :
620632 raise StatePersistenceError ("submission_state_invalid" ) from None
@@ -665,6 +677,14 @@ def _is_order_transport_uncertainty(exc):
665677 )
666678
667679
680+ def _is_confirmed_earn_success (method_name , response ):
681+ response_id_field = _EARN_SUCCESS_ID_BY_METHOD .get (str (method_name ))
682+ if not response_id_field or not isinstance (response , Mapping ) or response .get ("success" ) is not True :
683+ return False
684+ response_id = response .get (response_id_field )
685+ return isinstance (response_id , int ) and not isinstance (response_id , bool ) and response_id > 0
686+
687+
668688def _reconcile_uncertain_order (client , symbol , identity_sha256 ):
669689 if not symbol or not identity_sha256 :
670690 raise OrderReconciliationError ("order_reconciliation_uncertain" ) from None
@@ -705,13 +725,20 @@ def runtime_call_client(runtime, report, *, method_name, payload, effect_type,
705725 raise RuntimeError ("runtime.client is not configured" )
706726
707727 is_order_call = str (effect_type or "" ).startswith ("order_" )
728+ earn_method = _EARN_METHOD_BY_EFFECT_TYPE .get (str (effect_type or "" ))
729+ is_earn_call = earn_method == str (method_name )
730+ if str (effect_type or "" ).startswith ("earn_" ) and not is_earn_call :
731+ raise StatePersistenceError ("submission_state_invalid" ) from None
732+ is_funding_mutation = is_order_call or is_earn_call
708733 client_payload = dict (payload )
709734 trade_state = None
710735 identity_sha256 = None
711- if is_order_call :
736+ if is_funding_mutation :
712737 trade_state , submission_record = _load_order_submission_state (runtime )
713738 submission_status = submission_record ["state" ]
714739 if submission_status == _ORDER_SUBMISSION_UNKNOWN :
740+ if "method_name" in submission_record or is_earn_call :
741+ raise OrderReconciliationError ("order_reconciliation_uncertain" ) from None
715742 current_payload , current_identity_sha256 = _ensure_order_logical_identity (runtime , method_name , payload )
716743 if current_identity_sha256 != submission_record ["identity_sha256" ]:
717744 raise OrderReconciliationError ("order_reconciliation_intent_mismatch" ) from None
@@ -730,19 +757,64 @@ def runtime_call_client(runtime, report, *, method_name, payload, effect_type,
730757 trade_state ,
731758 {"state" : _ORDER_SUBMISSION_RESERVED },
732759 )
733- client_payload , identity_sha256 = _ensure_order_logical_identity (runtime , method_name , payload )
734- association = _build_order_request_association (method_name , client_payload )
735- symbol = association ["symbol" ]
736- _persist_order_submission_state (
737- runtime ,
738- trade_state ,
739- {
760+ if is_order_call :
761+ client_payload , identity_sha256 = _ensure_order_logical_identity (runtime , method_name , payload )
762+ association = _build_order_request_association (method_name , client_payload )
763+ symbol = association ["symbol" ]
764+ unknown_record = {
740765 "state" : _ORDER_SUBMISSION_UNKNOWN ,
741766 "identity_sha256" : identity_sha256 ,
742767 "symbol" : symbol ,
743- },
768+ }
769+ else :
770+ _unused_order_payload , identity_sha256 = _ensure_order_logical_identity (runtime , method_name , payload )
771+ unknown_record = {
772+ "state" : _ORDER_SUBMISSION_UNKNOWN ,
773+ "identity_sha256" : identity_sha256 ,
774+ "method_name" : str (method_name ),
775+ }
776+ _persist_order_submission_state (
777+ runtime ,
778+ trade_state ,
779+ unknown_record ,
744780 )
745781 record_order_submission_attempt (report )
782+ if is_earn_call :
783+ _rate_limit_pause ()
784+ try :
785+ response = getattr (runtime .client , method_name )(** client_payload )
786+ except Exception as exc :
787+ if _is_order_transport_uncertainty (exc ):
788+ record_order_transport_uncertainty (report )
789+ record_side_effect (
790+ runtime ,
791+ report ,
792+ effect_type = f"{ effect_type } _failed" ,
793+ target = method_name ,
794+ payload = {"payload" : dict (client_payload ), "reason" : "order_reconciliation_uncertain" , "retries" : 0 },
795+ executed = False ,
796+ )
797+ raise OrderReconciliationError ("order_reconciliation_uncertain" ) from None
798+ if not _is_confirmed_earn_success (method_name , response ):
799+ record_side_effect (
800+ runtime ,
801+ report ,
802+ effect_type = f"{ effect_type } _failed" ,
803+ target = method_name ,
804+ payload = {"payload" : dict (client_payload ), "reason" : "order_reconciliation_uncertain" , "retries" : 0 },
805+ executed = False ,
806+ )
807+ raise OrderReconciliationError ("order_reconciliation_uncertain" ) from None
808+ record_side_effect (
809+ runtime ,
810+ report ,
811+ effect_type = effect_type ,
812+ target = method_name ,
813+ payload = dict (client_payload ),
814+ executed = True ,
815+ )
816+ _persist_order_submission_state (runtime , trade_state , {"state" : _ORDER_SUBMISSION_TERMINAL })
817+ return response
746818 _rate_limit_pause ()
747819 retries_used = max_retries
748820 for attempt in range (max_retries + 1 ):
0 commit comments