Behavioral Invariants
Behavioral Invariants are declarative rules that express organizational behavioral expectations in terms that compliance teams can read and governance systems can enforce. They go beyond scope and permissions to capture patterns, ratios, rates, distributions, and meaning.
Overview
Invariants describe what normal behavior looks like — and flag when behavior departs from those norms. They are the core of what makes the Behavioral Control Plane a true control plane: in networking, a control plane defines routing rules that the data plane enforces. In Nomotic, behavioral invariants define behavioral rules that the governance pipeline enforces.
Invariants are compiled into optimized evaluation artifacts that attach to Behavioral Contracts and integrate into the governance pipeline. The compilation step transforms human-readable behavioral declarations into efficient runtime checks, including pre-computed thresholds, window configurations, and aggregation functions.
Invariant Types
ratio
Distribution ratio constraints
Write-to-read ratio must stay below 0.3
distribution
Distribution shape constraints
No single target should exceed 60% of activity
drift
Drift threshold constraints
Action drift must stay below 0.20
semantic
Meaning fidelity constraints
Semantic fidelity for 'research' must stay above 0.85
temporal
Timing constraints
No activity outside business hours (8-18)
rate
Frequency constraints
Action rate must not exceed 2x baseline in window
count
Cardinality constraints
No more than 5 distinct targets per session
Quick Start
Using the Builder API
The InvariantBuilder provides a fluent API for creating invariant specifications:
Attaching to Contracts
Invariants are carried by Behavioral Contracts as a list of dictionaries:
Evaluating at Runtime
Pass current behavioral state to evaluate all invariants:
Core Concepts
InvariantSpec
A frozen dataclass that declares a single behavioral expectation:
invariant_id
str
Unique identifier (auto-generated by Builder)
type
str
One of: ratio, distribution, drift, semantic, temporal, rate, count
description
str
Human-readable description
metric
str
What to measure (interpretation depends on type)
operator
str
Comparison: lt, gt, lte, gte, eq, between
threshold
float
The threshold value
threshold_upper
float | None
Upper bound for "between" operator
window
int | None
Rolling window size (number of actions)
window_seconds
float | None
Time-based window alternative
Metric Interpretation by Type
ratio: The metric field uses X_to_Y format, e.g. "write_to_read". The value is computed as action_distribution[X] / action_distribution[Y].
distribution: Supported metrics include "target_max" (highest single target proportion), "action_max" (highest single action proportion), and "target_count" (number of distinct targets).
drift: The metric names a drift distribution: "action", "target", "temporal", "outcome", "semantic", or "overall".
semantic: The metric is the anchor term name (e.g., "research"). The threshold is expressed as fidelity (1.0 - drift), so gt 0.85 means "semantic drift for this term must stay below 0.15".
temporal: The metric specifies allowed hours as "start-end", e.g. "8-18" for business hours. The measured value is the fraction of actions outside those hours.
rate: The metric is "action_frequency". Value is actions per second within the window.
count: Supported metrics: "distinct_targets" and "distinct_actions" within the window.
Operators
lt
Current value must be less than threshold
gt
Current value must be greater than threshold
lte
Current value must be less than or equal to threshold
gte
Current value must be greater than or equal to threshold
eq
Current value must equal threshold (within 0.001)
between
Current value must be between threshold and threshold_upper
InvariantResult
Each evaluated invariant produces an InvariantResult:
invariant_id
str
Which invariant was evaluated
satisfied
bool
Whether the invariant passed
current_value
float
The measured metric value
threshold
float
The threshold it was compared against
margin
float
Distance from threshold (0.0 = at threshold, higher = safer)
status
str
"satisfied", "violated", or "approaching"
detail
str
Human-readable evaluation detail
Status logic:
"violated"— invariant is not satisfied"approaching"— satisfied but margin < 0.20 (within 20% of threshold)"satisfied"— satisfied with comfortable margin
CompiledInvariants
The compilation step validates all specs, groups them by evaluation strategy, and provides the evaluate() and summary() methods:
Runtime Integration
When a contract carries invariants, the governance runtime automatically evaluates them after every verdict and updates the Behavioral Provenance with invariant status counts:
Structural vs Semantic Invariants
Invariants fall into two categories:
Structural invariants describe operational patterns:
"Action frequency should not increase more than 2x within any 1-hour window"
"The write-to-read ratio should stay below 0.3"
"No more than 5 distinct target categories should be accessed in a single session"
Semantic invariants describe meaning preservation:
"Semantic similarity to contract anchor for 'research' must stay above 0.85 across any 10-action window"
"No instruction term should shift more than 15% from its baseline action mapping"
Both types are specified using the same InvariantSpec format and compiled into the same evaluation pipeline.
Example: Complete Contract with Invariants
Validation
Every InvariantSpec can be validated before compilation:
CompiledInvariants.compile() validates all specs and raises ValueError if any are invalid, ensuring only well-formed invariants reach runtime evaluation.
Last updated

