The reason it can for constants is that it knows the result will be okay. In the general case it doesn’t know that b will fit into a byte. If you changed b to be 1000, that cannot be written to a byte so it forces you (as does Java) to be explicit about your intention.
As far as your first example consider this variation:
// I have this java method
public static void foo(double bar){ println("%f".format(bar)) }
// in java I can do this
foo(987654321012345678);
The result is 987654321012345730.000000
because there is a loss of precision in the conversion to double. Java thought that was OK, Kotlin designers require you to be explicit since the conversion can be lossy