This document specifies version v0.48.0 of
the Vela protocol. Requirement keywords (
§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 independs-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
{
"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 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
finding.proposed·finding.contested·finding.replicated·finding.retractedrelation.added·relation.removedevidence.attached·evidence.detachedconfidence.attested·confidence.revokedactor.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
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 recorded_at timestamps
were issued; reducers
§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 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
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.