zinit 0.3.6

Process supervisor with dependency management
Documentation
# ADR-002: Shutdown Ordering

## Status

Accepted (Implemented)

## Context

Services have dependencies. When shutting down, the order matters:
- Dependents should stop before their dependencies
- A service shouldn't be stopped while others still need it

Without proper ordering, dependents crash or misbehave when their dependencies disappear.

## Decision

### Shutdown All (system shutdown)

Use **reverse topological order**: dependents before dependencies.

```
Example:
  database <- app
  database <- worker

Startup order:  database -> app -> worker
Shutdown order: worker -> app -> database
```

- Stop services one at a time
- Wait for each to fully exit before stopping the next
- Use SIGTERM -> timeout -> SIGKILL escalation

### Stop Single Service

**Cascade Rule**: First stop all services that depend on the target.

**Protection Rule**: Do NOT stop the target's dependencies (other services may need them).

```
Example:
  database <- app
  database <- worker

`zinit stop app`:
  1. Nothing depends on app
  2. Stop app
  3. Do NOT stop database (worker still needs it)

`zinit stop database`:
  1. app and worker depend on database
  2. Stop app first
  3. Stop worker
  4. Now stop database
```

### Edge Cases

- **Circular deps**: Rejected at config validation
- **Conflicts**: Stopping A doesn't affect conflicting B
- **Oneshot**: Already exited, skip
- **Targets**: Virtual, mark inactive after members stop

## Implementation

**graph.rs**:
```rust
pub fn all_dependents_ordered(&self, id: ServiceId) -> Vec<ServiceId>
pub fn shutdown_order(&self) -> Vec<ServiceId>  // reverse start order
```

**supervisor.rs**:
- `stop_all_services()`: Uses shutdown_order()
- `stop_service()`: Cascades to dependents first

## Consequences

- Clean shutdown without crashes
- Explicit dependency protection
- Predictable behavior for operators