Carsten thanks that thread has lots of good info.
For one thing, it specifically tells me that __gc can resurrect an object, but also that it may not work on LuaJIT, which is good to know, because I am using LuaJIT now. That's OK for me, I don't need to resurrect in __gc, I just need to ensure that __gc doesn't happen if I reuse the full userdata from the weak table (even after all strong references are gone) which does seem to be the case.
Otherwise, yeah, I'm doing pretty much exactly what you say. I want to divorce the lifetimes of the C++ and Lua objects. I'm *effectively* using the solution you describe with smart pointers, except without actually using smart pointers. (Basically, my Lua full userdata, C++ class, and another C++ class all know how to collaborate ownership.) And I'm extending the class with auxillary data.
So I have the same problem you noted, how to keep alive ("anchor") the auxillary data even after references go. In my case though, I'm not going to try to keep the auxillary data associated with the full userdata and therefore keep the full userdata alive. Instead, I'm going to keep the auxillary data associated with the light userdata and let the full userdata go away if it wishes. If the object lives on in C++, its auxillary data will also live on. It can be recovered when a new full userdata is made for it. This effectively means even though full userdata may come and go, the lifetime of the *conceptual* Lua object can be anchored solely through C++ (i.e. it can be a different full userdata but that's OK). This is sort of like how strings keep identity while they exist, but maybe not after they "go away and come back". The only caveat, as I mentioned earlier in the thread, is I need a "native" finalizer for when the C++ object goes away, to clean up any auxillary data, so it won't be reused for a new C++ object at the same address. That's OK, I have that.