Parent: #612
Depends on: #615
背景
既存のDrizzle migrationはLanceDBを読めず、extract-ccip-batch.ts は全件再推論であってデータ移行scriptではない。既存embeddingを再計算せず、欠損・重複・検索結果の変化を検証しながらPostgreSQLへ移す専用backfill/cutoverが必要。
スコープ
- LanceDB
media_ccip をpage/batch単位で読むapplication migration script
- 768次元、UUID、media FK、model/version、timestampの検証
--dry-run、batch size、source filter、再開、冪等upsert
- 件数・media ID差分・model/version内訳・orphanの検証report
- サンプルanchorのcosine値と最終top-K/reranking比較
- 最終差分同期、read backend切替、rollback手順
- 検証期間中はLanceDBをread-only backupとして保持する
非スコープ
- source dump/export用LanceDB cacheの撤去
- CCIP再推論
- crop embeddingの生成
受け入れ条件
主な参照
apps/server/src/infrastructure/ai/lancedb-ccip-vector-store.ts:11
apps/server/scripts/extract-ccip-batch.ts:103
apps/server/scripts/optimize-ccip-lancedb.ts:5
packages/application/src/services/lancedb-dump-service.ts:351
packages/core/src/domain/config/config-schema.ts:154
評価反映(2026-07-18)
以下を移行・cutoverの追加必須条件とする。
事前データ監査
2026-07-18時点のCCIP用LanceDBには次の状態が確認された。
- raw rows: 62
- unique media IDs: 46
- duplicate groups: 16
現時点の重複はvector、model、version、source、media revisionが一致し、主にextracted_atだけが異なる。実行時にも再集計し、reportへrawRows、uniqueLogicalRows、collapsedDuplicatesを必ず記録する。
重複keyは(mediaId, model, embeddingVersion)とする。同一keyの内容が一致する場合だけ最新のextracted_atを採用してcollapseし、vectorまたは入力metadataが競合する場合は自動選択せず移行を失敗させる。orphan、不正UUID、不正次元も黙ってskipしない。
再開可能なbackfill
LanceDBの現在のlist()順序には依存しない。移行元snapshotのfingerprintと、決定的にsortされたkeyに基づくcheckpointを保存し、入力snapshotが変わった場合は古いcheckpointで再開しない。
backfillは次の順で冪等に実行する。
- 対象mediaの唯一の
kind=full regionを確保する
(region_id, model, embedding_version)でembeddingをupsertする
- checkpointと件数・差分reportを更新する
dry-run
--dry-runはPostgresだけでなくLanceDBも一切変更しない。openOrCreateTable、index作成、schema更新など副作用を伴う経路を使用せず、真にread-onlyなreaderまたは検証用snapshotを使用する。実行前後のLanceDB file manifestを比較し、変更がないことを自動確認する。
Cutoverとrollback
「cutover後はPostgresだけへwriteする」と「静的なLanceDBへrollbackできる」は両立しないため、本Issueでは次のrollback windowを採用する。
- LanceDBを正本としたままinitial backfillを行う
- new/update/deleteを単一service経由でPostgresとCCIP用LanceDBへdual-writeする
- final deltaを適用してparityを確認する
- read backendをPostgresへ切り替える
- rollback観測期間中はdual-writeを継続する
- 観測期間終了後にLanceDB writeを停止し、以後はLanceDB rollbackを保証しない
rollback期間中は両方への永続化が確認できないwriteを正常完了扱いにせず、失敗または再調整対象として記録する。LanceDBへreadを戻せるのはdual-write completenessが成立している期間だけとする。dual-writeを採用できない場合は、代替としてCCIP writeをfreezeしたcutoverを明示的に選び、rollback可能期間中はfreezeを解除しない。
Parity判定
現在の論理46件については全件をanchorにできるため、代表サンプルだけでなく全論理recordを検証する。
- 重複collapse後のID/key集合が完全一致する
- model/version/input revisionが完全一致する
- cosine値の絶対差を
1e-6以下とする
- top-Kのmedia集合と順序を一致させる。ただし差が
1e-6以内の同点候補は同一tie groupとして扱う
- Rust再ranking後のmedia集合・順序・distanceが同じ規則で一致する
- 不一致、orphan、collapse、skip件数を機械可読reportへ出力する
追加受け入れ条件
Parent: #612
Depends on: #615
背景
既存のDrizzle migrationはLanceDBを読めず、
extract-ccip-batch.tsは全件再推論であってデータ移行scriptではない。既存embeddingを再計算せず、欠損・重複・検索結果の変化を検証しながらPostgreSQLへ移す専用backfill/cutoverが必要。スコープ
media_ccipをpage/batch単位で読むapplication migration script--dry-run、batch size、source filter、再開、冪等upsert非スコープ
受け入れ条件
主な参照
apps/server/src/infrastructure/ai/lancedb-ccip-vector-store.ts:11apps/server/scripts/extract-ccip-batch.ts:103apps/server/scripts/optimize-ccip-lancedb.ts:5packages/application/src/services/lancedb-dump-service.ts:351packages/core/src/domain/config/config-schema.ts:154評価反映(2026-07-18)
以下を移行・cutoverの追加必須条件とする。
事前データ監査
2026-07-18時点のCCIP用LanceDBには次の状態が確認された。
現時点の重複はvector、model、version、source、media revisionが一致し、主に
extracted_atだけが異なる。実行時にも再集計し、reportへrawRows、uniqueLogicalRows、collapsedDuplicatesを必ず記録する。重複keyは
(mediaId, model, embeddingVersion)とする。同一keyの内容が一致する場合だけ最新のextracted_atを採用してcollapseし、vectorまたは入力metadataが競合する場合は自動選択せず移行を失敗させる。orphan、不正UUID、不正次元も黙ってskipしない。再開可能なbackfill
LanceDBの現在の
list()順序には依存しない。移行元snapshotのfingerprintと、決定的にsortされたkeyに基づくcheckpointを保存し、入力snapshotが変わった場合は古いcheckpointで再開しない。backfillは次の順で冪等に実行する。
kind=fullregionを確保する(region_id, model, embedding_version)でembeddingをupsertするdry-run
--dry-runはPostgresだけでなくLanceDBも一切変更しない。openOrCreateTable、index作成、schema更新など副作用を伴う経路を使用せず、真にread-onlyなreaderまたは検証用snapshotを使用する。実行前後のLanceDB file manifestを比較し、変更がないことを自動確認する。Cutoverとrollback
「cutover後はPostgresだけへwriteする」と「静的なLanceDBへrollbackできる」は両立しないため、本Issueでは次のrollback windowを採用する。
rollback期間中は両方への永続化が確認できないwriteを正常完了扱いにせず、失敗または再調整対象として記録する。LanceDBへreadを戻せるのはdual-write completenessが成立している期間だけとする。dual-writeを採用できない場合は、代替としてCCIP writeをfreezeしたcutoverを明示的に選び、rollback可能期間中はfreezeを解除しない。
Parity判定
現在の論理46件については全件をanchorにできるため、代表サンプルだけでなく全論理recordを検証する。
1e-6以下とする1e-6以内の同点候補は同一tie groupとして扱う追加受け入れ条件