Complete Rule Files

Start from a complete loadable file rather than assembling isolated rule fragments.

The examples below show complete rule documents for common deployment styles. File paths are resolved relative to the rules file unless an absolute path or s3:// URI is used.

Inference-first ruleset

This file provides only the entity and timestamp hints needed for stateful rules. BlazeRules infers the remaining referenced field types from the first batch.

schema_version: "2.1"

fields:
  customer.id: {type: entity_key, nullable: false}
  event_ts_ms: {type: timestamp_ms, nullable: false}

decisions:
  default: approve
  precedence: [approve, score, flag, review, block]

ruleset:
  name: Checkout Basics
  version: "1.0.0"
  rules:
    - id: large_new_customer_order
      action: review
      weight: 35
      conditions:
        and:
          - {field: order.amount, op: gte, value: 750}
          - {field: customer.account_age_days, op: lt, value: 14}

    - id: external_bot
      action: block
      weight: 65
      conditions:
        and:
          - {field: http.user_agent, op: regex, value: "(?i)(bot|crawler|headless)"}
          - {field: network.ip, op: ip_not_in_subnet, value: "10.0.0.0/8"}

    - id: checkout_velocity
      action: flag
      conditions:
        window:
          entity_field: customer.id
          function: count
          duration_seconds: 600
          op: gte
          value: 5

Once inference has bound a field type, later incompatible values are ingest errors. Use explicit hints where upstream type drift must fail before the first evaluation.

Explicit schema and lookup sets

schema_version: "2.1"

fields:
  event_id: {type: string, nullable: false}
  customer_id: {type: entity_key, nullable: false}
  merchant.id: {type: string, nullable: false}
  network.ip_address: {type: string, nullable: false}
  order.amount: {type: float32, nullable: false}
  event_ts_ms: {type: timestamp_ms, nullable: false}

lookups:
  risky_merchants:
    type: string_set
    path: lookups/risky_merchants.csv
  vpn_ranges:
    type: ipv4_cidr_set
    path: lookups/vpn_ranges.csv

decisions:
  default: approve
  precedence: [approve, flag, review, merchant_hold, block]

ruleset:
  name: Lookup-backed Routing
  version: "1.0.0"
  rules:
    - id: risky_merchant_hold
      action: review
      label: merchant_hold
      reason_code: RISKY_MERCHANT
      conditions:
        and:
          - {field: merchant.id, op: in_lookup, lookup: risky_merchants}
          - {field: order.amount, op: gte, value: 500}

    - id: vpn_source
      action: flag
      conditions: {field: network.ip_address, op: in_lookup, lookup: vpn_ranges}

Lookup CSV headers are value for string_set and int_set, and cidr for ipv4_cidr_set.

Model, vector, and window signals

schema_version: "2.1"

fields:
  customer_id: {type: entity_key, nullable: false}
  event_ts_ms: {type: timestamp_ms, nullable: false}
  order_amount: {type: float32, nullable: false}
  account_age_days: {type: float32, nullable: false}
  device_risk: {type: float32, nullable: false}
  embedding_0: {type: float32, nullable: false}
  embedding_1: {type: float32, nullable: false}
  embedding_2: {type: float32, nullable: false}
  embedding_3: {type: float32, nullable: false}

decisions:
  default: approve
  precedence: [approve, flag, review, block]

ruleset:
  name: Derived Signal Rules
  version: "1.0.0"
  rules:
    - id: model_high_risk
      action: block
      conditions:
        model_score:
          model: checkout_risk
          features: [order_amount, account_age_days, device_risk]
          op: gte
          value: 0.9

    - id: similar_device_cluster
      action: review
      conditions:
        vector_distance:
          dims: [embedding_0, embedding_1, embedding_2, embedding_3]
          metric: cosine
          reference: [0.12, -0.04, 0.33, 0.78]
          op: gte
          value: 0.92

    - id: repeated_high_value
      action: review
      conditions:
        and:
          - {field: order_amount, op: gte, value: 750}
          - window:
              entity_field: customer_id
              function: count
              duration_seconds: 900
              op: gte
              value: 4

Register checkout_risk before loading or evaluating model-backed rules:

  import blazerules

  engine = blazerules.RuleEngine()
  engine.register_model("checkout_risk", "models/checkout_risk.onnx")
  engine.load_rules("rules.yaml")

Model features and vector dimensions are numeric scalar fields. An ONNX file is loaded once during registration; inference executes as a derived channel during batch evaluation.

Production checklist

  • Keep rule IDs unique and stable across releases.
  • Hint entity, timestamp, and ambiguity-sensitive fields.
  • Put large membership lists in lookup CSVs rather than inline values arrays.
  • Include every custom decision label in decisions.precedence.
  • Register every referenced ONNX model before evaluation.
  • Route parallel stateful streams by the same entity key used by windows.
  • Load candidate rules with shadow: true before allowing them to affect decisions.
  • Validate locally with blazerules validate --rules rules.yaml before deployment.

Did this page help you?