feat(kebab-config + kebab-app): p9-fb-05 workspace.root path policy #76
Reference in New Issue
Block a user
Delete Branch "feat/p9-fb-05-path"
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?
요약
도그푸딩 item 3 —
workspace.root의 허용 형식이 명문화 안 돼 사용자가 "상대 경로면 어디 기준?" 가 불명확. 절대/tilde/env/상대 모두 지원하되 상대 경로의 base 는 config.toml 자체가 위치한 디렉토리 (cwd 와 무관) 정책 도입.변경
kebab_config::expand_path_with_base(raw, data_dir, base_dir)신규 — relative path 만 base_dir 에 join, 절대/tilde/env 는 그대로Config.source_dir: Option<PathBuf>(#[serde(skip)]) —from_file/load가path.parent()stampConfig::resolve_workspace_root()helper — 모든 callsite 통일expand_tilde(&workspace.root)4 군데 →cfg.resolve_workspace_root()expand_tilde+dirs_home헬퍼 제거kebab init가 생성하는config.toml위에 path policy 안내 헤더 코멘트 prepend테스트
expand_path_with_base: relative→base, absolute / tilde /${VAR}는 ignore base)cargo test --workspace --no-fail-fast -j 1exit 0cargo clippy --workspace --all-targets -- -D warningsclean문서
영향
기존 사용자 (defaults
~/KnowledgeBase= tilde-rooted) 영향 없음. 새 사용자가--config /tmp/cfg.toml+root = \"kb\"쓰면 cwd 무관하게/tmp/kb가 워크스페이스 — 이전엔 cwd 기준이라 invisible foot-gun.Out of scope
expand_tilde통일 (kebab-app 의storage.data_dir한 군데 남음) — spec out-of-scope, P+도그푸딩 item 3 — `workspace.root` 의 허용 형식이 명문화 안 돼 사용자가 \"상대 경로면 어디 기준?\" 가 불명확. 이제 절대/tilde/env/상대 모두 지원하되, 상대 경로의 base 는 **config.toml 자체가 위치한 디렉토리** (사용자의 cwd 와 무관) 로 일관 정책. ## 핵심 변경 - **`kebab_config::expand_path_with_base(raw, data_dir, base_dir)`** 신규. 기존 `expand_path` (tilde + env 만) 위에 relative-path resolution 추가: - tilde / 절대 / `${VAR}` 입력은 base_dir 무시 (이미 absolute) - relative 입력만 `base_dir.join(...)` 로 절대화 - **`Config.source_dir: Option<PathBuf>`** 신규 (`#[serde(skip)]`). `Config::from_file` / `load` 가 `path.parent()` 로 stamp. defaults 는 None (cwd fallback). - **`Config::resolve_workspace_root()`** helper: source_dir 있으면 그것 기준, 없으면 cwd 기준. - **callsite 정리**: - `kebab-app::lib.rs` 의 3 군데 `expand_tilde(&app.config.workspace .root)` → `app.config.resolve_workspace_root()` - `kebab-app::init_workspace` 도 동일 - `kebab-source-fs::FsSourceConnector::new` → 동일 - kebab-source-fs 의 fork 된 local `expand_tilde` + `dirs_home` 헬퍼 제거 (kebab-config 가 canonical) - **`kebab init`** 가 생성하는 `config.toml` 위에 path policy 안내 헤더 코멘트 prepend (절대/tilde/env/상대 + 상대 base = config dir). 기존 `expand_tilde` 가 kebab-app/lib.rs 에 한 군데 (storage.data_dir) 남음 — spec out-of-scope (\"expand_tilde 통일 P+\") 라 보류. ## 테스트 - `expand_path_with_base` 에 신규 4 unit (relative→base, absolute ignores base, tilde ignores base, ${XDG} ignores base) - 기존 27 kebab-config tests + workspace 전체 (`cargo test --workspace --no-fail-fast -j 1` exit 0) 모두 통과 - `cargo clippy --workspace --all-targets -- -D warnings` clean ## 문서 - README Configuration 절: workspace.root 형식 + relative base 규칙 한 줄 추가 - HANDOFF: 2026-05-03 entry - spec status planned → in_progress ## 영향 기존 사용자: 영향 없음 (defaults 의 `~/KnowledgeBase` 는 tilde-rooted, relative path 분기 안 탐). 새 사용자가 `--config /tmp/cfg.toml` + `root = "kb"` 같이 쓰면 cwd 무관하게 `/tmp/kb` 가 워크스페이스가 됨 — 이전엔 이 케이스가 cwd 기준이라 invisible foot-gun. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>회차 1 — path policy 정책 자체와 구현 모두 깔끔. expand_path_with_base 가 기존 expand_path 위에 if-absolute 한 줄만 추가 = 위험 적고 검증 쉬움. Config.source_dir 의 #[serde(skip)] + from_file/load stamp 패턴 정석. kebab init 의 header prepend 로 사용자 발견성도 chase.
actionable nit 2 건 — (a) Config.source_dir 의 pub mutability 가 invariant 보호 안 함, (b) current_dir() 실패 시 silently '.' 로 떨어지는 fallback 의 가시성 부족.
@@ -35,0 +38,4 @@/// `expand_path_with_base` to resolve relative `workspace.root`/// against the config file's location instead of the user's/// `cwd` (so `--config /tmp/cfg.toml` + `root = "kb"` reads/// `/tmp/kb` no matter where the user invoked from).source_dir가pub이라 외부 코드가 직접 mutate 할 수 있는데,from_file/load가 stamp 하는 invariant 를 깨면resolve_workspace_root()가 잘못된 base 를 쓰게 됩니다. 두 옵션:pub(crate)로 좁히고pub fn source_dir(&self) -> Option<&Path>getter +pub fn with_source_dir(self, dir: PathBuf) -> Selfbuilder 노출 (테스트 / 프로그래마틱 사용에는 builder).pub그대로 두되 doc 마지막에 "외부 코드는 직접 set 하지 말 것;from_file/load만이 정당한 setter" 한 줄 추가.저는 (1) 이 invariant 보호 측면에서 더 명확하다고 봅니다 —
serde(skip)라 외부 source 는from_file가 stamp 하지 않은 채로는 절대 set 될 수 없어야 함.std::env::current_dir().unwrap_or_else(|_| PathBuf::from("."))의"."fallback 이 silently 실패합니다 —.+ relative root =./<root>가 되고, 이후std::fs::create_dir_all등이cwd기준으로 해석하긴 하지만 "cwd 가 reading 실패" 라는 진짜 에러는 사라집니다.fallback 자체는 합리적이지만 (panic 보다는 낫다),
tracing::warn!한 줄 추가하면 사용자가 환경 이상 (chroot, deleted cwd 등) 일 때 silently 잘못된 경로로 빠지는 걸 발견할 수 있습니다:- `Config.source_dir` 를 `pub(crate)` 로 좁힘. invariant ("from_file / load 만이 정당한 setter") 가 외부 mutation 으로 깨지지 않도록. 대신 `pub fn source_dir(&self) -> Option<&Path>` (read-only) + `pub fn with_source_dir(self, dir) -> Self` (builder) 노출 — 테스트 / 프로그래마틱 사용은 builder 통과. - `resolve_workspace_root` 의 `current_dir()` 실패 fallback 에 `tracing::warn!` 추가. chroot / deleted-cwd / permission 문제로 cwd 가 안 잡힐 때 silently `./root` 로 떨어지지 않고 로그가 남음. `tracing` 을 kebab-config 의 deps 에 추가 (workspace dep). 테스트 27 통과 + 워크스페이스 clippy clean. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>회차 2 — nit 2 건 깔끔히 반영.
추가 지적 없음. 머지 OK.