I think the way I would approach this ipairs thing would be to move all of the raw* functions to a raw.* library, with raw.set(tbl, k, v), raw.ipairs(t), raw.equals(a, b) and so forth. Then ipairs() would clearly iterate over the length of the array portion as stored in C, which should both be apparent from the name, and more predictable w.r.t. performance. In addition you clear up the main namespace and it's clear that these functions do not interact with metatables.
__ipairs, and for that matter __construct and __sort, are basically duplicated functionality from __len and __call / __lt, respectively. It's hard (for me) to imagine a situation where using both such (corresponding) methods, differently, would solve a problem without making code unnecessarily confusing and opaque.