> I'm missing the crucial design bits which would influence
> embeddability:
Your points are crucial but mundane. For people who have done extension and embedding with other languages like Perl, Python, Tcl, etc, what really matters for productivity and maintenance are the more subtle details.For example, in Lua you can create _instances_ of a wrapped C function that has upvalues, which are analogous to closed-over variable slots. In other words, you can implement C callbacks as closures, a more functional-oriented approach which also generally more performant than many alternatives. In many languages to associate instance data with wrapped functions (as opposed to wrapped methods where you're always passed an instance object) you're stuck using some sort of global registry or other coarse mechanism. Lua supports many such alternatives, as well, including some novel alternatives. But the upvalue mechanism is particularly elegant and useful.
Another useful feature, which is discussed by that paper, is how Lua designed coroutines--the semantics, the implementation, and the public C API. Languages like JavaScript, Perl, and Python don't support stackful coroutines (i.e. being table to yield a coroutine from any arbitrary function, not simply the function initially invoked/resumed). They neither support them within the language nor outside the language for use by C, and with exception (a brilliantly complex Perl XS module comes to mind) you can't even begin to fake this. This is because implementations of those languages conflate the host C stack with the logical call stack of the language. And because you can neither grow the C stack nor easily yield and resume, these languages simply eschew stackful coroutines altogether. The implementation restricts the semantics they can implement at the language level.
Lua not only supports stackful coroutines, but it provides a mechanism and API for resuming and yielding a Lua/C function, all in strict ISO C. This was more limited in Lua 5.1, and made more powerful in Lua 5.2. In any event, this mechanism makes it easy to, among other things, write asynchronous I/O frameworks in Lua that behave like green threading. You don't need to pepper your code with async/await everywhere, nor do you need to create trampolines in your FFI binding code to get yield semantics from the C callback, which results in messy and complex modules.
Lua is awesome as both an extension and embedding language because it was built from the ground keeping those requirements and constraints in mind. The only serious concession most languages make for integration with C is either to avoid moving pointers, or providing a special type to wrap objects visible in C. All the rest occurs as an after thought, and while the results are often acceptable, they're just not remotely as convenient or seamless.
The biggest exception to my points above are Tcl. I find Lua more elegant and powerful, both the language and the C APIs, but Tcl deserves its due.