# 7.1 Relationships

_Peios / Advanced Peios / peinit / Dependencies_

> The four relationship types — Requires, Wants, BindsTo and Conflicts — and what each means at start, at stop and on failure.

Four relationship types. Each says something different about how two
services interact at start, at stop, and on failure.

## 7.1.1 Requires

A hard dependency. If A `Requires` B:

- **Start.** B has to reach a dependent-satisfying state before A
  starts.
  If B is not running, peinit starts it with cause `DependencyStart`. If
  B enters Failed, A goes to Failed with cause `DependencyFailure`
  without attempting to start.
- **Stop.** Stopping B does not stop A. This is a start-ordering
  constraint, not a runtime coupling.
- **Runtime failure.** If B crashes while A is Active, A is unaffected
  and keeps running. B's own restart policy handles B.
- **Missing target.** A goes to Failed with `DependencyFailure`,
  detected at graph validation.

## 7.1.2 Wants

A soft dependency. If A `Wants` B, peinit starts B before A — with
cause `DependencyStart` — provided B exists and is not disabled. If B
fails to start, or does not exist at all, A starts anyway. There is no
stop or failure effect in either direction.

The waiting rule is where the difference from `Requires` actually lives:
a dependent blocked on a `Requires` target waits for it to reach a
*satisfying* state, while a dependent blocked on a `Wants` target waits
only for it to reach *any terminal* state, satisfying or not. That is
what makes `Wants` ordering rather than dependency — "start this first
if you can, but I will work without it".

## 7.1.3 BindsTo

A runtime coupling. If A `BindsTo` B:

- **Start.** Identical to `Requires`.
- **Stop.** If B stops for *any* reason — explicit stop, conflict,
  crash, shutdown — A stops too, transitioning to Stopping with cause
  `BindsToPropagation`.
- **Recovery.** When B returns to Active, peinit automatically restarts
  anything sitting in Failed with cause `BindsToPropagation` from B's
  stop. This is reactive rather than polled: peinit watches for the
  transition into Active from a non-satisfying state, and reacts to it.
  These restarts do **not** consume the restart budget — the dependent
  never failed on its own, it was stopped because its binding target
  went away.

`BindsTo` implies `Requires`. A definition may list both for clarity,
and if it does, the `BindsTo` semantics apply.

## 7.1.4 Conflicts

Mutual exclusion. Starting A while B is Active creates a stop operation
for B — source `ConflictResolution`, cause `ConflictEviction` — and A
does not start until B has left every state in which it could still be
running.

Conflicts are **symmetric**. If A declares `Conflicts = ["B"]`, starting
either one stops the other; B does not have to declare it reciprocally,
and peinit scans both a starting service's own conflicts and everything
that declares a conflict against it.

If both A and B are boot-triggered and they conflict, graph validation
detects an unresolvable conflict and fails both with `ValidationError`.

A missing conflict target is silently dropped — there is nothing to
conflict with.

> [!NOTE]
> `Conflicts` is for real mutual exclusion: two services binding the
> same port, or two implementations of one role where exactly one must
> run. It is not a way to solve resource contention that has a better
> answer.

## 7.1.5 Ordering and self-reference

Dependencies imply start ordering, and — except for `BindsTo` — imply
nothing about stopping. peinit starts dependencies before dependents;
during shutdown it reverses the same graph and stops dependents before
dependencies (§12.2), derived from the one graph rather than from a
separate stop-ordering configuration.

A service may not name itself in any dependency field. peinit rejects a
self-reference at graph validation as a `CycleDetected` failure, which
is what it is — a cycle of length one.
