Relations between runbooks

Normative for RUNBOOK.md §22. Implementation: packages/graph/src/relations.ts, checked by the relations gate in @runbooks/lint.

A procedure rarely stands alone: one prepares another, one undoes another, one is where a third hands off, one is a step of something larger. These four edges are how a record says so, and the graph stops being intra-runbook and becomes a graph of runbooks.

A relation is authored. Unlike an attestation — issued by somebody else and verified — only the author can say how their procedure stands to another. What they cannot do is make the claim resolve.

The four kinds

Kind What it asserts Version Across publishers
requires this cannot run until that one has must pin yes
rollback_of this undoes that one must pin yes
escalates_to when this hands off, it hands off to that one must not pin yes
part_of this is a step of that larger procedure (§18.6) must not pin no

Why two of them pin and two must not

requires and rollback_of assert what another record does — it prepares this, it is undone by this. That is only true of a version. Unpinned, the claim silently follows the other author's next edit, which is exactly the update drift this catalog exists to expose rather than to inherit.

part_of and escalates_to are structural: this belongs to that, failures go there. Pinning those freezes an arrangement, so a playbook keeps pointing at last year's version of its own step and the composition rots while every reference still resolves.

The safer choice is different for the two groups, which is why there is no single answer.

Why part_of may not cross a publisher

Declaring yourself part of somebody else's procedure is a claim about their composition, made without them. The containing record decides what it contains. The other three are claims about your own record's relationship to theirs, which is yours to make — and to be wrong about in public.

Cycles

All four must be acyclic, for reasons that differ by kind and agree in outcome:

A reference that does not resolve

Blocking. A relation to a record this catalog does not hold is a composition that cannot be assembled, and it fails the record rather than degrading it: the difference between a broken link in prose and a broken edge in a graph is that something is going to try to traverse this one.

A pinned reference to a version that record does not have fails the same way, and the message names the versions it does have.

The trust of a composition

The weakest member's, and never better.

Stated because intuition here is optimistic. A playbook of a T4 and a T1 is a procedure that will run the T1: the level of the thing you assembled cannot exceed the level of the part you did not check, and averaging would let one good member launder four bad ones.

A member whose upstream is gone

Not a broken relation. The record is still here, still published, still what it was; what has gone is the source it was indexed from, which is a fact about its provenance. The composition inherits it the way it inherits everything else about that member — through the member's own trust level, which fell when its upstream did (§10).