{"record":{"id":"31948c0344171f0d","repo":"sansan0/TrendRadar","slug":"join-conflicting-now-hhmm","errorCode":null,"errorMessage":"检测到时间段重叠冲突: {', '.join(conflicting)} 在 {now_hhmm} 重叠。请调整时间段配置，或将 overlap.policy 设为 'last_wins'","messagePattern":"检测到时间段重叠冲突: (.+?) 在 (.+?) 重叠。请调整时间段配置，或将 overlap\\.policy 设为 'last_wins'","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"trendradar/core/scheduler.py","lineNumber":220,"sourceCode":"        \"\"\"\n        candidates = []\n        for idx, key in enumerate(day_plan.get(\"periods\", [])):\n            period = self.timeline[\"periods\"].get(key)\n            if period is None:\n                continue\n            if self._in_range(now_hhmm, period[\"start\"], period[\"end\"]):\n                candidates.append((idx, key))\n\n        if not candidates:\n            return None\n\n        # 检查冲突\n        if len(candidates) > 1:\n            policy = self.timeline.get(\"overlap\", {}).get(\"policy\", \"error_on_overlap\")\n            conflicting = [c[1] for c in candidates]\n\n            if policy == \"error_on_overlap\":\n                raise ValueError(\n                    f\"检测到时间段重叠冲突: {', '.join(conflicting)} 在 {now_hhmm} 重叠。\"\n                    f\"请调整时间段配置，或将 overlap.policy 设为 'last_wins'\"\n                )\n\n            # last_wins：输出重叠警告，列表中后面的优先\n            print(\n                f\"[调度] 检测到时间段重叠: {', '.join(conflicting)} 在 {now_hhmm} 重叠\"\n            )\n            winner = candidates[-1]\n            print(f\"[调度] 冲突策略: last_wins，生效时间段: {winner[1]}\")\n            return winner[1]\n\n        return candidates[0][1]\n\n    @staticmethod\n    def _in_range(now_hhmm: str, start: str, end: str) -> bool:\n        \"\"\"\n        检查时间是否在范围内（支持跨日）","sourceCodeStart":202,"sourceCodeEnd":238,"githubUrl":"https://github.com/sansan0/TrendRadar/blob/8ee26026ba6c11dec41a95fb3895a7162876caa1/trendradar/core/scheduler.py#L202-L238","documentation":"Raised at resolution time when the current HH:MM falls inside two or more periods of the same day plan and overlap.policy is 'error_on_overlap' (the default). The scheduler refuses to guess which period wins; the message names the conflicting periods and points to the 'last_wins' policy as the opt-in resolution.","triggerScenarios":"Two periods like 08:00-12:00 and 11:00-13:00 in one day_plan, and the clock hits 11:30 during resolve(); policy unset or explicitly error_on_overlap.","commonSituations":"Hand-editing periods and forgetting the earlier boundary; periods intended for different day plans accidentally listed in the same one; cross-midnight periods (e.g. 22:00-02:00) unintentionally overlapping early-morning periods.","solutions":["Adjust start/end times so the periods do not overlap.","If the overlap is intentional and the later-defined period should win, set overlap.policy: last_wins in the timeline (the scheduler then logs a warning and picks the last match).","Move periods that belong to different schedules into separate day_plans."],"exampleFix":"# timeline config\n# before\nperiods:\n  morning: {start: \"08:00\", end: \"12:00\"}\n  late:    {start: \"11:00\", end: \"13:00\"}\n# after\nperiods:\n  morning: {start: \"08:00\", end: \"11:00\"}\n  late:    {start: \"11:00\", end: \"13:00\"}\n# or: overlap: {policy: last_wins}","handlingStrategy":"validation","validationCode":"def ranges_overlap(s1, e1, s2, e2):\n    m = lambda t: int(t[:2]) * 60 + int(t[3:])\n    a, b, c, d = m(s1), m(e1), m(s2), m(e2)\n    def ol(x, y):  # handles cross-midnight\n        return x[0] < y[1] and y[0] < x[1] if x[0] < x[1] else not (b <= c or d <= a)\n    # simpler: normalize both to minute intervals and test intersection per-day\nfor plan in timeline[\"day_plans\"].values():\n    ps = [timeline[\"periods\"][k] for k in plan.get(\"periods\", [])]\n    for i in range(len(ps)):\n        for j in range(i + 1, len(ps)):\n            # reject overlaps unless policy is last_wins\n            assert not overlaps(ps[i], ps[j]), f\"{ps[i]} overlaps {ps[j]}\"","typeGuard":null,"tryCatchPattern":"try:\n    cfg = scheduler.resolve()\nexcept ValueError as e:\n    if \"时间段重叠冲突\" in str(e):\n        # config bug — either fix periods or set overlap.policy=last_wins, then rebuild\n        raise SystemExit(f\"schedule config error: {e}\")\n    raise","preventionTips":["Lint period boundaries for pairwise overlap whenever the timeline changes.","If overlap is intentional, declare overlap.policy: last_wins explicitly."],"tags":["scheduler","config","overlap","time-range"],"backgroundTag":null,"analyzedSha":"8ee26026ba6c11dec41a95fb3895a7162876caa1","analyzedAt":"2026-08-15T01:42:18.084Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}