I've heard it said:
"In fact, everything coming directly from the lexer should be locked."
I used to agree with this (in fact, this is how Ren-C worked for a year or two). That was a good era to shore up the read-only checks, and build ways to make sure at compile-time via C++ type system that they were being honored by native code.
BUT I ultimately found myself uncomfortable with making it a hard rule. Something just got lost when you have to change:
>> x: [a b c]
>> append x 'd
== [a b c d]
To:
>> x: copy [a b c]
>> append x 'd
== [a b c d]
It seems small. But Rebol is about the avoidance of small things. Like parentheses when you don't want them... sure you COULD be forced to add them, it would reduce some risks, but it's left as a choice.
I think here this is another example of one of those small choices that adds up. You're using the word COPY you don't necessarily want to use or see. You're making a copy you don't necessarily want to pay for. Saying you can't do that without the copy felt like it was a drift from the premises that make Rebol be Rebol.
So eventually I was swayed to believe this should be a choice. The script or module header should be able to say "I want this transcoded frozen" or "I want it left mutable". Right now it chooses the liberal default, and I feel like it's the right choice.
The way I protected people from themselves is CONST; and when you have something like the execution of a function body, or a loop body, that const Cell bit trickles down (as with the binding).
https://rebol.metaeducation.com/t/value-vs-series-modification-bit-const-and-mutable/976