Skip to content

Decision 0011 - CLI stdout / stderr semantics and --quiet behavior

Status

Date: 23/01/2026 Status: Accepted

Context

During the implementation and stabilization of the CLI output behavior for fontshow create-catalog, several inconsistencies emerged between:

  • expected CLI behavior
  • actual runtime behavior
  • test assumptions

In particular, the interaction between:

  • --quiet
  • --verbose
  • warnings emitted during font processing
  • argparse error handling

required clarification and formalization.

Observed Behavior

  1. argparse always writes parsing errors to stderr
  2. This includes mutually exclusive flags such as --quiet and --verbose
  3. Exit code is non-zero
  4. Output is not suppressible via --quiet

  5. Warnings during font processing

  6. Warnings (e.g. unexpected font entries) are written to stderr
  7. They are not fatal
  8. They are not controlled by --quiet

  9. --quiet affects only stdout

  10. It suppresses progress messages and informational output
  11. It does not suppress:

    • warnings
    • errors
    • argparse diagnostics
  12. Fallback behavior is not an error

  13. When --inventory points to a missing file:
    • fallback to system font detection occurs
    • execution continues
    • exit code is 0
    • warnings may be emitted

Decision

1. Semantics of --quiet

--quiet suppresses:

  • informational output on stdout

--quiet does not suppress:

  • warnings
  • error messages
  • argparse diagnostics

This behavior is intentional and aligned with standard UNIX CLI conventions.


2. stderr is allowed output

The following outputs are valid on stderr:

  • warnings emitted during font normalization
  • fallback notifications
  • argument parsing errors
  • runtime errors

Tests must not assume stderr == "" unless explicitly testing silence.


3. Tests must reflect real CLI behavior

Tests asserting:

assert result.stderr.strip() == ""

are invalid unless:

  • the command is expected to be completely silent
  • no warnings or argparse errors are possible

Tests must instead:

  • assert return code
  • assert presence or absence of stdout
  • optionally match specific stderr content

4. Responsibility separation

Layer Responsibility
CLI (argparse) Argument validation, usage errors
Core logic Processing, fallback behavior
Logging Warnings and diagnostics
Tests Validate observable behavior, not assumptions

Consequences

  • CLI behavior is now clearly defined
  • Tests are aligned with real execution
  • No hidden coupling between --quiet and error handling
  • Logging remains consistent and debuggable
  • No further changes required in core logic

Follow-up

  • Future CLI commands should follow the same stdout/stderr contract
  • Tests should avoid asserting empty stderr unless strictly necessary
  • This decision applies to all subcommands