1. If you mess up the command line to the program in a script or pipe, and get a bunch of usage output in stdout, a downstream consumer of that stdout might think its legit program output and try to parse it.
2. If your user actually calls the program with -h or --help, they might want to |less through it to read it on a small terminal screen. Output that to stdout.
3. Generally, you can always tell if something is going wrong by grepping for errors or warnings a single stream (stderr), or by looking for a nonzero exit code.
But your general principle applies: Output expected by the user -> stdout. Diagnostic output or output incidental to the program's operation or errors -> stderr.
1: https://pubs.opengroup.org/onlinepubs/9799919799/functions/s...