日次ニュースの48時間判定を修正:人工14例と日本語JSON 3件の追試

日次ニュースの整理ツールは、ニュースの内容以前に入力形式の変化で止まることがあります。2026年9月5日に作った判定ツールも、従来の items / url / published_at では動いた一方、9月11日と15日の日本語キーを持つJSONでは終了コード2になりました。
そこで9月15日、失敗を再現してから、項目 / URL / 公開日時 だけを内部形式へ写す処理を追加しました。修正版では9月15日の3件を読み取れましたが、3件とも日付だけで時刻がなかったため review です。結論は「3件が新しい」でも「3件が誤り」でもありません。形式を読めたことと、48時間内だと確定できたことを分けるのが今回の判断です。
9月5日の成功が、9月11日に通用しなかった
初回の9月5日は、Windows、PowerShell、Python 3.14.2、標準ライブラリだけで検証しました。両端を含む48時間を対象に、人工入力14件を4区分へ分け、10個のテストメソッドを通しました。当時の実素材5件は英語キー形式で読み取れ、公開日が年月日だけだったため5件とも review になりました。
しかし、9月11日の入力はトップ階層が 項目、各行が URL と 公開日時 になっていました。旧版は items がないと入力なしとして扱うため、9月11日の4件、9月15日の3件のどちらも次の結果で停止しました。
Input rejected: items must be a list
exit code: 2
これはニュース7件の内容や鮮度を否定した結果ではなく、入力schemaを読めなかっただけです。日次レポートは題材発見用の内部素材なので、本稿にも配布ファイルにもニュース本文、要約、内部の事業案を転載していません。
検証条件と、変えてよいキーを固定した
追試日は2026年9月15日(日本時間)、環境はWindows、PowerShell、Python 3.14.2です。追加ライブラリ、API、URLへのアクセス、外部送信は使っていません。実素材では各レポートの調査期間終了時刻を --as-of に指定し、そこから48時間を閉区間として判定しました。
| 入力 | 読み取る階層 | 行から写すキー | 欠損・混在時 |
|---|---|---|---|
| 従来のオブジェクト | items | url, published_at | 欠損はreview |
| 従来の配列 | 配列自体 | url, published_at | 欠損はreview |
| 現行の日本語オブジェクト | 項目 | URL, 公開日時 | 欠損はreview |
| 両schemaが混在 | 読み取らない | 推測変換しない | exit 2 |
| 未知のトップ階層 | 読み取らない | 似たキーを探さない | exit 2 |
タイトル、要約、カテゴリ、活用案などは無視し、出力もしません。URLや日時のない行は消さず、missing_date や invalid_url の理由付きでreviewへ残します。
許可した2項目だけを新しい辞書へ写す
修正の中心は、判定前の小さな正規化処理です。以下は公開コードからの抜粋です。
LEGACY_ROW_KEYS = ("url", "published_at")
JAPANESE_ROW_KEYS = ("URL", "公開日時")
row = {}
if source_keys[0] in item:
row["url"] = item[source_keys[0]]
if source_keys[1] in item:
row["published_at"] = item[source_keys[1]]
normalized.append(row)
元の辞書を書き換えず、新しい辞書を作ります。混在検知はこのコピーより先です。たとえばトップに 項目 があるのに行へ published_at が入っていたら、都合のよい方を採用せず入力全体を拒否します。柔軟性より、schema変更を見落とさないことを優先した設計です。
人工14例は同じ内訳、テストは10から17へ増えた
9月5日の人工14例を修正版へ再入力した結果は変わりませんでした。
| 区分 | 件数 | 意味 |
|---|---|---|
| keep | 4 | URLと日時が今回の期間条件を満たす候補 |
| review | 8 | 日時不足、未来、矛盾、不正形式などで確認待ち |
| outside_window | 1 | 指定した48時間より前 |
| duplicate | 1 | 完全一致URLかつ同じ公開時点の先行行がある |
合計は14件です。keep は内容の正しさや公開承認、outside_window は情報の無価値、duplicate は削除許可を意味しません。
テストメソッドは初回の10個から17個へ増やしました。追加した7つは、日本語schemaで許可キーだけを写す、従来形式を維持する、入力を変更しない、トップ階層と行の混在を拒否する、未知schemaを拒否する、URLや日時の欠損をreviewに残す、という回帰確認です。17テストはすべて通過しました。「17」はニュース件数ではありません。
9月11日の4件と9月15日の3件を追試した
| 入力日 | 項目数 | 旧版 | 修正版 | 修正版の内訳 |
|---|---|---|---|---|
| 2026-09-11 | 4 | exit 2、schema未対応 | exit 0 | review 4、全件 date_only |
| 2026-09-15 | 3 | exit 2、schema未対応 | exit 0 | review 3、全件 date_only |
タイトルの「日本語JSON 3件」は最新の9月15日分です。9月11日分は4件であり、合計3件とは数えていません。修正版のexit 0は集計完了の意味で、一次情報確認済みや公開可能の意味ではありません。
入力のSHA-256は処理前後で一致しました。9月11日は 1C2FB2E5CCA78631B326732EBD6077A5EACD015B25C5BA62F3A5439FC274C667、9月15日は DCAEC18B4A7712AE38C3209792C7E473537A6A6A18C6EC5F6524F0BB15938024 です。ハッシュ一致は同じバイト列だった証拠で、内容の正確性は保証しません。
手元で人工入力を再実行する
コード・人工入力・テスト・説明書の4ファイルを展開し、PowerShellで次を実行します。
python -m unittest discover -s . -p 'test_*.py' -v
python .\report_gate.py .\cases.json --as-of "2026-09-05T05:30:00+09:00" --summary
2つ目は keep=4, review=8, outside_window=1, duplicate=1 を返します。実素材や秘密情報をZIPへ追加する必要はありません。
日時はタイムゾーン付きの時刻だけを48時間の比較対象にします。Python公式のdatetime資料は、awareな日時と、時点を一意に置けないnaiveな日時を区別しています。日付だけをreviewにするのは、それを踏まえた本ツールの保守的な編集ルールです。
URLは最低限の構文だけを確認します。Python公式のurllib.parse資料にも、urlsplit() 自体は入力検証を行わないという注意があります。存在、信頼性、安全なアクセス先かは判定外です。両資料は9月15日に開き直しました。
実務への影響と、次に人が確認すること
完全一致URLと同じ公開時点しか重複候補にしません。追跡引数だけ違うURL、別URLで同じ出来事を扱う記事、本文が更新された同一URLは判別できません。日付だけの項目へレポート全体のタイムゾーンと午前0時を補うこともしないため、今回のようにreviewが多く残ります。
次はreview行の一次情報を開き、発表日と更新日、時刻とタイムゾーンを確認します。確認できなければ48時間内という表現を外すか、判断を保留します。keep でも本文の裏取りと独自検証は別に必要です。
Lyriaの公式資料を6項目で照合した記事は、一つの主張を一次資料へ戻す方法を扱います。本稿はその前段で、JSONの形式・URL・日時を壊さず仕分ける方法です。メタデータを通過した候補に次の照合票を使う関係で、検索意図は重なりません。
表紙は工程を表す生成イラストで、検証証拠ではありません。独自証拠は失敗と修正後のコマンド結果、人工入力、テスト、入力ハッシュです。