ExMaude. AI
(ExMaude v0.4.0)
View Source
AI rule conflict detection using a Maude equational model.
Companion to ExMaude.IoT. Where ExMaude.IoT analyzes physical-
IoT automation rules over Things, Properties, and Actions, this
module analyzes AI-generated automation rules over Agents,
Capabilities, ToolInvocations, and richer predicates (capability,
budget, jurisdiction, authority, approval).
Targets the bundled priv/maude/ai-rules.maude template.
Conflict types
Seven conflict types are detected:
:tool_call_conflict— same agent, same tool, conflicting required arguments:capability_shadowing— two rules grant the same capability at equal priority within a tenant:pack_tool_composition_mismatch— same capability name with mismatched type-shape signatures:sovereignty_violation— tool invocation routes through a jurisdiction outside the tenant's allowed set:authority_escalation— rule grants a capability that another rule requires at higher authority:approval_gate_bypass— high-impact invocation reachable without traversing an approval gate:agent_loop_cascade— one rule's capability grants another rule's required capability (cascade edge)
Usage
tenant = "acme"
rules = [
%{
id: "approve-then-dose",
agent_id: {tenant, "ph-controller"},
trigger: {:prop_lt, "ph", {:int, 6}},
invocations: [
{:require_approval, "dosing_high_delta"},
{:invoke_tool, "dose_chemical",
%{"chemical" => "ph_up", "ml" => 50}, "high_impact", :eu}
],
capability_grants: [{:cap, "ph_dosing", "v1"}],
authority_required: 2,
priority: 1
},
%{
id: "auto-dose",
agent_id: {tenant, "ph-controller"},
trigger: {:prop_lt, "ph", {:int, 5}},
invocations: [
{:invoke_tool, "dose_chemical",
%{"chemical" => "ph_up", "ml" => 100}, "high_impact", :eu}
],
capability_grants: [],
authority_required: 0,
priority: 1
}
]
{:ok, conflicts} = ExMaude.AI.detect_conflicts(rules, jurisdictions: [:eu])
# => [%{type: :approval_gate_bypass, rule1: "auto-dose", rule2: nil, ...}]Telemetry
Emits [:ex_maude, :ai, :detect_conflicts, :start | :stop] events
with measurements :duration, :rule_count, :conflict_count
and metadata including :result and :template (:ai_rules).
See ExMaude.Telemetry for full event documentation.
Summary
Functions
Detects all AI-rule conflicts in a rule set.
Detects only pairwise conflicts (tool-call, capability shadowing, pack-tool composition, authority escalation, agent-loop cascade).
Detects only sovereignty + approval-gate conflicts (single-rule conflicts independent of pair analysis).
Validates an AI rule structure without sending it to Maude.
Validates a list of AI rules. Returns :ok if all are valid, or
{:error, %{rule_id => [errors]}}.
Types
@type ai_rule() :: %{ :id => String.t(), :agent_id => agent_id(), :trigger => predicate(), :invocations => [tool_invocation()], optional(:capability_grants) => [capability()], optional(:authority_required) => non_neg_integer(), optional(:priority) => non_neg_integer() }
@type conflict() :: ExMaude.AI.ConflictParser.conflict()
@type predicate() :: {:always} | {:prop_eq, String.t(), term()} | {:prop_gt, String.t(), term()} | {:prop_lt, String.t(), term()} | {:prop_gte, String.t(), term()} | {:prop_lte, String.t(), term()} | {:capability_required, String.t()} | {:capability_granted, String.t()} | {:budget_within, String.t(), {:interval, non_neg_integer(), non_neg_integer()}} | {:authority_at_least, non_neg_integer()} | {:authority_required, non_neg_integer()} | {:jurisdiction_allowed, atom()} | {:jurisdiction_forbidden, atom()} | {:latency_at_most, non_neg_integer()} | {:and, predicate(), predicate()} | {:or, predicate(), predicate()} | {:not, predicate()}
@type tenant_id() :: String.t()
@type value() :: {:str, String.t()} | {:int, integer()} | {:bool, boolean()} | {:interval, non_neg_integer(), non_neg_integer()} | {:jurisdiction, atom()} | nil | String.t() | integer() | boolean()
Functions
Detects all AI-rule conflicts in a rule set.
Options
:jurisdictions— list of allowed jurisdiction atoms for the tenant (default[]which disables sovereignty checking — pass explicit allowed set to enable):timeout— Maude command timeout in milliseconds (default 10_000):pool— registered caller-owned pool (default:ex_maude_pool)
Examples
{:ok, conflicts} = ExMaude.AI.detect_conflicts(rules, jurisdictions: [:eu, :ch])
Detects only pairwise conflicts (tool-call, capability shadowing, pack-tool composition, authority escalation, agent-loop cascade).
Skips single-rule conflicts (sovereignty, approval-gate bypass).
@spec detect_single_rule_conflicts( [ai_rule()], keyword() ) :: {:ok, [conflict()]} | {:error, term()}
Detects only sovereignty + approval-gate conflicts (single-rule conflicts independent of pair analysis).
Requires :jurisdictions option for sovereignty checking. Approval-
gate bypass detection runs regardless of jurisdiction set.
Validates an AI rule structure without sending it to Maude.
Returns :ok if the rule is valid, or {:error, errors} with a
list of validation error messages.
Validates a list of AI rules. Returns :ok if all are valid, or
{:error, %{rule_id => [errors]}}.