Variables like $1 are populated after a regex match is performed. Simplifying your example a little:
s.gsub('original(value)', "replacement#{$1}")
The "replacement#{$1}" expression is evaluated before the gsub function is called. So $1 will be leftover from some previous regex task. (That’s why your second attempt works - it takes $1 from the first attempt)
There are a couple of options to solve this problem. gsub has lots of different functionalities.
My preference would be to pass a block to gsub. The block is evaluated after the regex has been matched, so $1 will work as you expect:
s.gsub('original(value)') { |match| "replacement#{$1}" }
Or you can use the ‘backreference’ feature of gsub. I’m not a fan of this syntax, but it does work. Rather than using "replacement#{$1}", you use 'replacement\1' (or \2, or \3, etc.)
s.gsub('original(value)', 'replacement\1')