Optimisation turns assertion/1 into a no-op, which is why there’s a singleton warning - the assertion check has disappeared and the code has become equivalent to forall((between(0,3,N), Y is N*3), true).
The documentation for assertion/1 (and some other predicates) in library(debug) needs to be improved to point out that optimisation turns them off – it is documented in the overview section of the documentation. You can control this behavior with Prolog flag optimise_debug.
to stop optimizing debug/3 and assertion, even in debug mode. In this case it is about the intended semantics, so the warning is ok. If it is correct to optimize the assertion/1 away (or debug/3), you can use the variable _0Name, as _<Digit>* variables are never subject to singleton or “multiton” messages.