Skip to content

The Pipeline Spec Format

A pipeline spec is a YAML file under docs/methodology/specs/, with schema: branes.pipeline/1. It is a development artifact: the tool reads it and generates the site’s pages, and no code in sdk/ or daemons/ parses it. All paths are relative to the repository root. The worked example is docs/methodology/specs/openvins-msckf.yaml.

KeyRequiredMeaning
schemayesbranes.pipeline/1
nameyeskebab-case; names the generated page and figure
titleyesthe pipeline’s name on the site
summarynoa paragraph: what the algorithm does
sourcesyesthe papers: {id, cite} each; every node cites one
edgesyesthe data structures (below)
nodesyesthe transformations (below)
scheduleyesthe call sequence (below)
system_invariantsnowhat the whole graph must satisfy (below)
base, unchanged_consumersdelta onlysee Delta specs
KeyMeaning
idthe name nodes use in reads and writes
kinddata (default); input (a sensor or a calibration: no node writes it); state (the shared mutable state); output (leaves the graph: no node reads it)
contentswhat it holds, with units
code, symbolthe file and the type or function that implements it; the symbol must occur in the file
invariantsa list of {text, check, bound?}; check is a reference, bound is below. An invariant without a check is a gap
precisionfree text: how narrow a type this structure tolerates
deviationshow the implementation departs from the paper; each is a gap
KeyMeaning
id, stage, titlethe node’s name, its stage label (e.g. S2), its title
doesone line: inputs → outputs
reads, writesedge ids. A node that reads and writes the same edge updates it in place
source{ref, where}: a sources id and the section or equations
pre, postthe pre- and post-conditions, one per list item
codethe sdk/ header that implements it
bencha reference to its stage bench
testsa list of references to its unit tests
statusimplemented, partial, planned (specified ahead of the code: the schedule may call it, and it is reported as a gap) or missing (deliberately left out: the schedule must not call it)
optionaltrue for a node the algorithm can run without
precision{policy, note}: the node’s arithmetic-type policy and what was measured
decisionsthe choices the paper leaves open, below
deviationshow the implementation departs from the paper; each is a gap
schedule:
driver: sdk/include/branes/sdk/msckf_backend.hpp # the code that runs it
events:
- event: imu # not `on:` — YAML reads a bare `on` as true
rate_hz: 200
steps:
- {call: propagate, when: initialized}

Each step is {call, when?, foreach?, note?}. Every node that isn’t missing must be called, and a missing node must not be. A spec written before its code calls its planned nodes.

{id, text, check?, bound?, status?, note?}, where status is holds, failing or unknown (the default). A failing invariant is reported as a gap together with its note.

A paper often leaves a choice open, or names options: a zeroth-order hold or RK4 for the IMU mean, a gate line, a prior. Each is recorded on the node that makes it:

decisions:
- question: the IMU input over each interval
chosen: the sample that ends it, held constant
alternatives: [the previous sample held, "both samples, interpolated and integrated by RK4"]
reason: "…" # what was measured or argued; omitted, the choice was a default

question and chosen are required. A decision without a reason is reported as a gap: the choice was made by default rather than decided. The rule exists because of #616. The VIO mean integrator was a one-sample Euler step from the first commit (#186). The canonical pipeline document named RK4 as OpenVINS’s alternative, but nothing recorded a decision. Five months later the choice turned out to hold each IMU sample 2.5 ms off the camera: NIS 1.1–1.9 on the fast sequences, and ATE 10–15× worse there than with both samples used.

A check’s tolerance comes from what the node that consumes the result must resolve, never from what the implementation currently achieves:

bound:
value: 1.1e-4 rad over a 0.55 s clone window
consumer: msckf_update # a node id: whose resolution the bound comes from
derivation: a tenth of the 0.5 px track noise the update resolves, at fx = 458.65

value and derivation are required, and consumer must name a node in the spec. The rule exists because of #613. Its first S2-closure test measured S2’s first-order error, then set its threshold to accept it, and so passed exactly the defect #616 later found. A bound derived from the camera’s resolution failed it 28×.

A reference is {file, symbol?, case?}. The file must exist; a symbol must occur in its code as an identifier (a mention in a comment or a string literal doesn’t count, so prefer a distinctive type or function name); a case must be the beginning of the name of one of its active TEST_CASE or TEMPLATE_TEST_CASE calls (a commented-out case doesn’t count). A broken reference is an error, so a rename in the code fails the spec’s check rather than leaving a stale page.

A paper that changes an existing pipeline is written against it:

schema: branes.pipeline/1
base: openvins-msckf.yaml # relative to this file; must be a full spec
name: riekf-msckf
title: Right-invariant MSCKF
edges:
- {id: FilterState, op: replace, kind: state, contents: ...}
nodes:
- {id: propagate, op: replace, ...}
unchanged_consumers:
FilterState: {sensor_model: "reads only the calibration"}
  • A delta has its own name and title; reusing the base’s name is an error, since it would overwrite the base’s generated page.
  • Each edge or node entry carries op: add (the base must not have it), replace (it must) or remove (it must). A replaced entry is written out in full.
  • sources are appended to the base’s; a schedule or system_invariants given in the delta replaces the base’s.
  • When a delta replaces or removes an edge, every base node that reads or writes it must be replaced or removed in the delta, or named under unchanged_consumers.<edge>.<node> with the reason it is unaffected. Otherwise the tool reports an error.
  • # starts a comment in a plain scalar, so (#474, #574) would silently become (#474,. The tool reports any string with unbalanced brackets. Quote strings that cite issues.
  • A repeated key keeps only its last value in plain YAML, so a second deviations: would erase the first. The tool rejects a duplicate key.
  • A comma splits a flow list, so pre: [at rest, or moving] is two conditions. Use a block list of quoted strings for prose.