diff --git a/ROADMAP.md b/ROADMAP.md index 4e635166..93ce6cec 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -7673,3 +7673,5 @@ Original filing (2026-04-18): the session emitted `SessionStart hook (completed) 752. **`claw --output-format json ` returned `hint: null` for all `cli_parse` errors when an unrecognized positional arg was supplied** — dogfooded 2026-05-26 on `ddc71b56`. Generic `unrecognized argument` format string had no `\n` so `split_error_hint` emitted null hint (only the `--json` special-case added a hint). Fix: add else-branch appending `\nRun `claw --help` for usage.` to the generic arm. Affected surfaces: `sandbox`, `doctor`, `version`, and any other subcommand routing through the same unrecognized-arg path. Source: Jobdori dogfood on `ddc71b56`, 2026-05-26. 753. **`claw --output-format json -p` (no prompt arg) returned `error_kind:"unknown"` and `hint: null`** — parity gap with #750/#751 which fixed the explicit `prompt` verb. Identified by gaebal-gajae on `ddc71b56`. Fix: same `missing_prompt:` prefix + newline usage hint as #750. Regression guard: `short_p_flag_no_arg_json_error_kind_753` asserting nonzero exit, `error_kind:"missing_prompt"`, non-empty hint mentioning `claw -p` or `claw prompt`. Source: gaebal-gajae dogfood on `ddc71b56`, 2026-05-26. + +754. **`missing_credentials` JSON envelope always had `hint: null` even when a contextual hint was available** — dogfooded 2026-05-26 on `e9327135`. `ApiError::Display` for `MissingCredentials` appended the hint via ` — hint: {hint}` (inline, no `\n`), so `split_error_hint()` could not extract it and left the JSON `hint` field null. Fix: change delimiter from ` — hint: ` to `\n` in `api/src/error.rs` Display impl; update two tests in `api/src/error.rs` and `api/src/providers/mod.rs` to assert newline separator. Source: Jobdori dogfood on `e9327135`, 2026-05-26. diff --git a/rust/crates/api/src/error.rs b/rust/crates/api/src/error.rs index 21d980af..1dc4fb29 100644 --- a/rust/crates/api/src/error.rs +++ b/rust/crates/api/src/error.rs @@ -273,7 +273,10 @@ impl Display for ApiError { } } if let Some(hint) = hint { - write!(f, " — hint: {hint}")?; + // #754: newline-delimited so split_error_hint() can extract the hint + // into the JSON envelope's `hint` field. The em-dash form was a + // single-line string that left hint:null in --output-format json. + write!(f, "\n{hint}")?; } Ok(()) } @@ -608,11 +611,16 @@ mod tests { rendered.starts_with("missing Anthropic credentials;"), "hint should be appended, not replace the base message: {rendered}" ); - let hint_marker = " — hint: I see OPENAI_API_KEY is set — if you meant to use the OpenAI-compat provider, prefix your model name with `openai/` so prefix routing selects it."; + // #754: hint is now newline-delimited so split_error_hint() can extract it + let hint_text = "I see OPENAI_API_KEY is set — if you meant to use the OpenAI-compat provider, prefix your model name with `openai/` so prefix routing selects it."; assert!( - rendered.ends_with(hint_marker), + rendered.ends_with(hint_text), "rendered error should end with the hint: {rendered}" ); + assert!( + rendered.contains('\n'), + "rendered error must contain newline separator so split_error_hint works: {rendered}" + ); // Classification semantics are unaffected by the presence of a hint. assert_eq!(error.safe_failure_class(), "provider_auth"); assert!(!error.is_retryable()); diff --git a/rust/crates/api/src/providers/mod.rs b/rust/crates/api/src/providers/mod.rs index ca1086d2..237e9799 100644 --- a/rust/crates/api/src/providers/mod.rs +++ b/rust/crates/api/src/providers/mod.rs @@ -1649,10 +1649,15 @@ NO_EQUALS_LINE rendered.starts_with("missing Anthropic credentials;"), "canonical base message should still lead the rendered error: {rendered}" ); + // #754: hint delimiter changed from " — hint: " to "\n" so split_error_hint works assert!( - rendered.contains(" — hint: I see OPENAI_API_KEY is set"), + rendered.contains("I see OPENAI_API_KEY is set"), "rendered error should carry the env-driven hint: {rendered}" ); + assert!( + rendered.contains('\n'), + "rendered error must use newline separator (#754): {rendered}" + ); } #[test]