spec(p9-fb-15): RAG multi-turn 정책 + answer.v1 conversation_id/turn_index #59

Merged
altair823 merged 2 commits from spec/p9-fb-15-multi-turn-ask into main 2026-05-02 22:12:08 +00:00
Owner

Summary

도그푸딩 항목 13 (ask 의 꼬리 물기) — multi-turn surface 의 frozen design + wire schema spec PR. 후속 4 impl PR (p9-fb-15 RAG core / p9-fb-16 TUI UI / p9-fb-17 V004 chat sessions / p9-fb-18 CLI session/repl) 의 contract.

변경

Frozen design §3.8

  • Answer struct 에 두 optional field: conversation_id: Option<String>, turn_index: Option<u32>.
  • Turn struct 신설 (history 가 prompt 에 들어갈 때 한 turn).
  • "Multi-turn behaviour" 신설 절:
    • kebab-rag::ask (single-shot, 기존) vs ask_with_history (multi-turn) 두 entry.
    • prompt 빌드 priority: system + new_question (필수) → retrieved chunks (k 줄여 fit) → history (newest 우선, oldest drop).
    • retrieval query expansion: 직전 answer 첫 200 자 concat (간단). LLM-based standalone question rewriting 은 P+.
    • Aborted vs Completed: ask 는 single-shot 이라 cancel 시 partial token + grounded=false + new LlmStreamAborted refusal_reason variant (impl PR 에서 함께 추가).

Wire schema §2.3 (answer.v1)

{
  \"conversation_id\": { \"type\": [\"string\", \"null\"] },
  \"turn_index\":      { \"type\": [\"integer\", \"null\"], \"minimum\": 0 }
}

기존 single-shot 소비자 (외부 wrapper / Claude Code skill / MCP) 영향 0 — 두 필드 모두 optional, default null.

Out of scope (impl PR 들에서 처리)

  • kebab-rag::ask_with_history impl + token budget enforcement → p9-fb-15
  • Answer::conversation_id / turn_index 채움 + RAG facade signature → p9-fb-15
  • TUI ask conversation transcript UI → p9-fb-16
  • SQLite V004 (chat_sessions / chat_turns) → p9-fb-17
  • CLI --session / --repl → p9-fb-18

Test plan

코드 변경 없음. doc + JSON Schema 만.

  • JSON Schema 7 valid (수동 검토)
  • 기존 answer.v1 와 backward-compat (두 새 필드 optional)
  • frozen design §11 동결 범위 준수 — wire schema 의 새 optional field + 새 struct (Turn) 만 추가, 기존 변경 0
## Summary 도그푸딩 항목 13 (ask 의 꼬리 물기) — multi-turn surface 의 frozen design + wire schema spec PR. 후속 4 impl PR (p9-fb-15 RAG core / p9-fb-16 TUI UI / p9-fb-17 V004 chat sessions / p9-fb-18 CLI session/repl) 의 contract. ## 변경 ### Frozen design §3.8 - `Answer` struct 에 두 optional field: `conversation_id: Option<String>`, `turn_index: Option<u32>`. - `Turn` struct 신설 (history 가 prompt 에 들어갈 때 한 turn). - \"Multi-turn behaviour\" 신설 절: - `kebab-rag::ask` (single-shot, 기존) vs `ask_with_history` (multi-turn) 두 entry. - prompt 빌드 priority: `system + new_question` (필수) → retrieved chunks (k 줄여 fit) → history (newest 우선, oldest drop). - retrieval query expansion: 직전 answer 첫 200 자 concat (간단). LLM-based standalone question rewriting 은 P+. - Aborted vs Completed: ask 는 single-shot 이라 cancel 시 partial token + `grounded=false` + new `LlmStreamAborted` refusal_reason variant (impl PR 에서 함께 추가). ### Wire schema §2.3 (`answer.v1`) ```json { \"conversation_id\": { \"type\": [\"string\", \"null\"] }, \"turn_index\": { \"type\": [\"integer\", \"null\"], \"minimum\": 0 } } ``` 기존 single-shot 소비자 (외부 wrapper / Claude Code skill / MCP) 영향 0 — 두 필드 모두 optional, default null. ### Out of scope (impl PR 들에서 처리) - `kebab-rag::ask_with_history` impl + token budget enforcement → p9-fb-15 - `Answer::conversation_id / turn_index` 채움 + RAG facade signature → p9-fb-15 - TUI ask conversation transcript UI → p9-fb-16 - SQLite V004 (chat_sessions / chat_turns) → p9-fb-17 - CLI `--session` / `--repl` → p9-fb-18 ## Test plan 코드 변경 없음. doc + JSON Schema 만. - [x] JSON Schema 7 valid (수동 검토) - [x] 기존 `answer.v1` 와 backward-compat (두 새 필드 optional) - [x] frozen design §11 동결 범위 준수 — wire schema 의 새 optional field + 새 struct (Turn) 만 추가, 기존 변경 0
altair823 added 1 commit 2026-05-02 22:09:40 +00:00
도그푸딩 후 추가된 ask multi-turn (꼬리 물기) surface 를 frozen design
+ wire schema 에 명시. p9-fb-15 (RAG core) + p9-fb-16 (TUI UI) +
p9-fb-17 (V004 chat sessions) + p9-fb-18 (CLI session/repl) 의 spec
PR — impl PR 들이 이어진다.

변경:
- §2.3 Answer wire schema: conversation_id (String?) + turn_index
  (u32?) 두 optional 필드. 기존 single-shot 소비자 (외부 wrapper)
  영향 없음 — 두 필드 모두 optional.
- §3.8 RAG types:
  - Answer struct 에 conversation_id / turn_index field 추가.
  - Turn struct 신설 (history 가 prompt 에 들어갈 때 한 turn).
- §3.8 \"Multi-turn behaviour\" 신설 절:
  - kebab-rag::ask vs ask_with_history 두 entry.
  - prompt 빌드 priority: system+question (필수) → retrieved chunks
    (k 줄여 fit) → history (newest 우선, oldest drop).
  - retrieval query expansion (직전 answer 첫 200자 concat).
  - Aborted vs Completed semantics — ask 는 single-shot 이라 cancel
    시 partial token + grounded=false + LlmStreamAborted refusal
    (variant 추가는 p9-fb-15 impl 가 함께).
- docs/wire-schema/v1/answer.schema.json: 두 필드 추가 +
  created_at 에 format: date-time (sibling ingest_progress.v1 와
  일관).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
claude-reviewer-01 requested changes 2026-05-02 22:11:22 +00:00
Dismissed
claude-reviewer-01 left a comment
Member

회차 1 — formatting nit 1건 + RefusalReason variant 미정의 1건 + 칭찬 3건.

핵심 actionable:

  1. (formatting) Aborted vs Completed semantics 절 끝 빈 줄 2 → 1.
  2. (완전성) RefusalReason enum 에 LlmStreamAborted variant 추가 — 본 spec PR 이 self-contained 가 되어야 p9-fb-15 impl PR 이 spec 변경 없이 진행 가능.

총평: 두 optional 필드의 backward-compat / prompt 빌드 priority 의 trade-off 명시 / ingest vs ask cancel semantics 비교 — spec 본문이 미래 review 부담을 사전 차단. 위 actionable 2 건만 정리하면 머지.

회차 1 — formatting nit 1건 + RefusalReason variant 미정의 1건 + 칭찬 3건. 핵심 actionable: 1. (formatting) `Aborted vs Completed semantics` 절 끝 빈 줄 2 → 1. 2. (완전성) `RefusalReason` enum 에 `LlmStreamAborted` variant 추가 — 본 spec PR 이 self-contained 가 되어야 p9-fb-15 impl PR 이 spec 변경 없이 진행 가능. 총평: 두 optional 필드의 backward-compat / prompt 빌드 priority 의 trade-off 명시 / ingest vs ask cancel semantics 비교 — spec 본문이 미래 review 부담을 사전 차단. 위 actionable 2 건만 정리하면 머지.

(칭찬) 두 optional 필드 (conversation_id / turn_index) backward-compat 명시 — "두 필드 모두 optional 이라 기존 answer.v1 소비자 (외부 wrapper) 영향 없음. multi-turn 모르는 wrapper 는 그냥 무시". external integration (Claude Code skill / MCP) 의 회귀 안전 보장이 spec 옆에서 명시. wire schema 의 ["string", "null"] / ["integer", "null"] 와 일치.

(칭찬) 두 optional 필드 (`conversation_id` / `turn_index`) backward-compat 명시 — "두 필드 모두 optional 이라 기존 `answer.v1` 소비자 (외부 wrapper) 영향 없음. multi-turn 모르는 wrapper 는 그냥 무시". external integration (Claude Code skill / MCP) 의 회귀 안전 보장이 spec 옆에서 명시. wire schema 의 `["string", "null"]` / `["integer", "null"]` 와 일치.

(칭찬) prompt 빌드 priority 의 명확한 3 단 + 이유 한 줄. system+question (필수) → retrieved chunks (k 줄여 fit) → history (newest 우선, oldest drop). 이유 명시: "history 의 가치는 보통 직전 1~2 turn 이 가장 큼. 오래된 turn 이 retrieved chunk 에 비해 marginal 가치라 trade-off 시 history 양보". 미래 reader 가 "왜 history 가 chunks 보다 후순위?" 의문 즉시 차단 — impl PR review 시 trade-off 설명 부담 ↓.

(칭찬) prompt 빌드 priority 의 명확한 3 단 + 이유 한 줄. `system+question` (필수) → `retrieved chunks` (k 줄여 fit) → `history` (newest 우선, oldest drop). 이유 명시: "history 의 가치는 보통 직전 1~2 turn 이 가장 큼. 오래된 turn 이 retrieved chunk 에 비해 marginal 가치라 trade-off 시 history 양보". 미래 reader 가 "왜 history 가 chunks 보다 후순위?" 의문 즉시 차단 — impl PR review 시 trade-off 설명 부담 ↓.

(완전성 / RefusalReason variant 미정의) Multi-turn behaviour 절이 refusal_reason=Some(LlmStreamAborted) 라는 variant 를 명시하지만 §3.8 의 pub enum RefusalReason { ScoreGate, LlmSelfJudge, NoIndex, NoChunks } 에 추가 안 함. spec PR 가 enum 까지 갱신해야 impl PR 가 spec 변경 없이 진행 가능 — frozen design contract 의 self-contained 원칙.

Why: spec PR / impl PR 분리 룰의 핵심은 "impl PR 이 spec 변경 안 함". 새 variant 가 본 PR 안에 정의되어 있어야 p9-fb-15 impl PR 이 spec 무수정 진행 가능.

How to apply 두 가지 중:

  1. pub enum RefusalReason { ScoreGate, LlmSelfJudge, NoIndex, NoChunks, LlmStreamAborted } 로 같은 PR 에 추가 + wire schema refusal_reason enum 추가 (현재 free string 이라 새 값도 자동 통과 — wire 변경 불필요).
  2. 문구를 (p9-fb-15 가 새 RefusalReason variant 또는 별 boolean field 로 처리) 로 약화 + impl PR 이 spec 변경하지 않도록 LlmStreamAborted 명시 자체를 빼기.

권장: 1 — variant 한 줄 추가가 가장 작은 surface.

(완전성 / RefusalReason variant 미정의) Multi-turn behaviour 절이 `refusal_reason=Some(LlmStreamAborted)` 라는 variant 를 명시하지만 §3.8 의 `pub enum RefusalReason { ScoreGate, LlmSelfJudge, NoIndex, NoChunks }` 에 추가 안 함. spec PR 가 enum 까지 갱신해야 impl PR 가 spec 변경 없이 진행 가능 — frozen design contract 의 self-contained 원칙. Why: spec PR / impl PR 분리 룰의 핵심은 "impl PR 이 spec 변경 안 함". 새 variant 가 본 PR 안에 정의되어 있어야 p9-fb-15 impl PR 이 spec 무수정 진행 가능. How to apply 두 가지 중: 1. `pub enum RefusalReason { ScoreGate, LlmSelfJudge, NoIndex, NoChunks, LlmStreamAborted }` 로 같은 PR 에 추가 + wire schema `refusal_reason` enum 추가 (현재 free `string` 이라 새 값도 자동 통과 — wire 변경 불필요). 2. 문구를 `(p9-fb-15 가 새 RefusalReason variant 또는 별 boolean field 로 처리)` 로 약화 + impl PR 이 spec 변경하지 않도록 `LlmStreamAborted` 명시 자체를 빼기. 권장: 1 — variant 한 줄 추가가 가장 작은 surface.

(칭찬) ingest cancel 의 "Aborted = Ok(IngestReport) 정상 반환" semantics 와 ask cancel 의 "partial token + grounded=false + refusal" semantics 의 차이를 spec 옆에서 구분. 두 surface 가 다른 contract 를 갖는 이유 (ingest = 부분 commit + idempotent re-run; ask = single-shot stream) 가 spec 의 같은 위치에서 비교 가능 — 미래 누군가 "왜 ingest 는 Ok 반환인데 ask 는 grounded=false?" 의문 즉시 답.

(칭찬) ingest cancel 의 "Aborted = `Ok(IngestReport)` 정상 반환" semantics 와 ask cancel 의 "partial token + `grounded=false` + refusal" semantics 의 차이를 spec 옆에서 구분. 두 surface 가 다른 contract 를 갖는 이유 (ingest = 부분 commit + idempotent re-run; ask = single-shot stream) 가 spec 의 같은 위치에서 비교 가능 — 미래 누군가 "왜 ingest 는 Ok 반환인데 ask 는 grounded=false?" 의문 즉시 답.

(nit / 가독성) Aborted vs Completed semantics 절 끝에 빈 줄 2 줄 (+ 두 번 line 75-76 in diff). 한 줄이면 충분 — 다른 절 사이는 모두 1 줄.

Why: markdown 자체 렌더링은 영향 없지만 raw spec 의 일관성 ↓. spec PR #51 머지 후속도 같은 nit 이 회차 1 에 잡혔던 이력 (§10 long-running 절 빈 줄 3→1).

How to apply: 빈 줄 1 줄 제거.

(nit / 가독성) `Aborted vs Completed semantics` 절 끝에 빈 줄 2 줄 (`+` 두 번 line 75-76 in diff). 한 줄이면 충분 — 다른 절 사이는 모두 1 줄. Why: markdown 자체 렌더링은 영향 없지만 raw spec 의 일관성 ↓. spec PR #51 머지 후속도 같은 nit 이 회차 1 에 잡혔던 이력 (`§10 long-running 절` 빈 줄 3→1). How to apply: 빈 줄 1 줄 제거.
altair823 added 1 commit 2026-05-02 22:11:56 +00:00
회차 1 actionable 2건 반영.

- §3.8 RefusalReason enum 에 LlmStreamAborted variant 추가 + doc
  comment (RAG retrieval 정상, model generation 단계에서만 중단).
  spec PR self-contained 원칙 — impl PR 이 spec 변경 없이 진행
  가능.
- Multi-turn behaviour 절 끝 빈 줄 2 → 1 + RefusalReason 정의
  cross-link 한 줄 추가.

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

회차 2 — RefusalReason::LlmStreamAborted variant 추가 + 빈 줄 정리. spec PR self-contained 원칙 정확. APPROVE.

회차 2 — RefusalReason::LlmStreamAborted variant 추가 + 빈 줄 정리. spec PR self-contained 원칙 정확. APPROVE.
altair823 merged commit 9ddd199727 into main 2026-05-02 22:12:08 +00:00
altair823 deleted branch spec/p9-fb-15-multi-turn-ask 2026-05-02 22:12:09 +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#59