If I have this value class:
class ActionId(val value: Int) extends AnyVal
Then, in all the examples below, an object will be allocated for
None of your examples result in boxing. Value classes are only boxed with generics, with arrays, and when typed as a superclass/trait (e.g. Any/AnyVal)
They're boxed with generics because otherwise you can't distinguish them from the value (and primitives need a box anyway). Same deal with Any, and other superclasses/traits need a box or the type relationship is wrong.
They're boxed with arrays because arrays need to know the type of the contents, but the JVM doesn't understand the concept of a "value type". So you'd end up with an array that said it was the type being boxed, but which Scala was pretending was an array of the value type; a decision was made (based on previous issues with Array when it wasn't just a plain Java/JVM array) that this would lead to too many subtle bugs and corner cases.
Here's an example of the three ways to get boxing:
trait Q extends Any {}
class X(val x: String) extends AnyVal with Q {}
// Array
val a = Array(new X("salmon")) // boxed
// Generic
val b = Option(new X("minnow")) // boxed
// Upcast
val c = (new X("perch"): Any) // boxed
val d = (new X("cod"): AnyVal) // boxed
val e = (new X("herring"): Q) // boxed
Everything else--passing around through various functions, etc.--doesn't require boxing, including all of your examples.
Arrays are a bit of a special case because you can store the primitives and pull them out again as value classes with zero bytecode overhead, but a lot of syntactic overhead:
class Y(val repr: String) extends AnyVal {}
val y1 = new Y("apple") // unboxed
val y2 = new Y("orange") // unboxed
val ys: Array[String] = Array(y1.repr, y2.repr) // no overhead
val y3 = new Y(ys(0)) // no overhead