Thanks for the feedback Russell, now and early. It deeply informed the version I'm proposing here.
I weighed carefully when selecting this design that I thought it would be an acceptable tradeoff after our discussion, but I recognize this isn't exactly what you had argued for.
First off, with respect to the 'global state' issue, I figured it was reasonable with this choice of constexpr rule given that a reasonable tail recursive parser might look something like:
parse (code : rest) stack alt_stack just_pushed =
match code with
OP_PUSH => parse rest (x:stack) alt_stack True
OP_DUP => parse rest (x:stack) alt_stack False
// ...
So we're only adding one parameter which is a bool, and we only need to ever set it to an exact value based on the current code path, no complicated rules. I'm sensitive to the complexity added when formally modeling script, but I think because it is only ever a literal, you could re-write it as co-recursive:
parse_non_constexpr (code : rest) stack alt_stack =
match code with
OP_PUSH => parse_constexpr rest (x:stack) alt_stack
OP_DUP => parse_non_constexpr rest (x:stack) alt_stack
// ...
parse_constexpr (code : rest) stack alt_stack =
match code with
OP_CTV => ...
_ => parese_non_constexpr (code : rest) stack alt_stack
If I recall, this should help a bit with the proof automatability as it's easier in the case by case breakdown to see the unconditional code paths.
In terms of upgrade-ability, one of the other reasons I liked this design is that if we do enable OP_CTV for non-constexpr arguments, the issue basically goes away and the OP becomes "pure" without any state tracking. (I think the switching on argument size is much less a concern because we already use similar upgrade mechanisms elsewhere, and it doesn't add parsing context).
It's also possible, as I think *should be done* for tooling to treat an unbalanced OP_CTV as a parsing error. This will always produce consensus-valid scripts! However by keeping the consensus rules more relaxed we keep our upgrade-ability paths open for OP_CTV, which as I understand from speaking with other users is quite desirable.
Best (and happy thanksgiving to those celebrating),
Jeremy