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

提交原始紀錄

fix: order news by displayed source publication time (#234)

SHA
f0eaa940a004893a4a814ed8810e84885e64bcd6
提交時間
作者
nnneeeooo-nnneeeooo
提交者
web-flow

變更檔案 (3)

  • .github/deploy-trigger modified · +1 / −1
  • pipeline/build.py modified · +6 / −4
  • tests/test_news_chronology.py added · +54 / −0

完整差異

@@ -3,5 +3,5 @@\n This file intentionally triggers the manual-article-deploy workflow.\n \n source_main_commit=370d81ed1fc0465c7d39f2c2842f4105680db802\n-reason=publish manual Tigerair Taiwan B-50031 delivery article\n+reason=sort news feeds and search by displayed source publication time\n triggered_at=2026-10-01\n@@ -1201,8 +1201,8 @@ def side(own, other):\n     image = normalize_image(selected_image, titles=[\n         (raw.get(lang) or {}).get("title") for lang in ("zh", "en")])\n     # Display the SOURCE's newest publication time when the write stage\n-    # recorded one; the generation time (dt) is used for ordering only, so\n-    # a days-old official release is never presented as breaking news.\n+    # recorded one. Chronological feeds use this same timestamp so a late\n+    # generated article cannot place an older source above newer news.\n     display_dt = publication_dt\n     if raw.get("sourcePublishedUtc"):\n         try:\n@@ -1227,6 +1227,7 @@ def side(own, other):\n     return {\n         "id": art_id,\n         "dt": dt,\n+        "news_dt": display_dt,\n         "published_dt": publication_dt,\n         "modified_dt": modified_dt,\n         "published_iso": iso_timestamp(publication_dt),\n@@ -1281,7 +1282,8 @@ def collect_articles():\n         prev = by_id.get(a["id"])\n         if prev is None or a["dt"] > prev["dt"]:\n             by_id[a["id"]] = a\n-    return sorted(by_id.values(), key=lambda a: a["dt"], reverse=True)\n+    return sorted(by_id.values(),\n+                  key=lambda a: (a["news_dt"], a["id"]), reverse=True)\n \n \n @lru_cache(maxsize=1)\n@@ -1920,7 +1922,7 @@ def search_index_item(article, alias_groups, prompt_aliases=(),\n         },\n         "source": article["source"],\n         "date": article["meta_ts"],\n-        "published": article["dt"].isoformat(),\n+        "published": article["news_dt"].isoformat(),\n         "articleFormat": article["article_format"],\n         "availableLanguages": article["available_languages"],\n         "airlines": article_airline_keys(article, airline_catalog),\n@@ -0,0 +1,54 @@\n+"""Chronological feeds and search must agree with the displayed news time."""\n+import json\n+import sys\n+import tempfile\n+from pathlib import Path\n+from unittest.mock import patch\n+\n+sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "pipeline"))\n+import build\n+\n+\n+def test_news_chronology():\n+    def article(id, published, source=None, sort=None):\n+        row = {\n+            "id": id, "publishedUtc": published, "cat": "ops",\n+            "zh": {"title": "台灣虎航接收A320neo客機", "body": ["交機新聞。"]},\n+            "sources": [{"name": "Test", "url": "https://example.com/news"}],\n+        }\n+        if source is not None:\n+            row["sourcePublishedUtc"] = source\n+        if sort is not None:\n+            row["sortUtc"] = sort\n+        return row\n+\n+    rows = [\n+        article("older-late-generated", "2026-10-01T02:00:00Z",\n+                "2026-09-28T08:00:00Z"),\n+        article("newer-manual", "2026-09-30T08:50:00Z",\n+                "2026-09-30T08:50:00Z", "2026-09-20T00:00:00Z"),\n+        article("no-source-time", "2026-09-29T08:00:00Z"),\n+        article("invalid-source-time", "2026-09-27T08:00:00Z", "invalid"),\n+        article("date-only-source", "2026-10-01T03:00:00Z",\n+                "2026-09-26T00:00:00Z"),\n+    ]\n+    with tempfile.TemporaryDirectory() as tmp:\n+        folder = Path(tmp)\n+        (folder / "fixture.json").write_text(json.dumps({"articles": rows}))\n+        with patch.object(build, "ARTICLES_DIR", folder):\n+            collected = build.collect_articles()\n+    assert [a["id"] for a in collected] == [\n+        "newer-manual", "no-source-time", "older-late-generated",\n+        "invalid-source-time", "date-only-source",\n+    ]\n+    assert collected[0]["meta_ts"] == "2026-09-30 4:50 PM UTC+8"\n+    assert collected[-1]["meta_ts"] == "2026-09-26"\n+    for prepared in collected:\n+        indexed = build.search_index_item(prepared, [])\n+        assert build.parse_iso(indexed["published"]) == prepared["news_dt"]\n+    assert collected[0]["published_iso"] == "2026-09-30T08:50:00Z"\n+\n+\n+if __name__ == "__main__":\n+    test_news_chronology()\n+    print("PASS news chronology, source-time fallback and search timestamps")

你發現了隱藏主題!

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