That said, why not use env vars which tell the child process what to expect on which file descriptor numbers?
Depending how crazy you want to get, you could also use unix sockets to pass around FDs instead of inheritance. In that scenario, a process would be passed a unix socket either by a socket pair file descriptor or the shell would have a named socket which it tells child processes about using an env var. You can then use the sendfd functionality of unix sockets to pass around arbitrary file descriptors with arbitrary metadata.
You could also use the unix socket to instead have the child process optionally ask the shell what the descriptor's metadata is. That way you'd keep backwards compatibility with unix tools, but the child process could sendfd the file descriptor back to its parent to ask for data about it. The parent could look it up by calling fstat on it and comparing the fstat data to the other file descriptors it sent to the child.
But regardless, when you can't add a new syscall and need to do file descriptor stuff on behalf of another process, unix sockets + sendfd can really start to look like a userspace syscall interface which you can do a lot with.