Actually, you do get (limited) dependency management through insserv, which was standardized by LSB and its set of initscript headers. Most dpkg and RPM-based distros used them.
Automatic respawning is a job for a process supervisor, not a process manager or initd. It's a separate duty altogether. So is resource limiting, which is probably better serviced through separate tools that wrap around syscalls.
I disagree about respawning, but it probably comes from a difference in opinion about what the scope of a "process manager or initd" should be.
To me, starting a service expresses the intent: This service should be running. What the underlying process is is of no concern; a service is an abstraction of an OS process, not the process itself. The service's "target state" drives what to do with the process. I want to the service to be running, irrespective of what the underlying process is, which means that a process dying just implies it must be started again.
This functionality belongs in the init system first because it's closest to the source, secondly because it's such a common requirement that it belongs there. Sure, one can argue the technical design; respawning can be a separate subsystem forked from the init, for example. But it should be an integral feature of the init system, not something I have to get from a third party. To paraphrase Jobs, it's a feature, not a product.
This conflation of "target state" and "actual state" is something that so many apps get wrong. For example, consider an FTP client or an IM client: If I connect to a remote server and the connection fails, the app should not require me to manually connect again. I, as a user, has expressed the intent that I wanted to be connected. That's my target state. Whether that state is reachable is the concern of the underlying connection manager. The underlying connection is just an implementation detail. Imagine if the lights and all your electrical appliances didn't automatically come back on after the power went out.
In other words, high-level abstractions should always attempt to be seamless.
Most people don't make a distinction, but I feel that is important to note these.
Strictly speaking, init(8)'s sole responsibility is to reap children, set the session and process group IDs, and optionally exec the actual process manager. In practice, this is bare bones, but strictly that's all that's required.
A process manager then usually provides an abstraction around processes (usually PIDs) called a "service", implementing a minimum of start/stop/restart/status. Status is most primitively done using a PID file. Other extensions like conditional restart can be added.
A process supervisor then ensures that processes are automatically restarted, that inotify(7) triggers are added, that system load is monitored, applying resource limits, emailing an admin upon state change, etc.
Such a trichotomy is rarely expressed, but a hypothetical example that would likely work would be sinit + svc + perp.
Autorestart should be expressly enabled by the sysadmin's choice and disabled by default, due to the possibility of buggy daemons improperly backing up their state, as well as edge cases that may be present in the admin's particular environment.
The problem for me with such a strict view is the special status of pid 1. You can not have a reliable process manager without either putting it in pid 1, or having restart logic in pid 1, since a process manager outside of pid 1 can be killed without taking down the system, and thus can die unnoticed unless the init includes restart logic.
You also have a second problem: How do you log failures reliably? Your process manager can not do that, or be responsible for spawning something to do that if it itself is pid 1 - it could be brutally murdered the instant it spawns the next process, or at any random time, unable to pass on any temporarily collected data while waiting on a suitable place to store said data.
There's a lot of thinking behind the systemd architecture that actually make substantial advances over what we used to have, and that solves issues that are not at all addressed by most other init systems. Your suggested sinit + svc + perp for example would suffer from both the dead process manager problem and the log problem. They are real - I've run into that more than once.
While I'm not in love with, or convinced by, how much stuff they've added to it, also keep in mind that systemd is not just a pid 1 replacement. The systemd project includes multiple components, only the core of which runs as pid 1.
Maybe it'd be nice and useful to see that decomposed with clear API's connecting them, but for now they're developed and shipped together, and I understand why they don't particularly want to have to deal with that, but seeing systemd-the-project as just an init replacement is not really the case (though pid 1 in a systemd install still contains more than you suggests it should).
You can trap virtually all signals beyond SIGKILL.
Keep in mind I'm not advocating a strict separation, it does make sense to intertwine to an extent for practical purposes. I'm mostly trying to say that they're separate stages, and should not be completely equated for each other, lest some undesirable design properties emerge.
Despite your suggestion that it is not for an initd to do process respawning, all init's I've ever used (since '93 or so) have the logic built in anyway. It's just that making use of it restricts you to /etc/inittab for your configuration.
Automatic respawning is a job for a process supervisor, not a process manager or initd. It's a separate duty altogether. So is resource limiting, which is probably better serviced through separate tools that wrap around syscalls.