mirror of
https://github.com/instructkr/claw-code.git
synced 2026-04-27 00:24:58 +08:00
fix: #247 classify prompt-related parse errors + unify JSON hint plumbing
Cycle #34 dogfood follow-through on Jobdori cycle #33 pinpoint (#247 filed
at fbcbe9d). Closes the two typed-error contract drifts surfaced in that
pinpoint against the Rust `claw` binary.
## What was wrong
1. `classify_error_kind()` (main.rs:~251) used substring matching but did
NOT match two common prompt-related parse errors:
- "prompt subcommand requires a prompt string"
- "empty prompt: provide a subcommand..."
Both fell through to `"unknown"`. §4.44 typed-error contract specifies
`parse | usage | unknown` as distinct classes, so claws dispatching on
`error.kind == "cli_parse"` missed those paths entirely.
2. JSON mode dropped the `Run `claw --help` for usage.` hint. Text mode
appends it at stderr-print time (main.rs:~234) AFTER split_error_hint()
has already serialized the envelope, so JSON consumers never saw it.
Text-mode humans got an actionable pointer; machine consumers did not.
## Fix
Two small, targeted edits:
1. `classify_error_kind()`: add explicit branches for "prompt subcommand
requires" and "empty prompt:" (the latter anchored with `starts_with`
so it never hijacks unrelated error messages containing the word).
Both route to `cli_parse`.
2. JSON error render path in `main()`: after calling split_error_hint(),
if the message carried no embedded hint AND kind is `cli_parse` AND
the short-reason does not already embed a `claw --help` pointer,
synthesize the same `Run `claw --help` for usage.` trailer that
text-mode stderr appends. The embedded-pointer check prevents
duplication on the `empty prompt: ... (run `claw --help`)` message
which already carries inline guidance.
## Verification
Direct repro on the compiled binary:
$ claw --output-format json prompt
{"error":"prompt subcommand requires a prompt string",
"hint":"Run `claw --help` for usage.",
"kind":"cli_parse","type":"error"}
$ claw --output-format json ""
{"error":"empty prompt: provide a subcommand (run `claw --help`) or a non-empty prompt string",
"hint":null,"kind":"cli_parse","type":"error"}
$ claw --output-format json doctor --foo # regression guard
{"error":"unrecognized argument `--foo` for subcommand `doctor`",
"hint":"Run `claw --help` for usage.",
"kind":"cli_parse","type":"error"}
Text mode unchanged in shape; `[error-kind: ...]` prefix now reads
`cli_parse` for the two previously-misclassified paths.
## Regression coverage
- Unit test `classify_error_kind_covers_prompt_parse_errors_247`: locks
both patterns route to `cli_parse` AND that generic "prompt"-containing
messages still fall through to `unknown`.
- Integration tests in `tests/output_format_contract.rs`:
* prompt_subcommand_without_arg_emits_cli_parse_envelope_with_hint_247
* empty_positional_arg_emits_cli_parse_envelope_247
* whitespace_only_positional_arg_emits_cli_parse_envelope_247
* unrecognized_argument_still_classifies_as_cli_parse_247_regression_guard
- Full rusty-claude-cli test suite: 218 tests pass (180 bin unit + 15
output_format_contract + 12 resume_slash + 7 compact + 3 mock + 1 cli).
## Family / related
Joins §4.44 typed-envelope contract gap family closure: #130, #179, #181,
and now **#247**. All four quartet items now have real fixes landed on
the canonical binary surface rather than only the Python harness.
ROADMAP.md: #247 marked CLOSED with before/after evidence preserved.
This commit is contained in:
25
ROADMAP.md
25
ROADMAP.md
@@ -6565,7 +6565,30 @@ main.py: error: the following arguments are required: command
|
||||
|
||||
---
|
||||
|
||||
## Pinpoint #247. `classify_error_kind()` misses prompt-related parse errors — "empty prompt" and "prompt subcommand requires" classified as `unknown` instead of `cli_parse`; JSON envelope also drops the `Run claw --help for usage` hint
|
||||
## Pinpoint #247. `classify_error_kind()` misses prompt-related parse errors — "empty prompt" and "prompt subcommand requires" classified as `unknown` instead of `cli_parse`; JSON envelope also drops the `Run claw --help for usage` hint **[CLOSED 2026-04-22 cycle #34]**
|
||||
|
||||
**Status.** CLOSED. Fix landed on `feat/jobdori-247-classify-prompt-errors` (cycle #34, Jobdori, 2026-04-22 22:4x KST). Two atomic edits in `rust/crates/rusty-claude-cli/src/main.rs` + one unit test + four integration tests. Verified on the compiled `claw` binary: both prompt-related parse errors now classify as `cli_parse`, and JSON envelopes for the bare-`claw prompt` path now carry the same `Run \`claw --help\` for usage.` hint as text mode. Regression guard locks in that the existing `unrecognized argument` hint/kind path is untouched.
|
||||
|
||||
**What landed.**
|
||||
1. `classify_error_kind()` gained two explicit branches for `prompt subcommand requires` and `empty prompt:`, both routed to `cli_parse`. Patterns are specific enough that generic prompt-adjacent messages still fall through to `unknown` (locked by unit test).
|
||||
2. JSON error path in `main()` now synthesizes the `Run \`claw --help\` for usage.` hint when `kind == "cli_parse"` AND the message itself did not already embed one (prevents duplication on the `empty prompt: … (run \`claw --help\`)` path which carries guidance inline).
|
||||
3. Regression tests added: one unit test (`classify_error_kind_covers_prompt_parse_errors_247`) + four integration tests in `tests/output_format_contract.rs` covering bare `claw prompt`, `claw ""`, `claw " "`, and the `doctor --foo` unrecognized-argument regression guard.
|
||||
|
||||
**Cross-channel parity after fix.**
|
||||
|
||||
```
|
||||
$ claw --output-format json prompt
|
||||
{"error":"prompt subcommand requires a prompt string","hint":"Run `claw --help` for usage.","kind":"cli_parse","type":"error"}
|
||||
|
||||
$ claw --output-format json ""
|
||||
{"error":"empty prompt: provide a subcommand (run `claw --help`) or a non-empty prompt string","hint":null,"kind":"cli_parse","type":"error"}
|
||||
```
|
||||
|
||||
Text mode remains unchanged (still prints `[error-kind: cli_parse]` + trailer). Both channels now carry `kind == cli_parse` and the hint content is either explicit (JSON field) or embedded (inline in `error`), closing the typed-envelope asymmetry flagged in the pinpoint.
|
||||
|
||||
**Original gap (preserved for history below).**
|
||||
|
||||
## Pinpoint #247 (original). `classify_error_kind()` misses prompt-related parse errors — "empty prompt" and "prompt subcommand requires" classified as `unknown` instead of `cli_parse`; JSON envelope also drops the `Run claw --help for usage` hint
|
||||
|
||||
**Gap.** Typed-error contract (§4.44) specifies an enumerated error kind set: `filesystem | auth | session | parse | runtime | mcp | delivery | usage | policy | unknown`. The `classify_error_kind()` function at `rust/crates/rusty-claude-cli/src/main.rs:246-280` uses substring matching to map error messages to these kinds. Two common prompt-related parse errors are NOT matched and fall through to `unknown`:
|
||||
|
||||
|
||||
Reference in New Issue
Block a user