feat(cli): kebab ask citation block (p9-fb-20) #64
Reference in New Issue
Block a user
Delete Branch "feat/p9-fb-20-citation"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
도그푸딩 항목 16 (citation 풀 경로 + scroll) 의 CLI part. 답변 출력 후
근거:절 —[N] <full path>#<fragment> (score=<s>)한 줄씩. 사용자가 narrow terminal 에서 잘리던 inline citation 형식 ([1] notes/foo.md#L12-L34) 대신 full path 한 줄 단위.변경
CLI
Cmd::Ask에 두 flag 추가:--show-citations— default ON, conflicts_with hide.--hide-citations— 답변 본문만 출력 (pipe 시 trailing metadata 회피).!cli.json && show && !hide && !ans.citations.is_empty()시 citation block 출력. 형식:--json무영향 — citations 가 wire payload 에 항상 포함.미적용 (out of scope)
render_citations_or_explain가 일부 cover. 추가 surface 는 후속 task (사용자 도그푸딩 priority 5위 의 핵심 = full path 가독성 = CLI block 으로 충족).Test plan
cargo check -p kebab-cliclean.cargo clippy -p kebab-cli --all-targets -- -D warningsclean.kebab askintegration 은 Ollama mock 없이 어려움 (P9-3 ask_smoke 도 같은 한계). flag parsing + format 검증은 다음 PR 에서 add 가능.후속
in_progress→completed.회차 1 — information accuracy 1건 + cleanup nit 1건 + 칭찬 3건.
핵심 actionable:
ans.retrieval.top_score를 모든 citation 라인에 반복 출력 — 사용자 오해 위험 (per-citation score 같다?).AnswerCitation에 per-citation score 없으니 score 컬럼 제거 + retrieval 메타 한 줄로 분리 권장.c.marker.clone().unwrap_or_else(...)한 단계.총평: --show/--hide flag 패턴 + --json 무영향 명시 + spec scope 분리 정직 — 칭찬. 위 actionable 2건만 정리하면 머지.
(칭찬)
--show-citations(default ON, conflicts_with hide) +--hide-citations두 flag 패턴 — clap 의conflicts_with가 mutually-exclusive 강제, default ON 이라 사용자 별도 입력 없이 citation block 자동 출력.--hide-citations한 번 typing 으로 pipe 시 답변 본문만. p9-fb-06 의 reset scope flag 의 ArgGroup 패턴과 일관.(칭찬)
--json무영향 — citations 가 wire payload (answer.v1) 에 항상 ���함. 사람-친화 출력 toggle 만 flag 영향, 외부 wrapper (Claude Code skill / MCP) 의 contract 변경 0. 코멘트 "citations are always included in the wire payload regardless of this flag" 가 의도 명시.(cleanup / 두 번 변환)
c.marker.as_deref().unwrap_or(&format!(...)).to_string()—format!가 String 만들고&으로 ref,as_deref가Option<&str>,unwrap_or가&str, 다시to_string— 두 번 변환.Why: 동작 OK 지만 reader 가 한 줄에 두 번 conversion 보면 "왜?" 의문.
How to apply:
let marker = c.marker.clone().unwrap_or_else(|| format!("{}", idx + 1));— 한 단계로 끝남.(information accuracy)
ans.retrieval.top_score를 모든 citation 라인에 반복 출력 — 사용자가 N 개 citation 모두 같은 score 보면서 "per-citation 점수 같다?" 오해.top_score는 retrieval 의 max 한 값 — citation 별 점수 아님.현재
kebab_core::AnswerCitation { marker, citation }가 per-citation score 안 가짐 (Citation enum 도 위치 정보만). per-citation score 노출하려면 facade / Answer struct 변경 필요 — 본 PR scope 밖.Why: misleading 정보 노출보다 정보 누락이 정직. spec 본문의
(score=0.78, doc_id=abc123)형식은 미래 facade 확장 후 가능 — 본 PR 은 score 컬럼 자체 제거 + retrieval summary 한 줄로 분리 권장.How to apply: 출력 형식을
[N] <full path>#<fragment>단순으로 변경, citation block 아래에 한 줄(retrieval: top_score=X.XX, k=N, used=N/M)으로 retrieval 메타 분리. per-citation score 는 후속 task —AnswerCitation에score: Option<f32>추가 + RAG facade 가 SearchHit 와 매칭 시 채움.@@ -4,3 +4,3 @@task_id: p9-fb-20title: "Citation full path + scrollable pane (CLI block + TUI pane + jump)"status: plannedstatus: in_progress(칭찬) PR body + HANDOFF entry 가 spec scope 의 일부 (TUI fold + Enter/o jump + i inspect) 미적용을 정직 명시 + 후속 task 약속. p9-fb-04 의 "CLI Ctrl-C subprocess test 미적용" 패턴과 일관 — 본 PR 가 단일 PR scope 안에서 충분한 가치 제공 (full path 가독성 = 사용자 priority 5위 핵심) + 추가 surface 는 미래 PR. spec 본문 무수정.
회차 2 — actionable 2건 (per-citation score 제거 + retrieval 메타 한 줄로 분리 / marker fallback 단순화) 정확히 반영. APPROVE.