From 26a2e021b06faf43da39232eb134c100a8852d8d Mon Sep 17 00:00:00 2001
From: th-kim0823
Date: Thu, 7 May 2026 11:29:00 +0900
Subject: [PATCH] =?UTF-8?q?=F0=9F=8F=97=EF=B8=8F=20refactor(kebab-config):?=
=?UTF-8?q?=20stabilize=20ConfigInvalid.cause=20prefix=20(fb-27)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Replace `read failed: {e}` / `parse failed: {e}` with the underscore-
slugged `read_failed:` / `parse_failed:` prefixes so kebab-cli's
error_classify (Task 8) and the error.v1 JSON Schema (Task 14) can
treat the prefix as a stable wire contract while leaving the OS /
toml-crate detail in the suffix as free-form context.
Also add the symmetric `cause` non-empty assertion to the malformed-TOML
test so a regression that empties `cause` on the parse path would be
caught.
Co-Authored-By: Claude Opus 4.7 (1M context)
---
crates/kebab-config/src/lib.rs | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/crates/kebab-config/src/lib.rs b/crates/kebab-config/src/lib.rs
index ae99674..dd9b5d1 100644
--- a/crates/kebab-config/src/lib.rs
+++ b/crates/kebab-config/src/lib.rs
@@ -409,7 +409,7 @@ impl Config {
let text = std::fs::read_to_string(path).map_err(|e| {
anyhow::Error::new(ConfigInvalid {
path: path.to_path_buf(),
- cause: format!("read failed: {e}"),
+ cause: format!("read_failed: {e}"),
})
})?;
@@ -438,7 +438,7 @@ impl Config {
let mut cfg: Self = toml::from_str(&text).map_err(|e| {
anyhow::Error::new(ConfigInvalid {
path: path.to_path_buf(),
- cause: format!("parse failed: {e}"),
+ cause: format!("parse_failed: {e}"),
})
})?;
cfg.source_dir = path.parent().map(Path::to_path_buf);
@@ -982,5 +982,6 @@ mod fb27_tests {
let signal = err.downcast_ref::()
.expect("malformed TOML should downcast to ConfigInvalid");
assert_eq!(signal.path, p);
+ assert!(!signal.cause.is_empty(), "cause should be non-empty");
}
}