feat(search): provenance 출처 필터 — [[workspace.sources]] 멀티소스 + --source/--source-type

혼합 출처 KB(위키+jira 등)에서 색인은 전부 하되 질의 시 출처로 좁히는 provenance
레버. 전역 trust 곱셈가중(weighted-RRF)은 A/B 에서 반증(θ=0.85 만으로 incident MRR
0.918→0.340 절벽, 점수 압축) — 필터가 see-saw 없는 올바른 레버.

- config [[workspace.sources]] (각 id/root/exclude/trust_level/source_type);
  단일 root 는 implicit `default` source 로 정규화. validate: id 유일·비어있지 않음.
- config schema v3→v4 (step_3_to_4, root→[[workspace.sources]] id=default 미러, 멱등)
- V014 documents.source_id 컬럼+인덱스 (additive, DEFAULT 'default', 재색인 0)
- Metadata.source_id + BodyHints trust precedence(frontmatter > source 기본값 > Primary)
- ingest: --root 미지정 시 resolved_sources() 순회 + doc 마다 source_id/trust stamp
- 검색 SearchFilters.source_type/source_id → lexical + vector 두 site (IN, OR)
- CLI kebab search --source <id> / --source-type <type> (repeatable/comma-sep)

도그푸딩(620 doc, jira400+wiki220): --source wiki 로 개념 질의 MRR 0.780→0.810,
--source jira 로 incident 0.918→0.975. trust precedence 실측(jira=secondary 기본값).

version bump 0.28.0 → 0.29.0 (신규 CLI flag + config 키 + V014 migration → minor).
follow-up: MCP search 필터 미노출 · kebab list source_id 미표시 · RAG provenance 라벨.

자세한 내용: tasks/HOTFIXES.md (2026-06-21), docs/release-notes/v0.29.0-draft.md.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012Mc6W1fgsrbFKTsqA6P8La
This commit is contained in:
2026-06-21 08:35:19 +00:00
parent 403e162ac0
commit 58ac62d53a
101 changed files with 1201 additions and 111 deletions

View File

@@ -0,0 +1,104 @@
---
title: kebab v0.29.0 release notes (draft)
created: 2026-06-21
status: draft
release_trigger:
- 신규 CLI flag `kebab search --source` / `--source-type` — pre-1.0 minor bump
- 신규 config `[[workspace.sources]]` + V014 migration (documents.source_id) — 인터페이스 추가
- config schema v3→v4 (단일 root → implicit default source 미러)
---
# kebab v0.29.0 — provenance 출처 필터: 멀티소스 + `--source`
v0.28.0(config 스키마 재편) 후속 minor release. 혼합 출처 KB — 예컨대 위키
문서와 jira 이슈를 한 KB 에 같이 넣은 경우 — 에서 **색인은 전부 하되 질의 시
출처로 좁히는** provenance 레버를 추가한다. **기존 단일-폴더 사용자는 아무것도
손대지 않아도 된다** — 단일 `workspace.root` 는 자동으로 `default` 라는 하나의
source 로 정규화되고, 새 DB 컬럼은 기존 문서에 `default` 를 자동 채우는 additive
마이그레이션이라 재색인이 발생하지 않는다.
---
## 변경 사실
**1) 검색 출처 필터 2종.** `kebab search` 에 두 필터가 생겼다.
| flag | 의미 |
|---|---|
| `--source <id>` | `[[workspace.sources]]` 에 선언한 source 의 id 로 필터 (예: `--source jira`) |
| `--source-type <type>` | `markdown` / `note` / `paper` / `reference` / `inbox` 로 필터 |
둘 다 반복(`--source a --source b`) 또는 콤마(`--source a,b`)로 여러 값을 줄 수
있고 OR 로 묶인다. 빈 값 = 무필터. lexical · vector · hybrid **모든 검색 모드**에
동일하게 적용된다(직접 인덱스 컬럼 — 추가 비용 거의 없음).
**2) `[[workspace.sources]]` 멀티소스 config.** 단일 `[workspace] root` 대신
여러 폴더를 명명 source 로 선언할 수 있다.
```toml
[[workspace.sources]]
id = "notes"
root = "~/KnowledgeBase/notes"
[[workspace.sources]]
id = "jira"
root = "~/exports/jira"
trust_level = "secondary" # frontmatter 가 없을 때의 출처 기본 신뢰도
source_type = "reference" # frontmatter 가 없을 때의 출처 기본 타입
```
각 source 의 `id` 는 그 폴더에서 색인된 모든 문서에 stamp 되고
(`documents.source_id` 컬럼), `--source <id>` 필터의 대상이 된다.
`trust_level` / `source_type` 은 **출처 기본값**으로, 문서 frontmatter 가 해당
필드를 지정하지 않을 때만 적용된다 (우선순위: **frontmatter > source 기본값 >
하드코딩 Primary/Markdown**). `kebab ingest``--root` 를 주지 않으면 선언된
모든 source 를 각자의 root + exclude 로 순회한다.
## Trade-off — 왜 필터인가 (전역 trust 가중은 반증됨)
"출처가 섞이면 신뢰도로 가중하면 되지 않나?" 를 통제 실험으로 검증했고,
**전역 trust 곱셈가중은 반증됐다**. jira 를 docs KB 에 섞으면 개념 질의는 약하게
오염(top-3 정답은 유지, rank1→2 강등)되지만 운영/이슈 질의는 크게 개선된다
(jira_only hit@10 0/10 → 10/10). 그런데 jira 점수에 θ=0.85 만 곱해도 RAG 점수
압축 때문에 incident MRR 이 0.918→0.340 으로 절벽 하락한다 — 작은 오염을 잡으려다
큰 개선을 버리는 see-saw. 그래서 전역 가중은 **빌드하지 않았다**.
올바른 레버는 **질의 시 출처 필터링**이다: 색인은 전부 해 두고(운영 질의는
jira 가 답하게), 개념 질의에서만 `--source wiki` 로 좁힌다. see-saw 없이 양쪽을
다 얻는다.
## Mitigation — 기존 사용자 무영향 (재색인 0)
- **단일 root 그대로 동작**: `[[workspace.sources]]` 를 선언하지 않으면 기존
`workspace.root` 가 implicit `default` source 로 정규화된다. 모든 문서가
`source_id = "default"`.
- **V014 는 additive**: `documents.source_id` 컬럼은 `DEFAULT 'default'` 라 기존
row 가 자동으로 채워진다. 데이터 재작성·재색인·`corpus_revision` bump 없음.
- **config v3→v4 자동 변환**: load 시 메모리에서 자동 변환(디스크 미변경),
`kebab config migrate` 로 파일 갱신 시 값·주석 보존 + 멱등. 단일 `root`
`[[workspace.sources]]` id=default 로 **미러**되며 기존 `root` 키도 그대로 남는다.
도그푸딩(v0.29.0 release 빌드, 실험 corpus): 620 문서 / 0 error 색인,
`source_id = {jira: 400, wiki: 220}`. trust precedence 실측 — jira 는 source
기본값 secondary 라 `--trust-min primary` 시 0/6 노출, wiki 는 primary 유지.
출처 필터 실측 — `--source wiki` 로 개념 질의 MRR 0.780→0.810(오염 회복),
`--source jira` 로 incident 0.918→0.975.
## Upgrade 절차
1. 아무것도 안 해도 된다 — 기존 `config.toml` 과 KB 는 그대로 동작한다(단일 root
= `default` source, V014 자동 backfill).
2. 출처를 나누고 싶으면 `kebab config migrate` 로 config 를 v4 로 갱신한 뒤
`[[workspace.sources]]` 블록을 손으로 추가하고 `kebab ingest --force-reingest`
로 각 문서에 새 `source_id` 를 stamp 한다. (단순 `ingest` 는 내용이 안 바뀐
문서를 skip 하므로, 기존 문서의 source_id 를 `default` 외 값으로 바꾸려면
`--force-reingest` 필요.)
3. 검색에서 `--source <id>` / `--source-type <type>` 로 출처를 좁힌다.
## Known limitations / 다음
- **MCP search 도구**는 아직 `--source` / `--source-type` 를 노출하지 않는다
(CLI 전용). agent 용 MCP 필터 노출은 다음 additive 후보.
- **`kebab list`** 출력(`doc_summary.v1`)에 `source_id` 가 아직 안 실린다.
- **`kebab ask`** citation 에 provenance 라벨이 아직 없다 — 검색 필터는 되지만
답변 근거의 출처 표기는 다음 단계.