From bebf6e4ac7115325845b9c4dfb4548481911543e Mon Sep 17 00:00:00 2001 From: altair823 Date: Wed, 3 Jun 2026 13:40:02 +0000 Subject: [PATCH] =?UTF-8?q?docs(spec):=20ingest=20=EC=84=A4=EC=A0=95=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD=20=EC=9E=90=EB=8F=99=20=EC=9E=AC=EC=83=89?= =?UTF-8?q?=EC=9D=B8=20spec=20+=20plan?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 증분 skip 이 OCR/caption·청킹·코드 등 ingest 산출 영향 설정 변경을 못 잡아 재색인 안 되던 갭 일반화 수정. per-asset-type "ingest config signature" 를 effective parser_version 에 폴딩 → 영향 설정 변경 시 영향 자산만 자동 재색인. patch(0.26.2). Co-Authored-By: Claude Opus 4.8 (1M context) --- .../2026-06-03-config-invalidation-plan.md | 37 +++++++++++++ ...2026-06-03-ocr-toggle-invalidation-spec.md | 55 +++++++++++++++++++ 2 files changed, 92 insertions(+) create mode 100644 docs/superpowers/plans/2026-06-03-config-invalidation-plan.md create mode 100644 docs/superpowers/specs/2026-06-03-ocr-toggle-invalidation-spec.md diff --git a/docs/superpowers/plans/2026-06-03-config-invalidation-plan.md b/docs/superpowers/plans/2026-06-03-config-invalidation-plan.md new file mode 100644 index 0000000..c871431 --- /dev/null +++ b/docs/superpowers/plans/2026-06-03-config-invalidation-plan.md @@ -0,0 +1,37 @@ +# Plan: ingest 설정 변경 자동 재색인 구현 + +spec: `docs/superpowers/specs/2026-06-03-ocr-toggle-invalidation-spec.md`. 브랜치 `fix/ingest-config-invalidation`. 빌드 `CARGO_TARGET_DIR=/build/out/cargo-target`, **테스트 `-j 8`**(절대 `-j 1` 금지), cli 통합테스트용 `target` 심링크 후 정리. + +## Task 1 — ingest_config_signature 헬퍼 (kebab-app) +- `fn ingest_config_signature(config: &Config, media: &MediaType) -> String` 추가. +- 공통: `[chunking]` target_tokens, overlap_tokens, respect_markdown_headings, chunker_version. +- image: + image.ocr.enabled (+model if enabled) + image.caption.enabled (+prompt_template_version if enabled). +- pdf: + pdf.ocr.enabled (+model, always_on if enabled). +- code: + ingest.code.{skip_generated_header, max_file_bytes, max_file_lines, extra_skip_globs(join), ast_chunk_max_lines, fallback_lines_per_chunk, fallback_lines_overlap}. +- markdown: 공통만. +- 결정적(필드 순서 고정). 단위테스트: 같은 config→같은 서명, 관련 필드 변경→서명 변경, 무관 필드(search 등)→불변. + +## Task 2 — 4개 ingest 경로에 composite parser_version 적용 (kebab-app/lib.rs) +- md(~351), image(~1532), pdf(~2109), code 경로: `*_parser_version` = `ParserVersion(format!("{base}|{}", ingest_config_signature(config, media)))` (base = 각 extractor PARSER_VERSION). +- 이 composite 를 (1) `try_skip_unchanged` 의 `current_parser_version` 으로 전달, (2) **persist 전 `canonical.parser_version` override** 로 저장. 두 곳 동일 보장. +- doc_id 파생은 손대지 않음(workspace_path 조회). +- markdown/code/image/pdf 각 경로에서 동일 패턴 적용 — 누락 없게. + +## Task 3 — 테스트 +- image.ocr off→on, caption off→on: 재색인(skip 아님). off→off / 동일 설정: skip 유지. +- pdf.ocr off→on: 재색인. 동일: skip. +- chunking target_tokens 변경: 전 타입 재색인. 무변경: skip. +- ingest.code 변경: 코드 자산만 재색인. +- **search/rag/ui 변경: 재색인 0** (회귀 가드). +- 동일 config 재실행: 전 자산 skip (불필요 재색인 0). +- 기존 skip 테스트(markdown unchanged 등) 회귀 0. + +## Task 4 — 검증 + 문서 +- `cargo clippy --workspace --all-targets -j 8 -- -D warnings` 0. +- `cargo test -p kebab-app -p kebab-parse-image -p kebab-parse-pdf -p kebab-parse-code -p kebab-chunk -j 8` 통과(touched 크레이트 타깃; 전체 -j1 금지). +- 스모크: 이미지 ocr off 색인 → config ocr on → `kebab ingest`(force 없이) → 그 이미지 재색인 확인. +- tasks/HOTFIXES dated entry(일반화 + 업그레이드 1회 재색인 안내), Cargo.toml version **0.26.1 → 0.26.2**(+Cargo.lock), HANDOFF 1줄. README/wire 변화 없음. +- 결과 요약 `/tmp/cfginval-result.md`(게이트 + 스모크 캡처). + +## 리뷰 루프 +완료 → 리더 clippy/타깃테스트(-j8) 독립 재확인 + 토글 스모크 → `gitea-pr`(title `fix(ingest): ingest 설정 변경 시 영향 자산 자동 재색인`) → 리뷰 루프 → 사용자 머지. diff --git a/docs/superpowers/specs/2026-06-03-ocr-toggle-invalidation-spec.md b/docs/superpowers/specs/2026-06-03-ocr-toggle-invalidation-spec.md new file mode 100644 index 0000000..989562a --- /dev/null +++ b/docs/superpowers/specs/2026-06-03-ocr-toggle-invalidation-spec.md @@ -0,0 +1,55 @@ +# Spec: ingest 출력에 영향 주는 모든 설정 변경 시 자동 재색인 (skip 무효화 일반화) + +**날짜**: 2026-06-03 +**유형**: bug fix (patch) +**근거**: `[image.ocr]`/`[image.caption]` 를 off→색인→on 으로 바꿔도 증분 skip 이 이미지를 "Unchanged" 로 건너뛴다. 더 일반적으로, `try_skip_unchanged` 가 자산 내용(blake3)+`parser_version`+`chunker_version`+`embedding_version` 만 비교하는데, **ingest 산출물을 바꾸는 다른 설정들**(청킹 파라미터, OCR/caption, pdf.ocr, 코드 ingest 옵션)이 이 셋 중 어디에도 반영되지 않아 변경해도 재색인이 안 된다. 사용자 요구: **OCR/caption 뿐 아니라 ingest 출력에 영향 주는 모든 설정**이 같은 방식으로 동작(변경→영향 자산 자동 재색인). 결과 포맷·인터페이스·새 플래그 변화 없음(내부 skip 판정 정정) → **patch**. + +## 동작 사실 (코드 근거) +- `try_skip_unchanged`(lib.rs:866)는 `get_document_by_workspace_path` 로 기존 doc 조회 후 `existing_doc.parser_version != current_parser_version`(line 959) 면 재색인(cascade). **조회는 workspace_path** 이므로 doc_id 파생과 무관 — 비교는 저장된 `parser_version` 필드 대 현재값. +- 각 경로가 상수 parser_version 을 넘김: md `md-heading-v1`(351), image `image-meta-v1`(1532), pdf `pdf-text-v1`(2109), code 등. 청킹 파라미터(`target_tokens`/`overlap_tokens`/`respect_markdown_headings`)는 `chunker_version` 상수에 안 들어가 변경해도 재청킹 안 됨(동일 갭). + +## 설계: per-asset-type "ingest config signature" 를 effective parser_version 에 폴딩 + +`try_skip_unchanged` 에 넘기는 `current_parser_version` 과 **persist 되는 doc 의 `parser_version` 필드**를, 그 자산 타입의 **ingest 산출물에 영향을 주는 설정 전체의 결정적 서명**을 포함한 composite 로 만든다. 두 값이 같은 함수에서 나오므로, 관련 설정이 바뀌면 다음 run 비교가 mismatch → **영향 받는 자산만** 자동 재색인. doc_id 는 path 조회라 기존대로(안정, orphan churn 회피). + +### 어떤 설정이 어느 자산에 영향 (서명 구성) +공통 헬퍼 `ingest_config_signature(config, media_type) -> String`. **ingest 산출물에 영향 주는 것만** 포함(아래 외 search/rag/nli/ui/logging/storage/workspace 는 **제외** — 바뀌어도 재색인 안 함): + +- **공통(모든 타입)**: `[chunking]` target_tokens, overlap_tokens, respect_markdown_headings, chunker_version. (embedding model/dim 은 이미 `embedding_version` cascade 가 담당 — 서명에 중복 포함 불필요, 단 일관성 위해 포함해도 무방.) +- **image**: + `[image.ocr]` enabled (+enabled 면 model), `[image.caption]` enabled (+enabled 면 prompt_template_version). +- **pdf**: + `[pdf.ocr]` enabled (+enabled 면 model, always_on). +- **code**: + `[ingest.code]` skip_generated_header, max_file_bytes, max_file_lines, extra_skip_globs, ast_chunk_max_lines, fallback_lines_per_chunk, fallback_lines_overlap. +- **markdown**: 공통만. + +서명 형식: 결정적 문자열 또는 그 blake3-12. 예 `image-meta-v1|chunk:500:80:true|ocr:1:qwen2.5vl:3b|cap:1:caption-v1`. off/미적용 항목은 안정적 표현(빈값)으로 — 동일 설정 재실행은 서명 동일 → **불필요 재색인 0**. + +## 작업 (kebab-app) +1. `ingest_config_signature(config, media_type)` 헬퍼 추가(위 매핑). 출력 결정적(필드 순서 고정, Vec 는 join). +2. 각 ingest 경로에서 effective parser_version = `format!("{base}|{signature}")` 또는 base 를 서명으로 감싼 값으로: + - md(351), image(1532), pdf(2109), code 경로의 `*_parser_version` 계산을 composite 로. + - **persist 전 `canonical.parser_version` 을 동일 composite 로 override**(extractor 가 박은 상수 대신). skip-check 와 저장값이 같아야 함. +3. doc_id: 변경 불필요(workspace_path 조회). composite 는 비교 필드에만. + +## 동작 / 호환 +- ingest 영향 설정(청킹/OCR/caption/pdf.ocr/code) 변경 또는 모델·prompt 변경 → effective parser_version 변화 → **영향 자산만** `--force-reingest` 없이 자동 재색인(+UPSERT/purge). 비영향 설정(search/rag/ui/log) 변경 → 재색인 0. +- **업그레이드 1회 효과**: 기존 doc 의 저장 parser_version(상수)이 새 composite 와 달라 → 업그레이드 후 첫 ingest 에서 전 자산 1회 재색인(현재 설정대로). 마크다운/코드도 1회 재청킹되나 embedding 은 V012 캐시 히트라 재임베딩 비용 작음. (HOTFIXES/release notes 에 1회 재색인 명시.) +- `--force-reingest` 는 전체 강제용으로 그대로 유지. + +## 검증 기준 +- clippy 0. `cargo test -p kebab-app -p kebab-parse-image -p kebab-parse-pdf -p kebab-parse-code -p kebab-chunk -j 8` 통과 (**전체 워크스페이스 `-j 1` 금지 — `-j 8`**). +- 신규 테스트(자산 타입별): + - image.ocr off→on / caption off→on → 해당 이미지 재색인(skip 아님). off→off, on→on(동일) → skip 유지. + - pdf.ocr off→on → PDF 재색인. 동일 설정 → skip. + - chunking target_tokens 변경 → md/code/image/pdf 전부 재색인. 변경 없으면 skip. + - ingest.code 옵션 변경 → 코드 자산 재색인, 이미지/md 는 영향 받되 **공통(chunking) 변경 아니면 코드만** (code 전용 설정은 code 서명에만). + - search/rag/ui 설정 변경 → 재색인 0 (회귀 가드, 중요). + - 동일 config 재실행 → 전 자산 skip(불필요 재색인 0) — 회귀 가드. +- 스모크: 이미지 ocr off 색인 → config ocr on → `kebab ingest`(force 없이) → 그 이미지만 재색인 확인. + +## 비범위 +- 새 config 키/CLI 플래그/wire(없음). +- 서명에 max_pixels/languages/timeout 같은 *런타임 비-산출* 파라미터는 **제외**(산출물 불변 → 과도 무효화 회피). 포함 기준 = "그 값이 바뀌면 색인되는 chunk/embedding 내용이 달라지는가". +- search/rag/nli/ui/logging/storage/workspace 설정(ingest 산출 무관) 제외. + +## 문서/버전 +- tasks/HOTFIXES dated entry(일반화 + 1회 재색인 안내). Cargo.toml **patch bump (0.26.1 → 0.26.2)**(+Cargo.lock). README/wire 변화 없음. HANDOFF 1줄(선택).