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:
@@ -34,6 +34,7 @@ Cargo workspace, 함수 호출 기반 모듈러 모놀리스. UI binary (`kebab-
|
||||
| RRF fusion_score | `[0, 1]` 정규화 — `2 / (k_rrf + 1)` 로 나눠 mode 간 비교 가능 (post-merge hotfix) |
|
||||
| ~~doc-side expansion 별칭 (v0.21.0)~~ | **제거됨 (v0.25.0, HOTFIXES 2026-06-03)** — 색인-시 청크당 LLM 별칭 생성 + 별칭 검색 채널을 완전히 제거. 별칭 ROI 음수(cross-lingual 은 e5-large 단독으로 충분, 기여는 설명형 +2 그룹뿐인데 대가가 청크당 색인-시 LLM). V013 마이그레이션이 `chunk_aliases_fts` + `chunks.aliases` DROP. 기존 KB 의 잔존 별칭 벡터는 검색 시 `strip_alias_suffix` 로 본문 chunk 에 매핑(graceful)되거나 `kebab reset` 으로 정리. spec: `docs/superpowers/specs/2026-06-03-remove-doc-expansion-spec.md`. |
|
||||
| 파생물 캐시 `derivation_cache` (V012, v0.21.0) | 비싼 ingest 파생물(embedding 벡터)을 청크 **내용 해시** 키로 SQLite 에 캐싱 → 재색인 시 내용 불변 청크는 재계산 skip. `cache_key = blake3(kind ‖ text_blake3 ‖ version_key)[:32]`; version_key 에 model/dimensions 포함 → §9 cascade 와 정합(버전 bump 시 자동 miss). 위치 기반 `chunk_id` 와 달리 내용이 같으면 문서·위치 무관 동일 키. 순수 가산 — `corpus_revision` bump 안 함, 손상/삭제돼도 정확성 영향 0(miss → 재계산). search/ask 는 `kebab.sqlite`+`lancedb` 만으로 동작하므로 외부 서버 색인 후 DB 만 복사하는 이식 워크플로 가능 (HOTFIXES 2026-05-31). (별칭 LLM 캐싱 kind 는 v0.25.0 에서 제거 — embedding kind 만 남음.) |
|
||||
| provenance 출처 필터 (v0.29.0) | 혼합 출처 KB 의 레버 = **질의 시 출처 필터링** (전역 trust 가중 아님). config `[[workspace.sources]]`(각 id/root/trust_level/source_type) → `documents.source_id` 컬럼(V014, additive·DEFAULT `'default'`) stamp + 검색 `--source <id>` / `--source-type <type>`(lexical+vector 두 site, OR). 단일 root 는 implicit `default` source 로 정규화(config v3→v4 `step_3_to_4` 미러). per-source trust/type 는 frontmatter 부재 시 기본값(우선순위 frontmatter > source 기본값 > Primary). **전역 trust 곱셈가중(weighted-RRF)은 반증** — A/B 에서 θ=0.85 만으로 incident MRR 0.918→0.340 절벽(점수 압축), 작은 오염 잡으려다 큰 개선 버리는 see-saw 라 빌드 안 함. 필터는 see-saw 없음. (HOTFIXES 2026-06-21) |
|
||||
| layout | XDG (`~/.local/share/kebab/`, `~/.config/kebab/`, …) |
|
||||
|
||||
전체 frozen 설계는 [docs/superpowers/specs/2026-04-27-kebab-final-form-design.md](superpowers/specs/2026-04-27-kebab-final-form-design.md) 12 sections 참조.
|
||||
@@ -219,7 +220,7 @@ kebab/
|
||||
│ ├── kebab-tui/ # Ratatui shell + Library 패널 (P9-1)
|
||||
│ ├── kebab-mcp/ # stdio MCP server — tools: schema, doctor, search, ask (P9-FB-30)
|
||||
│ └── kebab-cli/ # binary (P0 → 핫픽스로 --config flag wiring 강화)
|
||||
├── migrations/ # SQLite refinery V001..V012 (V012 = derivation_cache, v0.21.0)
|
||||
├── migrations/ # SQLite refinery V001..V014 (V012 = derivation_cache v0.21.0, V013 = drop chunk_aliases v0.25.0, V014 = documents.source_id v0.29.0)
|
||||
└── fixtures/ # 테스트 fixture 트리
|
||||
```
|
||||
|
||||
|
||||
@@ -397,6 +397,22 @@ $KB search 'tokenizer' --mode lexical --json | jq '.hits | length' # ≥ 1 if co
|
||||
- `--lang` ISO code.
|
||||
- `--path-glob` workspace_path glob.
|
||||
|
||||
### §2.4bis Source / provenance filters (`--source` / `--source-type`, v0.29.0)
|
||||
|
||||
```bash
|
||||
# 출처 id 필터 ([[workspace.sources]] 의 id; 단일 root 는 "default").
|
||||
"$RELEASE_BIN" search --config "$DOGFOOD/config.toml" "query" --source jira --json | jq '.hits | length'
|
||||
# source_type 필터 (markdown/note/paper/reference/inbox).
|
||||
"$RELEASE_BIN" search --config "$DOGFOOD/config.toml" "query" --source-type reference,markdown --json
|
||||
```
|
||||
|
||||
**verify**:
|
||||
- `--source` / `--source-type` repeatable + comma-sep, OR within.
|
||||
- lexical · vector · hybrid 모든 모드에 동일 적용 (직접 인덱스 컬럼 `documents.source_id` / `source_type`).
|
||||
- 모르는 값 → silently empty (no error).
|
||||
- 멀티소스 KB 측정: `--source wiki` 가 개념 질의 오염 회복(MRR 0.780→0.810), `--source jira` 가 incident 0.918→0.975 (HOTFIXES 2026-06-21).
|
||||
- trust precedence: `[[workspace.sources]]` 의 per-source `trust_level` 가 frontmatter 부재 시 적용 → `--trust-min primary` 와 조합 시 secondary source 배제.
|
||||
|
||||
### §2.5 Search pagination (p9-fb-34)
|
||||
|
||||
```bash
|
||||
|
||||
@@ -290,6 +290,21 @@ kebab search "rust" --doc-id "<doc-id>" --tag rust --json
|
||||
Bad `--ingested-after` → `error.v1.code = config_invalid`, exit 2.
|
||||
Unknown `--media` value → silently empty (no error).
|
||||
|
||||
### Source filters (`--source` / `--source-type`)
|
||||
|
||||
````bash
|
||||
# 단일 root 워크스페이스는 implicit `default` source 로 정규화되므로
|
||||
# 모든 문서가 source_id="default" — 이 필터는 전체와 동일하다.
|
||||
kebab search "rust" --source default --json | jq '.hits | length'
|
||||
|
||||
# source_type 필터 (frontmatter 의 source_type: 또는 source 기본값).
|
||||
kebab search "rust" --source-type markdown,reference --json | jq '.hits | length'
|
||||
````
|
||||
|
||||
멀티소스 KB 는 `[[workspace.sources]]` 로 명명 source 를 선언하면
|
||||
`--source <id>` 로 출처를 좁힌다 (예: `--source jira` → jira 문서만).
|
||||
빈 값 = 무필터, 콤마/반복 = OR. 모르는 값 → silently empty (no error).
|
||||
|
||||
### Trace + stats (fb-37)
|
||||
|
||||
Re-run a search with `--trace` to see per-stage candidate lists + timing:
|
||||
|
||||
104
docs/release-notes/v0.29.0-draft.md
Normal file
104
docs/release-notes/v0.29.0-draft.md
Normal 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 라벨이 아직 없다 — 검색 필터는 되지만
|
||||
답변 근거의 출처 표기는 다음 단계.
|
||||
Reference in New Issue
Block a user