mekosotto Claude Opus 4.7 (1M context) commited on
Commit
95c5aff
·
1 Parent(s): c26a55c

feat(frontend): drift metric line + last-prediction session state

Browse files

- Renders one-line drift caption between the calibration caption and
the SHAP section. Three states: warming up (<10 samples), unavailable
(no train stats), drift z-score with magnitude tag (in-band / mild /
significant).
- Stashes /predict/bbb response in st.session_state["last_bbb_prediction"]
so the Day-7 T3C AI Assistant tab can pick it up.
- No backend / schema / test count changes.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

Files changed (1) hide show
  1. src/frontend/app.py +24 -0
src/frontend/app.py CHANGED
@@ -456,6 +456,7 @@ def _render_mri_tab() -> None:
456
 
457
  def _render_prediction_card(result: dict) -> None:
458
  """Render a B2B-styled decision card: label badge + confidence + SHAP bars."""
 
459
  label_text = _html.escape(str(result["label_text"]))
460
  badge_color = "#166534" if result["label"] == 1 else "#991B1B"
461
  badge_bg = "#DCFCE7" if result["label"] == 1 else "#FEE2E2"
@@ -509,6 +510,29 @@ def _render_prediction_card(result: dict) -> None:
509
  f"precision'ı **{precision_pct}%** (n={support})."
510
  )
511
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
512
  # SHAP attributions chart
513
  n_features = len(result["top_features"])
514
  st.markdown(
 
456
 
457
  def _render_prediction_card(result: dict) -> None:
458
  """Render a B2B-styled decision card: label badge + confidence + SHAP bars."""
459
+ st.session_state["last_bbb_prediction"] = result
460
  label_text = _html.escape(str(result["label_text"]))
461
  badge_color = "#166534" if result["label"] == 1 else "#991B1B"
462
  badge_bg = "#DCFCE7" if result["label"] == 1 else "#FEE2E2"
 
510
  f"precision'ı **{precision_pct}%** (n={support})."
511
  )
512
 
513
+ drift_z = result.get("drift_z")
514
+ rolling_n = result.get("rolling_n", 0)
515
+ if drift_z is None and rolling_n < 10:
516
+ st.caption(
517
+ f"📈 Drift: warming up ({rolling_n}/10 predictions buffered)."
518
+ )
519
+ elif drift_z is None:
520
+ st.caption(
521
+ "📈 Drift: unavailable (model lacks train-time confidence stats)."
522
+ )
523
+ else:
524
+ # Sign + magnitude: |z| < 1 in-band, 1–2 mild, >=2 significant.
525
+ if abs(drift_z) < 1.0:
526
+ tag = "within expected range"
527
+ elif abs(drift_z) < 2.0:
528
+ tag = "mild distribution shift"
529
+ else:
530
+ tag = "significant shift — retrain recommended"
531
+ st.caption(
532
+ f"📈 Drift: trailing-{rolling_n} confidence median is "
533
+ f"**{drift_z:+.2f}σ** from train-time distribution ({tag})."
534
+ )
535
+
536
  # SHAP attributions chart
537
  n_features = len(result["top_features"])
538
  st.markdown(