Boundary event
A Boundary event is the typed value an Accumulator emits and a Reactor reacts to. It is coupled to both — a boundary only exists between an accumulator and a reactor; it has no standalone lifecycle.
Mental model
Section titled “Mental model”- An accumulator’s
process()produces a boundary output, tagged with aSourceNameand sent to the reactor. - The reactor slots it into its input cache under that source name; the cache is what the Computation Graph reads when it fires.
- The boundary value is serialized (bytes) as it crosses the channel.
Key facts
Section titled “Key facts”- Names must line up. The boundary’s
SourceNamemust match the reactor’saccumulators = [...]/modesources and the graph’s entry-node source name. This is the most common wiring mistake. - One per emit. Each
process()that returns a value produces one boundary; returningNoneproduces none.
Typed inject/fire interface (opt-in)
Section titled “Typed inject/fire interface (opt-in)”The boundary type is also what an operator supplies when manually injecting into
an accumulator or firing a reactor with inputs (POST .../inject, fire_with).
The declared interface — GET /v1/health/{reactors|accumulators}/{name}/interface
— derives each slot’s JSON Schema from the boundary type, but only when that
type derives schemars::JsonSchema:
// Opt in → the slot exposes a rich {best_bid, best_ask} schema and the web UI// renders a typed inject/fire form. Without JsonSchema the slot schema is `{}`// (permissive) and the UI falls back to a raw-JSON field.#[derive(Debug, Clone, Serialize, Deserialize, schemars::JsonSchema)]pub struct OrderBookUpdate { pub best_bid: f64, pub best_ask: f64,}Add schemars = "1" to the package’s dependencies. Schema derivation is the
only thing the derive affects — boundary serialization on the wire is unchanged.
Python parity
Section titled “Python parity”Python boundaries are plain dicts, so there’s no type to derive from. Declare the
shape explicitly with @cloaca.boundary_schema(field=type, …) on the accumulator
(CLOACI-T-0770) — the compiler parses it from source at build time into the same
typed slot; at runtime it’s a no-op:
@cloaca.boundary_schema(bid=float, ask=float)@cloaca.passthrough_accumulatordef py_alpha(event): return eventSupported scalar types: str, int, float, bool, list, dict. Without
the decorator the slot stays untyped and inject/fire fall back to a raw-JSON
field — exactly like a Rust boundary that doesn’t derive JsonSchema.
See also
Section titled “See also”- Accumulator — emits boundaries.
- Reactor — reacts to them.