"{n}" used to evaluate to n itself. One character of surrounding text changed the type:
type_of("{1}")
type_of("x{1}")
The first was int. The second was string, and it still is. A literal with no hole was never affected: "hello" is the string hello.
The failure this caused pointed at the wrong thing. insert(m, "{n}", "value") reported insert needs a string, got int on a line where the argument is written in quotes. The quotes were real. The value was not a string, because a hole with nothing beside it was defined to unwrap.
"{n}" now renders n the way string(n) does.
n = 3
type_of("{n}")
"{n}"
The type is string and the text is 3. "x{n}" is still x3. Code that wanted text keeps working.
If you wanted the value
Drop the quotes.
n = 3
n
That is 3, an int. Wrapping it was never a conversion. It was an accident of the hole being alone.
If you have text and you want a number, parse it:
int("3")
float("1.5")
int and float are the conversions. The quotes around a hole are not.
A check that used to go quiet
The unwrapped-credential check looks for a secret read straight into a string. "key={os.env("K")}" reported it, because the surrounding text made the whole thing a string and the read was visible inside it. "{os.env("K")}" did not. The expression was the bare read, so the finding had nothing to attach to.
Both report it now. A lone hole no longer hides the read. If that finding has started appearing on a line that used to pass, drop the quotes, or keep them and accept that the check can see the read.