@@ -315,10 +315,7 @@ def trace_to_card_v11(
315315 "n_checkpoints" : len (headline_block .get ("checkpoints" , [])),
316316 "n_sessions" : len (sessions ),
317317 "headline_metric" : "telemetry_outcome_rate" if outcomes else "telemetry_partial" ,
318- "aging_detected" : (
319- headline_block .get ("decay_slope" ) is not None
320- and headline_block .get ("decay_slope" ) < - 0.01
321- ) if headline_block else None ,
318+ "aging_detected" : _aging_detected_v12 (headline_block ),
322319 "checkpoints" : headline_block .get ("checkpoints" , []),
323320 "session_results" : [],
324321 # Surface aggregated cost so build_aging_card._build_cost_block picks
@@ -527,6 +524,45 @@ def _headline_from_outcomes(sessions, outcomes) -> dict:
527524 }
528525
529526
527+ def _aging_detected_v12 (headline_block : Optional [dict ]) -> Optional [bool ]:
528+ """Return True/False/None for whether aging is detected.
529+
530+ Widened from the pre-v1.2 check (which required outcome-derived
531+ decay_slope to fire) so traces without OutcomeEvents still surface
532+ aging when v1.2 signals (behavior_drift on repeat tasks or rising
533+ aggregate mechanism trend) say so. Returns None only when the
534+ headline block is itself empty.
535+ """
536+ if not headline_block :
537+ return None
538+
539+ # Tier 1 (outcome-derived): decay_slope < -0.01 or ≥10% drop from m0
540+ decay = headline_block .get ("decay_slope" )
541+ if decay is not None and decay < - 0.01 :
542+ return True
543+ m0 = headline_block .get ("m0" )
544+ m_final = headline_block .get ("m_final" )
545+ if (m0 is not None and m_final is not None and m0 > 0
546+ and (m0 - m_final ) / m0 >= 0.10 ):
547+ return True
548+
549+ source = headline_block .get ("source" ) or ""
550+
551+ # Tier 2: behavior_drift on repeat tasks ≥ 10% counts as detected
552+ if source == "behavior_drift_at_repeat" :
553+ drift = headline_block .get ("behavior_drift_at_repeat" ) or 0.0
554+ if drift > 0.10 :
555+ return True
556+
557+ # Tier 3: aggregate mechanism severity rising
558+ if source == "aging_trend" :
559+ slope = headline_block .get ("aging_trend_slope" ) or 0.0
560+ if slope > 0.01 :
561+ return True
562+
563+ return False
564+
565+
530566def _augment_headline_with_fallbacks (
531567 headline : dict ,
532568 consistency : dict ,
0 commit comments