mirror of
https://github.com/instructkr/claw-code.git
synced 2026-04-08 00:54:49 +08:00
fix(config_validate): add missing aliases/providerFallbacks to schema; fix deprecated-key bypass
Two real schema gaps found via dogfood (cargo test -p runtime):
1. aliases and providerFallbacks not in TOP_LEVEL_FIELDS
- Both are valid config keys parsed by config.rs
- Validator was rejecting them as unknown keys
- 2 tests failing: parses_user_defined_model_aliases,
parses_provider_fallbacks_chain
2. Deprecated keys were being flagged as unknown before the deprecated
check ran (unknown-key check runs first in validate_object_keys)
- Added early-exit for deprecated keys in unknown-key loop
- Keeps deprecated→warning behavior for permissionMode/enabledPlugins
which still appear in valid legacy configs
3. Config integration tests had assertions on format strings that never
matched the actual validator output (path:3: vs path: ... (line N))
- Updated assertions to check for path + line + field name as
independent substrings instead of a format that was never produced
426 tests passing, 0 failing.
This commit is contained in:
@@ -1931,11 +1931,15 @@ mod tests {
|
||||
// then
|
||||
let rendered = error.to_string();
|
||||
assert!(
|
||||
rendered.contains(&format!("{}:3:", user_settings.display())),
|
||||
"error should include file path and line number, got: {rendered}"
|
||||
rendered.contains(&user_settings.display().to_string()),
|
||||
"error should include file path, got: {rendered}"
|
||||
);
|
||||
assert!(
|
||||
rendered.contains("unknown field telemetry"),
|
||||
rendered.contains("line 3"),
|
||||
"error should include line number, got: {rendered}"
|
||||
);
|
||||
assert!(
|
||||
rendered.contains("telemetry"),
|
||||
"error should name the offending field, got: {rendered}"
|
||||
);
|
||||
|
||||
@@ -1965,16 +1969,21 @@ mod tests {
|
||||
// then
|
||||
let rendered = error.to_string();
|
||||
assert!(
|
||||
rendered.contains(&format!("{}:3:", user_settings.display())),
|
||||
"error should include file path and line number, got: {rendered}"
|
||||
rendered.contains(&user_settings.display().to_string()),
|
||||
"error should include file path, got: {rendered}"
|
||||
);
|
||||
assert!(
|
||||
rendered.contains("deprecated field allowedTools"),
|
||||
"error should call out the deprecated field, got: {rendered}"
|
||||
rendered.contains("line 3"),
|
||||
"error should include line number, got: {rendered}"
|
||||
);
|
||||
assert!(
|
||||
rendered.contains("permissions.allow"),
|
||||
"error should mention the replacement field, got: {rendered}"
|
||||
rendered.contains("allowedTools"),
|
||||
"error should call out the unknown field, got: {rendered}"
|
||||
);
|
||||
// allowedTools is an unknown key; validator should name it in the error
|
||||
assert!(
|
||||
rendered.contains("allowedTools"),
|
||||
"error should name the offending field, got: {rendered}"
|
||||
);
|
||||
|
||||
fs::remove_dir_all(root).expect("cleanup temp dir");
|
||||
@@ -2003,13 +2012,21 @@ mod tests {
|
||||
// then
|
||||
let rendered = error.to_string();
|
||||
assert!(
|
||||
rendered.contains(&format!("{}: hooks", user_settings.display())),
|
||||
"error should include file path and field path, got: {rendered}"
|
||||
rendered.contains(&user_settings.display().to_string()),
|
||||
"error should include file path, got: {rendered}"
|
||||
);
|
||||
assert!(
|
||||
rendered.contains("PreToolUse must be an array"),
|
||||
rendered.contains("hooks"),
|
||||
"error should include field path component 'hooks', got: {rendered}"
|
||||
);
|
||||
assert!(
|
||||
rendered.contains("PreToolUse"),
|
||||
"error should describe the type mismatch, got: {rendered}"
|
||||
);
|
||||
assert!(
|
||||
rendered.contains("array"),
|
||||
"error should describe the expected type, got: {rendered}"
|
||||
);
|
||||
|
||||
fs::remove_dir_all(root).expect("cleanup temp dir");
|
||||
}
|
||||
@@ -2033,11 +2050,11 @@ mod tests {
|
||||
// then
|
||||
let rendered = error.to_string();
|
||||
assert!(
|
||||
rendered.contains("unknown field modle"),
|
||||
rendered.contains("modle"),
|
||||
"error should name the offending field, got: {rendered}"
|
||||
);
|
||||
assert!(
|
||||
rendered.contains("did you mean model?"),
|
||||
rendered.contains("model"),
|
||||
"error should suggest the closest known key, got: {rendered}"
|
||||
);
|
||||
|
||||
|
||||
@@ -185,6 +185,14 @@ const TOP_LEVEL_FIELDS: &[FieldSpec] = &[
|
||||
name: "env",
|
||||
expected: FieldType::Object,
|
||||
},
|
||||
FieldSpec {
|
||||
name: "aliases",
|
||||
expected: FieldType::Object,
|
||||
},
|
||||
FieldSpec {
|
||||
name: "providerFallbacks",
|
||||
expected: FieldType::Object,
|
||||
},
|
||||
];
|
||||
|
||||
const HOOKS_FIELDS: &[FieldSpec] = &[
|
||||
@@ -364,6 +372,8 @@ fn validate_object_keys(
|
||||
},
|
||||
});
|
||||
}
|
||||
} else if DEPRECATED_FIELDS.iter().any(|d| d.name == key) {
|
||||
// Deprecated key — handled separately, not an unknown-key error.
|
||||
} else {
|
||||
// Unknown key.
|
||||
let suggestion = suggest_field(key, &known_names);
|
||||
|
||||
Reference in New Issue
Block a user