Avoiding duplicate selection in repeat group

Yes, absolutely, that form does assume that each value is unique and not contained in other values. This is a reasonable assumption for selects but you're right that it doesn't make sense for arbitrary strings or integers.

This form shows an alternative using an XPath filter expression (the stuff in the square brackets):

join(' ', ${rpt}[position != current()/../position]/id)

That says to join all of the id values for repeats which are not the current one. I tend to try to avoid XPath in examples but in this case it may actually be a clearer solution all around and less risky because it doesn't assume anything about values entered. What do you think?

I didn't look at @bdra2778's example above in great detail but I think the concept works as well. It uses a parallel repeat to compare every prior value. Do note that it would be slower with a bigger repeat. @bdra2778 there also is one limitation I can think of: because your repeat count is position(..)-1, you won't immediately detect duplicates if someone comes back to edit an answer. For example, if they enter in 2, 6, 7 and then go back to change the 2 to a 7, I believe that will be accepted. However, on validation, the second 7 will show a constraint failure. This is not a big deal but I did want to point it out.