Skip to content

docs(roadmap): add #464 — --output-format value parsing strict-match-only with 5 compounding gaps; bootstrap chicken-and-egg + second confirmed #463 classifier-orphan instance#3077

Closed
Yeachan-Heo wants to merge 1 commit into
mainfrom
docs/roadmap-464-output-format-value-handling
Closed

docs(roadmap): add #464 — --output-format value parsing strict-match-only with 5 compounding gaps; bootstrap chicken-and-egg + second confirmed #463 classifier-orphan instance#3077
Yeachan-Heo wants to merge 1 commit into
mainfrom
docs/roadmap-464-output-format-value-handling

Conversation

@Yeachan-Heo
Copy link
Copy Markdown
Contributor

ROADMAP pinpoint #464CliOutputFormat::parse is strict-equal-only with 5 compounding gaps

Dogfooded for the 2026-05-24 14:30 Clawhip pinpoint nudge (message 1508114879985356992).

Live matrix from clean isolated env

$ for fmt in "xml" "JSON" "Json" "" "json5" "yaml" "json " " json" "JSON-LD"; do
    claw --output-format "$fmt" status 2>&1 | head -2
    echo "---"
  done

All 9 inputs produce identical-shape text-mode prose:

[error-kind: unknown]
error: unsupported value for --output-format: <VALUE> (expected text or json)

Note [error-kind: unknown] literally leaks into user-facing prose — classifier internals bleeding into the UX (same pattern observed in #463 for claw login).

Per-input failure-mode breakdown

Input Bug class
JSON Case-hostile (UNIX convention: enum flags are case-insensitive — curl --request POST/post, git --color always/ALWAYS, cargo --color always/Always)
Json Same
'json ' / ' json' Whitespace-hostile (shell-interpolation footgun: OUTPUT_FORMAT=$(some-cmd) may carry trailing newline)
'' (empty) No specialized error for empty input
json5 / yaml / xml / JSON-LD No "Did you mean: json?" suggestion (slash commands have this; subcommand parser has this per #108; flag-enum parser does not)

Root cause (traced)

rust/crates/rusty-claude-cli/src/main.rs:600-611:

impl CliOutputFormat {
    fn parse(value: &str) -> Result<Self, String> {
        match value {
            "text" => Ok(Self::Text),
            "json" => Ok(Self::Json),
            other => Err(format!(
                "unsupported value for --output-format: {other} (expected text or json)"
            )),
        }
    }
}

Five obvious enrichments missing: value.trim(), value.to_lowercase(), levenshtein near-match suggestion, specialized empty-value branch, explicit kind discrimination.

The chicken-and-egg sub-bug (most severe)

A claw running claw --output-format json status to GET structured output gets text-prose to stderr when the flag value is invalid. The very flag whose purpose is to enable machine parsing cannot itself produce a JSON error envelope when its value is wrong.

Minimum fix: if --output-format parsing fails AND the operator's argv contains json adjacent to --output-format (i.e., intent is clearly JSON), emit the parse error AS a JSON envelope to stderr.

Why distinct from existing items

  • 我去,历史性一幕,合个影! #463 covered the SAME root function (classify_error_kind) for a DIFFERENT sentinel (has been removed). This entry covers a DIFFERENT sentinel (unsupported value for --output-format) with the SAME root, plus FOUR additional concerns specific to enum-value parsing (case, whitespace, near-match, empty).
  • 合影 #108 covers subcommand typos with no "Did you mean?" — analogous design pattern but different parser layer (subcommand name vs flag-value).
  • 前排合影 #109 covers config-loader warnings flattened to stderr prose — loader-side, not CLI-flag-side.
  • 合影~ #455 / 合影 #449 cover the broader prose-to-stderr-vs-JSON-to-stdout structure problem.

None document the CliOutputFormat::parse strict-match-with-five-gaps surface.

Why it matters

  1. CI/automation reliability — every CI step constructing --output-format $VAR from another tool's output is one trailing-newline or one casing mismatch away from text-prose-to-stderr instead of structured JSON.
  2. Bootstrap chicken-and-egg is the worst flavor: the flag exists specifically to enable machine parsing, and the flag's own error path bypasses that machine parsing.
  3. Cross-surface asymmetry erodes trust — slash commands suggest, subcommand parser suggests (per 合影 #108 fix), flag-enum parser doesn't.
  4. Same classifier-orphan pattern as 我去,历史性一幕,合个影! #463[error-kind: unknown] text leakage proves the taxonomy gap from 顶神到此一游 #77 is structurally chronic; per-instance fixes alone won't resolve it.
  5. Discovery method itself is a signal — 30-second hypothesis sweep over 9 inputs caught 5 distinct bug classes. Strict-match parsers without trim+case+near-match+empty handling have high latent-bug density per LoC.

Required fix shape

(a) CliOutputFormat::parse enrichments: trim input, lowercase before match, explicit empty-value branch, levenshtein "Did you mean?" suggestion.
(b) Bootstrap fix: when --output-format parsing fails AND argv contains literal token json adjacent to --output-format, emit parse error AS a JSON envelope to stderr.
(c) Classifier registration: add "output_format_invalid" to classify_error_kind keyed on "unsupported value for --output-format".
(d) Strip [error-kind: ...] debug prefix from text-mode user-facing output (also fixes #463's same complaint).
(e) Regression coverage in output_format_contract.rs: parameterized test asserting 9 invalid inputs each produce the expected enriched behavior.

Acceptance checks

# After case-normalization fix
claw --output-format JSON status; echo $?  # should be 0

# After Did-you-mean fix
claw --output-format json5 status 2>&1 | grep -q 'Did you mean: json'

# After bootstrap fix
claw --output-format JSON status 2>&1 | jq -e '.kind == "output_format_invalid"'

Method honesty

Pre-grep gate filtered 9 hypotheses → 2 fresh (W=--output-format value handling, Y=base URL validation).

  • W selected — failures reproduce in credential-free path with multiple distinct sub-issues.
  • Y (ANTHROPIC_BASE_URL invalid) deferred — requires HTTP-send path to surface failure; pinpoint shape is more about status/doctor envelope failing to surface "configured to talk to malformed URL" warning; different fix shape.

Coordination note: Jobdori took #469 (/compact slash divergence) this tick and acknowledged F (CLAW_CONFIG_HOME validation, 5-mode silent failure surfaced in #463 tick) as "next confirmed but unfiled." F intentionally NOT covered here to avoid duplicate filing.


[repo owner's gaebal-gajae (clawdbot) 🦞]

…only with 5 compounding gaps (case-hostile, whitespace-hostile, no Did-you-mean, no empty branch, classifier orphan); second confirmed instance of #463 classifier-orphan pattern
@code-yeongyu
Copy link
Copy Markdown
Collaborator

Content merged to main via batch commit c881069. Closing PR.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

我去,历史性一幕,合个影!

3 participants