Skip to content

Rule Types

Prerequisites: Concepts.

This page explains the boundary between the public Rule authoring type and the internal EngineRule representation. Condition syntax belongs to Conditions, and engine-mode selection belongs to Choosing an Engine.

Public Rule

Rule is the public type for authoring and serialization. Its condition_dsl tree is the source of truth for boolean logic. Set persist=False in examples and tests to avoid writing to the configured database.

from fluxrules import Rule

rule = Rule(
    name="adult",
    condition_dsl={"type": "condition", "field": "age", "op": ">=", "value": 18},
    actions=("allow", "audit"),
    persist=False,
)

assert rule.action == "allow"  # compatibility view of actions[0]
assert rule.actions == ("allow", "audit")

See Concepts and the Pydantic Rule Guide for the complete field reference.

RuleBuilder

RuleBuilder is a fluent adapter for workflows that assemble a rule incrementally. Its build() method returns the public Rule, so a built rule needs no conversion before evaluation. Use build_engine_rule() when an internal boundary needs the EngineRule shape instead.

from fluxrules import RuleBuilder

rule = (
    RuleBuilder(rule_id=1)
    .name("High Value Transaction")
    .group("fraud_detection")
    .priority(10)
    .condition({"type": "condition", "field": "amount", "op": ">", "value": 10000})
    .action("flag_for_review")
    .build()
)

assert rule.condition_dsl["type"] == "condition"
assert rule.domain == "fraud_detection"

engine_rule = RuleBuilder(rule_id=2).name("internal").condition(
    {"type": "condition", "field": "amount", "op": ">", "value": 1}
).action("flag").build_engine_rule()
assert engine_rule.condition_dsl["type"] == "condition"

Implementation: src/fluxrules/domain/rule_builder.py.

Internal EngineRule

EngineRule is immutable and is used by the reference evaluator, persistence adapters, and internal services. Its authoritative logic is always the full condition_dsl tree. Its .conditions member is a derived flat leaf view for compatibility; it cannot preserve OR, NOT, or nesting and must not be used to rebuild rule logic.

Convert explicitly at an internal integration boundary:

from fluxrules import Rule

rule = Rule(
    name="adult",
    condition_dsl={"type": "condition", "field": "age", "op": ">=", "value": 18},
    action="allow",
    persist=False,
)

engine_rule = rule.to_engine_rule()
round_tripped = Rule.from_engine_rule(engine_rule, persist=False)

assert round_tripped.condition_dsl == rule.condition_dsl

Implementation: src/fluxrules/domain/models.py; conversion methods: src/fluxrules/domain/unified_rule.py.

Engine Input Contracts

API Accepted input Output or behavior
PhreakEngine.load_rules(rules) Public Rule objects or rule dictionaries Loads rules for stateless or streaming PHREAK evaluation
ReferenceEvaluator.evaluate(ruleset, facts) A Ruleset containing EngineRule objects Returns EvaluationResult with fired_rules and ordered actions
fluxrules.evaluate(rules, facts) A Rule, an iterable of rules, or a Ruleset Returns EvaluationResult with fired_rules and ordered actions
Rule.to_engine_rule() One public Rule Produces the immutable internal representation
Rule.from_engine_rule(engine_rule) One EngineRule Produces a public Rule; persistence is disabled by default

For normal application code, create Rule objects and pass them to PhreakEngine.load_rules(). Use EngineRule and ReferenceEvaluator at internal adapter, persistence, or parity-test boundaries.

Next Steps