"""Recommendation freshness contracts.""" from __future__ import annotations import shutil from pathlib import Path import pytest from backend.core import Backend _SEED = Path(__file__).resolve().parent.parent / "deploy/hf/seed/hf_bundled_store.db" @pytest.mark.skipif(not _SEED.is_file(), reason="bundled seed DB not present") def test_saved_recommendation_kink_must_not_appear_in_following_recommend_list(tmp_path: Path) -> None: """Fails when HTTP cache is not invalidated on play save (stale deck still lists the saved kink).""" dest = tmp_path / "rec_inval.db" shutil.copyfile(_SEED, dest) b = Backend(dest) u = b.create_user() first = b.recommend(u.id, limit=8) kid = first[0]["kink"]["id"] b.save_play_preference(u.id, kid, "like", ["together"]) after = b.recommend(u.id, limit=8) ids = {x["kink"]["id"] for x in after} assert kid not in ids, "saved kink must be excluded after invalidate + recompute" @pytest.mark.skipif(not _SEED.is_file(), reason="bundled seed DB not present") def test_recommendations_are_fresh_without_http_response_cache(tmp_path: Path) -> None: """Back-to-back stochastic lists may differ, but must stay valid and uncached.""" dest = tmp_path / "rec_fresh.db" shutil.copyfile(_SEED, dest) b = Backend(dest) u = b.create_user() a = b.recommend(u.id, limit=8) b2 = b.recommend(u.id, limit=8) assert a and b2 for batch in (a, b2): ids = [x["kink"]["id"] for x in batch] assert len(ids) == len(set(ids)) assert not (set(ids) & set(b.get_user(u.id)["plays"])) assert not hasattr(b, "_recommend_http_cache") @pytest.mark.skipif(not _SEED.is_file(), reason="bundled seed DB not present") def test_play_board_lists_dual_direction_play_in_to_me_and_by_me(tmp_path: Path) -> None: """Server board must place one play in every active direction bucket (regression guard).""" dest = tmp_path / "board_dual.db" shutil.copyfile(_SEED, dest) b = Backend(dest) u = b.create_user() kid = next(iter(b._catalog()["detail_by_id"])) b.save_play_preference(u.id, kid, "like", ["to_me", "by_me"]) board = b.play_board(u.id) to_me = {x["id"] for x in board["to_me"]} by_me = {x["id"] for x in board["by_me"]} assert kid in to_me and kid in by_me