I get the distinction between unitialized and actual byte value, and that’s definitely useful. However, I’m not sure about giving pointer values special status.
If I understand correctly, you’d like to keep the extra edge-case-solving hidden properties of pointers even through casts to integers (and back?), so you’re trying to attach metadata to pointer-derived bytes and integers.
That doesn’t fit my mental model. In my ideal machine the check whether something is a valid pointer or not would not depend on how the value was obtained, but only whether it happens to look like any valid pointer (of compatible type) at the moment the pointer is crated from an integer (i.e. at the moment of foo as *mut u8 search through all possible valid values of pointers, and decide which pointer it is).
The pointer->integer->pointer cast does create ambiguity. You can’t know whether it was one-past-end of first array, or start of second array. That’s fine. Just pick one (preferably the latter) in a well-defined fashion. If you need this unambiguous for static analysis, then leave gaps between arrays 
So while x[y-x] is UB, the same thing “lanudered” through integers IMHO should be allowed and point to y.
In other words IMHO:
let x = &[0u8; 10];
let y = rand() as *const u8;
y could point to x sometimes.