I have to say that I found that surprising too. Here's my simplest version of your code:
So I looked at the relevant API documentation, which turned out to be the method
public StringBuilder insert(int dstOffset, CharSequence s, int start, int end). Since both StringBuilder and String implement CharSequence, this should describe what happens for both types of object. So what makes them different? The documentation describes very carefully how it works:
The character at index k in this sequence becomes equal to:
the character at index k in this sequence, if k is less than dstOffset
the character at index k+start-dstOffset in the argument s, if k is greater than or equal to dstOffset but is less than dstOffset+end-start
the character at index k-(end-start) in this sequence, if k is greater than or equal to dstOffset+end-start
So the first three characters in the result are "123" according to the first of those three rules. Then the second rule kicks in and starts inserting characters. The first three are copied from the CharSequence and they are "123" in both cases. The fourth is also copied from the CharSequence but here's where the difference arises. When you're inserting the StringBuilder, that character is copied from the fourth character of the StringBuilder, which is now "1" because we just inserted "1" into the fourth position. Whereas when you're inserting the String copied from the StringBuilder, that character is copied from the fourth character of the String, which is still "4".
Therefore, what you're seeing is strange but correct, according to a close reading of the documentation. At least in my opinion it is.