AOS Hub / Docs

Fault bindings

A fault binding is the only bridge from signal values to production adapter mutations. It says when inputs are sampled, which concrete targets and opportunities are eligible, how values become effect parameters, how concurrent effects compose, and what evidence is retained.

Read Signal programs first when designing causes. Use the guide map to select an executable effect and the reference for exact TOML shapes.

#Binding contract

Each [[plan.fault_binding]] contains:

FieldContract
idUnique stable binding identity.
signalsOrdered, nonempty exported signal IDs; maximum 128.
samplingBoundary, opportunity, change, cadence, or typed event sampling.
selectorA finite, homogeneous target set resolved against the declared World.
mappingClosed typed transfer from signal inputs to effect parameters.
phasesNonempty set of exact adapter phases, also used by the opportunity filter.
effectOne effect kind, semantic version, parameter payload, and lifetime.
opportunity_filterRequired where opportunity sampling cannot be inferred; adapter, operations, phases, optional target kinds.
searchFixed policy or a finite, declared branch/mutation space.
observabilitySample and mapped-value retention policy.
transition_declarationRequired only for state_transition; the versioned exhaustive table carried by this binding.
service_declarationRequired only for service_profile; the versioned named physical-input contract carried by this binding.

Admission validates all of these together. A mapping that produces a valid parameter type can still be rejected if its selected target, phase, lifetime, operation, capability, or composition algebra is illegal for that effect.

#Sampling

Sampling kindCoordinate and behaviorTypical use
at_boundaryOnce at each deterministic scheduler boundaryGlobal modes and slowly changing state.
at_opportunityOnce for each matching typed adapter opportunityPer-packet, per-I/O, per-instruction, and similar effects.
at_changeWhenever an input changesAnalytic transitions without polling.
cadence_nanosAt a positive exact virtual-time cadencePeriodic control or sampling.
at_eventAt one typed event with explicit parent coordinateEvent-triggered effects that preserve causality.

at_event parents are virtual_time, node_counter { node }, opportunity_operation, or opportunity_state. Opportunity parents require a matching opportunity filter. Event ordering and the parent coordinate become replay evidence.

Do not use a cadence to approximate an opportunity-level probability. Sample a keyed stochastic signal at the opportunity so retries, filtering, and replay retain stable identities.

#Target selectors

Selectors are resolved and canonicalized at admission:

  • exact contains exactly one concrete target.
  • target_set contains an explicit finite set.
  • fault_domain names a static topology domain and retains its resolved set.
  • dynamic_path names a versioned network path, an initial set, and membership semantic version 1; it is network-only.

A resolved set is empty only when allow_empty explicitly permits it. It may contain at most 65,536 targets, no duplicates, and targets from only one adapter. Dynamic membership changes are deterministic state transitions, not ad hoc host queries.

The complete target-kind vocabulary is:

AdapterTarget kinds
Networknetwork_interface, network_segment, network_medium, network_queue, network_forwarder, network_path, network_attachment, network_contact
Storageblock_device, block_range, storage_controller, storage_array, ninep_device
Nodenode, vcpu, register, memory_range, interrupt, clock_source, accelerator

Sensor targets are not executable in the current schema. See Topology for the objects from which targets are resolved.

#Opportunity filters

An opportunity filter has one adapter, a nonempty operation set, a nonempty phase set, and optionally a target-kind restriction. Every operation must belong to the adapter. Every phase and target kind must be legal for the chosen effect.

[plan.fault_binding.opportunity_filter]
adapter = "network"
operations = ["network_transmit", "network_receive"]
phases = ["admit"]
target_kinds = ["network_interface"]

The closed operation vocabulary has 22 network operations, 13 storage operations, and 27 node/CPU/memory/interrupt/clock/accelerator operations. Use the operation table rather than inventing names. Filters are predicates over opportunities already declared by an adapter; they do not create new observation points.

#Mapping signal values

Mappings are closed, typed functions. They cannot call arbitrary code or mutate an adapter directly.

Mapping kindInput-to-output ruleAuthoring constraints
active_when_trueBoolean controls persistent activation, optionally invertedExactly one Boolean input; effect lifetime is persistent.
active_when_equalEnum activates for one declared variantExactly one compatible enum input; effect lifetime is persistent.
thresholdNumeric comparison controls activation, with optional clear threshold and residenceThresholds share input shape/unit; deadband direction must agree with comparison.
map_parameterOne input fills one registered dynamic effect fieldField contract accepts the exact value shape.
piecewise_parameterOrdered points interpolate one dynamic fieldStrictly increasing inputs, explicit rounding/overflow, compatible output shape.
hazardProbability is evaluated at each matching opportunityOpportunity sampling and opportunity lifetime only.
impulse_on_eventEach typed event produces one impulseEvent sampling and impulse lifetime only.
state_transitionValue selects a registered transition table entryTable is declared, finite, and compatible.
service_profileValue selects a named physical-input service profileProfile exists in the policy registry and matches the effect.

#Named mapping declarations

state_transition carries one adjacent [plan.fault_binding.transition_declaration] with id, semantic_version = 1, event/enum input value type, owning effect, default_transition, and singular transition = [{ request, transition }] rows. Rows are canonicalized by typed request value; duplicate requests are rejected. The mapping's transition_table must equal the declaration id, every selected transition must be valid for the effect, and the default handles every request not listed.

service_profile carries one adjacent [plan.fault_binding.service_declaration] with id, semantic_version = 1, owning effect, canonical inputs = [{ role, shape }], and nonempty parameters. Each shape is the complete signal value type, unit, and decimal exponent for that physical role. Parameter values are from the closed dynamic-field vocabulary: probability, duration_nanos, bits_per_second, bytes_per_second, operations_per_second, capacity_ratio, signed_offset, and unsigned_count. Input count/order/shapes and every parameter's compatibility with the owning effect are checked at admission.

Mapping declarations and candidate sets are capped at 4,096. Piecewise tables must cover their domain explicitly; out-of-range behavior is not inferred. Mapped parameters are validated again by the effect implementation before an adapter command is emitted.

#Phases and lifetimes

Phases locate an effect within a typed adapter operation. The complete wire vocabulary is:

PhaseMeaning
Common adapterproduce, admit, queue, resolve, persist, visibility, deliver, transition, boundary, run
Instruction/registerbefore_instruction, after_instruction, before_read, after_read, before_write, after_write
Memoryfetch, load, store, dma_read, dma_write, page_table_walk, refresh
Interruptraise, route, acknowledge, interrupt_deliver, return
Clockclock_read, arm, fire, synchronize, source_switch
Acceleratorsubmit, execute, complete, accelerator_memory_access

Not every adapter exposes every phase, and every effect descriptor lists its legal subset. Choosing an earlier phase can change whether in-flight work is affected, so phase is part of the effect's semantic identity.

Lifetimes state how long mapped parameters remain active:

LifetimeBehavior
persistentRemains active until its binding deactivates it.
opportunityIs independently resolved for one opportunity.
impulseMutates state once and cannot be healed by later deactivation.
state_machineAdvances bounded adapter-owned state.

Deactivation restores the declared baseline or the composition result of other active bindings. Stateful effects and adapter-owned lifetime state are checkpointed.

#Composition

Overlapping active bindings must use the effect family's declared algebra. Crucible rejects ambiguous mixtures instead of relying on activation order.

AlgebraCombination ruleCommon family
outage_orAny active outage makes the target unavailableAvailability and hang.
checked_sumAdd in canonical binding order; overflow is an errorDelay and bounded duplicates.
minimumLeast non-null cap wins; all limiters remain visibleService constraints.
rational_productMultiply reduced ratios with checked intermediatesCapacity factors.
ordered_transformApply in binding order and retain every intermediate digestPayload/data/result transforms.
severitySelect the greatest value in a closed precedence latticeFailure dispositions and lifecycle.
state_machineApply declared transition precedenceStateful adapter transitions.
independent_hazardsEvaluate every keyed hazard; any firing outcome appliesIndependent loss/failure causes.
conflictReject distinct simultaneous contributionsComplete policy replacement.
compositeUse effect-specific component algebrasStructured multi-field effects.

Canonical order is based on stable identities and coordinates, never host thread timing. The effect registry is authoritative for which algebra an effect accepts.

#Search policy

Search never invents fault values. A binding declares a finite policy that is materialized before QEMU starts:

PolicySearch dimension
fixedNo binding variation.
branch_outcomeUp to maximum_branches mapped outcomes.
branch_transitionOne of the declared transition candidates.
branch_parameterOne named parameter takes one declared typed candidate.
mutate_trace_windowDeclared trace samples in a fixed time window take declared replacements, under maximum_mutations.
mutate_mappingDeclared mapping point indices take complete replacement points, under maximum_mutations.

The bounded Cartesian product consumes the same global --max-states budget as schedule-frontier expansion. Each materialized scenario root costs one state. Findings retain the exact ordered mutation recipe and authenticated signal object closure, so replay does not depend on the campaign's working store.

#Observability and evidence

observability.samples is every_sample, changes_and_effects, or every_nth { stride }. A binding can also retain inactive opportunities and complete mapped values. The default retains changes/effect-relevant samples, omits inactive opportunities, and retains mapped values.

More retention improves diagnosis but increases trace and artifact size. Even when a value is omitted, canonical digests and effect application evidence preserve replay validation. Evidence identifies binding, sample coordinate, input digest, mapping result digest, target, opportunity, phase, lifetime, composition result, capability decision, adapter command/result, and search mutation provenance where applicable.

#Admission checklist

Before running a campaign, verify:

  1. Every input is exported, acyclic, and shape/unit compatible with the mapping.
  2. The selector resolves to the intended homogeneous targets and empty matches are intentional.
  3. Sampling uses the causal coordinate that should make replay identities stable.
  4. Opportunity adapter, operations, phases, and target kinds agree.
  5. Effect parameters, phase, and lifetime are legal, and overlapping contributions obey the registry-selected composition algebra in the effect registry.
  6. Required topology policy objects and packaged capabilities exist.
  7. Search candidates and all history/work limits are finite and campaign-sized.
  8. Observability retains enough information to explain failures.

Admission and capability negotiation happen before guest execution. Unsupported or internally inconsistent bindings fail closed rather than becoming no-ops.