perf(registry): throttle the auto-embed ticker's width probe (#677 item 2) - #688
Conversation
…em 2) A busy, gloss-stable context paid one provider round trip (the width probe that guards against a silent backend swap under an unchanged model name) on every 5s flush tick, forever — refresh_embeddings and refresh_passage_embeddings both run per dirty context per tick, and a context whose writes never touch its top-N gloss facts stays a no-op refresh indefinitely. The provider's output width is its own property, not any one context's, so a process-wide "most recently observed width" (Inner:: observed_embed_width, recorded at timed_embed_for_refresh's one choke point) lets a refresh skip its own probe once a recent-enough observation already agrees with what it carries (provider_width_recently_confirmed, WIDTH_OBSERVATION_TRUST = 60s). The throttle is scoped to two new ticker-only entry points (auto_refresh_embeddings/auto_refresh_passage_embeddings) that main.rs's flusher calls instead. The existing public refresh_embeddings/ refresh_passage_embeddings — used by the HTTP refresh endpoint and every direct caller — are untouched and keep probing unconditionally, so an explicit refresh still reliably detects and heals a width change in one call, the contract tests/http_api/width_probe.rs pins. Item 3 (no TTL quarantine on vector-sidecar load failures) stays out of scope — the issue itself frames it as unverified real-world impact, not a known defect — so #677 stays open with that item. Refs #677 Claude-Session: https://claude.ai/code/session_0198T2iKZ17g3tt2bdNq1ju8
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (6)
Included review availability: 1 review is currently available. Based on recent review activity, included reviews refill at 2 per hour. 📝 WalkthroughWalkthrough自動埋め込み更新に専用メソッドを追加しました。直近のプロバイダー幅観測を共有し、信頼期間内の幅プローブを省略します。明示更新は従来どおり毎回プローブします。関連するグロス、パッセージ、幅変更のテストを追加しました。 Changes埋め込み自動更新
Estimated code review effort: 3 (Moderate) | ~20 minutes Merge Risk: ⚪ Minimal · up to The change reduces redundant provider width probes during automatic refreshes while preserving immediate probing for explicit refresh requests; no actionable merge-blocking risk remains after normal checks and review. Sequence Diagram(s)sequenceDiagram
participant Flush
participant Registry
participant Provider
Flush->>Registry: auto_refresh_embeddings または auto_refresh_passage_embeddings
alt 幅観測が60秒以内で保持幅と一致
Registry->>Registry: 幅プローブを省略
else 観測なしまたは期限切れ
Registry->>Provider: 幅プローブを実行
Provider-->>Registry: 埋め込みベクトル幅
Registry->>Registry: 観測幅と時刻を共有
end
Registry->>Provider: 必要な項目を自動埋め込み
Possibly related PRs
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
Summary
#677(#535監査由来、#682/PR #682で項目1完了済み)の項目2。refresh_embeddings/refresh_passage_embeddingsは、そのパスで1件も再embedしなかったとき「モデル名据え置きのままproviderの出力幅が変わった(backend swap)」を見逃さないため、width probeを1件だけ余分にproviderへ投げる。この関数はrun_flush_tick(main.rs、既定5秒間隔)からdirtyなcontext単位で毎tick呼ばれるため、書き込みは続くがgloss本文(name+上位GLOSS_FACTS件のfact)は動かない、という成熟したcontextで最も普通の状態で、probe呼び出しが無期限に積み上がっていた。やったこと: providerの出力幅はcontextごとの性質ではなくprovider自身の性質、という事実を使ってprobeを間引いた。
Inner::observed_embed_width: プロセス全体で共有する「直近に実際に観測したproviderの幅」。記録はtimed_embed_for_refresh(refresh系のembed呼び出しが全て通る唯一のチョークポイント)の1箇所のみ。provider_width_recently_confirmed: 観測が新しく(WIDTH_OBSERVATION_TRUST=60秒)、かつcarried幅と一致するかどうかの判定。LOAD_FAILURE_RETRY/still_quarantinedと同じ形。auto_refresh_embeddings/auto_refresh_passage_embeddings、main.rsのフラッシャーが呼ぶ)にのみ適用。既存の公開refresh_embeddings/refresh_passage_embeddings(HTTPリフレッシュエンドポイント、および全ての直接呼び出し)は変更なしで常にprobeする。なぜスコープを分けたか: 当初は公開関数自体を無条件でスロットルしたが、
tests/http_api/width_probe.rsのE2Eテスト(「1回のリフレッシュで検知・修復まで完了する」契約)がすぐに落ちた。60秒のtrust windowの間に明示的なリフレッシュ呼び出しが来ると、直前の(スワップ前の)観測を信頼してprobeをスキップしてしまい、まさに検知させたいbackend swapを見逃す。オペレーターが「なぜ検索が動かないか」を診断してリフレッシュを叩く操作は稀かつ意図的で、そこでの1回余分なprovider呼び出しは無視できるコストである一方、「1回のリフレッシュで確実に直る」という契約はそちらでこそ重要。issue自体もコストの発生源としてmain.rsのティッカー呼び出しを名指ししており(自動リフレッシュのみが問題)、このスコープ分けは issue の記述にも整合する。項目3(vector sidecarにTTL検疫が無い件)は、issue本文自ら「疑い、実害未検証」としており、実インシデントか実測が出るまで対象外(ユーザー判断)。
#677はこの項目を残してOPENのまま。Test plan
cargo fmtcargo clippy --all-targets --locked -- -D warningscargo nextest run --locked(3852 passed、width_probe.rsのE2E契約含む)cargo test --doc --locked--exclude-reは使わずローカルで全件実行) — 34 caught, 7 unviable, missed 0件Refs #677
https://claude.ai/code/session_0198T2iKZ17g3tt2bdNq1ju8
Summary by CodeRabbit
改善
バグ修正