Ctrl K
ComunidadGuías…

tests/test_daily_summary.py

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
from __future__ import annotations

import importlib
import sys
import unittest
from pathlib import Path
from unittest import mock

ROOT = Path(__file__).resolve().parents[1]
SCRIPTS = ROOT / "scripts"
if str(SCRIPTS) not in sys.path:
    sys.path.insert(0, str(SCRIPTS))


class DailySummaryTests(unittest.TestCase):
    """訊息第一行就要回答「這是我要處理的嗎」。

    原本的分法是「故障 vs 待辦」,而待辦 = 堆積。2026-09-12 發現那個分法是錯的:
    堆積有兩種。治理追不上是**故障**(系統自己該做的事做不完),而「要不要開一個
    新的 wiki 主題」才是**只有 Pan 能決定**的那種。

    舊分法把整個 governance_actionable section 當成決定類,於是「吸收追不上」每天
    被寫成「請你審核 180 筆」——實測那 180 筆裡 106 筆是 safe_promotion,一筆都不
    需要人。叫人決定一件系統自己會做的事,是這則訊息會被停止閱讀的直接原因。

    現在:追不上算故障,proposal / overdue 才進「等你決定」。
    """

    @classmethod
    def setUpClass(cls) -> None:
        cls.notify = importlib.import_module("health_check_notify")

    def _build(self, sections, failures):
        # Inventory reads the live workspace; not what these tests are about.
        with mock.patch.object(self.notify, "_inventory_lines", return_value=[]):
            return self.notify.build_message(sections, failures)

    def _governance(self, **counts):
        return {"name": "governance_actionable", "checks": [], "actionable_counts": counts}

    def test_all_clear(self) -> None:
        self.assertTrue(self._build([], []).startswith("XKB 一切正常"))

    def test_proposals_alone_are_a_decision_not_a_fault(self) -> None:
        """只有「要不要開新主題」時,不該說壞掉——那真的只有 Pan 能決定。"""
        message = self._build(
            [self._governance(pending=226, proposal=153, quarantine=23)], [])

        self.assertTrue(message.startswith("XKB 運作正常,有事情等你決定"))
        self.assertIn("153 條想開新的 wiki 主題", message)
        self.assertNotIn("壞掉了", message)

    def test_falling_behind_is_a_fault_not_a_decision(self) -> None:
        """治理吸收追不上是故障,不是待辦。

        這個測試原本斷言相反的事(「堆積不算壞掉」),而那個分法讓「追不上」
        每天被寫成「請你審核」。追不上是系統做不完自己該做的事,那是故障;
        要人決定的只有提案。
        """
        message = self._build(
            [self._governance(pending=226, proposal=0)],
            [("governance_actionable", "治理每天吸收 20 筆、進來 35 筆——追不上")],
        )

        self.assertTrue(message.startswith("XKB 有 1 個地方壞了"), message)
        self.assertIn("治理吸收追不上", message)      # 可讀標籤,不是內部識別字
        self.assertNotIn("等你決定", message)

    def test_a_fault_and_a_decision_are_both_reported(self) -> None:
        message = self._build(
            [self._governance(pending=226, proposal=153)],
            [("conversation_capture", "0/5 sessions recorded turns")],
        )

        self.assertTrue(message.startswith("XKB 有 1 個地方壞了"), message)
        self.assertIn("對話沒有被記錄下來", message)
        self.assertIn("等你決定", message)
        self.assertIn("153 條想開新的 wiki 主題", message)

    def test_raw_section_names_do_not_reach_the_reader(self) -> None:
        message = self._build([], [("conversation_capture", "0/5 sessions recorded turns")])
        self.assertNotIn("conversation_capture", message.split("\\n")[0])
        self.assertIn("對話沒有被記錄下來", message)

    def test_an_unknown_check_still_reports_something(self) -> None:
        """A check added later must not vanish from the message."""
        message = self._build([], [("something_new", "詳細說明")])
        self.assertIn("something_new", message)
        self.assertIn("詳細說明", message)

    def test_counts_that_do_not_apply_are_omitted(self) -> None:
        message = self._build([self._governance(pending=0, proposal=0, quarantine=0)], [])
        self.assertTrue(message.startswith("XKB 一切正常"))


if __name__ == "__main__":
    unittest.main()