I can't tell if there's a bug here, but it is certainly unintuitive. The problem seems to be that by defining the procedure as "unquoted" it assumes the parameter is a string and not a numeric. And so !$i = $i -1 actually does a string concat rather than an integer subtraction (I could understand + doing this, but - probably should give a syntax error!). So you can get it working as intended by either removing the "unquoted" from your procedure definition, or by using "!$i = %intval($i) - 1".
Here's your example with the %intval fix, but also a couple of extra lines to show that $i starts as a string and "-" acts as a concat but then $i turns in to a numeric and "-" acts as a minus.
@startuml
!unquoted function Service($name, $index)
!return 'component "'+$name+'_'+$index+'"'
!endfunction
!unquoted procedure ScaleService($i)
!while $i!=0
!$j = $i - 1
component %string("X" + $j)
Service(svc,$i)
!$i = %intval($i) - 1
!endwhile
!endprocedure
ScaleService(3)
@enduml
