Skip to main content
Early termination lets you define stopping rules that the runner evaluates against live telemetry during execution. When a rule fires, the runner kills the simulation process immediately and marks the job failed — no need to wait for job_timeout_seconds. This is useful for catching degenerate runs early: an orbit that has decayed, a vehicle that is tumbling, a battery that has hit a critical floor. Stopping bad runs fast saves compute and keeps your results clean.

Enabling early termination

Early termination is configured in the early_termination block of your batch submission:
"early_termination": {
  "enabled": true,
  "check_frequency_hz": 10.0,
  "conditions": [...]
}
FieldTypeDescription
enabledbooleanWhether early termination is active for this batch
check_frequency_hznumberHow many times per second the runner evaluates conditions against incoming telemetry
conditionsarrayOne or more named stopping rules
Set enabled: false to include conditions in your config without activating them — useful for staging rules before you trust them in production.

Simple condition

Each condition compares one telemetry variable against a threshold:
conditions:
  - name: battery_low
    description: Battery critically low
    variable: battery_state_of_charge
    operator: lt
    threshold: 10.0
    units: percent
This reads as: stop the run if battery_state_of_charge < 10.0 percent.

Condition fields

FieldRequiredDescription
nameyesIdentifier for this rule. Appears in logs and trigger events.
descriptionrecommendedHuman-readable explanation of why this rule exists
variableyesThe telemetry variable name to evaluate — must match what your scenario emits
operatoryesComparison operator (see below)
thresholdyesThe value to compare against
unitsyesUnits of the threshold value — must match what your scenario reports

Operators

OperatorMeaning
ltless than
lteless than or equal
gtgreater than
gtegreater than or equal
eqequal
neqnot equal

Units

units is explicit metadata — Lynx does not infer unit conversions. The value must match the scale your scenario uses when emitting that variable.
# If your scenario emits battery as 0–100:
threshold: 10.0
units: percent

# If your scenario emits battery as 0.0–1.0:
threshold: 0.10
units: fraction
Common unit strings: percent, fraction, km, m, deg, deg/s, rad/s, boolean, dimensionless.

Grouped conditions

For multi-variable logic, use all (AND) or any (OR) instead of a single variable field.

all — every condition must be true

conditions:
  - name: unsafe_orbit
    description: Low battery during orbital decay
    all:
      - variable: battery_state_of_charge
        operator: lt
        threshold: 10.0
        units: percent
      - variable: altitude_km
        operator: lt
        threshold: 150.0
        units: km
Fires when: battery_state_of_charge < 10.0% AND altitude_km < 150.0 km

any — at least one condition must be true

conditions:
  - name: vehicle_unstable
    description: Vehicle is tumbling or battery is critically low
    any:
      - variable: body_spin_rate_deg_s
        operator: gt
        threshold: 15.0
        units: deg/s
      - variable: battery_state_of_charge
        operator: lt
        threshold: 10.0
        units: percent
Fires when: body_spin_rate_deg_s > 15.0 deg/s OR battery_state_of_charge < 10.0%

Nested groups

all and any can be nested when the logic requires it:
conditions:
  - name: landing_abort
    description: Abort if low altitude and either unstable or poorly localized
    all:
      - variable: altitude_m
        operator: lt
        threshold: 30.0
        units: m
      - any:
          - variable: body_spin_rate_deg_s
            operator: gt
            threshold: 15.0
            units: deg/s
          - variable: vio_tracking_quality
            operator: lt
            threshold: 0.3
            units: dimensionless
Fires when: altitude_m < 30.0 m AND (body_spin_rate_deg_s > 15.0 deg/s OR vio_tracking_quality < 0.3)
Keep nesting shallow. If you can’t describe the rule in one sentence, consider splitting it into two named conditions.

Multiple conditions

You can define multiple top-level conditions. The run stops when any one of them fires:
conditions:
  - name: battery_low
    description: Battery critically low
    variable: battery_state_of_charge
    operator: lt
    threshold: 10.0
    units: percent

  - name: orbital_decay
    description: Orbit has decayed below safe altitude
    variable: altitude_km
    operator: lt
    threshold: 150.0
    units: km

Trigger events

When a condition fires, the runner records a structured event that appears in your job result and platform logs:
FieldDescription
rule_nameThe name you gave the condition
descriptionThe description from your config
elapsed_secondsHow far into the run the rule fired
telemetry_at_triggerThe telemetry frame that caused the rule to fire
This makes every early termination explainable — you can see exactly which condition fired, when, and what the simulation state was at that moment.

Schema reference

Simple condition:
early_termination:
  enabled: true
  check_frequency_hz: 10.0
  conditions:
    - name: string
      description: string
      variable: string
      operator: lt | lte | gt | gte | eq | neq
      threshold: number
      units: string
Grouped condition:
early_termination:
  enabled: true
  check_frequency_hz: 10.0
  conditions:
    - name: string
      description: string
      all:               # or any:
        - variable: string
          operator: lt | lte | gt | gte | eq | neq
          threshold: number
          units: string
        - variable: string
          operator: lt | lte | gt | gte | eq | neq
          threshold: number
          units: string