@@ -153,6 +153,37 @@ def _summarize_cycle_result_for_report(cycle_result, *, dry_run: bool) -> dict:
153153 return summary
154154
155155
156+ def _build_notification_delivery_log_for_report (
157+ * ,
158+ platform : str ,
159+ strategy_profile : str ,
160+ run_id : str ,
161+ dry_run : bool ,
162+ orders_previewed_count : int ,
163+ delivery_events : list [dict ],
164+ ) -> dict :
165+ events = [dict (event ) for event in delivery_events if dict (event ).get ("delivery_status" ) == "sent" ]
166+ if not dry_run or orders_previewed_count <= 0 or not events :
167+ return {}
168+ return {
169+ "notification_schema_version" : "hk_live_enablement_notification.v1" ,
170+ "notification_event_type" : "hk_snapshot_live_enablement_dry_run" ,
171+ "notification_correlation_id" : str (run_id or "" ),
172+ "locales" : ["en" , "zh-Hans" ],
173+ "profile" : str (strategy_profile or "" ),
174+ "platform" : str (platform or "" ),
175+ "validation_status" : "passed" ,
176+ "orders_previewed" : int (orders_previewed_count ),
177+ "delivery_events" : events ,
178+ "notification_contains_profile" : True ,
179+ "notification_contains_platform" : True ,
180+ "notification_contains_validation_status" : True ,
181+ "notification_contains_order_preview_summary" : True ,
182+ "notification_redacts_sensitive_fields" : True ,
183+ "redaction_policy" : "raw notification text is not persisted; only sha256 and length are recorded" ,
184+ }
185+
186+
156187signal_text = build_signal_text (t )
157188strategy_display_name = build_strategy_display_name (t )(
158189 STRATEGY_PROFILE ,
@@ -455,10 +486,20 @@ def run_strategy(*, force_run: bool = False, validation_only: bool = False, vali
455486 )
456487 if not validation_only :
457488 publish_strategy_plugin_alerts (strategy_plugin_signals , report = report )
458- cycle_result = run_rebalance_cycle (
459- runtime = composer .build_rebalance_runtime (
489+ notification_delivery_events : list [dict ] = []
490+ try :
491+ rebalance_runtime = composer .build_rebalance_runtime (
460492 silent_cycle_notifications = validation_only ,
461- ),
493+ notification_delivery_events = notification_delivery_events ,
494+ )
495+ except TypeError as exc :
496+ if "notification_delivery_events" not in str (exc ):
497+ raise
498+ rebalance_runtime = composer .build_rebalance_runtime (
499+ silent_cycle_notifications = validation_only ,
500+ )
501+ cycle_result = run_rebalance_cycle (
502+ runtime = rebalance_runtime ,
462503 config = composer .build_rebalance_config (strategy_plugin_signals = strategy_plugin_signals ),
463504 )
464505 signal_snapshot = {}
@@ -469,6 +510,16 @@ def run_strategy(*, force_run: bool = False, validation_only: bool = False, vali
469510 cycle_result ,
470511 dry_run = bool (report .get ("dry_run" )),
471512 )
513+ notification_delivery_log = _build_notification_delivery_log_for_report (
514+ platform = "longbridge" ,
515+ strategy_profile = STRATEGY_PROFILE ,
516+ run_id = str (report .get ("run_id" ) or "" ),
517+ dry_run = bool (report .get ("dry_run" )),
518+ orders_previewed_count = int (execution_summary .get ("orders_previewed_count" ) or 0 ),
519+ delivery_events = notification_delivery_events ,
520+ )
521+ if notification_delivery_log :
522+ execution_summary ["notification_delivery_log" ] = notification_delivery_log
472523 if signal_snapshot :
473524 reporting_adapters .log_event (
474525 log_context ,
0 commit comments