546c1564b0
feat(rag): fb-41 PR-9c-1 — core types + wire scaffolding (NLI verification)
...
Surface-only PR (no behavior wiring — that's PR-9c-2):
- kebab-core: RefusalReason::NliVerificationFailed + NliModelUnavailable (serde rename_all="snake_case", wire = identical strings).
- kebab-core: Answer.verification: Option<VerificationSummary> field (additive minor wire — pre-v0.18 reader 무영향).
- kebab-core: VerificationSummary { nli_score: f32, nli_threshold: f32, nli_passed: bool } struct + lib.rs 재-export.
- kebab-config: NliCfg { model, provider } + ModelsCfg.nli (default Xenova/mDeBERTa-v3-base-xnli-multilingual-nli-2mil7).
- kebab-config: RagCfg.nli_threshold: f32 (default 0.0 = disabled, spec §2.6 single gate).
- kebab-config: env override KEBAB_MODELS_NLI_MODEL/PROVIDER + KEBAB_RAG_NLI_THRESHOLD (parse 실패 시 tracing::warn + default 유지).
- kebab-rag: RagPipeline.verifier: Option<Arc<dyn NliVerifier>> field + with_verifier builder (모두 #[allow(dead_code)] — PR-9c-2 의 step 8.5 hook 가 활성화 시 제거). RagPipeline::new signature 유지 (round-2 NEW-M1 Option B).
- kebab-rag: Cargo.toml 에 kebab-nli path 의존 추가.
- kebab-store-sqlite + kebab-tui: 두 신규 RefusalReason variant 에 대한 exhaustive match arm 추가 (snake_case label / 표시 문구).
- 모든 Answer 구축 site (rag 6 + cli/tui/eval 3 fixture) 에 verification: None 추가.
- wire schemas: answer.schema.json verification field + \$defs.VerificationSummary + refusal_reason.enum 2 추가. error.schema.json code.enum + details.description 2 추가 (forward-looking reserved).
- docs/ARCHITECTURE.md: Mermaid Adapters subgraph 의 nli 노드 + rag→nli + app→nli (forward-looking) + nli→config edges. nli→core edge 는 skip (kebab-nli/Cargo.toml direct dep 가 config 만, ARCHITECTURE 컨벤션 = direct deps only). 디렉토리 트리에 crates/kebab-nli/ 추가.
Tests: kebab-core 3 (serde rename + verification skip + struct shape) + kebab-config 6 (defaults + legacy + env + malformed env) + kebab-cli wire 5 (schema verification + enum 검증).
검증: cargo test --workspace -j 1 회귀 0 (pre-existing kebab-mcp::tools_call_ask_multi_hop flaky 1개 동일 — spec 에 명시된 known-flaky). cargo clippy --workspace --all-targets -D warnings clean.
Wire 영향: additive minor — answer.v1 의 verification optional + refusal_reason.enum 확장 + error.v1.code 확장.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com >
2026-05-25 23:27:36 +00:00
17c48a0ee6
feat(cli): fb-41 PR-4 — CLI --multi-hop flag + answer.v1 / error.v1 wire 확장
...
fb-41 multi-hop RAG 의 **PR-4** (PR-3b-ii 의 ScriptedLm + tests 위에서
user-facing CLI surface + JSON Schema 확장). PR-3b-i / PR-3b-ii 의 multi-hop
pipeline 을 `kebab ask --multi-hop` 으로 사용자에게 노출.
설계: docs/superpowers/specs/2026-05-25-p9-fb-41-multi-hop-rag-design.md
계획: docs/superpowers/plans/2026-05-25-p9-fb-41-multi-hop-rag.md (PR-4 단락)
## CLI surface
- `kebab ask --multi-hop <query>` — 새 flag (default false). `AskOpts.multi_hop`
로 전달, stream + non-stream 두 callsite 모두 갱신.
- `--show-citations` / `--hide-citations` / `--stream` / `--session` 등 기존
flag 와 orthogonal.
- `--json` 모드에서 `Answer.hops` 배열이 multi-hop happy path / refusal-with-
partial-trace 양쪽 경로에서 노출됨 (PR-3b-i + PR-3b-ii 의 wiring).
## Wire schema 확장
- `docs/wire-schema/v1/answer.schema.json`:
- 신규 `hops: array | null` 필드 (optional, additive). `HopRecord` 의
`$defs` 추가 — `iter` / `kind` (decompose|decide|synthesize) /
`sub_queries` / `context_chunks_added` / `forced_stop` / `llm_call_ms`
6 필드 + per-field doc.
- `refusal_reason` 필드를 `anyOf [enum, null]` 로 명시 — 6 variant
(`score_gate`, `llm_self_judge`, `no_index`, `no_chunks`,
`llm_stream_aborted`, `multi_hop_decompose_failed`). 이전 schema 는
`type: string|null` 만 명시 → enum 명시는 agent / consumer 의 strict
validate 강화 (additive — 기존 producer 값 모두 enum 안).
- `$id` / `schema_version` 변경 없음 — additive minor.
- `docs/wire-schema/v1/error.schema.json`:
- `code` enum 에 `multi_hop_decompose_failed` 추가. **이는 forward-looking
enum extension** — 현재 RefusalReason 은 `Answer.refusal_reason` (stdout)
으로만 노출되고 `error.v1` (stderr) 경로 안 거침. 미래 PR 에서 fatal
promotion 정책 결정 시 trigger 가능하도록 enum 만 미리 reserve.
- details.description 의 per-code 안내에 `multi_hop_decompose_failed: {}`
note 추가 — reserved 상태 명시.
## Tests
- `crates/kebab-cli/tests/wire_ask_multi_hop.rs` 신규 (4 Ollama-free pins):
- `cli_ask_help_advertises_multi_hop_flag`: clap-level smoke, `kebab ask
--help` 출력에 `--multi-hop` 등장 확인.
- `answer_schema_declares_hops_property_with_hop_record_defs`: `hops`
property 존재 + `$defs.HopRecord` 의 `kind` enum 3 variant
(decompose/decide/synthesize) 회귀 핀.
- `answer_schema_refusal_reason_enum_includes_multi_hop_decompose_failed`:
6 variant 모두 enum 에 존재 — 기존 5 도 함께 핀 (회귀 방지).
- `error_schema_code_enum_includes_multi_hop_decompose_failed`: 신규
code enum 확장 + 기존 code (config_invalid / not_indexed / ...) 보존 핀.
End-to-end multi-hop ask 의 live Ollama 검증은 후속 `#[ignore]` test 로
(같은 `wire_ask_stale.rs` 패턴). PR-4 의 범위 = clap + schema 정합성 만.
## 변경 없음
- `crates/kebab-app/src/error_wire.rs` — plan 의 "error_wire 매핑" 항목은
현재 RefusalReason 가 `Answer.refusal_reason` 로만 노출 (anyhow chain 안
거침) 라 trigger 가 없음. enum reservation 만으로 충분, 매핑 코드는 dead
code 회피. 향후 fatal-promotion 정책 (refusal → error.v1) 결정 시 PR-4b
로 split.
- `prompt_template_version` — `rag-multi-hop-v1` 그대로.
- TUI / MCP surface — PR-5 / PR-6 에서.
## 검증
- `cargo test -p kebab-cli -j 1` — 모든 test 통과 (신규 wire_ask_multi_hop 4 +
기존 ask / search / schema / ingest / mcp / reset 등 모두).
- `cargo clippy -p kebab-cli --all-targets -j 1 -- -D warnings` clean.
- 단일 crate 직렬 build (16 GB RAM 제약).
## 다음 PR
- PR-5: MCP `ask` tool 의 `multi_hop: bool` argument + `integrations/claude-
code/kebab/SKILL.md` 의 ask 절 갱신.
- PR-6: TUI Ask 패널 multi-hop toggle (F2 / Ctrl-T) + hop trace render.
- v0.18.0 cut (PR-6 머지 후): `Cargo.toml` 0.17.2 → 0.18.0 + HANDOFF /
HOTFIXES / INDEX 갱신 + gitea-release.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com >
2026-05-25 08:45:01 +00:00