diff --git a/src/config.py b/src/config.py index d6a2a792..e274cdfd 100644 --- a/src/config.py +++ b/src/config.py @@ -51,10 +51,10 @@ class Config(BaseSettings): DEEPSEEK_BASE_URL: str = "https://api.deepseek.com" CHAT_AGENT_ENABLED: bool = False - # FFM-1161: gate cold_start engines so they only serve genuinely-new users - # (nsessions <= 1). Dormant returners with nmemes_sent < 30 but multiple - # sessions fall through to the growing-user blender instead. - COLD_START_NSESSIONS_GATE_ENABLED: bool = False + # FFM-1161/FFM-1689: gate cold_start engines so they only serve genuinely-new + # users (nsessions <= 1). Dormant returners with nmemes_sent < 30 but + # multiple sessions fall through to the growing-user blender instead. + COLD_START_NSESSIONS_GATE_ENABLED: bool = True # Recommendation batch diagnostics are realtime operational data, not # durable product facts. Keep compact logs/spans always on and sample full diff --git a/tests/recommendations/test_meme_queue.py b/tests/recommendations/test_meme_queue.py index 2214619a..1113256c 100644 --- a/tests/recommendations/test_meme_queue.py +++ b/tests/recommendations/test_meme_queue.py @@ -702,7 +702,7 @@ class TestRetriever(CandidatesRetriever): @pytest.mark.asyncio async def test_gate_off_dormant_returner_still_uses_cold_start(): - """Default (gate disabled): nsessions is ignored — cold_start still routes by nmemes_sent.""" + """Emergency override off: nsessions is ignored and cold_start routes by nmemes_sent.""" retriever = _growing_retriever_class()() with ( _patch_user_info(nsessions=5, nmemes_sent=8), @@ -714,6 +714,21 @@ async def test_gate_off_dormant_returner_still_uses_cold_start(): assert any(c["recommended_by"] == "cold_start_adapt" for c in candidates) +@pytest.mark.asyncio +async def test_gate_default_blocks_dormant_returner_from_cold_start(): + """Default config blocks nsessions>=2 low-sent users from cold_start engines.""" + retriever = _growing_retriever_class()() + with _patch_user_info(nsessions=3, nmemes_sent=8): + candidates = await generate_recommendations( + TEST_USER_ID, 10, nmemes_sent=8, retriever=retriever, random_seed=42 + ) + + sources = {c["recommended_by"] for c in candidates} + assert "cold_start_explore" not in sources + assert "cold_start_adapt" not in sources + assert candidates[0]["recommended_by"] == "lr_smoothed" + + @pytest.mark.asyncio async def test_gate_on_first_session_routes_to_cold_start_explore(): """Gate on + nsessions<=1 + nmemes_sent<6 → cold_start_explore (Phase 1)."""