feat(cli): fb-41 PR-4 CLI --multi-hop flag + answer.v1 / error.v1 wire #171

Merged
altair823 merged 2 commits from feat/fb-41-pr-4-cli-multi-hop-flag into main 2026-05-25 08:48:10 +00:00
Owner

요약

fb-41 multi-hop RAG 의 PR-4 (PR-3b-ii 머지 직후). PR-3b-i / PR-3b-ii 의 multi-hop pipeline 을 kebab ask --multi-hop 으로 user-facing CLI 표면에 노출 + answer.v1 / error.v1 JSON Schema 확장.

설계: 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 모두 갱신.
  • 기존 flag (--show-citations / --stream / --session 등) 와 orthogonal — multi-hop 가 다른 surface 와 자유 조합.
  • --json 모드에서 multi-hop happy path / refusal-with-partial-trace 양쪽 경로 모두 Answer.hops 배열 노출 (PR-3b-i + PR-3b-ii 의 wiring 그대로).

Wire schema 확장 (additive)

  • answer.schema.json:
    • 신규 hops: array | null 필드 (optional). $defs.HopRecord 추가 — iter / kind (decompose|decide|synthesize) / sub_queries / context_chunks_added / forced_stop / llm_call_ms 6 필드 + per-field doc.
    • refusal_reasonanyOf [enum, null] 로 명시화 — 6 variant (score_gate / llm_self_judge / no_index / no_chunks / llm_stream_aborted / multi_hop_decompose_failed). 이전 schema 의 type: string|null 보다 strict + 새 variant 정합.
  • error.schema.json:
    • code enum 에 multi_hop_decompose_failed 추가. forward-looking — 현재 RefusalReason 은 Answer.refusal_reason (stdout) 으로만 노출되고 error.v1 (stderr) 경로 안 거침. 미래 fatal-promotion 정책 결정 시 reserve.

schema_version 그대로 (answer.v1 / error.v1) — additive minor.

Tests (tests/wire_ask_multi_hop.rs 신규, 4 Ollama-free pins)

  • cli_ask_help_advertises_multi_hop_flagkebab ask --help 의 stdout 에 --multi-hop 등장 (clap-level smoke).
  • answer_schema_declares_hops_property_with_hop_record_defshops property + \$defs.HopRecord.kind 3 variant 회귀 핀.
  • answer_schema_refusal_reason_enum_includes_multi_hop_decompose_failed — 6 variant 모두 enum 안 (기존 5 도 함께 핀).
  • error_schema_code_enum_includes_multi_hop_decompose_failed — 신규 + 기존 code 보존 핀.

End-to-end live Ollama 검증은 후속 #[ignore] test (wire_ask_stale.rs 패턴).

변경 없음 (의도된 deviation)

  • kebab-app/src/error_wire.rs — plan 의 "error_wire 매핑" 항목은 현재 RefusalReasonAnswer.refusal_reason 로만 노출 (anyhow chain 안 거침) 라 trigger 가 없음. enum reservation 만으로 충분, 매핑 코드는 dead-code 회피. 향후 fatal-promotion 정책 결정 시 PR-4b 로 split.
  • prompt_template_version (rag-multi-hop-v1) / TUI / MCP — PR-5 / PR-6 의 책임.

검증

  • cargo test -p kebab-cli -j 1 — 신규 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 제약).

시험 항목 (Test Plan)

  • kebab ask --help 의 stdout 에 --multi-hop 등장
  • answer.schema.jsonhops property + \$defs.HopRecord 회귀 핀
  • answer.schema.jsonrefusal_reason enum 6 variant (multi_hop_decompose_failed + 기존 5)
  • error.schema.jsoncode enum 에 multi_hop_decompose_failed 추가
  • 기존 ask / search / schema / mcp / reset / ingest test 회귀 없음 (clippy clean)

다음 PR

  • PR-5: MCP ask tool multi_hop: bool argument + integrations/claude-code/kebab/SKILL.md 의 ask 절 갱신.
  • PR-6: TUI Ask 패널 multi-hop toggle + hop trace render.
  • v0.18.0 cut (PR-6 머지 후).

Assisted-by: Claude Code

## 요약 fb-41 multi-hop RAG 의 **PR-4** (PR-3b-ii 머지 직후). PR-3b-i / PR-3b-ii 의 multi-hop pipeline 을 `kebab ask --multi-hop` 으로 user-facing CLI 표면에 노출 + answer.v1 / error.v1 JSON Schema 확장. 설계: 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 모두 갱신. - 기존 flag (`--show-citations` / `--stream` / `--session` 등) 와 orthogonal — multi-hop 가 다른 surface 와 자유 조합. - `--json` 모드에서 multi-hop happy path / refusal-with-partial-trace 양쪽 경로 모두 `Answer.hops` 배열 노출 (PR-3b-i + PR-3b-ii 의 wiring 그대로). ## Wire schema 확장 (additive) - `answer.schema.json`: - 신규 `hops: array | null` 필드 (optional). `$defs.HopRecord` 추가 — `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` 보다 strict + 새 variant 정합. - `error.schema.json`: - `code` enum 에 `multi_hop_decompose_failed` 추가. **forward-looking** — 현재 RefusalReason 은 `Answer.refusal_reason` (stdout) 으로만 노출되고 `error.v1` (stderr) 경로 안 거침. 미래 fatal-promotion 정책 결정 시 reserve. `schema_version` 그대로 (`answer.v1` / `error.v1`) — additive minor. ## Tests (`tests/wire_ask_multi_hop.rs` 신규, 4 Ollama-free pins) - `cli_ask_help_advertises_multi_hop_flag` — `kebab ask --help` 의 stdout 에 `--multi-hop` 등장 (clap-level smoke). - `answer_schema_declares_hops_property_with_hop_record_defs` — `hops` property + `\$defs.HopRecord.kind` 3 variant 회귀 핀. - `answer_schema_refusal_reason_enum_includes_multi_hop_decompose_failed` — 6 variant 모두 enum 안 (기존 5 도 함께 핀). - `error_schema_code_enum_includes_multi_hop_decompose_failed` — 신규 + 기존 code 보존 핀. End-to-end live Ollama 검증은 후속 `#[ignore]` test (`wire_ask_stale.rs` 패턴). ## 변경 없음 (의도된 deviation) - `kebab-app/src/error_wire.rs` — plan 의 \"error_wire 매핑\" 항목은 현재 `RefusalReason` 가 `Answer.refusal_reason` 로만 노출 (anyhow chain 안 거침) 라 trigger 가 없음. enum reservation 만으로 충분, 매핑 코드는 dead-code 회피. 향후 fatal-promotion 정책 결정 시 PR-4b 로 split. - `prompt_template_version` (`rag-multi-hop-v1`) / TUI / MCP — PR-5 / PR-6 의 책임. ## 검증 - `cargo test -p kebab-cli -j 1` — 신규 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 제약). ## 시험 항목 (Test Plan) - [x] `kebab ask --help` 의 stdout 에 `--multi-hop` 등장 - [x] `answer.schema.json` 의 `hops` property + `\$defs.HopRecord` 회귀 핀 - [x] `answer.schema.json` 의 `refusal_reason` enum 6 variant (multi_hop_decompose_failed + 기존 5) - [x] `error.schema.json` 의 `code` enum 에 `multi_hop_decompose_failed` 추가 - [x] 기존 ask / search / schema / mcp / reset / ingest test 회귀 없음 (clippy clean) ## 다음 PR - PR-5: MCP `ask` tool `multi_hop: bool` argument + `integrations/claude-code/kebab/SKILL.md` 의 ask 절 갱신. - PR-6: TUI Ask 패널 multi-hop toggle + hop trace render. - v0.18.0 cut (PR-6 머지 후). Assisted-by: Claude Code
altair823 added 1 commit 2026-05-25 08:45:38 +00:00
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>
claude-reviewer-01 requested changes 2026-05-25 08:47:00 +00:00
Dismissed
claude-reviewer-01 left a comment
Member

회차 1 — schema description 의 PR 번호 doc 1 건만 정정.

PR-4 의 scope (CLI flag + JSON Schema 확장 + 4 Ollama-free pin) 자체는 컴팩트하고 흐름 깨끗. clap arg + destructure + 2 callsite 의 minimal wiring, additive schema 확장, 4 test 의 회귀 핀 모두 정합. plan 의 error_wire 매핑 항목을 dead-code 회피 차원에서 reserve enum 으로 갈음한 deviation 도 commit 본문 + PR body 에 잘 명시됨.

본 유일 nit: answer.schema.jsonrefusal_reason description 이 multi_hop_decompose_failed 의 도입 시점을 PR-3a 라고 적었지만 실제로는 PR-2 의 변경. inline 코멘트에 정정 제안.

회차 1 — schema description 의 PR 번호 doc 1 건만 정정. PR-4 의 scope (CLI flag + JSON Schema 확장 + 4 Ollama-free pin) 자체는 컴팩트하고 흐름 깨끗. clap arg + destructure + 2 callsite 의 minimal wiring, additive schema 확장, 4 test 의 회귀 핀 모두 정합. plan 의 `error_wire 매핑` 항목을 dead-code 회피 차원에서 reserve enum 으로 갈음한 deviation 도 commit 본문 + PR body 에 잘 명시됨. 본 유일 nit: `answer.schema.json` 의 `refusal_reason` description 이 `multi_hop_decompose_failed` 의 도입 시점을 PR-3a 라고 적었지만 실제로는 PR-2 의 변경. inline 코멘트에 정정 제안.
@@ -24,0 +35,4 @@
},
{ "type": "null" }
],
"description": "p9-fb-41: `multi_hop_decompose_failed` added in PR-3a for the multi-hop pipeline (only emitted when AskOpts.multi_hop = true and the decompose LLM call fails to parse). Other variants are unchanged from earlier phases."

doc 부정확: description 의 \multi_hop_decompose_failed` added in PR-3a가 부정확. 실제로는 **PR-2** (#167, commitcf35f36) 에서 RefusalReason::MultiHopDecomposeFailedvariant +ask_multi_hop의 decompose-failure 분기를 함께 도입했다. PR-3a (#168) 는Answer.hopsfield +RagCfg` multi-hop knob 만 — refusal_reason variant 와 무관.

수정: added in PR-3a for the multi-hop pipelineadded in PR-2 alongside the multi-hop pipeline skeleton.

**doc 부정확**: description 의 `\`multi_hop_decompose_failed\` added in PR-3a` 가 부정확. 실제로는 **PR-2** (#167, commit `cf35f36`) 에서 `RefusalReason::MultiHopDecomposeFailed` variant + `ask_multi_hop` 의 decompose-failure 분기를 함께 도입했다. PR-3a (#168) 는 `Answer.hops` field + `RagCfg` multi-hop knob 만 — refusal_reason variant 와 무관. 수정: `added in PR-3a for the multi-hop pipeline` → `added in PR-2 alongside the multi-hop pipeline skeleton`.
altair823 added 1 commit 2026-05-25 08:47:39 +00:00
`answer.schema.json` 의 `refusal_reason` description 의 PR 번호 정정:
`multi_hop_decompose_failed` 도입 시점 = PR-2 (#167, RefusalReason variant
+ ask_multi_hop decompose-failure 분기). PR-3a (#168) 는 `Answer.hops`
field + RagCfg knob 만 — refusal variant 와 무관.

검증
- `cargo test -p kebab-cli -j 1 --test wire_ask_multi_hop` 4 모두 통과.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
claude-reviewer-01 approved these changes 2026-05-25 08:47:57 +00:00
claude-reviewer-01 left a comment
Member

회차 2 — 회차 1 의 schema description nit (PR-3a → PR-2) 완벽 반영. 추가 actionable 항목 없음 — 머지에 동의.

요약:

  • CLI --multi-hop flag 가 user-facing surface 에 노출. clap arg + destructure + 2 callsite (stream + non-stream) wiring 깨끗.
  • answer.schema.jsonhops property + $defs.HopRecord (6 field, kind enum 3 variant) 추가, refusal_reason enum 6 variant 명시화 (multi_hop_decompose_failed 포함).
  • error.schema.jsoncode enum 에 multi_hop_decompose_failed 추가 (forward-looking reservation, error_wire 매핑은 별 PR-4b 로 split).
  • 4 Ollama-free pin (tests/wire_ask_multi_hop.rs) — clap-help smoke + 3 schema 회귀 핀.
  • Wire schema additive — schema_version (answer.v1 / error.v1) 그대로, 옛 producer / consumer 영향 없음.
  • cargo test -p kebab-cli -j 1 모든 test 통과 (회귀 없음), cargo clippy ... -- -D warnings clean.
회차 2 — 회차 1 의 schema description nit (PR-3a → PR-2) 완벽 반영. 추가 actionable 항목 없음 — 머지에 동의. 요약: - CLI `--multi-hop` flag 가 user-facing surface 에 노출. clap arg + destructure + 2 callsite (stream + non-stream) wiring 깨끗. - `answer.schema.json` 의 `hops` property + `$defs.HopRecord` (6 field, kind enum 3 variant) 추가, `refusal_reason` enum 6 variant 명시화 (`multi_hop_decompose_failed` 포함). - `error.schema.json` 의 `code` enum 에 `multi_hop_decompose_failed` 추가 (forward-looking reservation, error_wire 매핑은 별 PR-4b 로 split). - 4 Ollama-free pin (`tests/wire_ask_multi_hop.rs`) — clap-help smoke + 3 schema 회귀 핀. - Wire schema additive — `schema_version` (`answer.v1` / `error.v1`) 그대로, 옛 producer / consumer 영향 없음. - `cargo test -p kebab-cli -j 1` 모든 test 통과 (회귀 없음), `cargo clippy ... -- -D warnings` clean.
altair823 merged commit f28a422f79 into main 2026-05-25 08:48:10 +00:00
altair823 deleted branch feat/fb-41-pr-4-cli-multi-hop-flag 2026-05-25 08:48:11 +00:00
Sign in to join this conversation.
No Reviewers
No Label
2 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: altair823-org/kebab#171