Skip to content

Router warnings never reach the user without --explain #136

Description

@kiki830621

What

Every warning the router produces — including "requested backend 'X' is unavailable; selecting automatically" — is folded into the explanation string and printed only when --explain is passed.

Sources/bestasr/BestASRCommand.swift:143-146:

print("Wrote \(result.format) transcript to \(result.outputPath)")
if explain {
    FileHandle.standardError.write(Data((result.explanation + "\n").utf8))
}

CommandCore.swift:447 is the only place rec.warnings is consumed, and it appends into that same explanation.

Why it matters

The user asks for one backend and silently receives another's output. Observed during #121 verification:

$ bestasr transcribe cv-zhtw-2.wav --backend apple-speech --language zh
Wrote txt transcript to …/cv-zhtw-2.txt          ← that is the entire output

The transcript was produced by mlx-audio Whisper, not apple-speech. Only --explain revealed it. Anyone comparing backends by hand would have recorded one backend's numbers under another's name.

The same suppression hides the other router warnings, several of which exist precisely to stop a silent quality loss:

Each was written to be seen. None is, by default.

Scope

Pre-existing, not introduced by #121git log -L143,146:Sources/bestasr/BestASRCommand.swift traces it to the original CLI commit (471218a, 2026-07-02), and main is byte-identical there. It affects every backend, not just the new one.

Suggested direction

Separate reasons from warnings: reason is explanatory detail and belongs behind --explain; warnings are things the user needs to know to trust the output, and belong on stderr unconditionally (a --quiet can opt out). Both already exist as separate arrays on ASRRecommendation, so the split is available without a schema change.

Worth checking benchmark and recommend for the same pattern.

Acceptance

  • transcribe --backend <unavailable> prints the substitution warning without --explain
  • --explain output is unchanged
  • a test asserts the warning reaches stderr on the default path — the current suite would not have caught this

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions