Given the following code, the right property is being calculated on access, so it is guaranteed to be correct for the copied instances:

data class Thing(val left: Int, val width: Int) {
    val right: Int
        get() = left + width
}

Which can easily be checked:

fun main() {
    val a = Thing(left = 0, width = 15)
    assertEquals(15, a.right)
    val b = a.copy(left = 5)
    assertEquals(20, b.right)
}

Playground

Copy function

But since all data classes’ properties are vals and therefore can’t change, we would technically only need to calculate it once. For this to work the property initializers would need to be invoked by the copy function.

The official docs don’t specify this, but that is exactly what is happening:

data class Thing(val left: Int, val width: Int) {
    val right = left + width
}

Playground

Kotlin Playground is an amazing tool to quickly drill down into a specific question and easily answer it.