diff --git a/daily/delta.py b/daily/delta.py index ea25a77..339ecdc 100644 --- a/daily/delta.py +++ b/daily/delta.py @@ -8,7 +8,7 @@ from datetime import datetime, timedelta from pathlib import Path from typing import Any, Callable -from daily.config import OUTPUT_DIR, env_int +from daily.config import OUTPUT_DIR, delta_baseline_fallback, env_int, wecom_mode logger = logging.getLogger(__name__) @@ -311,3 +311,40 @@ def build_movement_context( "skills_stable": not skills_trending_all and not skills_hot_all, "github_stable": not github_trending_all and not github_emerging_all and not github_topic_all, } + + +def effective_wecom_mode(*, date_str: str, configured_mode: str | None = None) -> str: + mode = configured_mode or wecom_mode() + if mode != "delta": + return "full" + if find_previous_data(date_str) is None and delta_baseline_fallback() == "full": + return "full" + return "delta" + + +def partition_skill_moves_for_wecom( + trending_moves: list[dict[str, Any]], + hot_moves: list[dict[str, Any]], +) -> tuple[list[dict[str, Any]], list[dict[str, Any]]]: + hot_by_id = {skill_id(m): m for m in hot_moves if skill_id(m)} + trending_out: list[dict[str, Any]] = [] + consumed_hot: set[str] = set() + for move in trending_moves: + sid = skill_id(move) + copy = dict(move) + badges = [f"Trending #{move.get('rank', '?')}"] + hot_match = hot_by_id.get(sid) + if hot_match: + badges.append(f"Hot #{hot_match.get('rank', '?')}") + consumed_hot.add(sid) + copy["badge"] = " ยท ".join(badges) + trending_out.append(copy) + hot_out: list[dict[str, Any]] = [] + for move in hot_moves: + sid = skill_id(move) + if sid in consumed_hot: + continue + copy = dict(move) + copy["badge"] = f"Hot #{move.get('rank', '?')}" + hot_out.append(copy) + return trending_out, hot_out diff --git a/tests/test_wecom_delta.py b/tests/test_wecom_delta.py index 09ef523..eec3540 100644 --- a/tests/test_wecom_delta.py +++ b/tests/test_wecom_delta.py @@ -59,3 +59,44 @@ class NewsPushedLinksTests(unittest.TestCase): out = filter_unpushed_items(items, date_str="2026-07-09") self.assertEqual(len(out), 1) self.assertEqual(out[0]["link"], "https://example.com/b") + + +class SkillMovePartitionTests(unittest.TestCase): + def test_partition_dedupes_across_boards(self): + trending = [ + { + "id": "a/b/foo", + "rank": 4, + "title": "foo", + "source": "a/b", + "installs": 1, + "link": "", + "description": "", + } + ] + hot = [ + { + "id": "a/b/foo", + "rank": 2, + "title": "foo", + "source": "a/b", + "installs": 1, + "link": "", + "description": "", + } + ] + from daily.delta import partition_skill_moves_for_wecom + + t_out, h_out = partition_skill_moves_for_wecom(trending, hot) + self.assertEqual(len(t_out), 1) + self.assertEqual(len(h_out), 0) + self.assertIn("Trending #4", t_out[0]["badge"]) + self.assertIn("Hot #2", t_out[0]["badge"]) + + def test_effective_mode_fallback_full_without_baseline(self): + from daily.delta import effective_wecom_mode + + with patch("daily.delta.find_previous_data", return_value=None): + with patch("daily.delta.wecom_mode", return_value="delta"): + with patch("daily.delta.delta_baseline_fallback", return_value="full"): + self.assertEqual(effective_wecom_mode(date_str="2026-07-10"), "full")