> Python code executed by an x86 runtime, on a CPU emulated in a JavaScript VM, running on an ARM CPU.
So in this case, we have a tower of well-defined abstractions, most of which have extant well-tested implementations. I would expect the resultant tower to be semantically correct enough of the time to be a reasonable platform to work with--i.e. if you have a bug, it's probably in your code, not the platform. Where we'd see the abstractions leaking heavily is performance analysis, unless this tower collapse is also a Sufficiently Smart Compiler.
Or, to put it simpler, undefined behavior is mostly a C thing, you won't find much of it elsewhere.
If behavior is implementation-defined, then the language is actually a family of languages that can be instantiated according to the implementation's choices. This is consistent with the grandparent's description.
Underspecified behavior is just another way to say "implementation-defined". It's a problem of documentation and specification -- in principle, if you had enough of both, you should be able to tell how a stack of interpreters behaves. It's not a fundamental barrier.
As a matter of standardization, it is almost always a mistake to make anything implementation-defined. It is a common mistake among beginners writing their first proposal (don't be "that beginner"!) and inexperienced committee members who think it would resolve an impasse. Typically, when you find ID in a standard, it is because nobody cared enough to bother getting it right.
The definition an implementation provides for an ID thing may just say "undefined".
A comment below says that "undefined" doesn't mean "not defined". But it really does. Anything a standard does not define is undefined, and if you step in it, anything may happen, up to and including launching the missiles.
Implementations are allowed to provide their own definition for almost anything left undefined by a standard. Often they define things according to another published standard, and point there. For example, "#include <unistd.h>" is UB in ISO C, but implementations often defer to POSIX, another ISO Standard, there.
Sometimes a Standard will leave something undefined, but warn that they plan to define it later. Usually this is expressed as "reserve".
Another way to think about it is that undefined means they have defined it, and they've defined it as not having a definition.
Most of Ruby is not defined. But little of it is undefined.