arctic 도그푸딩에서 OCR/caption 켜진 Obsidian 볼트가 중간부터 느려졌으나 TTY 진행바가 파일명·phase·모델·경과시간을 안 보여 "멈춤"처럼 보인 문제. 파일명 표시 + 느린 phase(OCR/caption/embed)+모델 실시간 + asset 경과 heartbeat + 종료 시 최장 소요 top-N 요약. additive wire(asset_phase, ocr_ms/caption_ms). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
5.2 KiB
5.2 KiB
Spec: ingest 로그 개선 (파일명·phase·heartbeat·slowest 요약)
날짜: 2026-06-03 유형: feature (관측성/UX, additive wire) 근거: arctic 도그푸딩 중 Obsidian 볼트(이미지/PDF 혼재 + OCR/caption on)에서 ingest 가 중간부터 느려졌는데, TTY 진행바가 파일명·현재 phase·모델·경과시간을 안 보여줘 "멈춘 것처럼" 보였다. 원인(비전 모델 스와핑)을 로그만으로 파악 불가. v0.24.0 상세 진행 로깅의 후속 — 느린 phase(특히 이미지 OCR/caption)와 병목 파일을 가시화한다.
현재 한계 (코드 근거)
kebab-cli/src/progress.rs:145— TTY 에서 AssetStarted 는 위치만 갱신, 파일명 메시지 미설정(의도적; 비-TTY 줄에만 파일명). → 인터랙티브 실행 시 현재 파일 안 보임.- 이미지 OCR/caption 진행 이벤트 없음 —
PdfOcrStarted/Finished(PDF 페이지)만 존재. 이미지 OCR/caption(gemma 비전, 느림)은 무이벤트 → 진행바 정지처럼 보임(lib.rsapply_ocr/apply_caption 호출 주변). - 한 asset 이 오래 걸려도 경과시간 heartbeat 없음(완료 후
AssetTimings⏱ 한 번). - 병목 파일을 사후 파악할 요약 없음.
목표 (사용자 결정: 1+2+3+4)
- 파일명을 TTY 진행바 메시지에 표시.
- 느린 phase(OCR/caption/embed) + 모델명 실시간 표시.
- 현재 asset 경과시간 heartbeat.
- 종료 시 가장 오래 걸린 파일 top-N 요약.
작업
A. wire 이벤트 (additive, ingest_progress.v1)
- 신규
AssetPhase { idx, total, phase, model }— asset 이 느린 phase 진입 시 emit.phase: &str∈ {"ocr","caption","embed"};model: Option<String>(그 phase 를 수행하는 모델 — OCR/caption=비전 LLM 모델 id, embed=임베더 model_id). 짧은 phase(parse/chunk/store)는 emit 안 함(노이즈 방지). AssetTimings확장:ocr_ms,caption_ms필드 추가(additive, 기본 0). 기존 parse/chunk/embed/store/expansion_ms 유지. → top-N 요약의 정확한 per-asset 총시간 계산 근거.PdfOcrStarted/Finished(기존) 유지 — PDF 페이지 단위 진행은 이미 있음.- wire schema
docs/wire-schema/v1/ingest_progress.schema.json:asset_phasekind +phase/model+ocr_ms/caption_ms필드 문서화(additive, v1 유지).
B. emit 지점 (kebab-app)
ingest_one_asset/ 이미지·미디어 경로(apply_ocr/apply_caption호출 직전,lib.rs:~1568/1586): 각각AssetPhase{phase:"ocr"|"caption", model}emit. 임베딩 루프 진입 시AssetPhase{phase:"embed", model:embedder.model_id}emit(텍스트 asset 도 적용).- OCR/caption 소요를 측정해
AssetTimings.ocr_ms/caption_ms채움.
C. CLI 렌더 (kebab-cli/src/progress.rs)
- 파일명: AssetStarted TTY 핸들러에서
bar.set_message(<path 축약>)(현재 위치-only 주석 제거). 비-TTY 줄은 그대로. - phase+모델: AssetPhase 수신 시
bar.set_message("{path} · {phase}({model})…"). - heartbeat: AssetStarted 에서 현재 asset 시작 시각 기록 + steady-tick(예: 1s)으로 메시지 끝에
(Ns)경과 갱신. asset 전환/완료 시 리셋. - slowest 요약: AssetStarted(idx→path) + AssetTimings(idx→총ms=parse+chunk+embed+store+ocr+caption) 를 누적,
Completed수신 시 stderr 에⏱ 최장 소요 top-N(기본 N=5) 표 출력. 비-TTY/quiet 에서도 요약은 출력(유용),--json모드는 미출력(ndjson 오염 방지).
결정 사항
- 모두 additive wire →
ingest_progress.v1유지(major bump 없음). 신규 소비자는asset_phase부재 허용. - AssetPhase 는 emit 스로틀 불필요(asset·phase 당 1회, 빈도 낮음). PDF 페이지 OCR 은 기존 PdfOcrStarted 가 담당(페이지 많으면 그쪽 스로틀은 별도 — 본 spec 비범위).
- top-N 의 N: 상수 5(후속에 config 화 가능, 본 spec 비범위).
--quiet시 진행바·phase 메시지는 억제하되 slowest 요약은 출력(짧고 유용).--json은 전부 ndjson 으로만.
검증 기준
- clippy 0 / 전체 test 통과(기존 진행 렌더 테스트 갱신 + 신규 이벤트 직렬화 테스트).
- TTY 스모크: 이미지/PDF 포함 폴더 ingest 시 진행바에 파일명 + OCR/caption/embed phase + 모델 + 경과초 표시, 종료 시 top-N 요약.
- 비-TTY: 기존 줄 로그 유지 + 종료 요약.
--json:asset_phase/확장asset_timingsndjson 출력, 사람용 텍스트 미혼입.- wire schema 문서 동기화 + verbatim 일치(CI diff-check 있으면).
도그푸딩 (별도)
사용자 Obsidian 볼트(이미지/PDF + OCR on)로 재현 — 느린 구간에서 어떤 파일·phase·모델인지 즉시 보이는지, 종료 요약이 병목 파일을 짚는지 확인. HOTFIXES + release notes.
문서 동기화 (같은 PR)
docs/wire-schema/v1/ingest_progress.schema.json(asset_phase, ocr_ms/caption_ms).- README(진행 표시 설명 있으면 갱신, 명령표 영향 없음), HANDOFF 1줄, tasks/HOTFIXES dated entry, Cargo.toml version minor bump.
비범위
- PDF 페이지 OCR 진행 스로틀/요약(기존 이벤트 유지).
- 모델 스와핑 자체 해결(그건 Ollama 설정/OCR off — 본 작업은 가시화만).
- top-N 의 config 화.