fix(#169): classify invalid/missing CLI flag values as cli_parse

Pinpoint #169: typed-error classifier gap discovered during dogfood probe.

`claw --output-format json --output-format xml doctor` was emitting:
  {"error": "unsupported value for --output-format: xml ...",
   "hint": null,
   "kind": "unknown",
   "type": "error"}

After fix:
  {"error": "unsupported value for --output-format: xml ...",
   "hint": "Run `claw --help` for usage.",
   "kind": "cli_parse",
   "type": "error"}

The change adds two new classifier branches to `classify_error_kind`:
1. `unsupported value for --` → cli_parse
2. `missing value for --` → cli_parse

Covers all `CliOutputFormat::parse` / `parse_permission_mode_arg` rejections
and any future flag-value validation messages using the same pattern.

Side benefit: the #247 hint synthesizer ("Run `claw --help` for usage.")
now triggers automatically because the error is now correctly classified
as cli_parse. Consumers get both correct kind AND helpful hint.

Test added:
- `classify_error_kind_covers_flag_value_parse_errors_169` (4 positive +
  1 sanity case)

Tests: 224/224 pass (+1 from #169).

Discovered during dogfood probe 2026-04-23 07:00 Seoul, cycle #94.

Refs: #169, typed-error family (#121, #127, #129, #130, #164, #247)
This commit is contained in:
YeonGyu-Kim 2026-04-23 07:03:40 +09:00
parent 80f9914353
commit 834b0a91fe

View File

@ -292,6 +292,17 @@ fn classify_error_kind(message: &str) -> &'static str {
} else if message.starts_with("empty prompt:") {
// #247: `claw ""` or `claw " "` — a parse error, not `unknown`.
"cli_parse"
} else if message.contains("unsupported value for --") {
// #169: Invalid CLI flag values (e.g., `--output-format xml`,
// `--permission-mode bogus`) are parse errors, not `unknown`.
// This covers all `CliOutputFormat::parse` / `parse_permission_mode_arg`
// rejections and any future `unsupported value for --<flag>: <value>`
// messages emitted from the parse_args dispatcher.
"cli_parse"
} else if message.contains("missing value for --") {
// #169: Missing required flag values (e.g., `--output-format` with no
// trailing argument) are parse errors, same family as above.
"cli_parse"
} else if message.contains("invalid model syntax") {
"invalid_model_syntax"
} else if message.contains("is not yet implemented") {
@ -11100,6 +11111,45 @@ mod tests {
);
}
#[test]
fn classify_error_kind_covers_flag_value_parse_errors_169() {
// #169: Invalid CLI flag values must classify as `cli_parse`,
// not fall through to `unknown`. Regression guard found during
// dogfood probe 2026-04-23: `claw --output-format xml doctor`
// emitted `{"kind":"unknown"}` envelope instead of `cli_parse`.
assert_eq!(
classify_error_kind(
"unsupported value for --output-format: xml (expected text or json)"
),
"cli_parse",
"invalid --output-format value must classify as cli_parse"
);
assert_eq!(
classify_error_kind(
"unsupported value for --permission-mode: bogus (expected ...)"
),
"cli_parse",
"invalid --permission-mode value must classify as cli_parse"
);
assert_eq!(
classify_error_kind("missing value for --output-format"),
"cli_parse",
"missing --output-format value must classify as cli_parse"
);
assert_eq!(
classify_error_kind("missing value for --permission-mode"),
"cli_parse",
"missing --permission-mode value must classify as cli_parse"
);
// Sanity: must not hijack genuinely unknown errors that happen to
// contain the word `unsupported` or `missing`.
assert_eq!(
classify_error_kind("some unsupported runtime condition we don't recognize"),
"unknown",
"generic `unsupported` text should still fall through to unknown"
);
}
#[test]
fn split_error_hint_separates_reason_from_runbook() {
// #77: short reason / hint separation for JSON error payloads