STEP 1607 — harvest_lag v0.2 · ID-set diff with fetcher-window

2026-08-31 · chat-Claude STEP 1605 review pt ③ (harvest_lag 感度構造的にゼロ) 完全 fix

v0.1 の根本欠陥 (chat-Claude 指摘、正しい)

v0.1 (STEP 1601) は「max-published timestamp 差分」で verdict を出していた。 Internal と oracle が同 arXiv endpoint を叩く以上、 delta は定義上 ≡ 0。 「fetcher が動いていれば 0、止まれば大」以外の状態を検出できず、後者は計器 1 (source_freshness) で既に検出できていた。 50 本中 49 本欠落しても最新 1 本一致で TRUEを返す broken sensor。

v0.2 設計: ID 集合差分 + fetcher-window mode

Oracle 契約に askIdList(feed, limit) method 追加、直近 N 本の ID list を取得。 Internal set と set difference で「fetcher が publisher の直近 N 全部知ってるか」を測る。

missing = (oracle top-N IDs) \ (internal ID set)
missingRatio = missingCount / effectiveWindow

verdict:
  missingRatio ≤ 0.00  → TRUE     (exact match, healthy)
  missingRatio ≤ 0.10  → NEITHER  (aging)
  missingRatio ≤ 0.50  → FALSE    (lagging)
  missingRatio  > 0.50 → ZERO     (dead)

fetcher-window mode (default) — v0.2 実測後の追加設計

最初の実測で 9/9 feeds ZERO / 40 missing 各 feed が出た。 だが原因は fetcher retention (10) < oracle window (50) = 設計上の窓 mismatch であって fetcher lag ではないと判明。

fix: effectiveWindow = min(oracleReturned, fetcherRetention)。 fetcher が 10 保持なら oracle top 10 とのみ diff。 「fetcher が知るべき最新 N を全部知ってるか」を測る。 fixed-window mode も選択可 (fetcher retention 上限含む絶対 lag 計測)。

★ v0.2 fetcher-window mode 実測 (2026-08-31)

FeedVerdictMissingCovered
math.NTTRUE0/10 (0%)10/10
math.LOTRUE0/10 (0%)10/10
math.DGTRUE0/10 (0%)10/10
cs.LOTRUE0/10 (0%)10/10
cs.AITRUE0/10 (0%)10/10
cs.LGTRUE0/10 (0%)10/10
cs.CLTRUE0/10 (0%)10/10
physics.gen-phTRUE0/10 (0%)10/10
quant-phTRUE0/10 (0%)10/10

9/9 TRUE with covered 10/10 = arxiv-recent fetcher は publisher の直近 10 を全部取得済。 v0.1 の「delta 0 → TRUE」と数値は同じだが、 意味が根本的に異なる: v0.1 は感度ゼロの偽陽性、v0.2 は10 個の ID 個別一致による有意な verdict。

参考: fixed-window mode 実測 (絶対 lag)

9/9 ZERO / 40 missing (80%) each feed。 これは fetcher lag ではなく設計上の retention 10 < 50 差。 fetcher の retention window を広げれば覆せる (別 STEP 候補)。

実装

scripts/comparator/
├── lib/
│   ├── oracle.ts          — v0.2: OracleWithIdList (askIdList method 追加)
│   └── oracle-arxiv.ts    — askIdList impl + extractArxivIds + normalizeArxivId
├── gauges/
│   ├── harvest_lag.ts     — v0.1 保持 (deprecated, chat-Claude 感度指摘対象)
│   └── harvest_lag_v02.ts — NEW: ID-set diff + fetcher/fixed-window mode
└── run-harvest-lag-v02.ts — CLI runner (3.5s ToU 遵守)

test/step1607-harvest-lag-v02-id-set-diff-test.ts  — 38/38 PASS (13 section)

正規化

Rei stack 素子分類 進化

時点分類 (c) 汎用コンパレータ素子
STEP 1601 v0.11 本 (arXiv max-published、chat-Claude 指摘で broken sensor 確定)
STEP 1607 v0.21 本 (arXiv ID-set diff + fetcher-window、感度 復活)
次 STEP 候補Zenodo/HF/OpenAlex adapter で OracleWithIdList dogfood 拡大

Honest scope (9 件)

  1. v0.2 は set difference (oracleIds \ internalIds) を effective window (fetcher retention 尊重) で測る。「fetcher が publisher の直近 N 全部知ってるか」を答える。
  2. v0.1 は blind (max-published delta ≡ 0 by construction) だった。 chat-Claude 指摘完全応答。
  3. Default windowMode='fetcher-window': effectiveWindow = min(oracleReturned, fetcherRetention)。 「fetcher retention < oracle window」を lag と誤診しない (設計 vs bug)。
  4. windowMode='fixed-window': fetcher retention 上限含む絶対 publisher-side loss を測る場合に。
  5. IDs は version-agnostic (vN suffix strip) で version bump を missing にしない。
  6. FLOWING = oracle unreachable OR oracle 0 返却。 fetcher 失敗の verdict ではない。
  7. ZERO = internal=0 で oracle>0 (dead pipeline) OR missingRatio > laggingMaxRatio。
  8. Ratio threshold (fresh=0 / aging=0.10 / lagging=0.50) は heuristic。 per-feed tuning は v0.3+。
  9. arXiv ToU ≥ 3s/call 遵守 (runner 3.5s)。 v0.2 は arXiv のみ、 Zenodo/HF/OpenAlex adapter は OracleWithIdList 実装で同 gauge に plug 可能。

Related