When the whole string is an interpolation

A string that contains only a hole is text, the same as any other interpolation.

"{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.