feat(app): IngestEvent + ingest_with_config_progress (p9-fb-01) #52
Reference in New Issue
Block a user
Delete Branch "feat/p9-fb-01-progress"
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
Spec PR #51 (frozen design §2.4a + §10 + wire schema
ingest_progress.v1) 의 첫 impl PR.kebab-app가 progress event 를mpsc::Sender<IngestEvent>로 흘려보내는 surface 를 noop 까지 갖춤. 후속 PR 두 개 (p9-fb-02 CLI display, p9-fb-03 TUI background) 가 이 stream 을 소비.변경
신규 모듈
crates/kebab-app/src/ingest_progress.rsIngestEventenum —#[serde(tag = "kind", rename_all = "snake_case")]로 직렬화, wire schemaingest_progress.v1와 1:1.ScanStarted/ScanCompleted/AssetStarted/AssetFinished/Completed/Aborted.Aborted는 p9-fb-04 (cancel) 가 트리거 — 본 PR 에서는 미발신.AggregateCountsstruct:Completed/Aborted의 terminal 집계.media_label(MediaType) -> &'static str: §2.4a 의 short label (markdown/pdf/image/audio/other).emit(progress, event): best-effort send. dropped receiver 는 silent absorb — ingest hot path 가 slow consumer 에 stall 안 함.facade
기존
ingest_with_config는progress = Noneforwarding wrapper. CLI / TUI / 외부 caller 가 stream 원하면_progress직접 호출.발신 site
ScanStarted { root }.ScanCompleted { total }.AssetStarted { idx, total, path, media }(1-based idx).AssetFinished { idx, total, result, chunks }.Completed { counts: AggregateCounts }.embed_batch_* 는 §2.4a 의 "asset 이벤트 사이 임의 위치" — v1 단순화로 미발신. asset 단위 해상도면 CLI spinner / TUI status bar 충분. 후속 task 가 필요 판단 시 추가.
미적용 (별 task)
IngestEvent::Aborted발신 (cancel token wiring) → p9-fb-04Test plan
cargo test -p kebab-app --lib ingest_progress— 6 PASS (media_label / serde discriminator / serde Completed counts / emit None / emit dropped / emit live).cargo test -p kebab-app --test ingest_progress— 3 PASS (§2.4a invariant 의 sequence / forwarding wrapper / dropped receiver tolerance).cargo clippy -p kebab-app --all-targets -- -D warningsclean.Plan 갱신
tasks/p9/p9-fb-01-ingest-progress-callback.mdfrontmatterstatus: planned→status: in_progress. 머지 후 별도 한 줄 commit 으로completedflip.회차 1 — nit 1건 + 칭찬 4건. 첫 impl PR 이라 표면 균질.
핵심 actionable:
emit의tracing::trace!메시지 두 번째 절 ("suppressing further sends would require caller cooperation") 모호 — 단순 "receiver dropped; event discarded" 정도로 단축 권장.총평: spec PR #51 의 §2.4a 계약 (ordering invariant, best-effort send, embed_batch optional, Aborted 가 별 task 의 책임) 이 코드 + test + doc 세 곳에 정확히 매핑. forwarding wrapper 패턴이 backward-compat shim 이 아닌 entry-point 조합 — facade rule 준수. integration test 가 §2.4a invariant 자체를 코드화 — 미래 emit 위치 변경 시 즉시 잡힘. 위 nit 1건만 정리하면 머지.
@@ -0,0 +67,4 @@/// Finished processing the `idx`-th asset. `result` mirrors the/// asset's `IngestItemKind`; `chunks` is the number of chunks/// produced (0 for `Skipped` / `Error`).AssetFinished {(칭찬)
#[serde(tag = "kind", rename_all = "snake_case")]가 wire schemaingest_progress.v1의 discriminator + 필드명과 1:1 일치 —kind = "asset_started"/idx/total/path/media자동. CLI 의 wire layer 가schema_version만 한 줄 더 붙이면 spec §2.4a 와 동일 JSON 산출. 미래 변경 시 (variants 추가 / 이름 변경) serde tag 만 보면 wire 영향 즉시 추적.@@ -0,0 +116,4 @@use super::*;use kebab_core::MediaType;#[test](칭찬)
emithelper 가Option<&Sender>받아 None 단축 + dropped receiver silent absorb 두 corner case 를 한 함수에 묶음 + lib unit test 3 개 (None / dropped / live) 가 각 분기 cover. ingest 의 hot path 에서 emit 호출 자체가 if-let 한 줄이라 noop overhead 0. integration test 의 "dropped receiver tolerance" 와 짝.@@ -0,0 +124,4 @@media_label(&MediaType::Image(kebab_core::ImageType::Png)),"image");assert_eq!((nit / 메시지 모호) trace! 메시지
progress receiver dropped; suppressing further sends would require caller cooperation— 두 번째 절이 의미 불명확 ("caller cooperation" 이 어떻게 suppress 를 가능하게 하는가?). 단순 receiver drop 사실만 기록하면 충분.Why: 이 trace! 는 producer 측 best-effort fail 의 원인을 추적하는 용도. "caller cooperation" 추측은 미래 reader 에게 노이즈 — 사실 ("receiver dropped") + 영향 ("event discarded") 만 기록.
How to apply: 메시지를
progress receiver dropped; event discarded (best-effort send per ingest_progress contract)정도로 단순화. 또는 더 짧게progress receiver dropped.(칭찬) 기존
ingest_with_config(...)가_progress(.., None)forwarding wrapper 로 단순화 — 본 PR scope 안에서 호출자 (CLI / TUI / integration test) 변경 0. forwarding 패턴이 backward-compat shim 이 아니라 "progress 의식 없는 caller 의 자연 entry point" 로 doc comment 가 의도 명시. CLAUDE.md 의 "backward-compat shim 금지" 룰 정합 — facade 의 의도된 surface 조합.(칭찬) integration test
progress_event_sequence_matches_design_section_2_4a가 §2.4a 의 ordering invariant (ScanStarted < ScanCompleted < (AssetStarted < AssetFinished)* < Completed) 를 코드로 코드화 + monotonic idx + Started/Finished 1:1 pairing 까지 assert. 미래 누군가 새 step 추가 또는 emit 위치 옮기면 이 테스트가 즉시 실패 — spec 변경 없이 invariant drift 막음. 회귀 안전망 정확히 spec 옆에서.회차 2 — 회차 1 nit 1건 (emit trace 메시지 단순화) 정확히 반영. 추가 actionable 0. APPROVE.