I don't have a strong objection to also providing .end, but a few points here.
I'm not sure this is true in my case, I seem to use a fair mix of the open and closed ranges. Is this supported by usage statistics or documentation somewhere?
I'm having a lot of trouble seeing the “gotcha” aspect of this. It's essentially equivalent asking how many elements this replaces:
c.replaceRange(.first ... .first + 5, with: "foobar")
or how many elements this has
array[0 ... 5]
i.e. it's just the obvious/standard property of a closed range.
I had this same thought when the pitch for this proposal was posted and looked up this exact article, but when I re-read it I didn't find it that relevant here. Swift already didn't choose to have a single range type, so all the parts about choosing [a, b) vs [a, b] aren't particularly relevant. And since you're counting from the back when using .last, it's as natural to start from 0 offset (not -1) as it is when counting from the front. And it makes things symmetric, so you can easily flip a range from being relative to .first to be relative to .last by just flipping the bounds around and negating the offsets, as I did above. Though the one tricky part, as you demonstrate above, is that there's currently no >.. operator, which would let you write:
c.replaceRange(.last - 6 >.. .last, with: "foobar")