2026-10-20 TUE UTC 12:42 PM TPE 8:42 PM 每小時自動更新 中文 EN
LIVE 快訊
← 返回網站更新紀錄 Site Changelog

提交原始紀錄

Briefing = pure bulletin: formal site articles no longer mirrored Owner direction: the briefing page duplicates stories already on 最新; keep only the Perplexity-style bulleted bulletin. run_edition now fills sections from the grounded sweep only; the repo var BRIEFING_INCLUDE_ARTICLES=true restores the merged mode (machinery and its tests kept intact). Grounded-failure warnings are now reader-facing zh (quota-limited / key missing / generic) instead of raw errors, and the index subtitle explains the bulletin scope. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

SHA
b309c745abd04e031cc4db5e5698242152d9cc60
提交時間
作者
avwire
提交者
avwire

變更檔案 (4)

  • .github/workflows/briefing.yml modified · +2 / −0
  • pipeline/briefing.py modified · +25 / −7
  • pipeline/build.py modified · +2 / −2
  • tests/test_briefing.py modified · +17 / −0

完整差異

@@ -86,6 +86,8 @@ jobs:\n           # BETA grounded search sweep (owner-approved; off unless var set)\n           BRIEFING_GROUNDED: ${{ vars.BRIEFING_GROUNDED }}\n           BRIEFING_GROUNDED_MODEL: ${{ vars.BRIEFING_GROUNDED_MODEL }}\n+          # bulletin-only by default; true restores merged site articles\n+          BRIEFING_INCLUDE_ARTICLES: ${{ vars.BRIEFING_INCLUDE_ARTICLES }}\n         run: |\n           if [ -n "${{ steps.ed.outputs.date }}" ]; then\n             python pipeline/briefing.py --edition "${{ steps.ed.outputs.edition }}" --date "${{ steps.ed.outputs.date }}"\n@@ -105,6 +105,15 @@ def _llm_intro_enabled() -> bool:\n             in ("1", "true", "yes"))\n \n \n+def _include_articles() -> bool:\n+    """Owner decision 2026-07-27: the briefing page is a pure bulletin\n+    (grounded sweep items only) - formal site articles live on 最新 and\n+    are NOT mirrored here. Repo var BRIEFING_INCLUDE_ARTICLES=true\n+    restores the old merged behaviour."""\n+    return (os.environ.get("BRIEFING_INCLUDE_ARTICLES", "").strip().lower()\n+            in ("1", "true", "yes"))\n+\n+\n def load_editions() -> dict:\n     editions = load_json(EDITIONS_PATH, None)\n     if not isinstance(editions, dict) or set(editions) != {\n@@ -725,15 +734,20 @@ def run_edition(edition: str, taipei_date: date) -> int:\n     window = get_briefing_window(edition, taipei_date)\n     warnings: list[str] = []\n \n-    articles, load_warnings = load_published_articles()\n-    warnings.extend(load_warnings)\n     checked_sources, source_warnings = checked_sources_snapshot()\n     warnings.extend(source_warnings)\n \n     event_index = load_event_index()\n     prune_event_index(event_index, now)\n-    picked = select_items(articles, window, event_index, now, warnings)\n-    sections = arrange_sections(picked, warnings)\n+    load_warnings: list[str] = []\n+    if _include_articles():\n+        articles, load_warnings = load_published_articles()\n+        warnings.extend(load_warnings)\n+        picked = select_items(articles, window, event_index, now, warnings)\n+        sections = arrange_sections(picked, warnings)\n+    else:\n+        # pure bulletin mode: sections are filled by the grounded sweep\n+        sections = {name: [] for name in SECTIONS}\n \n     # BETA: owner-approved model-assisted search sweep (grounded.py).\n     # Only Google-retrieved sources can be cited; any failure degrades to\n@@ -749,7 +763,7 @@ def run_edition(edition: str, taipei_date: date) -> int:\n                                for sec in sections.values() for it in sec]\n             data, shim = grounded.call_grounded(window)\n             if data is None:\n-                warnings.append("grounded sweep skipped: no GEMINI_API_KEY")\n+                warnings.append("AI 搜尋所需的模型金鑰未設定,本期未產生條列內容")\n             else:\n                 g_items, g_warnings = grounded.sanitize_items(\n                     data, existing_titles, g_seen, now)\n@@ -771,8 +785,12 @@ def run_edition(edition: str, taipei_date: date) -> int:\n                     except Exception:\n                         pass\n     except Exception as exc:\n-        warnings.append(f"grounded sweep failed: "\n-                        f"{type(exc).__name__}: {exc}")\n+        if "429" in str(exc):\n+            warnings.append("AI 搜尋暫時受免費額度限制(配額不足),本期未能"\n+                            "產生條列內容;下一期將自動重試")\n+        else:\n+            warnings.append(f"AI 搜尋本期失敗({type(exc).__name__}: "\n+                            f"{str(exc)[:120]}),已略過")\n \n     # partial = our own inputs were degraded, never "no events".\n     partial = bool(load_warnings or source_warnings)\n@@ -88,7 +88,7 @@\n         "cats": ["全部", "事故", "法規", "商業", "營運"],\n         # daily briefings\n         "brKicker": "Daily Briefing", "brIndexTitle": "快報",\n-        "brIndexSub": "每日三次(臺北時間 07:15/15:15/23:15)自動彙整固定八小時窗口內、已通過驗證發布的航空與交通事件。",\n+        "brIndexSub": "每日三次(臺北時間 07:15/15:15/23:15)的條列式全球航空與交通要聞快報,由具搜尋能力的模型彙整(Beta);本站正式新聞請見「最新」。",\n         "brLatest": "最新快報", "brWindow": "資料範圍", "brCutoff": "資料截止",\n         "brGenerated": "系統整理完成", "brTo": "至",\n         "brEmpty": "截至本期資料截止時間,系統在本次查核的指定來源中,未發現符合收錄門檻的新事件。",\n@@ -149,7 +149,7 @@\n         "cats": ["All", "Safety", "Regulation", "Business", "Operations"],\n         # daily briefings\n         "brKicker": "Daily Briefing", "brIndexTitle": "Briefings",\n-        "brIndexSub": "Three times daily (07:15 / 15:15 / 23:15 Taipei time): verified aviation and transport events from a fixed eight-hour window.",\n+        "brIndexSub": "A bulleted global air & transport bulletin three times daily (07:15 / 15:15 / 23:15 Taipei time), compiled by a search-capable model (Beta); the site's formal articles live under Latest.",\n         "brLatest": "Latest briefing", "brWindow": "Data window",\n         "brCutoff": "Data cutoff", "brGenerated": "Compiled", "brTo": "to",\n         "brEmpty": "As of this edition's data cutoff, no new events meeting the inclusion bar were found in the sources checked for this edition.",\n@@ -23,6 +23,9 @@\n REPO = Path(__file__).resolve().parent.parent\n TMP = Path(tempfile.mkdtemp(prefix="avwire-briefing-"))\n os.environ["AVWIRE_DATA_DIR"] = str(TMP)\n+# The selection/dedup/update machinery below is exercised with the merged\n+# mode on; production default is the pure bulletin (owner 2026-07-27).\n+os.environ["BRIEFING_INCLUDE_ARTICLES"] = "true"\n \n sys.path.insert(0, str(REPO / "pipeline"))\n import briefing  # noqa: E402\n@@ -530,6 +533,20 @@ def _art_text(text):\n check("fatal items render warning+red marks",\n       "⚠" in _marks_fatal and "\U0001f534" in _marks_fatal)\n \n+# ── bulletin-only production default ─────────────────────────────────────────\n+\n+reset()\n+write_sources(ok=True)\n+write_articles([make_article("a-bul", "正式新聞不入快報",\n+                             tpe(2026, 7, 27, 6))])\n+del os.environ["BRIEFING_INCLUDE_ARTICLES"]\n+briefing.main(["--edition", "morning", "--date", "2026-07-27"])\n+os.environ["BRIEFING_INCLUDE_ARTICLES"] = "true"\n+bm = load_brief("2026-07-27-morning")\n+check("default mode keeps formal site articles OUT of the bulletin",\n+      bm["item_count"] == 0\n+      and all(v == [] for v in bm["sections"].values()))\n+\n # ── caps ─────────────────────────────────────────────────────────────────────\n \n reset()

你發現了隱藏主題!

8-bit 主題已解鎖。重新整理後,就能在主題選單選擇 8-bit。