My number one use case for comments is documenting invariants/preconditions/postconditions that are not enforced by any automated mechanism (e.g., a type system). I'm surprised no one else has mentioned this. To me these are exactly the things that MUST be commented. Of course, it's useful to have some mental heuristics around what other kinds of comments are helpful to readers, but unenforced assumptions/guarantees need to be documented so programmers in the future can see what they are.
One might argue that all invariants should be covered by tests, but tests (by themselves) cannot even ensure some the most basic properties about functions, such as that a function always returns a sorted list no matter what input it's given. Tests also cannot ensure that a function's preconditions are always satisfied at every call site, because new call sites can be added in the future without causing the existing tests to fail.