Trust ladder, v1
Normative. Derived from RUNBOOK.md §8; where the two differ, RUNBOOK.md wins.
Implemented by @runbooks/lint; every rule here has a test in
packages/lint/src/trust.test.ts.
A level is computed, never assigned. Every one is a predicate over evidence a third party could recompute. The moment a level can be set by hand, the badge means nothing — and §19's argument against unexplained safety scores would apply to us rather than to the neighbours.
It is computed at read time from evidence plus a clock, and never stored. There is
deliberately no trust field to sweep: a stored level is one somebody forgets to
refresh, and a stale T4 is worse than no badge at all.
The levels
| Level | Claim | Evidence | Verifiable without a runner |
|---|---|---|---|
| T0 indexed | parsed, metadata extracted | the document exists and parsed | yes |
| T1 conformant | schema and profile linter passed | gate results | yes |
| T2 audited | links resolve; no secrets; capabilities match the commands; no instructions addressed to the model | the conjunction of four named gates | yes |
| T3 attested | a verified attestation of a run, bound to this content hash | signature + hash | no, but both are checkable |
| T4 corroborated | three independent attestations inside the window | aggregation | yes |
T2 is a conjunction of named gates rather than a judgement, so a failure says which gate and what to do about it.
Attestations count only when they are about this document
An attestation binds to a content_hash, not to a version. Binding to the version would
let an attestation about one document be read as an attestation about a later edit of
it — which is update drift wearing a signature.
It must also be verified. An unverifiable attestation is not weak evidence; it is not evidence.
Expiry
Anything older than 180 days stops counting, and the record falls back to T2. Update drift is cured by an expiry date, not by a promise.
The badge shows the attestation's date, never the day the level was computed. Showing the build date would make every badge look fresh on every deploy, which is the opposite of what decay is for. A badge without a date is forbidden (§18.5).
Corroboration needs independence
T4 requires three distinct issuers within the window, at least two of them not the publisher.
A vendor attesting its own runbook is honest and counts for T3 — the interface shows that attester and publisher coincide. Three signatures from one vendor are not corroboration; they are one opinion repeated.
Defaults
Search results and the API return T2 and above. Anything below is served only on an
explicit include_untrusted=true, and its step bodies are marked untrusted because
below T2 the content is untrusted input for whoever reads it (§12).
A served record is a cache of this computation
The level is computed from evidence and a clock. /v1/runbooks/{publisher}/{slug}.json
is that computation written down at one moment and read at another, so it carries
trust_evidence.expires_on for the levels that decay: the day, 180 days after the
attestation it rests on, when the record becomes T2.
Apply it. A reader holding the file can tell whether the level is still current without asking us anything, which is the same standard as a hash anyone can recompute and a signature anyone can verify. A rebuild is what makes the default answer right; the expiry is what makes a stale answer detectable — both, not either (docs/decisions/P13-decay-in-artifacts.md).
T0–T2 carry no expiry. Those levels are what the gates said, and a gate result does not age into a different gate result.