diff --git a/crates/kebab-config/src/lib.rs b/crates/kebab-config/src/lib.rs index e2d18fe..49c47f9 100644 --- a/crates/kebab-config/src/lib.rs +++ b/crates/kebab-config/src/lib.rs @@ -606,8 +606,6 @@ impl UiCfg { #[serde(default)] pub struct IngestCfg { pub code: IngestCodeCfg, - #[serde(default)] - pub expansion: IngestExpansionCfg, } /// p10-1A-1: settings for the code ingest pipeline. All fields have @@ -648,34 +646,6 @@ impl Default for IngestCodeCfg { } } -/// doc-side expansion config. Default: disabled (requires explicit opt-in). -#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] -#[serde(default)] -pub struct IngestExpansionCfg { - /// Whether doc-side alias expansion is enabled during ingest. - pub enabled: bool, - /// Ollama model used for alias generation (empty = use LLM default). - pub model: String, - /// Maximum aliases generated per chunk. - pub max_aliases_per_chunk: usize, - /// Prompt template version tag. - pub prompt_version: String, - /// Whether alias embeddings are stored as separate dense vectors. - pub embed_aliases: bool, -} - -impl Default for IngestExpansionCfg { - fn default() -> Self { - Self { - enabled: false, - model: String::new(), - max_aliases_per_chunk: 8, - prompt_version: "expansion-v1".to_string(), - embed_aliases: false, - } - } -} - impl Config { /// Defaults per design §6.4. pub fn defaults() -> Self { @@ -1166,25 +1136,6 @@ impl Config { self.pdf.ocr.lang_hint = if v.is_empty() { None } else { Some(v.clone()) }; } - // ingest.expansion - "KEBAB_INGEST_EXPANSION_ENABLED" => { - self.ingest.expansion.enabled = parse_bool(v); - } - "KEBAB_INGEST_EXPANSION_MODEL" => { - self.ingest.expansion.model = v.clone(); - } - "KEBAB_INGEST_EXPANSION_MAX_ALIASES" => { - if let Ok(n) = v.parse::() { - self.ingest.expansion.max_aliases_per_chunk = n; - } - } - "KEBAB_INGEST_EXPANSION_PROMPT_VERSION" => { - self.ingest.expansion.prompt_version = v.clone(); - } - "KEBAB_INGEST_EXPANSION_EMBED_ALIASES" => { - self.ingest.expansion.embed_aliases = parse_bool(v); - } - // Unknown KEBAB_* keys are silently ignored — see // `env_unknown_key_is_ignored` test. _ => {} @@ -1913,41 +1864,6 @@ max_context_tokens = 8000 assert_eq!(cfg.ingest.code.max_file_bytes, 524_288); } - #[test] - fn expansion_defaults_off() { - let cfg = Config::defaults(); - assert!(!cfg.ingest.expansion.enabled); - assert_eq!(cfg.ingest.expansion.max_aliases_per_chunk, 8); - assert_eq!(cfg.ingest.expansion.prompt_version, "expansion-v1"); - } - - #[test] - fn expansion_env_override() { - let mut env = HashMap::new(); - env.insert("KEBAB_INGEST_EXPANSION_ENABLED".into(), "true".into()); - env.insert("KEBAB_INGEST_EXPANSION_MODEL".into(), "gemma3:4b".into()); - env.insert("KEBAB_INGEST_EXPANSION_MAX_ALIASES".into(), "12".into()); - env.insert("KEBAB_INGEST_EXPANSION_PROMPT_VERSION".into(), "expansion-v2".into()); - let c = Config::defaults().apply_env(&env); - assert!(c.ingest.expansion.enabled); - assert_eq!(c.ingest.expansion.model, "gemma3:4b"); - assert_eq!(c.ingest.expansion.max_aliases_per_chunk, 12); - assert_eq!(c.ingest.expansion.prompt_version, "expansion-v2"); - } - - #[test] - fn embed_aliases_defaults_off() { - let cfg = Config::defaults(); - assert!(!cfg.ingest.expansion.embed_aliases); - } - - #[test] - fn embed_aliases_env_override() { - let mut env = HashMap::new(); - env.insert("KEBAB_INGEST_EXPANSION_EMBED_ALIASES".into(), "true".into()); - let c = Config::defaults().apply_env(&env); - assert!(c.ingest.expansion.embed_aliases); - } } #[cfg(test)] diff --git a/crates/kebab-config/src/migrate.rs b/crates/kebab-config/src/migrate.rs index 38fa892..d58f4c7 100644 --- a/crates/kebab-config/src/migrate.rs +++ b/crates/kebab-config/src/migrate.rs @@ -15,7 +15,7 @@ pub const CURRENT_SCHEMA_VERSION: u32 = 2; #[derive(Clone, Debug, PartialEq, serde::Serialize)] pub struct MigrationChange { pub kind: ChangeKind, - /// dotted path, 예: `ingest.expansion`, `workspace.include`. + /// dotted path, 예: `ingest.code`, `workspace.include`. pub path: String, /// 사람·wire 용 한 줄 설명. pub detail: String, @@ -83,7 +83,6 @@ fn section_comment(path: &str) -> Option<&'static str> { "ui" => "# TUI 팔레트·role 스타일.", "ingest" => "# ingest 정책(code skip 등).", "ingest.code" => "# code ingest skip 정책(.gitignore 자동 honor).", - "ingest.expansion" => "# doc-side 별칭 확장(기본 off). 패러프레이즈 강건성↑, LLM 비용 큼.", "pdf" => "# PDF ingest. scanned PDF OCR 은 기본 off(page 당 cost).", "pdf.ocr" => "# scanned PDF page-단위 OCR(기본 off).", "logging" => "# ingest 로그(기본 on, ~/.local/state/kebab/logs).", @@ -259,7 +258,7 @@ mod tests { // `[pdf]` 등은 안 나오고 `[pdf.ocr]` 같은 하위 테이블만 직렬화된다. for section in [ "[workspace]", - "[ingest.expansion]", + "[ingest.code]", "[pdf.ocr]", "[logging]", "[ui]", @@ -273,8 +272,8 @@ mod tests { #[test] fn reconcile_adds_missing_section_preserving_user_values_and_comments() { - // ingest 는 code 만 있고 expansion 누락(v0.21.0 동기 시나리오), - // logging 통째 누락, score 는 사용자가 바꿈, 주석 보유. + // ingest 통째 누락(→ ingest.code 추가), logging 통째 누락, + // default_k 는 사용자가 바꿈, 주석 보유. let user_text = "\ schema_version = 1 @@ -283,9 +282,6 @@ root = \"/my/notes\" # 내 워크스페이스 [search] default_k = 25 - -[ingest.code] -skip_generated_header = true "; let mut user: DocumentMut = user_text.parse().unwrap(); let reference = annotated_default_document(); @@ -294,25 +290,22 @@ skip_generated_header = true reconcile(&ref_tbl, user.as_table_mut(), "", &mut changes); let out = user.to_string(); - // 부분 존재하는 [ingest] 에 expansion 만 주석과 함께 추가. - assert!(out.contains("[ingest.expansion]"), "expansion not added:\n{out}"); + // 누락된 [ingest.code] 가 주석과 함께 추가. + assert!(out.contains("[ingest.code]"), "ingest.code not added:\n{out}"); // 통째 누락된 logging 추가. assert!(out.contains("[logging]"), "logging not added"); // 사용자 값/주석/기존 섹션 보존. assert!(out.contains("root = \"/my/notes\"")); assert!(out.contains("# 내 워크스페이스")); assert!(out.contains("default_k = 25")); - assert!(out.contains("skip_generated_header = true")); // 새 섹션 주석 부착. - assert!(out.contains("doc-side 별칭")); - // 부분 존재 부모로 재귀해 leaf 경로를 기록. + assert!(out.contains("code ingest skip 정책")); + // 통째 누락 부모는 부모 경로로 한 번 기록. assert!( changes .iter() - .any(|c| c.kind == ChangeKind::AddedSection && c.path == "ingest.expansion"), - "changes: {changes:?}" + .any(|c| c.kind == ChangeKind::AddedSection && c.path == "ingest") ); - // 통째 누락 부모는 부모 경로로 한 번 기록. assert!( changes .iter() @@ -381,7 +374,7 @@ include = [\"*.md\"] assert_eq!(outcome.to_schema_version, CURRENT_SCHEMA_VERSION); assert!(outcome.changed()); assert!(!outcome.new_text.contains("include")); - assert!(outcome.new_text.contains("[ingest.expansion]")); + assert!(outcome.new_text.contains("[ingest.code]")); assert_eq!(read_schema_version(&outcome.new_text), CURRENT_SCHEMA_VERSION); let again = migrate_document(&outcome.new_text);