feat(app): 임베딩 캐시 전면화 — image/pdf/code 를 embed_with_cache 경유로 #216

Merged
altair823 merged 6 commits from feat/embed-cache-handlers into main 2026-06-25 00:25:00 +00:00
Owner

요약

image/pdf/code 청크 임베딩을 markdown 이 이미 쓰는 embed_with_cache(content-hash derivation 캐시) 경유로 통일한다. 그동안 markdown 만 캐시를 타고 나머지 3 미디어는 직접 emb.embed 라, 재인덱싱 시 청크 텍스트가 byte-identical 이어도 매번 재임베딩했다. 이제 4 미디어 모두 동일 경로 — 출력은 byte-identical(fresh-dir=전부 miss=기존과 동일, 재인덱싱=캐시 히트로 동일 벡터 반환), 재인덱싱 비용만 줄어든다. 미디어 무관 version_key(doc|{model_id}|{model_version}|{dim})라 같은 텍스트는 미디어 교차로 한 엔트리를 공유한다.

설계: docs/superpowers/specs/2026-06-24-cache-everywhere-ocr-caption-design.md §2
계획: docs/superpowers/plans/2026-06-24-pr1-embed-cache-everywhere.md

변경

  • 3 핸들러 배선 (crates/kebab-app/src/ingest.rs): image/pdf/code 의 직접 emb.embed(&inputs) → markdown 패턴 verbatim embed_with_cache(&**emb, &app.sqlite, &body_texts, &emb_version_key, …) + upsert 직후 derivation_cache_touch. records/upsert 블록·version_key 는 무변경(byte-identical).
  • 관측성 대칭: 3 핸들러도 markdown 처럼 cache hit/miss 를 tracing::info! 로 노출 — 도그푸딩 시 4 미디어 전부에서 warm 재인덱싱이 embed 0 회인지 확인 가능.
  • 결정적 검증 테스트 (crates/kebab-app/tests/embed_cache_reingest.rs, AVX-gated #[ignore]): code asset 을 인덱싱 후 force_reingest 재인덱싱 → 임베딩 캐시 row 불변(순수 히트) + vector-search 결과 byte-identical. workspace 격리(clear_workspace)로 code 핸들러만 측정, faithful-break(직접 embed 복원) 시 실제 fail 확인.

검증

  • cargo clippy --workspace --all-targets -- -D warnings 0.
  • 검증 테스트 green: cold/warm 재인덱싱 임베딩 row 2/2 불변, 2 hit byte-identical. (cargo test -p kebab-app --test embed_cache_reingest -- --ignored)
  • byte-identical: records/upsert diff-proven 동일, version_key 4 미디어 char-동일, embed_with_cache/derivation_payload 무수정.
  • markdown 패리티 게이트는 markdown 무수정이라 trivially IDENTICAL.

비범위 / 후속

  • OCR/caption 중간 산출물 캐시(설계 §3)는 PR2 로 분리(별도 계획).
  • 버전 bump 없음 — 관측성/성능만, 인터페이스·출력 불변이라 patch 이며 release/정리 단계에서 처리.
  • (optional) 테스트 hardening: 인덱싱 doc 수 == 1 단언. 비차단.

Assisted-by: Claude Code

## 요약 image/pdf/code 청크 임베딩을 markdown 이 이미 쓰는 `embed_with_cache`(content-hash derivation 캐시) 경유로 통일한다. 그동안 markdown 만 캐시를 타고 나머지 3 미디어는 직접 `emb.embed` 라, 재인덱싱 시 청크 텍스트가 byte-identical 이어도 매번 재임베딩했다. 이제 4 미디어 모두 동일 경로 — **출력은 byte-identical**(fresh-dir=전부 miss=기존과 동일, 재인덱싱=캐시 히트로 동일 벡터 반환), 재인덱싱 비용만 줄어든다. 미디어 무관 version_key(`doc|{model_id}|{model_version}|{dim}`)라 같은 텍스트는 미디어 교차로 한 엔트리를 공유한다. 설계: docs/superpowers/specs/2026-06-24-cache-everywhere-ocr-caption-design.md §2 계획: docs/superpowers/plans/2026-06-24-pr1-embed-cache-everywhere.md ## 변경 - **3 핸들러 배선** (`crates/kebab-app/src/ingest.rs`): image/pdf/code 의 직접 `emb.embed(&inputs)` → markdown 패턴 verbatim `embed_with_cache(&**emb, &app.sqlite, &body_texts, &emb_version_key, …)` + upsert 직후 `derivation_cache_touch`. `records`/`upsert` 블록·version_key 는 무변경(byte-identical). - **관측성 대칭**: 3 핸들러도 markdown 처럼 cache hit/miss 를 `tracing::info!` 로 노출 — 도그푸딩 시 4 미디어 전부에서 warm 재인덱싱이 embed 0 회인지 확인 가능. - **결정적 검증 테스트** (`crates/kebab-app/tests/embed_cache_reingest.rs`, AVX-gated `#[ignore]`): code asset 을 인덱싱 후 `force_reingest` 재인덱싱 → 임베딩 캐시 row 불변(순수 히트) + vector-search 결과 byte-identical. workspace 격리(`clear_workspace`)로 code 핸들러만 측정, faithful-break(직접 embed 복원) 시 실제 fail 확인. ## 검증 - `cargo clippy --workspace --all-targets -- -D warnings` 0. - 검증 테스트 green: cold/warm 재인덱싱 임베딩 row 2/2 불변, 2 hit byte-identical. (`cargo test -p kebab-app --test embed_cache_reingest -- --ignored`) - byte-identical: records/upsert diff-proven 동일, version_key 4 미디어 char-동일, `embed_with_cache`/`derivation_payload` 무수정. - markdown 패리티 게이트는 markdown 무수정이라 trivially IDENTICAL. ## 비범위 / 후속 - OCR/caption 중간 산출물 캐시(설계 §3)는 **PR2** 로 분리(별도 계획). - 버전 bump 없음 — 관측성/성능만, 인터페이스·출력 불변이라 **patch** 이며 release/정리 단계에서 처리. - (optional) 테스트 hardening: 인덱싱 doc 수 == 1 단언. 비차단. Assisted-by: Claude Code
altair823 added 5 commits 2026-06-24 23:50:52 +00:00
(a) embed_with_cache 를 image/pdf/code 핸들러에 배선(markdown 전용→전미디어) — PR1.
(b) ocr/caption derivation_cache 네임스페이스로 OCR/caption 중간 산출물 캐싱 —
    버전-캐스케이드 분리 + ollama-vision 비결정성 박제 — PR2.

리서치로 해소: provenance 는 wire/게이트에 없어 캐시 히트 시 재현 불필요(byte-identical
유지) · payload 는 full 구조체 serde(block 레벨까지 byte-identical) · derivation_cache_key_bytes
신설 · paddle ONNX 자산은 이미 레포 번들(다운로드 불필요) → 결정적 게이트 가능.
열린 항목: paddle 게이트용 text-bearing OCR 코퍼스 생성(R2, plan 에서 해소).
claude-reviewer-01 requested changes 2026-06-24 23:52:03 +00:00
Dismissed
claude-reviewer-01 left a comment
Member

회차 1 — subagent-driven 개발로 task 리뷰 2회 + whole-branch 최종 리뷰를 이미 거쳤고(전부 APPROVE/READY), 그 검증 사실 + 잔여 actionable 1건. REQUEST_CHANGES(actionable nit 1건 — 반영 후 APPROVE).

검증 완료 (재확인)

  • byte-identical (hard gate): image/pdf/code 의 records(VectorRecord 필드맵)·vec_store.upsert 가 pre-PR 대비 diff-proven 동일. version_key doc|{model_id}|{model_version}|{dim} 4 미디어 char-동일(미디어 무관 → 교차 캐시 재사용). embed_with_cache/derivation_payload 무수정. 청크 텍스트·순서 보존.
  • derivation_cache_touch 위치: upsert 직후·? 뒤 → 실패한 upsert 는 키를 used 로 안 찍음(LRU 정합).
  • 관측성 커밋(ff4f9b7): 로깅-only(카운터 hoist + tracing::info), 로직 무변경.
  • 검증 테스트 유효성: clear_workspace 로 markdown fixture 제거 → code 핸들러만 측정(없으면 markdown 이 공유 cache 채워 false-green). fusion_score.to_bits() 결정적 비교. force_reingest 가 skip 우회 → 재임베딩 경로 실제 실행. faithful-break(직접 embed 복원) 시 실제 fail 확인. 3중 어설션(rows>0 / rows 불변 / hits byte-identical) 약화 없음.
  • clippy --workspace --all-targets 0.

Actionable (nit, 반영 요청)

[nit] 테스트가 clear_workspace 격리에만 의존 — 인덱싱 자산 수를 단언하지 않음.
crates/kebab-app/tests/embed_cache_reingest.rs:49-50. embedding_cache_rows 는 모든 kind='embedding' row 를 센다. 지금은 clear_workspacesample.rs 단일 자산을 보장해 정확하지만, 미래에 TestEnv::with_embeddings()/fixture 가 비-markdown 자산을 추가하면 격리가 조용히 침식된다. 첫 인덱싱 리포트에 report.new == 1 단언을 더해, 격리 가정이 깨지면 loud fail 하도록 하자. (cheap, byte-neutral.)

비-actionable (유지)

  • 3 핸들러의 hit/miss 주석 4× 중복 → markdown 과 의도적 대칭이라 유지.
  • if hit+miss>0 가드 redundancy → markdown 패턴과 동일, 유지.
회차 1 — subagent-driven 개발로 task 리뷰 2회 + whole-branch 최종 리뷰를 이미 거쳤고(전부 APPROVE/READY), 그 검증 사실 + 잔여 actionable 1건. **REQUEST_CHANGES**(actionable nit 1건 — 반영 후 APPROVE). ## 검증 완료 (재확인) - **byte-identical (hard gate)**: image/pdf/code 의 `records`(VectorRecord 필드맵)·`vec_store.upsert` 가 pre-PR 대비 **diff-proven 동일**. version_key `doc|{model_id}|{model_version}|{dim}` 4 미디어 char-동일(미디어 무관 → 교차 캐시 재사용). `embed_with_cache`/`derivation_payload` 무수정. 청크 텍스트·순서 보존. - **`derivation_cache_touch` 위치**: upsert 직후·`?` 뒤 → 실패한 upsert 는 키를 used 로 안 찍음(LRU 정합). - **관측성 커밋(ff4f9b7)**: 로깅-only(카운터 hoist + tracing::info), 로직 무변경. - **검증 테스트 유효성**: `clear_workspace` 로 markdown fixture 제거 → code 핸들러만 측정(없으면 markdown 이 공유 cache 채워 false-green). `fusion_score.to_bits()` 결정적 비교. `force_reingest` 가 skip 우회 → 재임베딩 경로 실제 실행. faithful-break(직접 embed 복원) 시 실제 fail 확인. 3중 어설션(rows>0 / rows 불변 / hits byte-identical) 약화 없음. - clippy `--workspace --all-targets` 0. ## Actionable (nit, 반영 요청) **[nit] 테스트가 `clear_workspace` 격리에만 의존 — 인덱싱 자산 수를 단언하지 않음.** `crates/kebab-app/tests/embed_cache_reingest.rs:49-50`. `embedding_cache_rows` 는 모든 `kind='embedding'` row 를 센다. 지금은 `clear_workspace` 가 `sample.rs` 단일 자산을 보장해 정확하지만, 미래에 `TestEnv::with_embeddings()`/fixture 가 비-markdown 자산을 추가하면 격리가 조용히 침식된다. 첫 인덱싱 리포트에 `report.new == 1` 단언을 더해, 격리 가정이 깨지면 loud fail 하도록 하자. (cheap, byte-neutral.) ## 비-actionable (유지) - 3 핸들러의 hit/miss 주석 4× 중복 → markdown 과 의도적 대칭이라 유지. - `if hit+miss>0` 가드 redundancy → markdown 패턴과 동일, 유지.
altair823 added 1 commit 2026-06-24 23:53:44 +00:00
claude-reviewer-01 approved these changes 2026-06-24 23:53:56 +00:00
claude-reviewer-01 left a comment
Member

회차 2 — 회차 1 actionable nit 반영 확인. APPROVE.

  • 단일-자산 격리 단언 추가(ec2ee25): 첫 인덱싱 리포트에 report.new == 1 단언 → 미래 fixture/with_embeddings 변경으로 비-markdown 자산이 끼어들면 loud fail. clear_workspace 격리 가정을 명시적으로 잠금.
  • 검증: 컴파일 0, --ignored 테스트 green(39s warm — rows 2/2 불변, hits byte-identical, report.new==1 통과).

머지 차단 0건. byte-identical(diff-proven) + 테스트 유효성(회귀 핀, false-green 아님) 모두 확인. APPROVE.

회차 2 — 회차 1 actionable nit 반영 확인. **APPROVE.** - 단일-자산 격리 단언 추가(`ec2ee25`): 첫 인덱싱 리포트에 `report.new == 1` 단언 → 미래 fixture/with_embeddings 변경으로 비-markdown 자산이 끼어들면 loud fail. `clear_workspace` 격리 가정을 명시적으로 잠금. - 검증: 컴파일 0, `--ignored` 테스트 green(39s warm — rows 2/2 불변, hits byte-identical, report.new==1 통과). 머지 차단 0건. byte-identical(diff-proven) + 테스트 유효성(회귀 핀, false-green 아님) 모두 확인. APPROVE.
altair823 merged commit 3d9715b623 into main 2026-06-25 00:25:00 +00:00
altair823 deleted branch feat/embed-cache-handlers 2026-06-25 00:25:01 +00:00
Sign in to join this conversation.
No Reviewers
No Label
2 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: altair823-org/kebab#216