Files
kebab/HANDOFF.md
altair823 0490b6a126 feat(kebab-tui): P9-2 Search pane — input + dense hits + preview + editor jump
Library 의 / 키가 활성화. App.search slot 이 lazy 채워지고 (run loop 가 SwitchPane(Search) 받을 때),
debounce 200 ms 후 kebab-app::search 호출, 선택된 hit 의 chunk 를 preview pane 에 표시.
g 키로 $EDITOR (vim/nvim/code/cursor 자동 감지) 에서 citation 위치 열림.

핵심:
- SearchState 본체 (`app.rs` 의 forward decl 채움) — input / mode / hits /
  selected_hit / input_dirty_at / last_query / searching / preview.
- `src/search.rs` (신규):
  - `render_search(f, area, state)` — 3-pane layout (input bar / 결과 리스트 / preview).
    각 hit 는 §1.5 dense 4-line format (rank.score URI / heading / snippet).
  - `handle_key_search`: typing → input + dirty mark. Tab → mode 순환. Enter →
    immediate refresh. j/k → 선택 이동 + preview invalidate. g → editor jump
    (RAII raw-mode suspend). Esc → Library 복귀.
  - `build_jump_command(citation, editor_env, workspace_root)` 가 vim 류
    `+<line> path` / VS Code `code -g path:line` / cursor `cursor -g`
    자동 분기. unit test 로 잠금.
  - `jump_to_citation` 가 raw-mode + AltScreen 을 RAII 로 suspend/restore
    (panic 안전).
  - run-loop hook 4 함수: `debounce_due` / `fire_search` /
    `refresh_preview` (private to crate).
- run.rs:
  - Pane::Search arm 이 `handle_key_search` 로 dispatch + `render_search`.
  - SwitchPane(Search) 시 `app.search = Some(SearchState::default())` lazy init.
  - Idle tick 마다 debounce_due → fire_search, preview None → refresh_preview.
- 테스트 13개 (`tests/search.rs`) — Esc/typing/backspace/Tab cycle/Enter
  refresh/j-k 이동/jump cmd vim+code+args/render w/hits/empty render/no slot.

Spec deviation (HOTFIXES `2026-05-02 P9-2`):
- `render_search<B: Backend>` generic 제거 (P9-1 와 동일 사유 — ratatui 0.28
  Frame backend-agnostic).
- `jump_to_citation` 가 `workspace_root: &Path` 인자 추가. Citation.path 가
  workspace 상대 라 editor 호출 시 절대 경로 필요. spec literal 의 시그니처
  는 unimplementable.

Docs (sync rule):
- README: TUI 행 \"Library + Search 패널, ask/inspect 진행 중\" + Quick start
  의 `kebab tui` 코멘트 갱신.
- HANDOFF: 한 줄 요약 + Phase status (P9 1/5 → 2/5) + deviation 한 줄 추가.
- HOTFIXES: P9-2 entry 추가.
- tasks/p9/p9-2 status: completed.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-02 14:38:17 +00:00

5.5 KiB
Raw Blame History

HANDOFF — 진척도

새 conversation / 다른 사람이 이어받을 때 "지금 어디까지 됐고 다음에 뭘 할지" 의 단일 출처. 사용자 사용법은 README.md, 아키텍처는 docs/ARCHITECTURE.md, per-component 진행은 tasks/INDEX.md, 머지 후 발견된 버그는 tasks/HOTFIXES.md. 이 파일은 "phase 단위 진척" + "다음 task 후보" 만 담는다.

한 줄 요약

P0P5 + P6 + P7 + P9-1 (Library) + P9-2 (Search) 머지 완료. kebab ingest 가 markdown / image / PDF 모두 처리. kebab search / kebab ask 가 매체 가로질러 결과 + page citation 반환. kebab tui 가 Library + Search 패널 제공 (ask/inspect/desktop 진행 예정). 다음 후보 = P9-3 (TUI ask) / P9-4 (TUI inspect) / P9-5 (desktop tauri), 또는 보류 중인 P8 (audio) 의 시스템 dep brainstorm.

Phase 로드맵

Phase 내용 핵심 산출 crate 선행 상태
P0 Workspace 뼈대 + 도메인 계약 + ID recipe kebab-core, kebab-parse-types, kebab-config, kebab-app, kebab-cli 완료
P1 Markdown ingestion (walk → parse → chunk → SQLite) kebab-source-fs, kebab-parse-md, kebab-normalize, kebab-chunk, kebab-store-sqlite P0 완료
P2 SQLite FTS5 lexical 검색 + citation kebab-search (lexical) P1 완료
P3 Local embedding + LanceDB + hybrid (RRF) + kebab-app wiring kebab-embed, kebab-embed-local, kebab-store-vector, kebab-search P2 완료
P4 Local LLM + RAG + grounded answer kebab-llm, kebab-llm-local, kebab-rag P3 완료
P5 Golden query / regression eval kebab-eval P4 완료
P6 이미지 ingestion (OCR + caption) kebab-parse-image P5 완료 (4/4 component, OCR/caption Ollama-vision)
P7 PDF text + page citation kebab-parse-pdf P5 완료 (3/3 component, page-level chunker + ingest wiring)
P8 음성 transcription + timestamp citation kebab-parse-audio P5 ⏸ 보류 (whisper-rs 시스템 dep brainstorm 필요)
P9 TUI + desktop app kebab-tui, kebab-desktop P5 🟡 진행 (2/5 component — P9-1 Library + P9-2 Search 완료, P9-3/4/5 예정)

P0P5 직렬. P6P9 P5 이후 병렬 가능.

Component 카운트

총 33 component task — spec 시점 31 개 + 후속 wiring task 3 (P3-5 / P6-4 / P7-3) 가 머지 시점에 추가됨. per-component 진행 + status 는 tasks/INDEX.md.

머지 후 발견된 버그 / 결정 (요약)

머지 후 발견된 모든 deviation / hotfix 의 dated 로그는 tasks/HOTFIXES.md. 본 요약은 "누군가가 인수받을 때 알아두면 시간을 많이 절약하는" 항목만:

  • P3-5 / P4-3 --config 누락kebab-cli--config <path> 를 honor 하려면 kebab_app::*_with_config companion 을 호출해야 함. 두 번 같은 모양으로 회귀했음.
  • P6-2 OCR 기본 엔진 — spec literal 의 Tesseract 가 시스템 dep 부담으로 거부됨, Ollama vision LM 으로 대체. OcrEngine trait 그대로라 future swap 가능.
  • P6-3 captionGenerateRequest.images 필드를 kebab-core::LanguageModel trait 에 신설. 기존 caller 모두 images: Vec::new() 로 마이그레이션.
  • P7-2 chunk_id 충돌 — pdf-page-v1 가 한 페이지 여러 chunk 분할 → 같은 block_ids 충돌. per-chunk policy_hash#c{char_start} 변형 으로 회피.
  • P7-3 storage UNIQUE bugassets.workspace_path UNIQUE + upsert_asset_rowON CONFLICT(asset_id) gap 으로 byte 변경 re-ingest 실패. purge_orphan_at_workspace_path helper 추가, follow-up PR 으로 vector store orphan cleanup 까지 닫음 (VectorStore::delete_by_chunk_ids).
  • P9-1 ratatui 0.28 — spec literal 의 render_library<B: Backend> generic 이 ratatui 0.28 의 backend-agnostic Frame 과 어긋나 있어 제거. 테스트 seam App::populate_library_for_testing (#[doc(hidden)]) 추가.
  • P9-2 jump_to_citation workspace_root — spec literal 의 jump_to_citation(citation, editor_env) 가 workspace_root 인자 누락. citation.path 가 workspace 상대라 editor 호출 시 절대 경로 필요 → workspace_root: &Path 인자 추가. 동일하게 render_search<B: Backend> generic 도 P9-1 과 같은 사유로 제거.

다음 task 후보

  • P9-2 TUI searchApp.search slot 채움. Library 의 / 가 enable 됨.
  • P9-3 TUI askApp.ask slot 채움. ? enable.
  • P9-4 TUI inspectApp.inspect slot 채움. Enter enable.
  • P9-5 desktop tauri — 별도 분기. PDF citation rendering UI 가치 큼.
  • P8 audio brainstorm — whisper-rs 시스템 dep 받을지 / 외부 transcription endpoint 사용할지 사용자 결정 필요. 사용자 패턴 (책+PDF 위주, audio 의향 없음) 상 후순위.

P9-2/3/4 는 P9-1 의 parallel-safety contract (sub-state slot 패턴) 덕에 병렬 진행 가능 — 같은 App 손대지 않음.

검증된 운영 동작 (release binary, fastembed enabled)

P7-3 머지 직후 25 시나리오 smoke 통과 — markdown + image + PDF 5 자산 워크스페이스에서 doctor / ingest / list / inspect / search (lex/vec/hybrid) / re-ingest / byte-edit re-ingest / corrupt PDF / RAG ask + page citation 모두. 자세한 시나리오 표는 conversation 기록 참조; 워크스페이스에 직접 돌려보는 절차는 docs/SMOKE.md.