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

Type
Description
Example

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:

Field
Type
Description

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

Operator
Meaning

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:

Field
Type
Description

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