• altair823 released this 2026-08-16 21:23:27 +00:00 | 0 commits to main since this release

    v0.33.0 — 28.4k 문서 도그푸딩이 드러낸 다섯 결함

    v0.32.0 이후 실제 코퍼스(나무위키 18,282 + Apache Jira 10,146 = 28,427 문서 / 600,808 청크)로 도그푸딩하면서 등록한 이슈 #228~#232 를 전부 처리한 릴리스. 다섯 건 모두 단위 테스트가 잡지 못하는 종류였다 — 규모에서만 드러나는 성능 붕괴, 조용히 사라지는 내용, 멈춘 것처럼 보이는 진행 표시.

    minor bump 트리거는 두 가지다. #232parser_version cascade(pdf-text-v1pdf-text-v2, 기존 색인 PDF 재처리 유발)와 신규 config 키([ingest.pdf.ocr] render_library / render_dpi). 나머지 셋은 additive wire 변경 + 관측성 개선이라 자체로는 patch 급이다.

    실측 evidence 는 전부 tasks/HOTFIXES.md 의 2026-08-16 / 2026-08-17 dated entry 에 있다.


    1. 스캔 PDF 가 인코딩에 따라 통째로 버려지던 문제 (#232) — minor

    변경 사실. 스캔 페이지를 래스터화하는 방식이 "페이지에 박힌 JPEG 을 그대로 꺼내기" 에서 "페이지를 렌더링하기" 로 바뀌었다. 예전에는 /Filter정확히 DCTDecode 인 이미지 하나뿐인 페이지만 OCR 됐다. 실제 스캔본에서 흔한 CCITTFaxDecode·JBIG2Decode·FlateDecode·JPXDecode, 필터 체인, 그리고 "배경 + 마스크" 로 나뉜 구조는 전부 걸러졌다.

    걸러진 페이지는 조용히 사라졌다. 색인은 "성공" 으로 끝나고, 검색이 안 되는 시점에야 알게 되며, 그때 원인이 PDF 인코더라는 걸 역추적할 방법이 없었다.

    trade-off. 렌더러(pdfium)는 공유 라이브러리로만 배포되고 정적 빌드가 없다. 바이너리에 넣으면 kebab 의 단일 실행 파일 성질이 깨지므로 런타임에 찾아 쓰는 방식으로 붙였다. 즉 스캔본 커버리지가 환경에 따라 달라진다 — 라이브러리가 있으면 전부, 없으면 예전과 같이 DCTDecode 페이지만 처리한다.

    mitigation. 없을 때 조용히 넘어가지 않는다.

    • 페이지마다 이유를 찍는다: ⊘ OCR page 5 건너뜀 — 래스터 없음 — 이 페이지의 인코딩은 페이지 렌더러 없이 읽을 수 없다
    • run 요약에 건수가 나온다: scanned 1 new 1 … ocr-skipped 1
    • --jsoningest_report.ocr_skipped_pagespdf_ocr_finished.failure_reason (no_renderer / render_error / unopenable_pdf / ocr_error)
    • kebab doctorpdf_render 가 지금 어느 쪽인지 보고한다

    upgrade 절차. 스캔 PDF 를 쓰지 않으면 할 일이 없다. 쓴다면:

    1. libpdfium 을 로더가 찾는 곳에 두거나 [ingest.pdf.ocr] render_library = "/경로/libpdfium.so" 로 지정한다. 공개 빌드는 bblanchon/pdfium-binaries 에 있고 리눅스 x64 기준 7.4 MB 다.
    2. kebab doctorpdf_render 가 경로를 보고하는지 확인한다.
    3. 재색인은 자동이다. parser_versionpdf-text-v2 로 올라가서 다음 kebab ingest 가 기존 PDF 를 다시 처리한다 — --force-reingest 를 떠올릴 필요가 없다.

    해상도 노브. render_dpi (기본 300) 가 렌더 해상도 요청이고, max_pixels 가 실제 상한이다. PDF 기본값 max_pixels = 2048 이면 A4 는 175 DPI 언저리에서 잘린다. 더 선명하게 읽히고 싶으면 max_pixels 를 올려야 하는데(A4 300 DPI 는 약 3500), 그만큼 큰 이미지를 OCR 엔진이 받는다. 엔진 자체도 256~4096 으로 다시 조인다.

    도그푸딩. 정답 텍스트를 아는 한국어 스캔 합성 픽스처(CCITT 3건, 22쪽)를 config 기본 모델 qwen2.5vl:3b 로 읽혔다.

    문서 페이지 문자 오류율
    브렌다(메이즈 러너 시리즈) 8 15.65%
    비행대 스토리 8 12.55%
    구 아놀리엔 6 15.08%

    22쪽 전부 OCR 성공, 건너뜀 0. 이 릴리스 이전에는 세 문서 모두 본문이 0자였으므로 비교 대상 오류율은 100% 다.

    엔진 선택 주의. 범용 멀티모달 모델은 OCR 엔진이 아니다. 같은 픽스처를 gemma3:4b 로 읽혔더니 래스터는 정상인데 출력이 원문과 무관한 환각이었고("이 문서에 스무어라가 포함되어 있습니다"), 해상도가 올라가자 밀집 한국어 페이지에서 180초 타임아웃까지 났다. config 기본값이 qwen2.5vl:3b 인 이유가 이것이다.


    2. 어휘 인덱스 삭제가 코퍼스 전체 스캔이던 문제 (#229) — patch (동작 불변)

    변경 사실. chunks_fts 의 삭제 트리거가 행을 찾는 기준이 chunk_id 에서 rowid 로 바뀌었다 (마이그레이션 V016, 자동).

    chunk_id 는 FTS5 에서 색인되지 않는 컬럼이라 조건을 만족할 색인이 없었고, 청크 한 건 삭제가 인덱스 전체를 훑었다. 문서 삭제·수정 등 chunk 를 지우는 모든 경로가 이 비용을 냈고, 코퍼스가 커질수록 증분 재색인이 느려지는 형태였다.

    trade-off. 없다. 컬럼 구성과 토크나이저가 그대로라 검색 결과가 바뀌지 않는다. 실제 KB 에서 네 질의의 상위 20건을 점수와 스니펫까지 해시로 비교했고 마이그레이션 전후가 동일했다.

    mitigation / upgrade. 다음 실행 때 자동 적용된다. 60만 청크 기준 32초가 걸리고 재색인은 필요 없다chunks 와 임베딩은 손대지 않는다.

    도그푸딩. 문서 28,427건 / 청크 600,808개 KB 에서 문서 200건 삭제:

    소요
    이전 1,590초
    이후 2.0초

    약 800배다.


    3. LanceDB 메타데이터가 제곱으로 불어나던 문제 (#230) — patch (동작 불변)

    변경 사실. 벡터 스토어에 압축 정책이 생겼고, 삭제가 파일 단위에서 배치 단위로 바뀌었다.

    압축이 없던 동안 매 쓰기가 fragment 와 "지금까지의 모든 fragment 를 나열한" manifest 를 남겼고, 메타데이터가 실데이터보다 빠르게 커졌다. 문서 1.1만 건에서 2.5배였던 비율이 1.7만 건에서 7.2배였다.

    trade-off. 압축이 도는 순간에는 I/O 를 쓴다. 실측으로 15 GB 를 1.7 GB 로 되돌리는 데 153초였다.

    mitigation / upgrade. 자동이다. 별도 조치가 없다.

    도그푸딩. 2.8만 문서를 넣는 동안 색인 속도가 분당 32~36건으로 평평하게 유지됐다. 이전에는 30.7건에서 4.3건까지 단조롭게 떨어졌다. LanceDB 크기는 문서가 1.7배 늘었는데도 15 GB 에서 2.8 GB 로 줄었다. 문서 364건 삭제가 만드는 커밋은 364회에서 33회가 됐다.

    kebab doctorvector_store 정보성 체크가 생겨 fragment·���전 수를 보여준다(종료 코드 영향 없음).


    4. 삭제 구간이 멈춘 것처럼 보이던 문제 (#228) — patch (관측성)

    변경 사실. 파일이 지워진 문서를 정리하는 구간(sweep)이 진행 표시와 로그에 나온다.

    이 구간은 신호를 하나도 내지 않았다. 진행바는 색인 총계를 표시한 채 멈춰 보이고 ndjson 로그는 0바이트로 남았다. 프로세스는 정상 동작 중인데 밖에서는 hang 과 구별할 수 없었고, 실제로 세 번 연속 Ctrl-C 로 죽인 기록이 이슈에 남아 있다.

    trade-off. 없다. --json 에 이벤트 세 종(sweep_started / sweep_progress / sweep_completed)과 ndjson 로그에 세 종(purge / purge_failed / sweep_summary)이 추가된다. 기존 소비자는 모르는 종류를 무시하므로 영향이 없다.

    mitigation / upgrade. 자동이다.

    곁들여, sweep 이 취소 플래그를 보게 했다. 첫 Ctrl-C 가 "현재 파일까지만 하고 중단한다" 고 안내하는데 이 구간에서는 사실이 아니었다 — 유일한 수단인 두 번째 Ctrl-C 는 강제 종료라 버퍼에 쌓인 삭제가 고아로 남았다. 스캔 결과가 0건일 때 취소가 "완료" 로 보고되던 것도 함께 고쳤다.


    5. 임베딩 캐시 (#231) — patch, 그리고 가설이 재현되지 않았다

    이슈는 "캐시가 히트하는데도 우회하고 전량 재임베딩하는 편이 더 빠르다" 고 보고하면서 실측 표를 비워 뒀다. 그 표를 채웠는데 재현되지 않는다.

    문서 792건 / 청크 16,379개를 강제 재처리한 결과, 캐시 히트 경로가 139초, 캐시 우회가 1,180초로 히트가 8.5배 빠르다. 새로 넣은 계측으로 뜯어보면 캐시 경로 전체가 run 의 1.5% 이하다.

    다만 보고가 틀렸다고 단정하지 않는다. 보고 이후 #229#230 이 머지됐고, 이슈 본문 스스로 #229 와 같은 뮤텍스를 공유해 서로를 증폭한다고 적어 뒀다. 그러니 "#229 이후에는 재현되지 않는다" 로 읽는 것이 맞다.

    변경 사실. 캐시 조회를 배치로 접고(문서당 왕복 21회 → 1회), 삽입을 한 트랜잭션으로 묶고, 구문 캐시를 쓴다. 다만 벽시계 차이는 측정 오차 안이다 — 이 코퍼스에서는 체감이 없다.

    실질적인 산출물은 계측 쪽이다. --jsonasset_timingscache_hit / cache_miss / cache_ms 가 실린다. 이전에는 stderr 로만 흘러 run 이 끝나면 사라졌고, "내 코퍼스에서 캐시가 이득인가" 를 확인할 방법이 없었다. TTY 에서는 ⏱ … embed 75ms · cache 21/21 0ms · store 36ms 로 보인다.

    trade-off / upgrade. 없다. 자동이다.


    그 밖

    • cargo clippy --workspace --all-targets -- -D warnings 가 main 에서 실패하고 있었다(툴체인 상승으로 새 lint 두 개가 기존 코드에 걸림). 고쳤다. 방치하면 새 위반이 그 그늘에 숨는다는 것을 실제로 겪었다.
    • kebab doctor 에 체크 세 개가 추가됐다: pdf_render(정보성), vector_store(정보성), fts_shadow(어긋나면 exit 3 — 이 상태에서는 문서 삭제가 엉뚱한 인덱스 행을 지운다).
    Downloads
  • altair823 released this 2026-06-27 03:33:44 +00:00 | 44 commits to main since this release

    ponytail-audit over-engineering 정리 arc (#219–#222). 능력(검색·청킹·RAG) 불변, 표면·구조·crate 수만 단순화.

    • #219 죽은 search-cache scaffold 제거 — search() byte-identical, kebab search --no-cache/--explain 플래그 + [rag] explain_default config 키 제거 (ask --explain/search --trace 는 live).
    • #220 9개 동일 code AST chunker → 단일 CodeAstV1Chunker 통합 (−3030줄) — chunker_version 라벨 verbatim 유지 → chunk_id byte-identical → 재인덱싱 0.
    • #221 빈 re-export shim kebab-embed/kebab-llmkebab-core 의 default-OFF mock feature 흡수 — crate 22→20, 동작 불변.
    • #222 FusionPolicy 1-arm enum inline + serde_yamlserde_yaml_ng 일원화 + NliVerifier default 제거 — 출력 불변.

    minor 트리거 = #219 의 CLI 플래그/config 키 제거(인터페이스 변경). 누적 −3414줄 / 이 arc crate 22→20.

    도그푸딩(2026-06-27): pre-arc(v0.31.0, 9-chunker) vs post-arc(consolidated) 실코퍼스 ingest → 120 chunks, chunk_id+chunker_version diff 완전 비어있음(byte-identical 종단 확증). GPU r9700 ollama(arctic-embed2) ingest + lexical 검색 정상, lemonade 복구 확인.

    상세: docs/release-notes/v0.32.0-draft.md · HOTFIXES 2026-06-27.

    Downloads
  • altair823 released this 2026-06-25 02:08:11 +00:00 | 61 commits to main since this release

    v0.31.0 — 척추 단순화 + 캐시 전면화.

    척추 재작성(#214, breaking: tui·세션·rag-v1/v2·search캐시·candle 제거, config v4→v5 마이그레이션, V015 drop chat_sessions) + 임베딩 캐시 전면화(#216) + OCR/caption derivation 캐시(#217). 캐시는 출력 byte-identical; minor = 척추의 breaking 마이그레이션.

    상세: docs/release-notes/v0.31.0-draft.md
    도그푸딩: tasks/HOTFIXES.md 2026-06-25 (OCR 캐시 17 jira PNG 재인덱싱 7× + 실 v3 KB 마이그레이션).

    Downloads
  • altair823 released this 2026-06-24 06:01:38 +00:00 | 111 commits to main since this release

    v0.30.0(md-heading-v2) 후속 patch release — 후속 3건.

    전체 릴리스 노트(정밀/정직 버전): docs/release-notes/v0.30.1-draft.md

    변경 요약

    • pdf-page-v1.2 — md-heading-v2 의 oversize 분할을 PDF 청커로 확장. 거대 PDF 페이지(> max_chunk_tokens)만 공유 crate::oversize 모듈로 재분할, 미분할 페이지는 v1.1 과 byte-identical. chunker_version pdf-page-v1.1v1.2.
    • rag-v4 — RAG 컨텍스트에 source=/trust= provenance 라벨 + 신뢰도 우선·[#번호] 귀속 2규칙. prompt_template_version 기본 rag-v3rag-v4(multi-hop v1v2). search_hit.v1source_id/trust_level additive optional 필드.
    • config [ingest.chunking] budget floor 검증target ≥ 16, overlap < target, max_chunk ≥ target 위반 시 load 거부. valid config 동작 불변.

    도그푸딩(rag-v4, 정직)

    gemma3:4b@R9700 + competing 66 질의로 rag-v3 vs rag-v4 LLM-judge. 타깃 실패 모드(저신뢰 jira 가 권위 wiki 를 덮어씀)는 두 버전 모두 0/34(실패 모드 미재현) — 품질 지표 표본오차 내 구분 불가. rag-v4 는 무해(회귀 0) + 라벨 도달 확인이나 trust-steering 효과는 미입증. 본 릴리스는 그 효능을 주장하지 않는다.

    업그레이드

    새 바이너리로 교체 후 다음 kebab ingest(PDF 1회 자동 재청크) / kebab ask(자동 rag-v4) 면 적용. 새 명령·플래그·필수 config 키 없음. single-hop 은 prompt_template_version = "rag-v3" 로 opt-out 가능(multi-hop 은 불가). answer.v1.prompt_template_version(required 필드)의 rag-v3rag-v4 로 바뀌므로 이 필드를 파싱하는 통합은 반영 필요(schema shape 불변, v2 bump 아님).

    NB (버전)

    chunker_version·prompt_template_version 변경은 §Versioning 상 minor(0.31.0) 트리거지만, 결과 실질 변화가 없고 도그푸딩 회귀 0 이라 사용자 재량으로 patch(0.30.1) 처리.

    Downloads
  • altair823 released this 2026-06-24 01:28:03 +00:00 | 121 commits to main since this release

    kebab v0.30.0 — md-heading-v2: 거대 청크가 임베딩을 깨지 않도록

    v0.29.0(provenance 출처 필터) 후속 minor release. markdown 청커가 하나의 거대
    블록이 임베더 컨텍스트를 초과해 임베딩을 통째로 실패시키던
    문제를 해소한다.
    긴 로그·스택트레이스·표가 통으로 들어간 문서(예: jira 이슈)를 색인할 때 그
    문서가 검색에서 통째로 사라지던 회귀를 막는다. 일반 사용자는 업그레이드 후
    다음 kebab ingest 한 번이면 끝
    — markdown 자산만 1회 자동 재청크된다.


    변경 사실

    1) md-heading-v2 청커가 기본값이 됐다. v1은 코드/테이블 블록을 (크기와
    무관하게) 절대 분할하지 않았고, list·paragraph도 블록 하나가 곧 청크 하나였다.
    그래서 거대한 단일 블록 — 예컨대 로그 덤프가 1000줄짜리 불릿 리스트로 변환된 것 —
    이 임베더의 입력 한도를 넘으면 그 문서 전체의 벡터 색인이 실패했다. v2는 v1과
    모든 출력이 동일하되, 마지막에 예산을 넘는 청크만 줄(\n) 경계로,
    한 줄이 홀로 예산을 넘으면 UTF-8 문자 경계로 잘라 각 조각이 예산 이하가 되게 한다.

    2) 신규 config [ingest.chunking] max_chunk_tokens (byte/3 토큰, default
    4000). 이 값을 넘는 청크가 분할 대상이 된다. 4000은 8192-context 임베더(예:
    snowflake-arctic-embed2)에 약 2배 안전마진을 두면서 일반적인 코드·문단은 그대로
    한 청크로 유지하는 값이다. kebab config migrate로 기존 config에 additive 주입.

    [ingest.chunking]
    chunker_version = "md-heading-v2"
    max_chunk_tokens = 4000
    

    3) 분할 조각의 chunk_id·citation. 한 블록에서 나온 분할 조각들은 같은
    block_ids를 공유하므로 chunk_id에 #seg{i} 접미사를 붙여 충돌을 막는다. 분할
    조각의 citation은 블록 단위(원 블록 범위) — sub-line 정밀도는 아니다.
    미분할 청크(대다수)는 v0.29.0과 출력·citation이 완전히 동일하다.

    Trade-off

    • 거대 블록이 여러 검색 hit로 나뉜다. 이전엔 그 문서가 (임베딩 실패로)
      벡터 검색에서 아예 안 나왔거나, ollama처럼 조용히 잘린 채 한 hit였다. 이제는
      여러 조각으로 정상 색인되어 각각 hit로 잡힐 수 있다 — 같은 문서가 상위에 여러
      번 보일 수 있다.
    • 분할 조각 citation은 블록 단위다. fenced 코드의 줄 span이 fence를 포함하는
      비대칭 때문에 조각별 정확한 줄 범위를 (span, code)만으로 복원할 수 없어,
      "절대 틀리지 않되 블록 단위"를 택했다. 정밀 sub-line citation이 필요하면 향후
      파서가 content 줄 범위를 직접 제공하는 개선이 필요하다.
    • byte/3 휴리스틱. 토큰 수는 실제 토크나이저가 아니라 바이트/3 근사다. CJK는
      과대추정(더 안전), 영문 코드는 실토큰과 비슷. strict 임베더에 대해 보수적이다.

    Mitigation

    • 결과·CLI·wire 포맷 불변. --json 스키마, exit code, citation 모양 모두
      동일. 내부적으로 거대 블록이 분할될 뿐이다.
    • 공유 ChunkPolicy 미변경. max_chunk_tokens는 v2 청커의 policy_hash에만
      fold되어 코드·PDF 청커의 cascade를 건드리지 않는다 — 코드/PDF 자산은 재청크되지
      않는다.
    • strict 임베더 호환. v1 시절 ollama가 조용히 truncate하던 것을 청커가 애초에
      예산 이하로 만들므로, oversize 입력을 truncate가 아닌 거부(500 too large)로
      처리하는 백엔드(예: AMD Lemonade)에서도 색인이 깨지지 않는다.
    • 이미지 OCR 텍스트도 보호. 분할 판정은 청크의 실제 임베드 text 크기로 한다 —
      이미지 청크는 내부적으로 token_estimate가 0이지만 그 OCR/캡션 text는 클 수 있어
      (빽빽한 스크린샷), 실제 text 길이로 판정해야 oversize 이미지 OCR도 분할된다.

    Known limitation

    PDF는 별도 청커(pdf-page-v1.1)를 쓰므로 이 oversize-split이 적용되지 않는다 —
    초고밀도 scanned page 한 장의 OCR이 한 청크로 예산을 넘으면 그대로 임베드된다
    (일반 PDF는 무관). 후속 작업으로 PDF 청커에도 동일 분할을 넣을 수 있다.

    업그레이드 절차

    1. 새 바이너리로 교체.
    2. (선택) kebab config migrate — config 파일에 max_chunk_tokens = 4000
      additive 주입(주석·값 보존). 안 해도 기본값으로 동작한다.
    3. kebab ingestchunker_versionmd-heading-v1md-heading-v2
      바뀌었으므로 markdown 자산이 1회 자동 재청크된다(--force-reingest
      불필요). 코드/PDF 자산은 영향 없음. embedding은 파생물 캐시(V012) 히트로
      대부분 재계산을 피하지만, 분할된 거대 블록의 새 조각은 새로 임베드된다.
    4. 대용량 KB라면 첫 ingest가 markdown 재청크로 평소보다 길어질 수 있다(1회성).

    도그푸딩 evidence

    실험 KB(MongoDB 문서 220 + jira 400, arctic-embed-l-v2 @ Lemonade GPU). v2 전:
    620 문서 중 2개(SERVER-22906=76189토큰 list, SERVER-23097=20643토큰 list)가
    임베드 실패. v2 후: 620/620, errors=0, 전 코퍼스 7114 청크가 모두 ≤ 4000
    (초과 0). SERVER-22906은 14 청크로, SERVER-23097은 5 청크로 분할. "WiredTiger
    excessive memory cache size" 질의에서 그동안 색인조차 안 되던 SERVER-22906
    **1위 결과(0.977)**로 — "임베드 불가"에서 "최상위 검색 결과"로 전환됐다. 출처
    필터(--trust-min primary 등)는 정상 유지.

    Downloads
  • altair823 released this 2026-06-04 22:34:52 +00:00 | 125 commits to main since this release

    kebab v0.28.0 — config 스키마 v2→v3: 미디어 ingest 통합

    v0.27.0(PP-OCRv5 ONNX OCR) 후속 minor release. config.toml 에 흩어져
    있던 미디어 형식 설정을 [ingest.*] 우산 하나로 모은다. 기존 사용자는
    아무것도 손대지 않아도 된다
    — 옛 v2 파일은 로드 시 메모리에서 자동 변환되고,
    검색·색인 결과는 바이트 단위로 동일하다(재색인 0).


    변경 사실

    미디어 형식 설정이 top-level 에서 [ingest.*] 하위로 이동했다.

    v2 (top-level) v3 ([ingest.*])
    [indexing] (스칼라) [ingest] 스칼라 (max_parallel_extractors 등)
    [chunking] [ingest.chunking]
    [image.ocr] [ingest.image.ocr]
    [image.caption] [ingest.image.caption]
    [pdf.ocr] [ingest.pdf.ocr]
    [ingest.code] [ingest.code] (변화 없음)

    부수적으로 [ingest.pdf.ocr] 가 paddle-onnx 모델 경로 키(det_model/rec_model/
    dict/score_thresh/unclip_ratio/max_boxes)를 PDF 자체적으로 가질 수 있게
    됐다(v2 는 image.ocr 의 값을 빌려썼다). 신규 env KEBAB_PDF_OCR_* 6키.

    Trade-off

    비-additive rename 마이그레이션이라(첫 사례), 옛 섹션 이름을 그대로 두면
    serde 가 모르는 키로 무시될 수 있다. 이를 피하려고 두 겹의 안전장치를 깔았다:
    (1) Config::from_file 이 load 시 메모리에서 v3 로 자동 변환 — 미변환 v2 파일도
    설정 유실 0. (2) kebab config migrate 가 디스크 파일을 새 레이아웃으로 갱신하되
    값·주석·대안(commented) 줄을 전부 보존하고 멱등이다.

    env override 이름(예 KEBAB_CHUNKING_TARGET_TOKENS,
    KEBAB_INDEXING_MAX_PARALLEL_EXTRACTORS)은 그대로 유지된다 — 대입 대상만
    새 경로로 바뀌므로 기존 KEBAB_* 스크립트는 손댈 필요가 없다.

    Mitigation — 재색인 0 보장

    ingest_config_signature 는 값 기반이라 struct 경로가 바뀌어도 출력 문자열이
    v2 와 바이트 동일하다. paddle 모델 경로는 미디어별(image/pdf)로 호출자가
    넘기도록 인자화했고, 마이그레이션이 v2 의 image↔pdf paddle 비대칭을 값 복사로
    보존한다. 도그푸딩(v0.28.0 release 빌드)에서 v2 config 로 first ingest 후
    (a) 동일 v2 config 재ingest(자동변환), (b) v3 로 config migrate 후 재ingest
    모두 new=0 updated=0 unchanged=2 — 업그레이드 시 재색인이 발생하지 않음을
    실증했다.

    Upgrade 절차

    1. 아무것도 안 해도 된다 — 옛 config.toml 은 그대로 로드된다(자동 변환,
      디스크 미변경, 일회성 warn 으로 안내).
    2. 파일을 새 레이아웃으로 정리하려면: kebab config migrate (자동 .bak 백업,
      --dry-run 으로 미리보기). kebab doctor 가 갱신 필요 시 안내한다.
    3. kebab init 으로 새로 만드는 config 는 v3 레이아웃 + per-option 주석 포함.

    검색·RAG 결과와 색인은 변하지 않는다.

    Downloads
  • altair823 released this 2026-06-03 14:35:20 +00:00 | 147 commits to main since this release

    v0.26.2 — ingest 설정 변경 시 영향 자산 자동 재색인

    지금까지 증분 ingest 의 "변경 안 됨(skip)" 판정은 파일 내용 + parser/chunker/embedding 버전만 봤습니다. 그래서 config.toml 에서 색인 결과를 바꾸는 설정(이미지 OCR/caption, 청킹 파라미터, PDF OCR, 코드 ingest 옵션)을 바꾼 뒤 다시 kebab ingest 해도, 파일 자체는 그대로니 자산이 그냥 건너뛰어졌습니다 — 바뀐 설정이 반영되지 않았죠. 이번 patch 가 그 갭을 일반화해 고칩니다.

    무엇이 바뀌나. 자산 타입별로 "그 자산의 색인 결과에 영향을 주는 설정"의 결정적 서명을 계산해 skip 판정에 포함시킵니다. 이제 해당 설정을 바꾸면 --force-reingest 없이도 영향 받는 자산만 자동으로 다시 색인됩니다:

    • [chunking] (target_tokens/overlap_tokens/respect_markdown_headings/chunker_version) → 모든 자산 재색인
    • [image.ocr] · [image.caption]이미지
    • [pdf.ocr]PDF
    • [ingest.code]코드 파일

    무엇은 안 바뀌나(중요). 색인 산출물과 무관한 설정 — [search] / [rag] / [models.nli] / [ui] / [logging] / 저장 경로, 그리고 max_pixels / languages / *_timeout_secs 같은 런타임 파라미터 — 는 바꿔도 재색인을 유발하지 않습니다(불필요한 전체 재색인 회피). 동일한 설정으로 다시 ingest 하면 종전처럼 전부 skip 됩니다.

    업그레이드 시 1회 재색인. 이 버전으로 올린 뒤 첫 kebab ingest 에서는 기존 자산이 현재 설정대로 한 번 재색인됩니다(저장돼 있던 옛 parser_version 이 새 서명과 달라서). 임베딩은 내용 해시 기반 파생물 캐시(V012)가 그대로라 캐시 히트로 저렴하고, 그 1회 이후로는 설정을 바꾸지 않는 한 다시 skip 됩니다. --force-reingest 는 전체 강제 재색인용으로 그대로 유지됩니다.

    호환성. CLI·config 키·wire schema·검색 결과 포맷에는 변화가 없습니다(내부 skip 판정만 정정) — 그래서 patch 릴리스입니다. 검증: clippy 0, 관련 크레이트 테스트 67 그룹 0 실패(토글/skip/제외 e2e 포함). 상세: tasks/HOTFIXES.md 2026-06-03 entry.

    Downloads
  • altair823 released this 2026-06-03 11:07:20 +00:00 | 152 commits to main since this release

    v0.26.1 — ingest 진행 로그 개선

    OCR/caption 이 켜진 볼트(이미지·PDF 혼재)를 색인할 때, 진행바가 멈춘 것처럼 보이는데 무엇 때문에 느린지 알 수 없던 문제를 해결합니다. 검색·색인 결과나 명령/설정은 전혀 바뀌지 않는 관측성(observability) 개선이라 patch 릴리스입니다(기본 동작 불변).

    무엇이 보이게 되었나.

    • 현재 파일명 — 진행바에 지금 처리 중인 파일이 표시됩니다 (ingest [===>] 142/997 · vault/foo.png).
    • 느린 phase + 모델 — 이미지 OCR·caption·임베딩이 도는 동안 그 사실과 사용 모델이 실시간으로 보입니다 (· OCR(gemma4:e4b)…). 이전엔 이미지 OCR/caption 에 진행 이벤트가 없어 "정지"처럼 보였습니다.
    • 경과시간 heartbeat — 한 파일이 오래 걸려도 (45s) 처럼 경과초가 이벤트 사이에도 계속 갱신되어, 멈춘 게 아니라 무거운 작업 중임이 드러납니다.
    • 종료 요약 — 끝에 가장 오래 걸린 파일 top-5 가 출력되어 병목 파일을 사후에 바로 파악할 수 있습니다.

    Trade-off / 호환성. 사람용 진행바(stderr) 표시만 풍부해졌고, --json 출력에는 additive wire 이벤트가 더해졌습니다 — 신규 asset_phase(ingest_progress.v1) + asset_timingsocr_ms/caption_ms 필드. 모두 backward-compat(기존 소비자는 새 필드를 무시하면 그만)이라 wire major bump 없이 v1 유지. 미디어가 없는 텍스트 위주 ingest 의 표시·성능에는 변화가 없습니다.

    검증. clippy 0, kebab-app/cli 61 그룹·parse-image/tui 14 그룹 테스트 0 failed. 상세: tasks/HOTFIXES.md 2026-06-03 entry.

    참고: 색인이 느린 근본 원인이 미디어 OCR/caption 인 경우, 텍스트 위주 볼트라면 [image.ocr]/[image.caption]/[pdf.ocr]enabled = false 로 두면 크게 빨라집니다(이 릴리스의 로그가 그 판단을 돕습니다).

    Downloads
  • altair823 released this 2026-06-03 07:20:27 +00:00 | 158 commits to main since this release

    v0.26.0 — arctic-embed 임베더 + doc-side expansion(별칭) 제거

    v0.24.0 이후 두 개의 큰 변화가 쌓였습니다. 검색 임베더를 더 강한 모델로 교체할 수 있게 되었고(설명형/풀어쓴 질의의 검색 품질이 크게 올라갑니다), 그 과정에서 유지보수 부담만 크고 효과는 미미했던 별칭(doc-side expansion) 기능을 제거했습니다. 두 변화 모두 측정(나무위키 ~1000 문서, 132개 변형 질의 골든)으로 근거를 잡았습니다.


    1. 새 임베더: arctic-embed-l-v2.0 (provider candle / ollama) — opt-in

    무엇이 바뀌나. [models.embedding] 에서 기본 multilingual-e5-large 대신 Snowflake arctic-embed-l-v2.0 임베더를 선택할 수 있습니다. 측정에서 같은 골든의 recall@10 이 e5 123/132 → arctic 130/132 (+7), recall@50 은 132/132(완벽) 으로 올랐고, 결정적으로 용어·약어·영어·동의어 질의는 손실 없이(72/72 유지) 설명형/풀어쓴 질의만 끌어올렸습니다(예: "마지막에 넣은 것을 먼저 꺼내는 자료구조" → 스택 문서). 두 백엔드를 제공합니다:

    # (A) candle — 순수 Rust, in-process (NUMA 안전, macOS Metal GPU 가능)
    [models.embedding]
    provider = "candle"
    model    = "snowflake-arctic-embed-l-v2.0"   # CLS pooling, query 에 "query: " 접두어
    dimensions = 1024
    
    # (B) ollama — 로컬/원격 Ollama 데몬에 위임 (POST /api/embed)
    [models.embedding]
    provider = "ollama"
    model    = "snowflake-arctic-embed2"          # ollama pull 필요
    dimensions = 1024
    endpoint = "http://127.0.0.1:11434"           # 생략 시 [models.llm].endpoint 로 폴백
    

    Trade-off. arctic 으로 바꾸면 임베딩 벡터 공간이 달라지므로(embedding_version cascade) 기존 e5 KB 와 혼용할 수 없습니다 — 전환하려면 한 번 재색인이 필요합니다. 별칭과 달리 이 비용은 색인 1회뿐이고, per-query 추가 비용도 LLM 호출도 없어 살아있는(계속 갱신되는) KB 에 지속 가능합니다.

    Mitigation / 검증. 기본값은 그대로 e5-large 이므로 아무것도 안 바꾸면 동작·벡터가 100% 동일합니다(arctic 은 완전 opt-in). candle 백엔드의 정확성은 측정에 쓴 Ollama 경로와 코사인 0.999984 일치로 검증했고(같은 pooling/prefix), v0.26.0 실제 바이너리로 namu 를 재색인해 recall@10 130/132 를 종단 재현했습니다. 새 크레이트 kebab-embed-ollama 가 추가됐습니다.

    Upgrade 절차. (1) ollama pull snowflake-arctic-embed2(ollama 경로) 또는 candle 경로는 첫 색인 시 safetensors(~2GB) 자동 다운로드. (2) 위 config 로 변경 + dimensions = 1024. (3) kebab reset 후 재 ingest. macOS 는 cargo install --path crates/kebab-cli --features embed_metal --locked 로 candle GPU 가속.


    2. doc-side expansion(별칭) 기능 제거

    무엇이 바뀌나. 청크마다 LLM 을 호출해 "검색용 별칭"을 생성하던 기능([ingest.expansion])을 완전히 제거했습니다. 측정 결과 이 기능의 실효는 설명형 질의 +2 그룹뿐인데, 그 대가가 색인할 때마다 청크당 LLM 호출(나무위키 18문서 cold 2.5시간)이라 계속 갱신되는 KB 에서는 지속 불가능했습니다. 별칭이 노렸던 한↔영 교차언어 recall 은 임베더 단독으로 이미 충분했고, 남은 설명형 약점은 위 arctic 교체가 더 깔끔하게 해결합니다.

    Trade-off / 영향. 별칭은 이미 기본 비활성(default-off)이었으므로 일반 사용자 체감은 0 입니다. config.toml[ingest.expansion] 섹션이 남아 있어도 무시되며(forward-compat), 신규 마이그레이션 V013 이 사용되지 않던 chunk_aliases_fts 테이블과 chunks.aliases 컬럼을 정리합니다. wire 의 ingest_progress.v1 에서 expansion_progress 이벤트가 빠졌습니다(추가 직후라 호환 영향 없음).


    기타

    • 상세 측정·방법 비교(리랭크 / query-side expansion / heading enrichment / bge-m3 등 대안 포함): tasks/HOTFIXES.md(2026-06-03 두 entry) + 연구 문서 docs/superpowers/research/2026-06-03-expansion-cost-rethink-research.md.
    • 잔존 설명형 약점 2개(추상적 정의 질의)는 후속 query-side 보강 후보로 남겨둠.
    • 문서 동기화: README Configuration, docs/SMOKE.md, docs/ARCHITECTURE.
    Downloads
  • altair823 released this 2026-06-02 17:46:47 +00:00 | 178 commits to main since this release

    v0.24.0 — 상세 ingest 진행 로깅 (asset 내부 phase 가시화)

    변경 사실

    ingest 진행 표시가 asset(문서) 단위뿐이라, 한 문서 내부의 parse / chunk / expansion(별칭 LLM, 청크당 순차 호출) / embed / store 가 보이지 않았다. 큰 문서 하나가 expansion 으로 수십 분 걸려도 진행바가 1/N 에 멈춘 듯 보여 병목을 찾기 어려웠다. 이번 릴리스는 asset 내부 phase 를 노출한다.

    추가된 것 (wire ingest_progress.v1 additive — 기존 consumer 호환)

    • asset_chunked { idx, total, chunks } — 청킹 직후 즉시 "이 문서가 N청크" 표시 (큰 첫 문서가 멈춘 게 아님을 바로 확인).
    • expansion_progress { idx, total, done, chunks } — 별칭 확장 중 라이브 카운터 (스로틀: 25청크 또는 1s).
    • asset_timings { idx, total, parse_ms, chunk_ms, expansion_ms, embed_ms, store_ms } — 문서 종료 시 phase 별 소요시간 (markdown 경로).

    사용자 체감

    • 사람용 출력: → N chunks, 별칭 확장 450/1843 (라이브), 종료 시 ⏱ parse 3ms · chunk 673ms · expand 1980s · embed 12s · store 33ms. → 어느 phase 가 병목인지(expansion vs embed) 한눈에.
    • --json: 새 이벤트가 line-delimited 로 흐름. --quiet 억제.

    호환 / 한계

    • wire v1 backward-compat (신규 kind 만 추가, 기존 필드 무변경). 동작/벡터/schema 메이저 변경 없음.
    • image/pdf 경로는 phase timing 없음(asset_chunked 만). expansion_progress 비-TTY human 은 기본 억제(--json 은 전량).
    • store_ms = SQLite persist 전용, embed_ms = 임베딩 + 벡터 upsert + stale-vector purge (정확한 귀속).
    Downloads