ERDL Specification v2.1

(Entity-Rule Definition Language · 实体规则定义语言)

Authority note (2026-09-04 · synced to v2.1): This file is a copy; the authoritative source is the erdl repo erdl-language-spec-v2.1.en.md. Normative facts follow the authority.

Status: v2.1 · Final Date: 2026-09-03 Version semantics: this document (the ERDL language specification) is version v2.1; the top-level protocol: "erdl/v2" (protocol identifier, fixed value) and version: "2.1.0" (rule-format version) are independent version identifiers, not to be conflated with the document version. Author: Tang Qixin(唐启鑫) Trademark: ERDL™ is a trademark of Shenzhen Miaojing Technology Co., Ltd. Positioning: ERDL (Entity-Rule Definition Language) is a declarative rule definition format, carried in YAML/JSON, for precisely expressing entity structures and behavior rules. This specification is independent and neutral — it defines only the format itself, depending on no particular implementation or upper-layer framework; its deterministic evaluation and canonical form support byte-for-byte cross-implementation verification. In ERDL, rules decide everything: rules are the carrier of semantics, the boundary of execution, the evidence of audit, and the fact of governance. Conformance language: MUST / MUST NOT / SHOULD / SHOULD NOT / MAY in this document are interpreted per [RFC 2119].


1. Introduction

1.1 What ERDL Is

ERDL (Entity-Rule Definition Language) is a declarative rule definition format carried in YAML/JSON, for precisely expressing entity structures and behavior rules. It contains two kinds of declarations: Entity defines data structure; Rule defines a when → then decision. Entity defines the structure of an object; Rule prescribes the consequence of a condition; together they form an executable, reviewable, and verifiable rule expression.

1.2 Design Philosophy

ERDL is a “multi-party semantic layer” — it is not just a rule format, but a semantic convention layer shared by human, LLM, system, and audit:

PartyERDL’s role
Human (business/domain expert)the precise translation of natural-language rules, readable and reviewable
LLM (general model)structured input that removes ambiguity and supports deterministic evaluation
System (rule engine)standardized rule description; fn delegation controls the call boundary
Audit (regulation/compliance)a traceable rule record clearer than code + natural language

In this semantic layer, rules decide everything: humans express intent, the LLM translates semantics, the system executes decisions, and audit reviews the evidence. ERDL’s deterministic semantic layer gives an LLM clear direction: a user describes a rule in natural language; after ERDL precisely translates it, the LLM deterministically executes it per structured semantics — the conversational interface is the unified entry point.

1.3 Value at the AI Governance Level

The core challenge of AI governance is not whether a model can answer, but how probabilistic outputs satisfy the deterministic boundary required by regulation, auditing, and accountability. ERDL encodes declarative rules in YAML/JSON, codifying entity structures, behavioral constraints, and disposition actions into a verifiable deterministic rule layer, and turns “how an AI should act” from a training assumption into an inspectable object.

From trust to verification: Traditional governance relies on alignment assessments or post hoc explanations, making it difficult to prove which constraints a specific decision followed. ERDL expresses constraints as when → then rules. Each evaluation is bound to a canonical_tree snapshot and an outcome hash, enabling independent recomputation and byte-for-byte verification across implementations. Governance stakeholders no longer merely trust that a model has been “properly trained”; they can verify whether an action matched a rule, which rule it matched, and why that result was produced.

Accountable evidence chain: ERDL evaluation results are hashable and recomputable. Rule versions, input snapshots, decision outputs, and hashes can be anchored together to form audit records. Auditing is not a restatement of logs, but a reproducible proof process — why an action was allowed, why it was blocked, and who approved it can all be traced and verified, preventing post hoc explanations from becoming the sole basis.

Mechanized human–machine accountability boundary: ERDL can use decision types such as REQUEST_HUMAN and ESCALATE to require human adjudication for high-risk operations, sensitive entity changes, irreversible actions, and similar cases. Final human decision-making authority no longer depends on procedural slogans; it is encoded as executable, testable, and auditable rule paths.

Compliance as code and cross-organizational mutual recognition: Regulations, platform policies, and internal red lines can be translated into ERDL rules and continuously validated through test vectors. Different organizations, implementations, or third-party auditors can independently recompute outcomes from the same rules and canonical_tree, establishing a “trust but verify” governance paradigm and turning compliance from declarative documentation into governance facts that are executable, inspectable, and mutually recognizable.

1.4 Design Goals

  1. Determinism: for the same rule and input, any conforming implementation MUST produce byte-for-byte identical evaluation results and hashes;
  2. Readability: any rule can be read back as natural language (gloss) that a human can instantly understand and review;
  3. Auditability: the rule’s evaluation process is independently recomputable and traceable;
  4. Cross-implementation verifiability: semantics converge to a single kernel, and conformance is proven by byte-for-byte comparison against test vectors.

1.5 Core Commitment

The semantic carrier is the kernel, not the syntax. Semantics = tree = hash. The three coincide in canonical form.

Any scheme that takes “operator syntax” as its semantic carrier is forced to expand operators linearly as new requirements appear, so its cost never converges. This specification therefore converges semantics onto a single kernel (the expression tree), and treats the multiple writing forms as deterministic projections of that kernel — they are not independent languages, but different views of the same semantics. Rules decide everything: a rule’s validity depends not on its writing entry point or implementation form, but on canonicalized semantics that are unique, recomputable, hashable, and byte-for-byte verifiable.


2. Document Structure

2.1 Top-Level Format

An ERDL document (*.erdl.yaml) consists of four top-level fields, whose order MUST be fixed:

protocol: "erdl/v2"       # protocol identifier, fixed value
version: "2.1.0"          # rule-format version
metadata: { ... }         # document-level metadata (see §2.2)
rules: [ ... ]            # rule list (see §4)
Top-level fieldTypeRequiredDescription
protocolstringMUSTProtocol identifier, fixed value "erdl/v2"
versionstringMUSTRule-format version (semantic versioning)
metadataobjectMUSTDocument-level metadata
rulesarrayMUSTRule list; elements defined in §4

2.2 metadata

metadata:
  name: "my-first-rule-set"
  description: "Allow file read operations"
  category: coding
  decision: ALLOW            # fallback decision when no rule matches
  tags: [example]
FieldTypeDescription
namestringRule set name
descriptionstringRule set description
categorystringRule set category (coding/security/compliance…)
decisionstringFallback decision (default verdict when no rule matches; see §6)
tagsarrayTags

2.3 Format Conventions

2.4 Parsing and Evaluation Overview

An ERDL document moves from file to decision result through a fixed five-step pipeline. Understanding this pipeline is understanding how ERDL is “parsed” and “evaluated”:

StepActionInput → OutputBasis
① LoadRead the rule document*.erdl.yaml → structured object§2.1–§2.3
② ValidateLoad-time type checkingstructured object → valid document (reject invalid)E5
③ CompileNormalize the three writing formsvalid document → expression tree (canonical_tree)E7, §8.2
④ EvaluateJudge the tree node-by-node against the factexpression tree + fact → decision§7
⑤ EmitProduce evaluation evidencedecision → hashable, recomputable resultE6, §8

The full contracts for the input fact and the evaluation output are in §7.0.


3. Entity Definition

An Entity is the subject a rule acts upon (passed via context). ERDL predefines the following Entity types:

Entity typeDescription
agentA single Agent instance
toolA tool invoked by the Agent
taskA task executed by the Agent
workflowA multi-Agent orchestration process
humanA human approver
guardianSupervisor

Field references in rules (e.g. tool.name, context.amount) use Entities as their semantic namespace. Field paths are load-bearing: a field name is frozen once published ([FREEZE-1]), and aliases MUST be normalized to the canonical name first.


4. Rule Definition

Rule is the core unit of ERDL: Rule = Metadata + When (condition) + Then (action) + Audit (audit). When compiles to an expression tree (§5), Then is a decision type (§6), and Audit records the audit information of the rule’s evaluation.

4.1 Field Definitions

The rules[] sub-field order MUST be fixed: namedescriptioncategorypriorityoverrideringenabledwhenthenmessageinstructioncorrectionunlessexplanationalternativelegal_basissource_text.

FieldTypeRequiredDescription
namestringMUSTUnique rule identifier, format [CAT]-[NNN]-description
descriptionstringMUSTHuman-readable description
categorystringMAYRule-level category; defaults to metadata.category (see §2.2), allows mixed categories within one document
priorityintegerMUSTSmaller number = higher precedence (see §7.1)
overridestringSHOULDOverride level: critical > high > normal > low (default normal)
ringintegerSHOULDExecution ring: 0 kernel / 1 recovery / 2 approval / 3 advisory
enabledbooleanMAYRule enable flag (default true); false skips the rule during evaluation
whenobjectMUSTTrigger condition (see §5)
thenstringMUSTDecision type (see §6)
messagestringSHOULDDecision message (blocking then MUST be non-empty)
instructionstringMAYAdvisory instruction (for the ALLOW + instruction case)
correctionstringMAYCorrection text (CORRECT decision; source of the evaluation output primary_correction, see §7.0.3)
unlessobject/nullMAYExemption condition block (optional)
explanationstring / objectMAYBilingual explanation (why the rule exists and what harm it prevents)
alternativestring / objectMAYSuggested alternative action when blocked
legal_basisstringMAYLegal basis (citation of the regulation clause)
source_textstringMAYExcerpt of the original regulation text

4.2 Complete Example

protocol: "erdl/v2"
version: "2.1.0"
metadata:
  name: "my-first-rule-set"
  description: "Allow file read operations"
  category: coding
  decision: ALLOW
  tags: [example]
rules:
  - name: "COD-001-allow-read"
    description: "Allow all read_file tool calls"
    priority: 10
    override: high
    ring: 3
    when:
      logic: AND
      conditions:
        - field: "tool.name"
          operator: eq
          value: "read_file"
    then: ALLOW
    message: "read_file call allowed"
    unless: null

5. The when Condition Expression

when is the rule’s embedded condition expression. ERDL provides three writing forms (Simple / Expression / Decision Table), any of which compiles and normalizes to the same semantic kernel (the expression tree) and can be rendered back into any form; there is additionally a readable projection gloss (§5.5) deterministically generated from the tree as natural language.

5.1 Writing Forms (Projections)

ProjectionCarriesApplicable tierDescription
A · Simple30 operators0–2 (MUST)Safety baseline, the most common writing form
B · Expressionfull 34-node tree≥3Business panorama: logic/quantifiers/arithmetic/time/aggregation
C · Decision TablematrixPreferred by business/finance staff; compiles to the same kernel

The three forms share the same semantics, differing only in expressiveness and tier authorization. tier is a rule hierarchy level (0–5), ordered low-to-high by the rule’s constraint strength and scope — in this document, tier 0–2 is the safety baseline (MUST use Simple), and tier ≥3 is the business panorama (Expression may be used). when and expr MUST NOT coexist (E5).

5.2 Projection A: Simple (30 Operators)

Simple is the preserved, existing set of semantic units — 30 operators = 28 conditions + 2 modifiers, unchanged. It corresponds to system safety rules (tier 0–2).

Set definition:

FamilyCountOperators
Comparison6eq · ne · gt · gte · lt · lte
List2in · not_in
String5contains · not_contains · match · starts_with · ends_with
Boundary negation2not_starts_with · not_ends_with
Existence2exists · not_exists
Length5length_gt · length_gte · length_lt · length_lte · length_eq
Range2between · not_between
Count4count_gt · count_gte · count_lt · count_lte
Modifier2within (time window) · rate (rate limit)

Semantic conventions (apply to all operators):

Authoritative compile mapping: all 30 operators have a definite compile target, with none dangling — 13 direct nodes (eq/ne/gt/gte/lt/lte·in·contains/starts_with/ends_with/match·exists·between), 6 not-derived (not_in/not_contains/not_starts_with/not_ends_with/not_exists/not_between), 9 length/count compositions (length_* 5 + count_* 4), 2 time modifiers (within/rate).

#Simple operatorCompile targetExpression tree form
1-6eq ne gt gte lt ltedirect nodecomparison node
7indirect nodeset node in
8not_innot + exists guardexists(field) AND not(in(...))
9-12contains starts_with ends_with matchdirect nodestring node
13not_containsnot + exists guardexists(field) AND not(contains(...))
14-15not_starts_with not_ends_withnot + exists guardexists(field) AND not(...)
16existsdirect nodeexistence node (value non-null and non-undefined; empty string "", 0, false all count as “existing” — “existing” ≠ “non-empty string”)
17not_existsnot compositionnot(exists(...))
18-22length_gt/gte/lt/lte/eqcomposition + exists guardexists(field) AND length(field) compare n
23betweendirect noderange node (numeric only)
24not_betweennot + exists guardexists(field) AND not(between(...))
25-28count_gt/gte/lt/ltecomposition + exists guardexists(field) AND aggregate(count(...)) compare n
29withintime modifiertime window (as_of injected by engine)
30ratetime modifier + aggregaterate limit (temporal_state)

exists guard (compile-layer guarantee of E11 null propagation): the not_* operators (except not_exists) and the length_*/count_* compositions MUST compile to exists(field) AND <derived expression>, not a bare not(positive operator) or a bare length/count(...) comparison. Reason: a positive operator returns false for a missing field and length(missing) returns 0; a direct not flip or numeric comparison would break null propagation (fail-open). not_exists is the sole exception — its semantics are “perceive field missing”, so it stays a bare not(exists(...)).

Stateful operators (within/rate): within and rate are the only two stateful operators, whose evaluation depends on sliding-window counts across decisions. This state is not stored in the expression tree node but is maintained by a separate Guard state manager, entering the audit record as the temporal_state field — the expression tree itself remains a pure function (E1 holds), while the state source is auditable and recomputable.

Stateful operator truth semantics (MUST): count reaches threshold → condition holds (trigger); below threshold → record this event and return false (allow).

OperatorThresholdFirst/under-limitAfter threshold
rate: "N/window"Nfirst N times: record + falsefrom the (N+1)-th time: true
within: "window"1first: record + falsefrom the 2nd time in window: true (dedup)

Supporting constraints (all MUST): ① post-counting (count only when the positive condition holds); ② count isolation key (within keys on field+operator+value, rate keys on field+operator+value+rate); ③ record timing in the “under-limit” branch.

5.3 Projection B: Expression (34-Node Tree)

Expression opens the kernel’s full expressive power for complex business rules (tier ≥3). The semantic kernel is a typed expression tree of 34 nodes (in 10 groups), frozen at [FREEZE-2]:

GroupNodesSemantic capability
Valuefield · var · literalreference fields, context variables, constants (var only $/$.path; MUST NOT read clock or randomness)
Logicand · or · notcomposition
Comparisoneq · ne · gt · gte · lt · lteoperands may be field, variable, literal, or arithmetic subtree
Setinscalar ∈ set
Stringcontains · match · starts_with · ends_withpattern matching; match uses safe regex
Existence/measureexists · length · betweenexistence, length (Unicode code points), closed interval
Quantifierall · any · noneper-element array judgment; empty array always false
Arithmeticadd · sub · mul · div · roundfixed-point deterministic arithmetic
Timedays_between · epoch_ms · date_add · date_part · month_last_daydate difference, timestamp, date arithmetic, component extraction, last day of month
Aggregateaggregate (count/sum/avg/min/max)array aggregation

Node total: Value 3 + Logic 3 + Comparison 6 + Set 1 + String 4 + Existence/measure 3 + Quantifier 3 + Arithmetic 5 + Time 5 + Aggregate 1 = 34. The 6 comparison operators, 4 string operators, 5 arithmetic operators, 3 quantifier kinds, and 5 aggregate functions are carried by parameterized node types in implementations (e.g. compare{op}, string{op}, arith{op}, quantifier{kind}, aggregate{fn}), so the “34 semantic nodes” map to fewer type literals in code — this is the relationship between semantic nodes and type projections, not a count contradiction.

Expression writing example:

when:
  expr:
    lt:
      - div:
          - sub: [{ field: "tool.args.price" }, { field: "context.cost" }]
          - field: "tool.args.price"
      - 0.15

5.4 Projection C: Decision Table (Matrix Form)

The decision table faces business and finance staff, expressing multi-condition combinations in row-column structure, compiled to the same kernel:

kind: decision_table
columns:
  - field: "context.amount"
    label: "application amount"
rows:
  - when: [["gte", 10000]]
    then: "REQUEST_HUMAN"
    priority: 100
  - when: [["gte", 5000]]
    then: "ESCALATE"
    priority: 90
  - when: []                       # default row (unconditional, fallback)
    then: "ALLOW"
    priority: 1

Compile rules (E7): ① each row’s when condition group compiles to logical AND in field-column order, and each condition unit compiles to a comparison node; ② row order is precedence (first match from top, consistent with priority; the two MUST NOT conflict); ③ the default row when: [] compiles to literal true; ④ then MUST belong to the §6 decision type enumeration; ⑤ the compiled tree is identical to a hand-written Simple/Expression tree.

5.5 Projection D: gloss (Natural-Language Readable Projection)

gloss is natural-language text deterministically generated from the tree:

gloss: "when (sale price minus cost) divided by sale price is less than 15%, human approval is required"   # engine-generated, lint-enforced

Five invariants (all MUST):

#Invariant
G1gloss = render(tree): deterministically generated by a frozen rendering template
G2every rule MUST carry gloss; lint checks gloss == render(tree); hand-writing forbidden
G3gloss forbids raw field paths and MUST use the Entity’s display_name (bilingual)
G4gloss is a render product (does not enter the hash); displayed via live render(tree)
G5Simple rules also generate gloss (rendered after compiling to a tree) — the reading layer is uniform

gloss rendering templates (per node, bilingual; {A}/{B}/{C} are recursive render results of sub-expressions):

NodeEnglish template
field{field}
var{variable}
literal{value}
and{A} and {B}
or{A} or {B}
notnot ({A})
eq{A} equals {B}
ne{A} does not equal {B}
gt{A} is greater than {B}
gte{A} is greater than or equal to {B}
lt{A} is less than {B}
lte{A} is less than or equal to {B}
in{A} is in {B}
contains{A} contains {B}
match{A} matches regex {B}
starts_with{A} starts with {B}
ends_with{A} ends with {B}
exists{A} exists
lengththe length of {A}
between{A} is between {B} and {C}
allevery item in {A} satisfies: {B}
anysome item in {A} satisfies: {B}
noneno item in {A} satisfies: {B}
add{A} plus {B}
sub{A} minus {B}
mul{A} times {B}
div{A} divided by {B}
round{A} rounded
days_betweendays between {A} and {B}
epoch_msthe epoch milliseconds of {A}
date_add{A} plus {B} duration
date_partthe {part} of {A}
month_last_daythe last day of the month of {A}
aggregate(count)the count of {A}
aggregate(sum)the sum of {A}
aggregate(avg)the average of {A}
aggregate(min)the minimum of {A}
aggregate(max)the maximum of {A}

exists boolean-field special case: when the field name matches is_*/has_* (boolean-field convention), exists renders as {A} is true instead of {A} exists — boolean fields are true when present, avoiding awkward phrasing (e.g. “has been notified exists”).


6. then Decision Types

The value of then MUST belong to the following 13 decision types:

#Decision typeSemantics
1ALLOWallow
2DENYblock
3CORRECTcorrect deviation
4NOTIFYnotify
5REQUEST_HUMANrequest human adjudication
6ESCALATEescalate
7DELEGATEdelegate
8DEFERdefer
9EMERGENCY_HALTemergency stop
10ROLLBACKroll back
11QUARANTINEquarantine
12WORKFLOWworkflow (state machine; substates WORKFLOW_WAITING / WORKFLOW_PROGRESS)
13GUIDEguide

7. Evaluation Semantics

7.0 Evaluation Overview

Evaluation = the pure-function process (E1) by which the expression tree (the compiled product of rules) judges the input fact node by node. This section defines the evaluation input contract, the algorithm steps, and the output contract, to align implementers and users.

7.0.1 Input Contract (Fact Object)

The evaluation input is a fact object carrying the current state of the rule’s subject entities, namespaced by Entity (§3):

fact:
  tool:                 # Entity: tool
    name: "issue_refund"
    args: { amount: 8000, order_id: "O1024" }
  context:              # free-form context fields (referenced by rules as context.*)
    country: "CN"
    role: "operator"
  # other Entities: agent / task / workflow / human / guardian (provided as needed)

7.0.2 Evaluation Algorithm

Input: rule set rules[] + fact object fact
Output: the decision result (see 7.0.3)

1. Sort: by priority ascending (smaller = higher priority)
2. Group: execute rings in order 0 to 3 (0 kernel → 1 recovery → 2 approval → 3 advice)
3. Within each ring, evaluate each rule in order:
   a. the unless exemption is judged before when — on exemption, record and skip the rule
   b. the compiled when expression tree judges fact node-by-node (true / false / error)
   c. first-match-wins within each ring (a match short-circuits that ring)
   d. override: only the DENY → ALLOW direction, never to a less-safe state (§7.1)
4. Fallback: no rule matched → metadata.decision (fallback decision, §2.2)
5. Summarize: produce decision + matched_rules + evidence (canonical_tree / hash / eval_trace)

7.0.3 Output Contract (Evaluation Result)

The evaluation result MUST contain the following fields:

FieldDescription
decisionthe final decision (one of the §6 enum, or the fallback decision)
matched_rulesthe matched rules (in evaluation order)
unless_exemptionsrules exempted via unless (recorded separately, not counted in matched_rules)
primary_instructionthe primary instruction (ALLOW + instruction scenario)
primary_reasonthe primary reason (DENY and other blocking scenarios)
primary_explanationthe primary explanation (may be bilingual)
primary_correctionthe correction text (CORRECT decision; sourced from the rule field correction, see §4.1)
total_evaluatedthe total number of rules evaluated
total_matchedthe total number of rules matched
temporal_statethe within/rate sliding-window state snapshot (omitted when nothing matched)

The evaluation evidence (canonical_tree snapshot, result hash, eval_trace) are independently recomputable derived products (§8.2, E6) — canonical_tree enters the hash, eval_trace does not (§8.3).

7.1 Precedence and Conflict Resolution

  1. Sort by priority ascending (smaller value = higher precedence);
  2. Among equal priority, those with an override marker go first;
  3. override enumeration: critical > high > normal > low (default normal);
  4. Equal priority and equal override: definition order;
  5. override is allowed only in the DENY → ALLOW direction (it MUST NOT override to a less-safe state).

7.2 Evaluation Constraints (E1–E12, all MUST)

#Constraint
E1Evaluation is a pure function: no side effects, no implicit external state, no clock reads; the state injection of within/rate (temporal_state) and as_of are controlled external inputs
E2Fixed-point decimal scale=14 + half-even + string serialization; intermediate computation uses high-precision bounded rationals, rounding only at output nodes
E3Evaluation errors are recorded as eval_warnings; folding direction follows E12 by tier
E4Resource limits (graded): Grade A arithmetic depth≤2 / tree depth≤6 / nodes≤64 / array≤10000 / per-rule≤50ms / no nested quantifiers / regex steps≤10000; Grade B tree depth≤10 / nodes≤256 / arithmetic depth≤4, quantifier nesting≤2; Grade C not applicable
E5Type checking at load; when and expr MUST NOT coexist
E6Tree as evidence: canonical_tree (a tree snapshot) serves as evaluation evidence and enters the hash; eval_trace is a recomputable derived product, not entering the hash
E7Simple and Expression compile to the same evaluation core; a second evaluator is forbidden
E8Quantifier safe folding: empty array → all/any/none all false (anti-vacuous-truth)
E9No wall-clock reads; as_of is injected by the engine and recorded in the audit record
E10String NFC normalization
E11undefined sentinel semantics (null propagation, see §7.3)
E12Evaluation error handling: tier≤2 and Guard contexts default to fail-close, tier 3–5 folds to false

The kernel explicitly excludes: string concatenation, regex replacement, bitwise operations, date formatting, recursive references, and user-defined nodes — to keep evaluation closed and verifiable.

7.3 Deterministic Semantics (Cross-Implementation Divergence Protection)

The following semantics MUST be explicitly annotated in the document and vectors, to avoid semantic misunderstanding against standard implementations:

(a) Null propagation (E11): Agent context is highly dynamic; missing fields are the norm. Evaluation MUST use safe failure under three-valued logic:

ScenarioBehavior
Equality/numeric comparison on a missing fieldreturns false (not NPE)
== null / != null checkreturns true / false normally
Type-mismatched comparisonreturns false (no implicit conversion)
Arithmetic on a missing fieldreturns false (condition) or EvaluationError (arithmetic expression)

(b) Quantifier empty-array safe folding (E8): under standard quantifier semantics all(empty)=true (vacuous truth). This specification deliberately deviates: all/any/none(empty) all fold to false — preventing “nothing to check yet judged as allowed” — and record the safe fold in the audit record. Third-party implementations MUST adopt this folding semantics.

(c) Fixed-point intermediate precision (E2): intermediate computation uses high-precision bounded rationals (e.g. 128-bit integer numerator/denominator); only output nodes round to scale=14 + half-even string serialization (IEEE 754-2019 ROUND_HALF_EVEN).

(d) Regex ReDoS protection: the match node MUST satisfy: ① single-match step limit ≤10000; ② input length limit; ③ prefer a deterministic engine (RE2-class) or a safe syntax subset.

(e) aggregate empty-array safe folding:

FunctionEmpty-array resultBasis
count(empty)0standard counting semantics
sum(empty)0empty-sum identity
avg(empty)falsesafe-failure fold (avoid division by zero)
min(empty)falsesafe-failure fold (standard +Infinity, disabled)
max(empty)falsesafe-failure fold (standard −Infinity, disabled)

The over of aggregate MUST be an array; a non-array (missing/scalar/object) returns null + type_mismatch warning (folded to false). count(missing) and count(empty array) differ: the former is type_mismatch, the latter is 0.

(f) Time-node UTC semantics (E9): all time nodes evaluate uniformly in UTC, guaranteeing byte-for-byte consistency across implementations and time zones:

Business local time zone is converted by the engine to a UTC instant when injecting as_of; the evaluator computes as a UTC pure function.

7.4 when Minimum-Completeness Constraints

when: "true" means “applies to all operations” and is allowed only for advisory rules:

RuleLevel
when: "true" MUST NOT pair with then: DENYMUST NOT
when: "true" MUST NOT pair with then: EMERGENCY_HALTMUST NOT
when: "true" MUST NOT pair with then: CORRECTMUST NOT
when: "true" MUST NOT pair with then: REQUEST_HUMANMUST NOT
when: "true" MAY pair with then: ALLOW + instructionMAY
when: "true" MAY pair with then: NOTIFYMAY
Safety rules (category=security) MUST contain at least 1 conditionMUST
Tool-interception rules SHOULD contain a tool.name conditionSHOULD
File-operation rules SHOULD contain tool.args.pathSHOULD
Command-operation rules SHOULD contain tool.args.commandSHOULD

8. Serialization and Canonicalization

8.1 Serialization

An ERDL document is carried in YAML and can be losslessly converted to JSON. The canonical tree (canonical_tree) is serialized as a JSON object.

8.2 Canonical Tree (Canonical Form)

The expression tree is the single benchmark object for evaluation, hashing, and recomputation. For its hash to be byte-for-byte identical across implementations, the tree MUST have a unique canonical form:

Canonicalization ruleDescription
Fixed node orderchild nodes are arranged in canonical order (strict left→right), independent of source writing order
Field names load-bearingfield reference paths are load-bearing — frozen once published ([FREEZE-1]); aliases MUST be normalized first
Literal canonicalizationnumbers are represented as fixed-point decimal strings (scale=14 + half-even); strings NFC-normalized
var canonicalizationonly $ / $.path, with path segments as definite byte sequences
Metadata strippingcomments, source line numbers, formatting, authors, and other non-semantic metadata never enter the canonical tree

The object of tree hashing is the canonical tree, not any particular implementation’s memory representation or serialized text. Two structurally equivalent trees (differing only in field writing order, whitespace, or variable naming) produce exactly the same byte sequence and hash after canonicalization.

8.3 Relationship between the Canonical Tree and gloss

This “hash the tree, verify gloss equals the tree” mechanism lets gloss obtain cryptographic anchoring of the tree without needing byte-for-byte identity or entering the hash.


9. How to Integrate ERDL

The integration goal of ERDL is to extract critical decisions from model inference, framework code, or informal conventions, and turn them into loadable, executable, and verifiable rule assets. ERDL is typically delivered as YAML/JSON rule documents, makes decisions through when → then, and outputs hashable evaluation evidence that can be recomputed byte for byte. The following three integration paths correspond to three typical engineering integration points.

9.1 Scenario 1: AI Agent (Behavioral Constraint Layer / Action Guard)

Role: In an AI Agent pipeline, ERDL is the deterministic gate between LLM intent and system execution — the Agent may generate actions, but whether an action is permitted must be determined by rule evaluation.

Simulation: A customer-service Agent receives a user request for a refund of 8,000 yuan. The LLM converts the intent into the tool call issue_refund(amount=8000, order_id=O1024). Before the call actually reaches the payment system, Action Guard packages the tool name, arguments, and session context into a fact object and submits it to ERDL for evaluation. In the rule set, R1 is written as when tool.name == "issue_refund" and tool.args.amount > 5000 → REQUEST_HUMAN, while R2 is written as when tool.name == "issue_refund" → ALLOW. Because R1 matches first, the system returns REQUEST_HUMAN. The Agent stops calling the payment tool, generates a human approval task instead, and returns a “manual review required” message to the user.

Integration points: First, rules are evaluated independently of the model, so prompts no longer carry the safety boundary. Second, match records, input digests, canonical_tree, and result hashes are written together to audit logs, making every interception replayable. Third, rule changes require only updating the ERDL document, without rewriting the Agent framework, tool implementations, or model prompts.

9.2 Scenario 2: MCP (Protocol Distribution / Cross-Implementation Interoperability)

Role: In the MCP ecosystem, ERDL rules are exposed as standard tools through an ERDL MCP Server. Any MCP-compatible Agent can invoke the same rule set, enabling compliance distribution and mutual recognition across implementations.

Simulation: An enterprise deploys its fund-compliance rules as an ERDL MCP Server and exposes the guard_check tool. A third-party Agent prepares to execute a high-value refund but does not possess the enterprise rules. Before execution, it calls guard_check through MCP, passing an action description (action=issue_refund, amount=8000, channel=payment). The ERDL MCP Server loads the rule set, performs evaluation, and returns decision=REQUEST_HUMAN, matched_rule=R1, hash=0x9f.... Based on the returned value, the third-party Agent stops direct execution, enters a human approval workflow, and records the decision evidence in its own execution log.

Integration points: The key here is “Rules-as-a-Service.” Rules are no longer hard-coded in a specific Agent framework; they are distributed through a standard protocol. Clients from different vendors, programming languages, and runtime environments can consume the same decision logic. Because the response includes rule-match and hash information, callers can archive decision evidence for later auditing or independent recomputation even without storing the original rule text. When rules are upgraded, only the MCP Server side needs to be updated; clients do not need to refactor their execution chains.

9.3 Scenario 3: Rule Engine (Rule Definition Language / Deterministic Evaluation)

Role: Inside a rule engine, ERDL is the rule definition language itself, responsible for expressing business policies declaratively and providing deterministic evaluation semantics.

Simulation: An anti-money-laundering engine needs to express “large transaction involving a high-risk country → block.” The business team writes the ERDL rule when context.amount > 10000 and context.country in [high-risk country list] → DENY. After loading the YAML, the engine does not treat it as ordinary configuration; it compiles it into an expression tree: comparison nodes handle amount thresholds, set nodes determine country membership, and logical nodes perform the AND operation. The engine then executes according to the E1–E12 evaluation semantics and outputs DENY. The rule can also generate canonical_tree and a hash value; another implementation can recompute the same result simply by loading the same rule and the same input.

Integration points: The core value here is “verifiable determinism.” ERDL not only makes rules readable, but also allows engine implementations to be constrained by test vectors. V-ENGINE-class test vectors can prove that different engines, platforms, and versions produce byte-for-byte identical results for the same rule. As a result, a rule engine is no longer merely an internal black box inside a business system; it becomes an executor that can be independently verified by third parties. Regulators, auditors, or platform operators can determine whether the engine computed correctly based on inputs, rule hashes, and evaluation evidence.


10. Examples and Conformance Verification

10.1 Quick Start

A minimal ERDL document plus one evaluation, walking the full “write → load → evaluate → get result” chain (pipeline in §2.4).

Step 1 · Write the rule (refund.erdl.yaml):

protocol: "erdl/v2"
version: "2.1.0"
metadata:
  name: "refund-guard"
  description: "Refund amount control"
  category: coding
  decision: ALLOW
rules:
  - name: "SEC-001-refund-limit"
    description: "Refunds over 5000 require human approval"
    priority: 10
    when:
      logic: AND
      conditions:
        - field: "tool.name"
          operator: eq
          value: "issue_refund"
        - field: "tool.args.amount"
          operator: gt
          value: 5000
    then: REQUEST_HUMAN
    message: "Refund amount over 5000, human approval required"

Step 2 · Load + validate + compile: parse the YAML, validate it, then compile when into an expression tree (§2.4 steps ①②③).

Step 3 · Evaluate: given the fact object:

fact:
  tool:
    name: "issue_refund"
    args: { amount: 8000 }

Rule SEC-001 matches (tool.name == "issue_refund" and amount > 5000).

Step 4 · Result:

decision: REQUEST_HUMAN
matched_rules: ["SEC-001-refund-limit"]
primary_reason: "Refund amount over 5000, human approval required"
total_evaluated: 1
total_matched: 1

If the input is changed to amount: 100, the rule does not match, and the metadata.decision fallback applies → decision: ALLOW.

10.2 Complete Examples

See §4.2 (Simple rule), §5.3 (Expression rule), and §5.4 (Decision Table).

10.3 Conformance Verification

The semantics of this specification MUST be proven by independently recomputable test vectors. The expression-layer vectors (V-ENGINE / V-GLOSS / V-PROJ) cover: 34 nodes × 4 scenarios (normal/boundary/exception/empty), E1–E12 semantics, the Simple 30-operator compile mapping, and gloss rendering templates.

Five-step verification: load vector input → generate expression tree → recompute evaluation result → compare with the answer → judge consistency.

Third-party Runner verification flow (from zero to conformance):

  1. Read this specification;
  2. Implement an independent verifier in your own chosen tech stack (without importing any existing implementation code);
  3. Load the test vectors and compare byte-for-byte;
  4. Confirm your implementation satisfies the Runner contract;
  5. Submit results to the implementation registry for third-party audit re-verification.

Appendix A · 34-Node Reference Table

GroupNodesCount
Valuefield · var · literal3
Logicand · or · not3
Comparisoneq · ne · gt · gte · lt · lte6
Setin1
Stringcontains · match · starts_with · ends_with4
Existence/measureexists · length · between3
Quantifierall · any · none3
Arithmeticadd · sub · mul · div · round5
Timedays_between · epoch_ms · date_add · date_part · month_last_day5
Aggregateaggregate (count/sum/avg/min/max)1

Total 34 nodes.

Appendix B · Simple 30-Operator Reference Table

FamilyOperatorsCount
Comparisoneq · ne · gt · gte · lt · lte6
Listin · not_in2
Stringcontains · not_contains · match · starts_with · ends_with5
Boundary negationnot_starts_with · not_ends_with2
Existenceexists · not_exists2
Lengthlength_gt · length_gte · length_lt · length_lte · length_eq5
Rangebetween · not_between2
Countcount_gt · count_gte · count_lt · count_lte4
Modifierwithin · rate2

Total 30 operators (28 condition operators + 2 condition modifiers).

Appendix C · Decision Type Enumeration (13 types)

See §6.

Appendix D · Function Delegation and Rule Grading

For scenarios explicitly excluded by the kernel but genuinely needed, function delegation (FnRegistry) is provided as a controlled fallback:

ConstraintDescription
Registrationa function MUST be registered before it can be referenced; unregistered calls are rejected
Sandboxed executionrestricted environment under resource quota and timeout
Determinism exemption declarationfunctions on the Guard evaluation path MUST declare and guarantee determinism
Auditabilityevery call is recorded in the audit record for offline verification

Rule grading (Grade):

GradeExpression formAudit SLA
Apure Simple (30 operators)highest, plain-text recomputable
BExpression treehigh, eval_trace MUST
Cwith function delegationlayered, Grade C MUST NOT pose as plain-text recomputable

Rules with function delegation (Grade C) MUST explicitly mark “contains non-recomputable function delegation” in gloss; the delegated function’s call input + output hash MUST enter the result hash’s preimage.


Appendix E · Glossary

TermOne-line definition
Entitya rule subject type (agent/tool/task/workflow/human/guardian), the namespace for field references (§3)
Rulea when → then decision unit
whena rule’s trigger condition (compiled to an expression tree)
thenthe decision type after a rule matches (§6)
tierrule level 0–5, low to high for constraint strength; tier 0–2 uses Simple, ≥3 may use Expression
ringexecution ring 0–3 (kernel/recovery/approval/advice); evaluation runs in ring order
overrideoverride level critical > high > normal > low; only the DENY → ALLOW direction is allowed
expression treethe evaluation semantic kernel (34 nodes, 10 groups); all three writing forms compile to it
canonical_treethe canonical tree, the sole basis for hashing and recomputation (§8.2)
glossthe natural-language readable projection deterministically generated from the tree (§5.5)
eval_tracethe node-level evaluation trace (recomputable derived product, does not enter the hash, E6)
eval_warningsnon-fatal warnings during evaluation (E3)
temporal_statethe within/rate sliding-window state (stateful operators)
as_ofthe evaluation moment injected by the engine (UTC, E9)
fact objectthe evaluation input carrying the current state of entities (§7.0.1)
fallback decisionthe metadata.decision fallback verdict when no rule matches (§2.2)
NFCUnicode Normalization Form C (string normalization, E10)
ReDoSregular-expression denial of service; the match node MUST guard against step explosion (§7.3(d))
half-evenbanker’s rounding (ROUND_HALF_EVEN), the E2 fixed-point output rounding
null propagationthe safe-failure semantics of returning false uniformly for missing fields (E11)

Revision History

VersionDateChanges
v2.12026-09-03§4.1 adds three optional fields — category (rule-level override), enabled (enable flag), correction (CORRECT fix text) — completing the field table and fixed order; §7.0.3 adds the primary_correction source cross-reference. Protocol erdl/v2 unchanged; rule-format version 2.0.0 → 2.1.0 (additive optional fields, non-breaking)
v2.02026-08-30Finalized

Normative References


© 2026 Shenzhen Miaojing Technology Co., Ltd. · MIT License

Source: GitHub (on-site mirror for readers in China)