diff --git a/agent-office/app/notifiers/telegram_lotto.py b/agent-office/app/notifiers/telegram_lotto.py
index 7835629..2d69796 100644
--- a/agent-office/app/notifiers/telegram_lotto.py
+++ b/agent-office/app/notifiers/telegram_lotto.py
@@ -225,3 +225,36 @@ async def send_evolution_report(eval_result: Dict[str, Any], current_base: List[
await send_raw(text)
except Exception as e:
logger.warning(f"[telegram_lotto] evolution report send failed: {e}")
+
+
+# ---------- 일요 회고 브리핑 ----------
+
+def format_sunday_review(payload: Dict[str, Any]) -> str:
+ """일요 회고 브리핑 텍스트 (HTML parse_mode)."""
+ wa = payload.get("winner_analysis") or {}
+ draw_no = payload.get("draw_no")
+ pct = wa.get("percentile")
+ pct_txt = f"{pct*100:.0f}%" if pct is not None else "—"
+ lines = [f"🔍 로또 #{draw_no} 일요 회고", ""]
+ if wa:
+ lines.append(f"이번 당첨조합 분석치: {wa.get('score_total',0):.2f} "
+ f"(무작위 분포 상위 {pct_txt})")
+ lines.append(f" 빈도 {wa.get('score_frequency',0):.2f} · 지문 {wa.get('score_fingerprint',0):.2f} "
+ f"· 갭 {wa.get('score_gap',0):.2f} · 공동출현 {wa.get('score_cooccur',0):.2f} "
+ f"· 다양성 {wa.get('score_diversity',0):.2f}")
+ lines.append("")
+ lines.append("📊 이번 회차 가상구매 성적")
+ for f in payload.get("forward", []):
+ p = f["prizes"]
+ name = {"engine_w": f"엔진({f['label']})", "random_null": "무작위", "coverage": "커버리지"}.get(
+ f["strategy"], f["strategy"])
+ lines.append(f" {name}: 최고 {f['best_match']}일치 / "
+ f"4등 {p['4th']} · 5등 {p['5th']}")
+ lines.append("")
+ lines.append("ℹ️ 무작위 대비 우위가 통계적으로 의미있을 때만 가중치가 진화합니다.")
+ return "\n".join(lines)
+
+
+async def send_sunday_review(payload: Dict[str, Any]) -> None:
+ from ..telegram.messaging import send_raw
+ await send_raw(format_sunday_review(payload))
diff --git a/agent-office/tests/test_sunday_review.py b/agent-office/tests/test_sunday_review.py
new file mode 100644
index 0000000..7d29ed6
--- /dev/null
+++ b/agent-office/tests/test_sunday_review.py
@@ -0,0 +1,23 @@
+import sys, os
+sys.path.insert(0, os.path.dirname(os.path.dirname(__file__)))
+
+from app.notifiers import telegram_lotto as tl
+
+
+def test_format_sunday_review_text():
+ payload = {
+ "draw_no": 1170,
+ "winner_analysis": {"score_total": 0.41, "percentile": 0.33,
+ "score_frequency": 0.4, "score_fingerprint": 0.5, "score_gap": 0.3,
+ "score_cooccur": 0.45, "score_diversity": 0.6},
+ "forward": [
+ {"strategy": "engine_w", "label": "w1", "prizes": {"1st":0,"2nd":0,"3rd":0,"4th":1,"5th":12}, "best_match": 4, "avg_meta_score": 0.55},
+ {"strategy": "random_null", "label": "-", "prizes": {"1st":0,"2nd":0,"3rd":0,"4th":0,"5th":10}, "best_match": 3, "avg_meta_score": 0.33},
+ ],
+ "track_record": {},
+ "calibration_trend": [{"draw_no":1170,"score_total":0.41,"percentile":0.33}],
+ }
+ txt = tl.format_sunday_review(payload)
+ assert "1170" in txt
+ assert "%" in txt # percentile 표기
+ assert "engine" in txt.lower() or "엔진" in txt