Specification

The normative document. Type primitives, canonical event shape, reducer mutation kinds, identity and signing, fork-choice, conformance.

This document specifies version v0.48.0 of the Vela protocol. Requirement keywords (MUST, SHOULD, MAY) follow RFC 2119. The specification is the contract every conforming reducer agrees to apply. For the editorial argument behind the design, see The Constellate Architecture.

§1 Type primitives

The kernel of primitive types is defined in the Rust crate vela. Every other reducer derives its types from this kernel. The primitive shapes are:

Finding (vf_*)
A scientific claim under review on a frontier. Carries a status (proposed, contested, replicated, retracted), one or more evidence pointers, and a context expression.
FindingRelation (vfr_*)
A directed relation between two findings (depends-on, contradicts, refines, replaces). Reducers MUST reject cycles in depends-on.
BoundedRange (vbr_*)
A constraint on a quantitative claim with explicit bounds and a unit. Used to express dose, age, cohort, effect size.
Confidence (vco_*)
A reviewer-attested confidence interval over a finding. Multiple confidences can attach to one finding; the reducer aggregates per the rule in §3.5.

Why four primitives and not one? Because the shape of a claim, the shape of a relation between claims, the shape of a bound on a quantity, and the shape of a stated confidence are different objects with different invariants. A single uber-type would let any of them violate the rules of any of the others. The cost of carrying four typed shapes is small; the cost of reasoning about a soup of fields is large.

§2 Canonical event shape

A Vela event is a signed JSON object. Reducers MUST canonicalize keys lexicographically before signing or hashing. The wire-level shape is:

{
  "type":       "vela.event.<kind>",
  "id":         "evt_<16-hex>",
  "frontier":   "<frontier-id>",
  "transition": { ...kind-specific body },
  "signatures": [ "<actor>:<key>", ... ],
  "recorded_at": "<RFC3339-UTC>"
}

The full grammar, including every kind-specific body, lives in spec/events.md. Reducers SHOULD reject events whose recorded_at drifts more than 90 seconds from the signer's transparency log timestamp (§5.3).

§3 Mutation kinds

Twelve mutation kinds are defined at v0.48.0. Each one maps an event to a deterministic state diff. Reducers MUST implement every kind; partial conformance is not a valid reducer. See the test-vector suite for the complete state machine.

  • finding.proposed · finding.contested · finding.replicated · finding.retracted
  • relation.added · relation.removed
  • evidence.attached · evidence.detached
  • confidence.attested · confidence.revoked
  • actor.bound · actor.rotated

§4 Identity and signing

Identity in Vela is keyed, not username-keyed. Every signing actor binds one or more public keys to an actor identifier via an actor.bound event. Key rotation uses actor.rotated; the rotation event MUST be signed by the outgoing key. Lost-key recovery requires a witness threshold defined in §6.

Why not just sign nanopubs? Nanopubs solve identity-attached claims, but their event model is monotonic and conflict-blind: a retraction is a new nanopub, not a state change. Vela needs the state change to be the primary object, with the signed event as the move that produces it. That is what makes the reducer deterministic and the log replayable.

§5 Append-only log per frontier

Each frontier has exactly one canonical event log. Operators (vela-hub.fly.dev is one) keep a transparency-log mirror of the log so any verifier can detect equivocation. Events MUST be appended in the order their recorded_at timestamps were issued; reducers MUST reject out-of-order events.

§6 Fork choice and witness sets

When two reducers compute different states for the same frontier, the witness set resolves the disagreement. A witness is an actor running a reducer that publishes a signed digest of its view at a known cadence. Reducers MUST adopt the state whose digest has been witnessed by a majority of the current witness set. Witness-set updates are themselves events (witness.added, witness.removed).

§7 Conformance and test vectors

A reducer conforms to Vela v0.48.0 if it passes every test vector in vectors/v0.48.0. The suite lives at vela-science/vela/test-vectors. Each vector pairs a canonical event with the state mutation a conforming reducer MUST produce. Conformance rates by reducer are published on /vela/reducers and re-checked at every release.

How is conformance computed? The Rust reducer (vela-rs) is taken as the reference: it passes its own vectors by construction. The other reducers run the same vectors and report the share that produce the exact mutation Rust produced. A vector that fails for the "wrong reason" (parsing, missing feature, off-by-one) counts as a failure no matter how close.

Anchor copied