fix(kebab-config): p9-fb-25 — workspace.include 제거 + 지원 형식 가시성 #101

Merged
altair823 merged 11 commits from fix/p9-fb-25-config-include-removal into main 2026-05-05 12:46:37 +00:00
Owner

요약

도그푸딩 피드백 2건 (2026-05-05):

  1. config 의 `workspace.include` + `workspace.exclude` 동시 존재가 case 4 (둘 다 매치 안 함) 의미 모호.
  2. 어차피 처리 가능 형식 (md / png / jpg / pdf) 이 정해져 있으니 사용자에게 명시 필요.

주요 변경

설정

  • `WorkspaceCfg.include` 제거 (denylist-only). 옛 config 의 `include = [...]` 는 silently 무시 + `Config::from_file` 가 단발 `tracing::warn` 으로 deprecation 안내 (`std::sync::OnceLock` — process 안에서 한 번만).

지원 형식 가시성

  • `IngestItem.warnings`: Skipped 시 사유 채움. `"unsupported media type: .docx"` (확장자 있음) / `"unsupported media type: "` (확장자 없음) / `"kb:// URI not yet supported"`.
  • `IngestReport.skipped_by_extension: BTreeMap<String, u32>` + `AggregateCounts.skipped_by_extension` 신규. key = lowercase ext, no-ext sentinel = ``. wire schema additive (v1 호환 유지 — release 트리거 안 됨 per CLAUDE.md).
  • CLI summary + TUI status_line: `"5 skipped: 3 docx, 1 txt, 1 epub"` 형식. desc 정렬 (count) + ties by key alphabetic + 모두 표시.
  • `kebab init` 헤더 주석: 지원 형식 (Markdown / 이미지 / PDF + 각 확장자) 명시.
  • README: `kebab ingest` 설명에 지원 형식 + skip 사유 + breakdown 표시 명시.

코드 정리

  • `IngestOpts` 진입점은 그대로. `SourceScope` 생성 사이트들 (`kebab-cli`, `kebab-tui`, kebab-app tests) 가 `..Default::default()` 패턴으로 통일.

Spec contract impact

  • design §6.2 의 `workspace.include` 항목 invalidate (frozen 그대로 두고 본 PR + spec `tasks/p9/p9-fb-25-config-include-removal.md` 가 source of truth).
  • design §3.x `IngestReport` + §2.4a `IngestEvent` 에 새 필드 / 새 warning 의미 추가 (additive).

테스트

  • 신규 5: kebab-config (legacy include 무시 + WorkspaceCfg destructure) / kebab-app 통합 1 (skip_reason) / kebab-app 통합 1 (init_template) / kebab-tui 단위 2 (status_line breakdown 완료/abort).
  • `cargo test --workspace -j 1` → 729 passed, 0 failed.
  • `cargo clippy --workspace --all-targets -- -D warnings` clean.

참조 문서

  • Design spec: `docs/superpowers/specs/2026-05-05-p9-fb-25-config-include-removal-design.md`
  • Implementation plan: `docs/superpowers/plans/2026-05-05-p9-fb-25-config-include-removal.md` (7 task TDD)
  • Per-task spec: `tasks/p9/p9-fb-25-config-include-removal.md`
  • Live deviations: `tasks/HOTFIXES.md` `2026-05-05 — p9-fb-25`

Known limitation (deferred)

  • `SourceScope.include` (`kebab-core::traits`) 그대로 — design §7.1 abstraction. 별 spec 으로 가능.
  • 새 extractor (txt / docx / epub) 도입은 별 spec.
  • `kebab doctor` 가 unsupported 파일 카운트 분석은 후속 task.

머지 후

사용자 요청: patch bump (0.2.0 → 0.2.1) 별 PR 로 진행 + 새 release.

## 요약 도그푸딩 피드백 2건 (2026-05-05): 1. config 의 \`workspace.include\` + \`workspace.exclude\` 동시 존재가 case 4 (둘 다 매치 안 함) 의미 모호. 2. 어차피 처리 가능 형식 (md / png / jpg / pdf) 이 정해져 있으니 사용자에게 명시 필요. ## 주요 변경 ### 설정 - **\`WorkspaceCfg.include\` 제거** (denylist-only). 옛 config 의 \`include = [...]\` 는 silently 무시 + \`Config::from_file\` 가 단발 \`tracing::warn\` 으로 deprecation 안내 (\`std::sync::OnceLock\` — process 안에서 한 번만). ### 지원 형식 가시성 - **\`IngestItem.warnings\`**: Skipped 시 사유 채움. \`\"unsupported media type: .docx\"\` (확장자 있음) / \`\"unsupported media type: <no-ext>\"\` (확장자 없음) / \`\"kb:// URI not yet supported\"\`. - **\`IngestReport.skipped_by_extension: BTreeMap<String, u32>\`** + \`AggregateCounts.skipped_by_extension\` 신규. key = lowercase ext, no-ext sentinel = \`<no-ext>\`. wire schema additive (v1 호환 유지 — release 트리거 안 됨 per CLAUDE.md). - **CLI summary + TUI status_line**: \`\"5 skipped: 3 docx, 1 txt, 1 epub\"\` 형식. desc 정렬 (count) + ties by key alphabetic + 모두 표시. - **\`kebab init\` 헤더 주석**: 지원 형식 (Markdown / 이미지 / PDF + 각 확장자) 명시. - **README**: \`kebab ingest\` 설명에 지원 형식 + skip 사유 + breakdown 표시 명시. ### 코드 정리 - \`IngestOpts\` 진입점은 그대로. \`SourceScope\` 생성 사이트들 (\`kebab-cli\`, \`kebab-tui\`, kebab-app tests) 가 \`..Default::default()\` 패턴으로 통일. ## Spec contract impact - design §6.2 의 \`workspace.include\` 항목 invalidate (frozen 그대로 두고 본 PR + spec \`tasks/p9/p9-fb-25-config-include-removal.md\` 가 source of truth). - design §3.x \`IngestReport\` + §2.4a \`IngestEvent\` 에 새 필드 / 새 warning 의미 추가 (additive). ## 테스트 - 신규 5: kebab-config (legacy include 무시 + WorkspaceCfg destructure) / kebab-app 통합 1 (skip_reason) / kebab-app 통합 1 (init_template) / kebab-tui 단위 2 (status_line breakdown 완료/abort). - \`cargo test --workspace -j 1\` → **729 passed, 0 failed**. - \`cargo clippy --workspace --all-targets -- -D warnings\` clean. ## 참조 문서 - Design spec: \`docs/superpowers/specs/2026-05-05-p9-fb-25-config-include-removal-design.md\` - Implementation plan: \`docs/superpowers/plans/2026-05-05-p9-fb-25-config-include-removal.md\` (7 task TDD) - Per-task spec: \`tasks/p9/p9-fb-25-config-include-removal.md\` - Live deviations: \`tasks/HOTFIXES.md\` \`2026-05-05 — p9-fb-25\` ## Known limitation (deferred) - \`SourceScope.include\` (\`kebab-core::traits\`) 그대로 — design §7.1 abstraction. 별 spec 으로 가능. - 새 extractor (txt / docx / epub) 도입은 별 spec. - \`kebab doctor\` 가 unsupported 파일 카운트 분석은 후속 task. ## 머지 후 사용자 요청: patch bump (0.2.0 → 0.2.1) 별 PR 로 진행 + 새 release.
altair823 added 10 commits 2026-05-05 12:21:37 +00:00
도그푸딩 피드백 2026-05-05:
1. config 의 include + exclude 동시 존재가 case 4 (둘 다 매치 안 함)
   에서 의미 모호.
2. 어차피 처리 가능 형식 (md / png / jpg / pdf) 이 정해져 있으니
   사용자에게 명시 필요.

설계 핵심:

- `WorkspaceCfg.include: Vec<String>` 제거 (denylist-only). 옛 config
  의 `include = [...]` 은 silently 무시 + Config::load 가 단발
  deprecation warning emit.
- `IngestItem.warnings` 에 skip 사유 채움 (`unsupported media type:
  .docx` / `kb:// URI not yet supported`).
- `IngestReport.skipped_by_extension: BTreeMap<String, u32>` 신규
  (additive wire — release 트리거 안 됨 per CLAUDE.md). key =
  lowercase ext (`docx`, `txt`), no-ext = `<no-ext>` sentinel.
- CLI / TUI summary 에 breakdown 표시 (`90 skipped: 80 docx, 5 txt,
  5 epub`) — 모두, desc 정렬.
- README + `kebab init` config.toml 주석에 지원 형식 명시.

Spec status `planned`. 다음 단계: writing-plans skill 로 implementation
plan 작성.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Spec → 7-step plan, TDD per task.

Tasks:
1. Drop WorkspaceCfg.include + deprecation probe in Config::from_file
   (legacy include silently ignored + 단발 tracing::warn).
2. SourceScope construction cleanup (CLI + TUI 사용 ..Default::default()).
3. init_workspace header 에 지원 형식 명시 (md / png / jpg / pdf) + 테스트.
4. IngestReport.skipped_by_extension + AggregateCounts.skipped_by_extension
   (BTreeMap, stable JSON key) + wire schema additive.
5. IngestItem.warnings 채움 (`unsupported media type: .docx` 등) +
   ext_for_skip_warning helper + asset 루프 bump.
6. CLI summary + TUI status_line render breakdown (desc 정렬, 모두).
7. Docs sync — README + HANDOFF + HOTFIXES + INDEX + per-task spec.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Remove `pub include: Vec<String>` from `WorkspaceCfg` struct (denylist-only model).
- Drop `include: vec!["**/*.md"]` from `Config::defaults()`.
- Add `from_file` deprecation probe: raw `toml::Value` scan fires a
  one-shot `tracing::warn!` (via `OnceLock`) when an old config still
  carries `workspace.include = [...]`. serde ignores the unknown field
  cleanly (no `deny_unknown_fields`).
- Compile-fix `kebab-cli` (main.rs:329) and `kebab-tui`
  (ingest_progress.rs:39): replace `cfg.workspace.include.clone()` with
  `Vec::new()` (Task 2 will switch to `..Default::default()`).
- Two new tests: `legacy_include_field_is_ignored_silently` (backward
  compat round-trip) + `workspace_cfg_has_only_root_and_exclude_fields`
  (exhaustive destructure — compile-time guard against re-introduction).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
reviewer-flagged: task 1 missed test files using cfg.workspace.include.

- crates/kebab-app/tests/common/mod.rs: SourceScope literal switched
  to ..Default::default().
- crates/kebab-app/tests/image_pipeline.rs (×3): drop dead-no-op
  cfg.workspace.include.push(...) calls; comment explains removal.
- crates/kebab-app/tests/pdf_pipeline.rs: same treatment.

Pre-fb-25 these pushes were no-ops (include was dead config field
not enforced anywhere). Removal is purely mechanical.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Append ": A docx, B txt, ..." after the N skipped count in both the
CLI ingest summary and TUI status_line terminal events (completed +
aborted). Breakdown is desc-sorted by count, ties broken by key
alphabetic; empty map produces no extra text.

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

회차 1 — 7-task TDD 분해 깔끔. Skip 4 사이트 (md fallback / 3 kb:// branches) 모두 채움 + asset 루프 BTreeMap bump + CLI/TUI render breakdown — 의도 일관. 729 워크스페이스 통과 + clippy clean.

actionable 4 건:

  1. render_skipped_breakdown 가 kebab-cli + kebab-tui 양쪽 동일 body. kebab-app::ingest_progress 로 추출 (양 crate 의 공통 의존) — single source.
  2. <no-ext> magic string 두 helper (ext_for_skip_warning + unsupported_media_warning) 에 박힘. const NO_EXT_SENTINEL 로 추출.
  3. HOTFIXES "기존 워크스페이스 테스트 무수정 통과" 정확화 — 6 fixture 가 mechanical adapter 로 수정됨 (assertion 의미 동일).
  4. deprecation 메시지 "다음 버전부터 config 갱신 권장" 모호 — 본 PR 머지 직후 v0.2.1 예정이라 "v0.2.1+" 명시 또는 직접적 "제거하세요" 액션.

3번 + 4번은 영구 기록 / 사용자 발견성 영향이라 정확화 가치 있음.

회차 1 — 7-task TDD 분해 깔끔. Skip 4 사이트 (md fallback / 3 kb:// branches) 모두 채움 + asset 루프 BTreeMap bump + CLI/TUI render breakdown — 의도 일관. 729 워크스페이스 통과 + clippy clean. actionable 4 건: 1. `render_skipped_breakdown` 가 kebab-cli + kebab-tui 양쪽 동일 body. `kebab-app::ingest_progress` 로 추출 (양 crate 의 공통 의존) — single source. 2. `<no-ext>` magic string 두 helper (ext_for_skip_warning + unsupported_media_warning) 에 박힘. `const NO_EXT_SENTINEL` 로 추출. 3. HOTFIXES "기존 워크스페이스 테스트 무수정 통과" 정확화 — 6 fixture 가 mechanical adapter 로 수정됨 (assertion 의미 동일). 4. deprecation 메시지 "다음 버전부터 config 갱신 권장" 모호 — 본 PR 머지 직후 v0.2.1 예정이라 "v0.2.1+" 명시 또는 직접적 "제거하세요" 액션. 3번 + 4번은 영구 기록 / 사용자 발견성 영향이라 정확화 가치 있음.

unsupported_media_warningif ext == "<no-ext>" 가 magic string. ext_for_skip_warning 의 sentinel 반환과 일치해야 하는데 두 곳 (fn ext_for_skip_warning line 167, fn unsupported_media_warning line 175) 에 literal 박힘.

const NO_EXT_SENTINEL: &str = "<no-ext>";

파일 상단에 추출 + 두 helper 모두 참조. wire schema description 문구도 <no-ext> literal 사용 — sentinel 이 wire 계약의 일부라는 점 더 명확.

`unsupported_media_warning` 의 `if ext == "<no-ext>"` 가 magic string. `ext_for_skip_warning` 의 sentinel 반환과 일치해야 하는데 두 곳 (`fn ext_for_skip_warning` line 167, `fn unsupported_media_warning` line 175) 에 literal 박힘. ```rust const NO_EXT_SENTINEL: &str = "<no-ext>"; ``` 파일 상단에 추출 + 두 helper 모두 참조. wire schema description 문구도 `<no-ext>` literal 사용 — sentinel 이 wire 계약의 일부라는 점 더 명확.
@@ -372,3 +386,4 @@
println!("{}", serde_json::to_string(&wire::wire_ingest(&report))?);
} else {
let skipped_breakdown = render_skipped_breakdown(&report.skipped_by_extension);
println!(

render_skipped_breakdown 가 본 파일 + crates/kebab-tui/src/ingest_progress.rs 양쪽에 동일한 12-line body 로 복제. DRY 위반.

plan 이 "DRY violation but acceptable" 라 했지만 양 crate 모두 kebab-app 의존 → kebab-app::ingest_progress 모듈에 pub fn render_skipped_breakdown(map: &BTreeMap<String, u32>) -> String 으로 추출 + 양쪽에서 import 하면 single source.

작은 helper 라 별 module 만들 필요 없고 기존 ingest_progress.rs (AggregateCounts + status_line 의 caller) 가 자연스러운 home. 후속 maintenance 시 정렬 / 형식 변경하면 한 곳만 고침.

`render_skipped_breakdown` 가 본 파일 + `crates/kebab-tui/src/ingest_progress.rs` 양쪽에 동일한 12-line body 로 복제. DRY 위반. plan 이 "DRY violation but acceptable" 라 했지만 양 crate 모두 `kebab-app` 의존 → `kebab-app::ingest_progress` 모듈에 `pub fn render_skipped_breakdown(map: &BTreeMap<String, u32>) -> String` 으로 추출 + 양쪽에서 import 하면 single source. 작은 helper 라 별 module 만들 필요 없고 기존 `ingest_progress.rs` (`AggregateCounts` + `status_line` 의 caller) 가 자연스러운 home. 후속 maintenance 시 정렬 / 형식 변경하면 한 곳만 고침.

deprecation 메시지의 "다음 버전부터 config 갱신 권장" 이 모호. 사용자가 "다음 버전 = 언제?" 의문 가능.

현 상황: 본 PR 머지 후 patch bump (0.2.0 → 0.2.1) 가 즉시 예정 (PR description 명시). 사용자 입장에서 "다음 release" = 0.2.1, 즉 곧 옴. 더 명확한 문구:

"deprecated config: `workspace.include` 필드는 더 이상 사용되지 않습니다 (p9-fb-25, v0.2.1+). 처리 가능한 형식 (md / png / jpg / pdf) 은 extractor 가 자동 결정. config 에서 이 필드를 제거하세요."

또는 단순 "config 에서 이 필드를 제거해도 안전 — 더 이상 enforce 안 됨" 식. 현 "다음 버전부터 갱신 권장" 보다 직접적 action.

deprecation 메시지의 "다음 버전부터 config 갱신 권장" 이 모호. 사용자가 "다음 버전 = 언제?" 의문 가능. 현 상황: 본 PR 머지 후 patch bump (0.2.0 → 0.2.1) 가 즉시 예정 (PR description 명시). 사용자 입장에서 "다음 release" = 0.2.1, 즉 곧 옴. 더 명확한 문구: ``` "deprecated config: `workspace.include` 필드는 더 이상 사용되지 않습니다 (p9-fb-25, v0.2.1+). 처리 가능한 형식 (md / png / jpg / pdf) 은 extractor 가 자동 결정. config 에서 이 필드를 제거하세요." ``` 또는 단순 "config 에서 이 필드를 제거해도 안전 — 더 이상 enforce 안 됨" 식. 현 "다음 버전부터 갱신 권장" 보다 직접적 action.
@@ -17,0 +22,4 @@
- `kebab-config::WorkspaceCfg.include: Vec<String>` 제거. denylist-only 모델. 옛 config 의 `include = [...]` 은 serde 가 silently 무시 + `Config::from_file` 가 단발 `tracing::warn!` 으로 deprecation 안내 (`std::sync::OnceLock` — 같은 process 안에서 한 번만).
- `kebab-core::IngestItem.warnings` 가 Skipped 시 사유 채움: `"unsupported media type: .{ext}"` (ext 없으면 `"unsupported media type: <no-ext>"`) / `"kb:// URI not yet supported"`.
- `kebab-core::IngestReport.skipped_by_extension: BTreeMap<String, u32>` + `kebab-app::AggregateCounts.skipped_by_extension` 신규. key = lowercase ext (`docx`, `txt`), no-ext sentinel = `<no-ext>`. wire schema `ingest_report.v1` 에 additive 추가 (v1 호환 유지 — release 트리거 안 됨 per CLAUDE.md release 규약).

"기존 워크스페이스 테스트 무수정 통과" 가 정확하지 않음. 본 PR 이 다음 5 개 기존 test fixture / production helper 수정:

  • crates/kebab-app/tests/common/mod.rs (SourceScope ..Default::default()).
  • crates/kebab-app/tests/image_pipeline.rs × 2 (dead cfg.workspace.include.push 제거).
  • crates/kebab-app/tests/pdf_pipeline.rs (동일).
  • crates/kebab-app/tests/ingest_report_snapshot.rs (literal 에 skipped_by_extension: BTreeMap::new() 추가).
  • crates/kebab-cli/src/wire.rs test (동일).
  • crates/kebab-store-sqlite/snapshots/ingest_report.snapshot.json ("skipped_by_extension": {} 추가).

assertion 의미는 동일 (mechanical adapter) 지만 "무수정" 문구는 잘못. 권장 변경:

신규 5 + 기존 6 fixture 어댑터 (mechanical: dead include push 제거 + 새 BTreeMap 필드 default 채움). assertion 의미 변경 없음.
"기존 워크스페이스 테스트 무수정 통과" 가 정확하지 않음. 본 PR 이 다음 5 개 기존 test fixture / production helper 수정: - `crates/kebab-app/tests/common/mod.rs` (SourceScope `..Default::default()`). - `crates/kebab-app/tests/image_pipeline.rs` × 2 (dead `cfg.workspace.include.push` 제거). - `crates/kebab-app/tests/pdf_pipeline.rs` (동일). - `crates/kebab-app/tests/ingest_report_snapshot.rs` (literal 에 `skipped_by_extension: BTreeMap::new()` 추가). - `crates/kebab-cli/src/wire.rs` test (동일). - `crates/kebab-store-sqlite/snapshots/ingest_report.snapshot.json` (`"skipped_by_extension": {}` 추가). assertion 의미는 동일 (mechanical adapter) 지만 "무수정" 문구는 잘못. 권장 변경: ``` 신규 5 + 기존 6 fixture 어댑터 (mechanical: dead include push 제거 + 새 BTreeMap 필드 default 채움). assertion 의미 변경 없음. ```
altair823 added 1 commit 2026-05-05 12:36:33 +00:00
claude-reviewer-01 approved these changes 2026-05-05 12:36:53 +00:00
claude-reviewer-01 left a comment
Member

회차 2 — 회차 1 의 4 건 모두 수렴.

  1. render_skipped_breakdown 단일 source (kebab-app::ingest_progress) + 양 crate 의 적절한 import path.
  2. NO_EXT_SENTINEL: &str 상수 + 두 helper + wire schema description 일관.
  3. HOTFIXES 카운트 정확화 (5 신규 + 1 unit + 6 fixture mechanical adapter).
  4. deprecation 메시지 액션 명시 (v0.2.1+ + "제거해도 안전").

config workspace.include 제거 + skip 사유 + breakdown 모두 정합. 730 워크스페이스 통과 + clippy clean. 사용자 도그푸딩 피드백 (case 4 모호 + 지원 형식 가시성) 정확히 해소.

머지 동의.

회차 2 — 회차 1 의 4 건 모두 수렴. 1. `render_skipped_breakdown` 단일 source (`kebab-app::ingest_progress`) + 양 crate 의 적절한 import path. 2. `NO_EXT_SENTINEL: &str` 상수 + 두 helper + wire schema description 일관. 3. HOTFIXES 카운트 정확화 (5 신규 + 1 unit + 6 fixture mechanical adapter). 4. deprecation 메시지 액션 명시 (`v0.2.1+` + "제거해도 안전"). config workspace.include 제거 + skip 사유 + breakdown 모두 정합. 730 워크스페이스 통과 + clippy clean. 사용자 도그푸딩 피드백 (case 4 모호 + 지원 형식 가시성) 정확히 해소. 머지 동의.

render_skipped_breakdownkebab-app::ingest_progress 로 이전 + 양 crate (kebab-cli direct re-export, kebab-tui qualified path) 가 single source 참조. AggregateCounts 가 사는 같은 모듈에 helper 가 모이는 구조 깔끔.

`render_skipped_breakdown` 가 `kebab-app::ingest_progress` 로 이전 + 양 crate (`kebab-cli` direct re-export, `kebab-tui` qualified path) 가 single source 참조. AggregateCounts 가 사는 같은 모듈에 helper 가 모이는 구조 깔끔.

pub const NO_EXT_SENTINEL 추출 + 두 helper (ext_for_skip_warning, unsupported_media_warning) 와 wire schema description 의 sentinel 일관 — single source. pub 인 점이 wire 계약 (BTreeMap key) 의 일부라는 신호로 좋음.

`pub const NO_EXT_SENTINEL` 추출 + 두 helper (`ext_for_skip_warning`, `unsupported_media_warning`) 와 wire schema description 의 sentinel 일관 — single source. `pub` 인 점이 wire 계약 (BTreeMap key) 의 일부라는 신호로 좋음.
altair823 merged commit 8dadac2a45 into main 2026-05-05 12:46:37 +00:00
altair823 deleted branch fix/p9-fb-25-config-include-removal 2026-05-05 12:46:38 +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#101