Are you wrapping your expression in quotes? This indicates that Matches only accepts strings as the pattern. If that doesn't work I'm really not sure what the issue is, and I would try to pass your values to a custom function where you can examine what's really going on, and see if you can replicate the problem. This is essentially what Jeffrey Drumm was suggesting.

Have you been able to reproduce this in essentially an empty delegated web app? If it works there then we know it's probably just a logic problem with your code.

The next thing I would try for nailing down the culprit is looking at where the 401 is generated. %CSP.Rest on its own contains two functions that output 401 errors, Page and Login. I'm brainstorming now, but if it's coming from Page, I'd think your logic is trying to load something after being logged out (a login page it can't find maybe?), and if it's from Login, that'd be odd to me but probably something in your logic trying to immediately log back in with empty or bad credentials.

If you're able to see those 401 calls being fired in the rest class, try overriding the functions and capturing more information from them to see what's really going on and why they're being called with improper authentication.

I use a similar setup with some projects, albeit not with delegation. But appending the param to my url has never given me 401 messages. What kind of permissions do you have setup for your web app? If you manually insert this param at any point in the app, does it always give 401? Are you still redirected to your login page? Where are you capturing the 401, or is it sent on its own?

I've never seen anything like that in the docs before, just working with either regex or the pattern match operator. To get what you're looking for you may very well have to make those extra calls. Alternatively a cool project would be to make your own converter.  That'd be pretty interesting to do,  but before I'd look into it I'd like to make sure there isn't some function out there I've never heard of in Cache that does it. It never ceases to amaze me how many obscure functions exist out there for Cache that I have yet to discover.

Unfortunately I don't know how to go about altering that value after or before it's been generated. You may have to experiment with including custom functions in your tags that output page numbers, or try to get the value from the special tag into one of your custom tag functions. Whatever you do, there doesn't seem to be a native way and you'll have to do something custom.

I'll try to answer just the conversion question. It looks like someone has asked about roman numerals before here:

https://community.intersystems.com/post/roman-number-converter

However the conclusion was that the referenced article in that question here:

http://docs.intersystems.com/latest/csp/docbook/DocBook.UI.FrameSet.cls?KEY=GVRF_basicfeatures

Doesn't support roman numeral conversion. Now there's a billion ways to do this yourself, and I was inspired by the unary method in one of the answers here, instead of complex loops:

https://stackoverflow.com/questions/12967896/converting-integers-to-roman-numerals-java

So I made something similar for ObjectScript, and it gets the job done in a very simple way. Note that it doesn't use a full Subtractive method for conversion, for that you'll need more cases. The replaces could be structured differently too but I wanted it to be as understandable as possible. Call it in your report however you like.

ClassMethod RomanNumeralConversion(pNum) As %Status {
   set roman = ""
   for x=1:1:pNum {
    set roman = roman_"I"
   }
 
   set roman = $REPLACE(roman,"IIIII", "V")
   set roman = $REPLACE(roman,"IIII","IV")
   set roman = $REPLACE(roman,"VV","X")
   set roman = $REPLACE(roman,"VIV", "IX")
   set roman = $REPLACE(roman,"XXXXX", "L")
   set roman = $REPLACE(roman,"LL", "C")
   set roman = $REPLACE(roman,"LXL", "XC")
   set roman = $REPLACE(roman,"CCCCC", "D")
   set roman = $REPLACE(roman,"CCCC", "CD")
   set roman = $REPLACE(roman,"DD", "M")
   set roman = $REPLACE(roman,"DCD", "CM")
   return roman
}

What you've shown me inspired me to try something else...I can't draw from %request.Content.Data directly because it's always undefined, so I've had to use Read() all of the time whenever I need Data values from POST messages.

This seems to be working for any size so far, and I think I can come up with something more efficient later, but at least it's working!

set stream = ##class(%Stream.GlobalCharacter).%New()
While (%request.Content.AtEnd = 0) {
     Set len = $$$MaxStringLength
     do stream.Write(%request.Content.Read(.len))

}

//etc..


Set outputStream = ##class(%Stream.GlobalCharacter).%Open(oid)
While (outputStream .AtEnd = 0) {
     Set len = $$$MaxStringLength
     Write outputStream .Read(.len)
 }