8-finding 도그푸딩 라운드 및 검색 품질 baseline 결과를 HOTFIXES 에 기록.
- 8 findings 요약 표 (rag-v3, bulk schema, list docs, index_version 등)
- Finding O-2 known limitation (소형 모델 refusal 언어 불일치)
- 검색 품질 baseline 표 (hybrid MRR=0.833, lexical MRR=0.7)
- golden 큐레이션 교훈 (dispatch.py 정답 정정 → hit@3 0.9→1.0)
- eval logs cross-link
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
사용자 실제 /home/altair823/KnowledgeBase/ (1781 markdown / 9050 chunk)
를 v0.20.1+N-gram supplement 포함 binary 로 backfill 재실행:
- Backfill duration: 26.6초 (9050 chunk, OnceLock 캐시 + 1000-row
batch transaction). ~3 ms/chunk amortized.
- '한국' query: V007 의 0 hit → V009 + N-gram 의 10 hit (Bug #8
functional closure 실측 검증).
- '한국어' query: 5 → 10 hit (morpheme + N-gram 동시 매칭).
- 영어 whole-token: 'token'/'pipeline'/'config' = 10 hit each
(V009 회귀 측면 정상).
Snippet evidence: KB 의 testdata/coding-md-corpus/*/...md 의
"문서를 한국어로 다시 정리하기" 패턴이 ko-dic 분해 + N-gram window
로 '한국' query 매칭 demonstrate.
기타 한국어 (서울, 지하철, 대한민국 등) 0 hit 는 KB corpus 의
단어 자체 부재 — data limitation, V009 implementation limitation X.
Test data 위치:
- /home/altair823/KnowledgeBase/ (사용자 실제 KB, 1781 markdown)
- /build/cache/tmp/v0.20.1-dogfood/kb/ (ingested SQLite + LanceDB)
- /build/cache/tmp/v0.20.1-dogfood2/corpus/ (한국어 wiki fixture)
- /build/cache/tmp/v0.20.1-v007strict/corpus/no-space.md (whitespace-less)
- /build/cache/tmp/v0.20.1-ngram/corpus/extra.md (대한민국, 한국정부, 주민등록번호)
Spec: docs/superpowers/specs/2026-05-28-v0.20.x-korean-morphological-tokenizer-spec.md §9 + Appendix B
Plan: docs/superpowers/plans/2026-05-28-v0.20.x-korean-morphological-tokenizer-plan.md (dogfood evidence final)
#4 (사용자 요청): spec §6.2 의 Option β (sub-token 추가 emit) 를
v0.21.x P9 follow-up 에서 v0.20.1 implementation 으로 promote.
dogfood 의 ko-dic compound noun limitation (`대한민국`, `한국정부`,
`주민등록번호` 등 단일 token 정책) 해소.
Implementation (`crates/kebab-chunk/src/lib.rs::tokenize_korean_morphological`):
- 신규 helper `is_hangul()` — 한글 음절 (U+AC00..D7A3) + 자모
(U+1100..11FF, U+3130..318F) 판정.
- lindera output 의 각 morpheme 에 대해, 한글만 + 길이 ≥ 3 인 경우
sliding window 2-gram 추가 emit. `[한국정부, 한국, 국정, 정부]`
형태로 token list expand.
- 영어 / 숫자 / 혼합 token 은 supplement X (false positive 회피).
Tests (`crates/kebab-chunk/tests/tokenize_korean.rs`):
- `tokenize_korean_morphological_emits_2gram_for_long_morpheme`: 5 probe
fixture 중 supplement 발화 case 확인 (실측 `서울특별시` →
`[서울, 특별시, 특별, 별시]`, `대한민국` → `[대한민국, 대한,
한민, 민국]`).
- `tokenize_korean_morphological_no_2gram_for_english`: Rust optimization
fixture 에서 영어 substring (`Rus`, `ust`, `imi`) emit 없음 보장.
Dogfood evidence (`tasks/HOTFIXES.md` 2026-05-28 entry 보강):
- '대한', '한민', '민국' query 모두 hit (대한민국 의 sliding window).
- '특별', '주민', '등록' 같은 sub-token query hit.
- 영어 'tokenizer' query 는 corpus 부재로 0 hit (supplement X).
- Trade-off: DB size +20-30% (Korean-heavy), false positive 작은 risk.
Spec: docs/superpowers/specs/2026-05-28-v0.20.x-korean-morphological-tokenizer-spec.md §6.2 (Option β promote)
Plan: docs/superpowers/plans/2026-05-28-v0.20.x-korean-morphological-tokenizer-plan.md (post-implementation enhancement)
V009 한국어 morphological tokenizer 의 dogfood 검증 결과를 HOTFIXES
2026-05-28 entry 에 보강. 14 scenario 의 hit count + ko-dic 의
compound noun 분해 evidence (서울특별시 → [서울, 특별시]) + Option α
acceptance 의 known limitation 명시.
Reference corpus: DOGFOOD.md §2.1bis 의 korea-overview.md +
korea-compound.md (10 KB 합계, 2 markdown). KB ingest + 14 query
검증 모두 expected.
사용자 KnowledgeBase 같은 영어/code 중심 KB 에서 한국어 lexical
0-hit 가 정상임을 reference fixture evidence 와 분리해 사용자
오인 방지.
Spec: docs/superpowers/specs/2026-05-28-v0.20.x-korean-morphological-tokenizer-spec.md §9
Plan: docs/superpowers/plans/2026-05-28-v0.20.x-korean-morphological-tokenizer-plan.md (S11 + dogfood evidence)
opus PR-level final review (Approved with notes) 의 4 minor finding
mechanical 정정:
1. README.md — `kebab search` row 의 영어 substring 매칭 표현이
V007 시절 그대로였음. V009 의 whole-token 회귀 (substring → V002
동작) 를 정직히 명시 + vector/hybrid mode 권장 안내.
2. tasks/HOTFIXES.md — 2026-05-28 entry 의 file path 정정. lexical.rs
는 lindera 호출자가 아니라 build_match_string 의 MIN_QUERY_CHARS
3→2 갱신만; lindera helper 의 실제 owner 는 kebab-chunk/src/lib.rs.
ingest.rs 는 본 PR scope 외, eager backfill hook 위치는 kebab-app/
src/app.rs::App::open_with_config.
3. docs/wire-schema/v1/search_response.schema.json — `hint` field
description 이 V007 trigram 3-char minimum 시절 advisory 시그니처
그대로. v0.20.1 에서 helper retired + always-omit 사실 명시
(forward-compat 차원에서 field 만 schema 에 보존).
4. integrations/claude-code/kebab/SKILL.md — `hint` field 설명의
self-contradiction ("present only with trigram in edge cases" vs
"Korean 2-char now supported") 해소. retired + reuse 가능 명시.
PR-level reviewer recommendation: "Merge as-is — block 사유 아님 (모든
finding minor)". 본 commit 은 reviewer 의 옵션 1 (별 docs hotfix
commit) 채택.
Spec: docs/superpowers/specs/2026-05-28-v0.20.x-korean-morphological-tokenizer-spec.md
Plan: docs/superpowers/plans/2026-05-28-v0.20.x-korean-morphological-tokenizer-plan.md (PR-level finding follow-up)
V009 한국어 morphological tokenizer 의 사용자 visible surface 변경 +
release notes scope 를 5 docs 에 cascade.
- README.md: kebab search 명령 row 에 한국어 2자 query 지원 명시.
- integrations/claude-code/kebab/SKILL.md: V007 3-char hint 제거 +
V009 2자 한국어 query 지원 1줄.
- HANDOFF.md: C task status 완료 flip + v0.20.1 release notes scope
에 본 변경 추가 + 머지 후 발견 summary 행.
- docs/ARCHITECTURE.md: embedding upgrade (e5-small → e5-large),
lindera-ko-dic FTS5 한국어 지원, version notes 추가.
- tasks/HOTFIXES.md: 2026-05-28 entry — Bug #8 V009 해소, lindera-ko-dic
실제 crate name (spec deviation), cargo-deny deferred, Path A
영어 substring 회귀 명시.
Spec: tasks/p9/p9-9-v0.20.x-korean-morphological-tokenizer-spec.md §7.4
Plan: docs/superpowers/plans/2026-05-28-v0.20.x-korean-morphological-tokenizer-plan.md
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Round 3 final dogfood (2026-05-28) 에서 60s default 가 dense Korean page
(metro-korea.pdf page 8/9/13) 의 OCR 을 강제 timeout — round 2 대비 1 page
더 indexed 손실. user perspective: cost vs coverage trade-off 가 60s 에선
coverage 쪽으로 너무 깎임.
Sweet spot 점진적 축소 정책 채택 — conservative starting point 180s 부터
dogfood evidence (OCR 평균 ms 분포) 기반 점진적 축소. 60s 같은 짧은 default
로 직접 jump 안 함.
- crates/kebab-config/src/lib.rs::default_pdf_ocr_request_timeout_secs() = 180
- unit test rename (_is_60s → _is_180s) + assertion 180
- crates/kebab-config/tests/pdf_ocr.rs assert_eq 180
- tasks/HOTFIXES.md 2026-05-28 follow-up entry 추가
User override path 보존 — config.toml [pdf.ocr] request_timeout_secs = N
로 user 가 직접 tune.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Bug #11 (이전 commit `fix(config): pdf.ocr.request_timeout_secs default 600 → 60`)
의 frozen-spec deviation handoff.
- tasks/HOTFIXES.md: 2026-05-27 dated subsection — Discovered / Symptom / Root cause /
Fix / Amends 5-field 포맷 (기존 entries 와 일치).
- docs/superpowers/specs/2026-05-27-pdf-scanned-ocr-spec.md: PDF OCR config block
line 1000 (default value) + OQ-1 line 1628 에 inline HTML 주석 2 줄 cross-link.
prose 변경 0 — parent spec frozen contract 보존, HTML 주석은 markdown render 시 invisible.
HOTFIXES entry 가 live source of truth (CLAUDE.md "Spec contract" 규칙).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Why: metro-korea.pdf (Identity-H CID font without ToUnicode CMap) 의
ingest 가 pdf_ocr_pages=0 으로 잘못 종료. lopdf 0.32.0 의 emit
`?Identity-H Unimplemented?` marker 28 ASCII char 가 is_valid_text_char()
의 0x0020..=0x007E range 통과 → ratio=1.0 → OCR fallback 0.5
threshold bypass.
Change: MOJIBAKE_MARKERS const + compute_valid_char_ratio() 4-단계
(strip → trim-empty zero → dominance cap-0.3 → 기존 ratio). marker
list extensible. is_valid_text_char() 본체 변경 0.
Tests: +2 unit (dominance + minority) on top of 기존 8. parser_version
/ wire schema 변경 0.
Refs: docs/superpowers/specs/2026-05-27-v0.20-sub1-bugfix2-spec.md
§4.1 / §4.2 / §6 R-1.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
PR-7 (v0.18 dogfood probe-first) 머지 후 PR-5 의 test `ask_tool_routes_multi_hop_true_to_decompose_first` 가 stale empty-KB contract 로 deterministic fail. test-only fix — production code 0 touch.
- `minimal_config`: `score_gate = 0.0` (probe 의 second gate `top_score < score_gate` 우회, test config isolation).
- fixture `workspace_root/note.md`: "This note is about a compound containing X and Y in detail." — build_match_string 의 token_and branch (FTS5 implicit-AND) 가 `compound` + `about` + `and` 셋 다 매칭 필요. empirical SQLite REPL (V007 trigram DDL) 로 1 hit 확정.
- 기존 assertion 보존, single-pass branch 도 query "anything" 으로 fixture 미매칭 → NoChunks refusal 유지.
- 신규 `_multi_hop_short_circuits_when_probe_empty` test (REQUIRED — round-1 critic HIGH + verifier 격상): probe-empty short-circuit 의 MCP-layer wire shape pin (kebab-rag::multi_hop_empty_probe_pool_refuses_before_any_llm_call 은 RAG-layer 만 pin, MCP-layer 안전망 부재).
- module doc 갱신: 두 test 가 각각 pin 하는 contract enumerate. inline 주석 (line 94-101) 도 새 contract 정합.
- HOTFIXES.md 신규 dated entry \`## 2026-05-26 — HOTFIX #15 ...\` (date-top convention).
검증: cargo test --workspace -j 1 — 회귀 0 (known flaky 1 → 0). cargo clippy --workspace --all-targets -j 1 -- -D warnings clean.
Wire / behavior / version cascade: 0.
Refs: docs/superpowers/specs/2026-05-26-hotfix-15-mcp-ask-multi-hop-flaky-spec.md (review 3 rounds APPROVE)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
HOTFIXES.md 의 fb-41 entry 에 *post-PR-7 dogfood retest + PR-8 partial
mitigation* sub-section 추가 + *PR-9 NLI plan* anchor + 사용자 영향
절 갱신. config.rs 의 doc reference 가 정확한 entry sub-section
가리키도록 조정 — dangling reference 해소.
검증
- `cargo test -p kebab-config -j 1` — 모든 test 통과.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
v0.18 cut 전 fb-41 multi-hop RAG 도그푸딩에서 발견된 **safety regression**
fix. 자세한 도그푸딩 결과는 `tasks/HOTFIXES.md` 의 2026-05-25 fb-41
pre-v0.18 entry + `/build/cache/dogfood-v018/results/SUMMARY.md` 참조.
## 문제 (S7)
Query: `What is the chemical formula of caffeine?` (KB 에 없는 fact).
- Single-pass `kebab ask`: retrieve top score 가 default `rag.score_gate
= 0.30` 미만 → `refuse_score_gate` → 안전한 refusal.
- Multi-hop `kebab ask --multi-hop`: **`grounded = true`**, 본문
`"카페인의 화학식은 C₉H₁₅N₃O 입니다 [#6]"` (hallucination — 실제
C₈H₁₀N₄O₂) + `[#6]` 가 Adam optimizer chunk 의 `g_t = ∂L/∂θ_i` 본문을
인용 (시각적 short structured token 매칭 trigger).
원인: `ask_multi_hop` 의 score-gate 검사가 *pool 의 top_score* 만 봤다.
multi-hop 의 pool 은 5 sub-queries 의 union — 한 sub-query 의 top score
가 gate 위면 다른 chunks 가 원본 query 와 무관해도 gate 통과 + synth →
LLM hallucinate.
## Fix
`ask_multi_hop` entry 에 **pre-decompose probe** 추가:
1. *원본 query* 로 retrieve 한 번 (LLM call 0회, ~ms).
2. probe empty → `refuse_no_chunks(None)` (decompose 안 함, hops=None).
3. probe top_score < gate → `refuse_score_gate(None)` (decompose 안 함).
4. probe pass → 기존 decompose / decide / synthesize flow 그대로.
Multi-hop 의 safety floor 가 single-pass 와 정확히 일치 — multi-hop 은
*원본 query 가 이미 KB 범위 내* 일 때만 cross-doc reasoning 추가.
비용: 한 번의 retrieve (수 ms), LLM call 없음. multi-hop 의 LLM-dominated
latency 대비 무시 가능.
## Tests
신규 3 회귀 핀 (`crates/kebab-rag/tests/multi_hop.rs`):
- `multi_hop_below_probe_gate_refuses_before_any_llm_call` — **S7 직접
회귀 핀**. low-score chunk + empty LM script → score_gate refusal, LM
calls 0회, hops=None. fix revert 시 즉시 panic.
- `multi_hop_empty_probe_pool_refuses_before_any_llm_call` — empty
retrieve 시 NoChunks refusal, LM calls 0회.
- `multi_hop_above_probe_gate_proceeds_to_decompose` — probe pass 시
full multi-hop flow 정상 (decompose + decide + synth).
기존 7 multi-hop test 의 `ScriptedRetriever` 에 *probe-pass entry*
prepend + `retriever_handle.calls()` expectation +1. test 2 / test 4
처럼 entry 두 개였던 곳도 prepend (3 entries).
`multi_hop_refuse_no_chunks_preserves_hops_trace` /
`multi_hop_refuse_score_gate_preserves_hops_trace` 의 의미 좁힘 — 이제
*decompose-driven* refusal (probe pass 후 sub-query retrieve 가 empty
또는 below-gate) 만 검증. *probe-driven* refusal 은 hops=None
(decompose 안 함) — 신규 test 가 그 path 핀.
## 검증
- `cargo test -p kebab-rag -j 1` — 10 multi-hop (7 갱신 + 3 신규) + 19
pipeline + 31 unit + 3 prompt_template + 3 streaming 모두 통과. 회귀
없음.
- `cargo clippy -p kebab-rag --all-targets -j 1 -- -D warnings` clean.
- 단일 crate 직렬 build (16 GB RAM 제약).
## 변경 없음
- Wire schema — `Answer.hops` shape 동일, `refusal_reason` enum 동일.
- 다른 도그푸딩 발견 (synthesize citation 일관성, latency, binary path
confusion) — v0.18.1 또는 별 PR 의 책임. HOTFIXES 의 "다른 도그푸딩
발견" 절에 명시.
## 다음
PR-7 머지 후:
1. Workspace `Cargo.toml` version 0.17.2 → 0.18.0 (minor bump).
2. HANDOFF.md / INDEX.md 갱신 + frozen design §3.8 multi-hop sub-section.
3. `gitea-release v0.18.0 --auto-notes`.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
v0.17.1 post-dogfood polish cut. 두 PR 묶어 release:
- PR #164 — `[image.ocr] request_timeout_secs` 별 노브 (v0.17.1
미진행 closure). LLM 패턴을 OCR 어댑터에 동일 적용, 별 노브로
분리 (OCR vs LLM 의 cold start 패턴 차이로 독립 조절).
- PR #165 — `heading_path` FTS5 column filter 로 text-only 매칭
+ raw-mode escape hatch (2026-05-24 v0.17.0 trigram entry 의
JSON 노이즈 closure). lexical.rs 가 non-raw 분기 결과를
`text : (<expr>)` 로 wrap, 색인 자체는 V007 verbatim 그대로
유지. raw mode `'heading_path : <token>'` 로 opt-in 가능.
둘 다 additive (옛 config 호환) + re-ingest 불필요. binary 교체만.
HANDOFF 한 줄 요약 + 머지 후 결정 절에 v0.17.2 entry 추가.
HOTFIXES 의 두 entry anchor 가 `post-v0.17.1 dogfood` → `v0.17.2`
로 갱신.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
HOTFIXES entry 의 **MCP / agent 가시성** 단락이 회차 1 의 SKILL.md
추가 결정과 contradiction (`별도 SKILL.md 갱신 불필요` 잘못된
표기). 갱신 사실 + 새 escape hatch 가 v0.17.0 raw mode pattern
위에 build 됐다는 점 명시.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- HOTFIXES test 카운트 표기 정정: `9 신규 / 갱신 unit test` 의 산수
ambiguity → `9 unit test (8 갱신 + 1 신규) + 2 신규 통합 test = 11
total` 로 명시.
- SKILL.md (Claude Code integration) 의 search 절에 column scoping +
heading_path raw-mode escape hatch 안내 한 bullet 추가. 회차 1
의 follow-up suggestion 반영 — heading 검색 의도 agent 가 새
escape hatch `'heading_path : <token>'` 를 발견 가능.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
v0.17.0 trigram tokenizer entry 가 미수정으로 남겨둔
heading_path_json JSON 노이즈 (HOTFIXES 2026-05-24) closure.
trigram 이 chunks_fts.heading_path 컬럼 (V002/V007 트리거가
chunks.heading_path_json 그대로 INSERT) 의 JSON 표기 + 안의 path
세그먼트 (app, src) 까지 3-gram 색인해서 query 가 우연히 false
positive hit 하는 문제. column filter 채택 — heading 색인 유지
(V007 verbatim 불변), 매칭 대상만 text 컬럼 한정.
- build_match_string 가 non-raw 분기에서 combined expression 을
`text : (<expr>)` 로 wrap. FTS5 column filter syntax 가 OR/AND
sub-expression 허용.
- Raw mode (`'...'`) 는 그대로 — 사용자가 명시 의도로
`'heading_path : agent'` 같은 explicit opt-in 가능 (escape hatch).
- 8 기존 build_match_string unit test expected string 갱신 +
`build_match_string_raw_mode_preserves_heading_filter` 신규.
- `lexical_heading_only_token_does_not_hit_default_mode` 신규 회귀 핀
(heading-only unique token 이 default mode 에서 0 hit).
- `lexical_raw_mode_can_opt_into_heading_path_filter` 신규 — 같은
fixture 가 raw mode 로 hit 확인 (escape hatch 동작 핀).
사용자 영향: lexical / hybrid 검색의 본문 precision ↑. recall
변화 없음 (text 본문 token 매칭은 동일). re-ingest 불필요 (FTS
query 시점 매칭만 변경). lexical_snapshot_run_1 + hybrid_snapshot
도 fixture regenerate 불필요 (text 본문 매칭 query 라 BM25 동일).
HOTFIXES: 2026-05-24 v0.17.0 entry 의 `heading_path_json` 노이즈
항목 closure 표기 + 새 2026-05-25 post-v0.17.1 dogfood entry 추가.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- HOTFIXES 헤더 `v0.17.2` (vaporware) → `post-v0.17.1 dogfood`
로 변경, release tag 결정과 무관하게 정확한 anchor.
- HOTFIXES caller 수 `6 (5+3)` → `9 call site (6+3)` 으로 정정.
- OcrCfg.request_timeout_secs doc 의 edge case 가 LlmCfg sister
doc 과 동일한 구체 예제 (`u64::MAX`, `86400`) + reqwest 0.12.x
명시 주석으로 강화.
- LLM + OCR 양쪽의 legacy TOML fixture (78 줄 거의 동일) 를
module-level `LEGACY_PRE_TIMEOUT_TOML` const 로 추출. 두 test
가 동일 source 공유 → 옛 schema 가 또 변하면 한 곳만 수정.
reqwest::Duration::ZERO fact-check (회차 1 점 5) 는 회차 2
reply 에서 검증 결과 보고.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
v0.17.1 (PR #162) 가 LLM 쪽 hard-coded 300s 를 [models.llm]
request_timeout_secs 로 풀어준 것과 같은 패턴을 OCR 어댑터에 적용.
사용자 결정으로 별 노브 분리 ([image.ocr] request_timeout_secs) —
OCR 는 LLM 대비 cold start 패턴이 달라 독립 조절이 편함.
- OcrCfg.request_timeout_secs: u64 (serde default 300)
- KEBAB_IMAGE_OCR_REQUEST_TIMEOUT_SECS env override
- OllamaVisionOcr::build / from_parts 시그니처에 timeout 인자 추가
- REQUEST_TIMEOUT 상수 제거
- 3 신규 unit test (default / env / legacy parse) — LlmCfg 패턴 그대로
- HOTFIXES 2026-05-25 v0.17.1 entry 의 두 미진행 항목 모두 closure
(OCR timeout = 본 PR, --stream docs = PR #163 에서 이미 완료)
기존 config / 옛 KB 영향 없음 — 새 필드는 default 로 채워지고
동작도 동일 (300s). vision 모델 cold start 가 길면 env 또는
config 로 늘릴 수 있음.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
PR #162 워커 리뷰 반영.
- MEDIUM (W2) + LOW (W1): request_timeout_secs = 0 이 reqwest 의
의미상 disable 이 아닌 instant timeout (모든 요청 즉시 실패).
LlmCfg field rustdoc + ollama.rs module-level comment + README
세 군데에 명시 + u64::MAX / 86400 같은 large finite 값 권장.
- NIT (W1): HOTFIXES 2026-05-25 entry 의 '답변이 인 5분' typo →
'답변이 5분' (1자 삭제).
- NIT (W1): README + HOTFIXES 의 '확장 도그푸딩' 내부 jargon →
'후속 도그푸딩' 으로 통일.
코드 동작 변경 없음 — doc only. cargo test request_timeout 3 PASS.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
v0.17.0 확장 도그푸딩 (2026-05-25) 에서 발견된 두 가지를
한 PR 에 묶음.
(1) llm.generate_stream 의 hard-coded 300s timeout 을 config 노브로
빼냄. 8B+ 모델 (gemma4:e4b 등) 은 CPU only 환경에서 5분
안에 첫 RAG 답변 못 마치고 `error: kb-rag: llm.generate_stream`
으로 떨어지던 문제.
- kebab-config::LlmCfg 에 request_timeout_secs: u64 additive
필드 (#[serde(default = "default_llm_request_timeout_secs")]
default 300). 옛 config 가 키 누락해도 그대로 파싱 + 동일
동작.
- env override KEBAB_MODELS_LLM_REQUEST_TIMEOUT_SECS.
- kebab-llm-local::ollama.rs 의 REQUEST_TIMEOUT 상수 제거 →
OllamaLanguageModel::new 가 Duration::from_secs(
llm.request_timeout_secs) 로 reqwest client 빌드. doc
comment 도 동일 갱신.
- 신규 unit test 3 — default 300 핀 / env override / legacy
config (필드 누락) backward-compat.
(2) docs — README 사전 요구 절 + docs/SMOKE.md ollama 안내에 한 단락:
CPU only / RAM ≤ 16 GB 환경 ⇒ ≤ 4B Q4 모델 권장
(gemma3:4b / qwen2.5:3b / phi3:mini). 8B+ 시도 시 timeout
패턴 사전 안내. request_timeout_secs 노브 사용법.
HOTFIXES 2026-05-25 entry — 위 두 변경 + 미진행 사항
(kebab-parse-image OCR 의 같은 hard-coded 300s 는 scope 외
follow-up 으로 등재 + ask --stream 권장 강조 후속) 기록.
workspace cargo test -j 1 + clippy 통과. 코드 변경은 backwards-compat
(additive serde field) 라 기존 사용자 영향 없음.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- tasks/HOTFIXES.md: 새 2026-05-24 PR-B closure entry — extractor 의
type_definition 분기, PARSER_VERSION bump, same-workspace_path
orphan purge, 사용자 영향, 잔여 nested typedef Risks.
- tasks/HOTFIXES.md: 기존 2026-05-21 typedef 항목의 Status / Next step
을 v0.17.0 closure 표현으로 갱신 (관찰 기록은 frozen 유지).
- tasks/p10/p10-1d-c-cpp-ast-chunker.md: Risks 의 typedef idiom 라인
을 closure ✅ + 잔여 nested typedef 안내로 갱신.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- HOTFIXES: 새 2026-05-24 절 — v0.17.0 closure 영향 (한국어
lexical 3-gram, 영어 substring 변경, BM25 분포, 디스크 용량,
heading_path JSON 노이즈 관찰). 기존 2026-05-22 한국어 lexical
항목의 Status / Next step 을 closure 표현으로 갱신.
- HANDOFF: 머지 후 발견 deviation 절에 2026-05-24 entry +
기존 2026-05-22 항목을 closure cross-link 로 정리. P10
백로그 한국어 tokenizer 항목 ✅ v0.17.0 + "다음 task 후보"
follow-up 라인의 상태 갱신.
- README: 검색 명령 행에 trigram 동작 + hint + 디스크 용량 한 줄.
- SMOKE: 새 "한국어 trigram 검색 (v0.17.0)" 절 — 도그푸딩 query
시퀀스 (충돌은 raw / 해시 충돌 multi-token / Rust 충돌은
mixed / 충돌 2자 + stderr / --json hint 검증) + 영어 substring
동작 변경 안내.
- SKILL.md: search 절에 hint 필드 안내 한 줄 — agent 가
short query 케이스에서 같은 query 재시도 대신 사용자에게
surface 하도록.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
PR #158 code-reviewer recommendation. Records the dogfood-discovered
k8s multi-resource chunk_id collision + the deliberate decision NOT to
bump chunker_version (dogfood-only stage, single-resource k8s chunk_id
shift is benign churn). Cross-link added to p10-2 spec Risks/notes.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
PR #156 reviewer nit #2. Documents the tension between spec body
("struct_specifier (named, top-level) → 1 unit") and the actual behavior
for the C idiom `typedef struct { ... } Foo;` — the inner struct_specifier
is anonymous, so the extractor falls into glue. Workaround: dogfood-driven
revisit if frequent pain point emerges.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
(1) tasks/HOTFIXES.md: add 2026-05-20 entry for path-sanitize gap in
module_path_for_python / _tsjs (promised in task spec line 55 but
not landed in round 0). Bidirectional cross-link added.
(2) crates/kebab-parse-code: dedup filename_from_workspace_path /
strip_extension / join_symbol via new pub(crate) module scaffold.rs.
Removed 9 byte-identical fn copies across rust/python/typescript/
javascript extractors. Pure refactor — no behavior change.
(3) crates/kebab-parse-code/tests/fixtures/sample.py: @staticmethod was
semantically inappropriate on a module-level fn (class-method
decorator). Changed to @no_type_check; test assertion updated.
(5)+(6) crates/kebab-parse-code/src/lang.rs: add tests/test_foo.py case
to module_path_for_python test + doc clarifying that tests/ /
examples/ / benches/ are intentionally not stripped.
(4) PUSH BACK — TS/JS class decorator handling is design intent of 1B
1차 (typescript.rs:242-244 + HOTFIXES entry 2 already in place).
No code change.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- error_wire: StructuredError wrapper preserves ErrorV1 through
anyhow → classify pipeline. Adds downcast short-circuit so
cursor::decode's typed code = "stale_cursor" reaches the wire
instead of being string-formatted to code = "generic".
- app: search_with_opts now wraps cursor::decode error in
StructuredError instead of anyhow! string format.
- test: error_wire pins both negative (bare anyhow → not
stale_cursor) AND positive (StructuredError → stale_cursor)
invariants. CLI integration test runs end-to-end and asserts
error.v1.code on stderr.
- app: next_cursor only emitted on full-page (k-pop) path; drop
speculative emit on snippet-only truncation that would point at
a different page than the agent expected.
- cursor: differentiate malformed-base64 / malformed-payload /
revision-mismatch error messages; all keep code = stale_cursor.
- test: cursor_rejected fixture uses .expect() to fail loud on
cursor non-emission instead of silent skip.
- test: max_tokens=0 → 1-hit floor + truncated=true.
- docs: SKILL.md + schema description distinguish snippet-shrink
(widen) vs k-pop (paginate) truncated cases. HOTFIXES notes
--no-cache semantic shift (cached path + clear vs uncached path).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Pointed at the actual fb-33 design spec path + clarified that
the AskOpts type widening is a byproduct of the new wire schema
forcing single-sink 3-stage transport, not a stand-alone breaking
change.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- pipeline: refresh module docstring step 5 to reflect new cancel
semantics (RetrievalDone/Token/Final + LlmStreamAborted)
- wire schema: spell out refusal-path behavior in answer_event.v1
description (only retrieval_done emitted; no final)
- test: factual comment on relax_score_gate-using test corrected
- test: new Ollama-gated stream_score_gate_refusal_emits_only_retrieval_done
- test: new ask_emits_no_final_when_cancelled_mid_stream pinning
the no-Final invariant on cancel
- pipeline: large_enum_variant comment broadened to acknowledge
RetrievalDone.hits as the dominant per-emit cost
- HOTFIXES: log AskOpts.stream_sink internal API break per spec
contract policy
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- spec: add one-line cross-link to HOTFIXES entry per CLAUDE.md
Spec-contract policy
- HOTFIXES: rename heading from "fb-32" to "p9-fb-32" matching
the rest of the file's full-ID convention
- config: defensive assert before string-replace in negative TOML
test guards against default-value drift causing unhelpful unwrap
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
dirs::config_dir() and dirs::data_dir() both return ~/Library/Application Support
on macOS, so data_dir == config parent dir. ResetScope::DataOnly removes data_dir
and silently deletes config.toml along with it.
Fix: bypass dirs crate fallback for config/data/cache dirs; use
$HOME/.config, $HOME/.local/share, $HOME/.cache directly (XDG standard).
xdg_state_dir already used this pattern. dirs::home_dir() still used for
portability.
Migration: Config::load(None) auto-copies legacy ~/Library/Application
Support/kebab/config.toml to the new ~/.config/kebab/ on first run and
prints a migration notice to stderr.
- fb-26 (progress.rs): Fixed Aborted unconditional writeln (TTY duplicate output)
and Completed TTY path missing summary line. Added KEBAB_PROGRESS=plain env
override and quiet field to ProgressMode.
- fb-28 (main.rs): Added --readonly / --quiet global flags with KEBAB_READONLY env.
Readonly blocks mutating commands (ingest/ingest-file/ingest-stdin/reset) with
exit code 1; error.v1 code "readonly_mode" in --json mode. Quiet suppresses all
human progress/hint stderr while preserving errors.
- Updated task spec status for p9-fb-26 and p9-fb-28 to 'merged'.
- Updated tasks/INDEX.md and HANDOFF.md with merge status and summary entries.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- schema.rs: extract `SCHEMA_V1_ID` const + re-export via kebab-app::lib.rs.
wire.rs::wire_schema 의 2 literal 도 import 해서 single source of truth.
- schema.rs::collect_models: parser_version 가 markdown 만 surface 함을
주석으로 명시 (PDF/image extractor 의 자체 version 은 SchemaV1.models 가
multi-medium map 으로 진화 시 surface).
- main.rs::print_schema_text: 헤더 줄 끝의 `\n` 제거 + `println!()` 추가 —
다른 section 들과 패턴 일관.
- error_classify.rs::llm_unreachable_classifies: timeout 50ms → 500ms (10x
headroom) + 접근 방식 + 한계 주석 추가.
- HOTFIXES: open_existing 의 RW flag + 주석-only enforcement 갭을
Known-limitation 에 명시.
Round 1 review summary: #104 (comment)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- SKILL.md: `streaming_ingest` → `streaming_ask`, `multi_turn` → `rag_multi_turn` (capability name mismatch flagged in final review — agents following the example literal would read non-existent fields).
- HOTFIXES.md: add `not_indexed.details` to the interim wire shape deviations list — emit `{ expected, found }` only (spec literal `{ data_dir, expected, found }` not honored because NotIndexed signal carries one full path, not separate data_dir).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
HOTFIXES 항목이 fb-27 의 live binding 변경 + interim wire shape
deviation 의 source of truth (error.v1.details 가 신규 typed signal
도입 전까지 spec literal 과 일부 일탈).
spec 상단 banner 와 frontmatter status 가 frozen 상태 + post-merge
HOTFIXES cross-link 으로 갱신.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>