{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://lemma.dev/schemas/explanation.v1.json",
"title": "Lemma rule explanation",
"description": "Structural explanation tree for one evaluated rule. Rule references embed their full explanation tree wherever they appear. Present at results..explanation only when evaluation was requested with explain: true, CLI --explain, or HTTP x-explanations with server explanations enabled.",
"$defs": {
"Cause": {
"type": "object",
"required": [
"condition",
"value"
],
"additionalProperties": false,
"description": "One evaluated unless condition, stated as a fact. A falsified comparison is flipped to its complement (a failed distance < 5 mile is stated as distance >= 5 mile), so the condition text describes what held.",
"properties": {
"condition": {
"type": "string",
"description": "True-form condition expression text from the source rule."
},
"value": {
"type": "string",
"description": ""true" for facts stated positively (including flipped conditions), "false" when the condition could not be flipped into a positive statement, or the veto text when evaluating the condition vetoed."
},
"children": {
"type": "array",
"description": "Inputs that drove the condition: data values and embedded rule explanations. Omitted when the fact text already states the value verbatim.",
"items": {
"$ref": "#/$defs/ExplanationNode"
}
}
}
},
"ConversionStep": {
"type": "object",
"required": [
"role",
"text"
],
"additionalProperties": false,
"properties": {
"role": {
"type": "string",
"enum": [
"outcome",
"rule",
"source"
]
},
"text": {
"type": "string"
}
}
},
"ExplanationNode": {
"oneOf": [
{
"$ref": "#/$defs/RuleNode"
},
{
"$ref": "#/$defs/ComposeNode"
},
{
"$ref": "#/$defs/DataNode"
},
{
"$ref": "#/$defs/DataUnusedNode"
},
{
"$ref": "#/$defs/ConversionNode"
},
{
"$ref": "#/$defs/VetoNode"
},
{
"$ref": "#/$defs/UnitEquivalenceNode"
}
]
},
"RuleNode": {
"type": "object",
"required": [
"type",
"name",
"result",
"body"
],
"additionalProperties": false,
"properties": {
"type": {
"const": "rule"
},
"result": {
"type": "string",
"description": "Display string for this rule's result."
},
"body": {
"type": "string"
},
"causes": {
"type": "array",
"items": {
"$ref": "#/$defs/Cause"
}
},
"children": {
"type": "array",
"items": {
"$ref": "#/$defs/ExplanationNode"
}
},
"name": {
"type": "string"
}
}
},
"ComposeNode": {
"type": "object",
"required": [
"type",
"expression",
"operands"
],
"additionalProperties": false,
"properties": {
"type": {
"const": "compose"
},
"expression": {
"type": "string"
},
"operands": {
"type": "array",
"items": {
"$ref": "#/$defs/ExplanationNode"
}
}
}
},
"DataNode": {
"type": "object",
"required": [
"type",
"name",
"display"
],
"additionalProperties": false,
"properties": {
"type": {
"const": "data"
},
"display": {
"type": "string"
},
"name": {
"type": "string"
}
}
},
"DataUnusedNode": {
"type": "object",
"required": [
"type",
"name"
],
"additionalProperties": false,
"description": "Data path present in a cause condition structure but never looked up (short-circuit or static and-false).",
"properties": {
"type": {
"const": "data_unused"
},
"name": {
"type": "string"
}
}
},
"ConversionNode": {
"type": "object",
"required": [
"type",
"expression",
"steps",
"operands"
],
"additionalProperties": false,
"properties": {
"type": {
"const": "conversion"
},
"expression": {
"type": "string"
},
"steps": {
"type": "array",
"items": {
"$ref": "#/$defs/ConversionStep"
}
},
"operands": {
"type": "array",
"items": {
"$ref": "#/$defs/ExplanationNode"
}
}
}
},
"VetoNode": {
"type": "object",
"required": [
"type"
],
"additionalProperties": false,
"properties": {
"type": {
"const": "veto"
},
"message": {
"type": "string"
}
}
},
"UnitEquivalenceNode": {
"type": "object",
"required": [
"type",
"text"
],
"additionalProperties": false,
"description": "A unit reconciliation fact stated when an operator's operands carry different units of the same measure family, so the implicit conversion inside the arithmetic is followable without external lookup tables. Derived from declared unit factors.",
"properties": {
"type": {
"const": "unit_equivalence"
},
"text": {
"type": "string",
"description": "Equivalence statement, e.g. "1 mile is 1.60934 kilometer"."
}
}
}
},
"examples": [
{
"result": "4821.09 eur",
"body": "subtotal + vat",
"children": [
{
"type": "rule",
"result": "3984.38 eur",
"body": "labor + rush_surcharge",
"children": [
{
"type": "rule",
"result": "3187.50 eur",
"body": "hourly_rate * hours_worked",
"children": [
{
"type": "data",
"display": "85.00 eur",
"name": "hourly_rate"
},
{
"type": "data",
"display": "37.5",
"name": "hours_worked"
}
],
"name": "labor"
},
{
"type": "rule",
"result": "796.88 eur",
"body": "labor * 25%",
"causes": [
{
"condition": "is_rush is true",
"value": "true"
},
{
"condition": "is_super_rush is false",
"value": "true"
}
],
"children": [
{
"type": "rule",
"result": "3187.50 eur",
"body": "hourly_rate * hours_worked",
"children": [
{
"type": "data",
"display": "85.00 eur",
"name": "hourly_rate"
},
{
"type": "data",
"display": "37.5",
"name": "hours_worked"
}
],
"name": "labor"
}
],
"name": "rush_surcharge"
}
],
"name": "subtotal"
},
{
"type": "rule",
"result": "836.72 eur",
"body": "subtotal * 21%",
"children": [
{
"type": "rule",
"result": "3984.38 eur",
"body": "labor + rush_surcharge",
"children": [
{
"type": "rule",
"result": "3187.50 eur",
"body": "hourly_rate * hours_worked",
"children": [
{
"type": "data",
"display": "85.00 eur",
"name": "hourly_rate"
},
{
"type": "data",
"display": "37.5",
"name": "hours_worked"
}
],
"name": "labor"
},
{
"type": "rule",
"result": "796.88 eur",
"body": "labor * 25%",
"causes": [
{
"condition": "is_rush is true",
"value": "true"
},
{
"condition": "is_super_rush is false",
"value": "true"
}
],
"children": [
{
"type": "rule",
"result": "3187.50 eur",
"body": "hourly_rate * hours_worked",
"children": [
{
"type": "data",
"display": "85.00 eur",
"name": "hourly_rate"
},
{
"type": "data",
"display": "37.5",
"name": "hours_worked"
}
],
"name": "labor"
}
],
"name": "rush_surcharge"
}
],
"name": "subtotal"
}
],
"name": "vat"
}
],
"type": "rule",
"name": "total"
}
],
"$ref": "#/$defs/RuleNode"
}
schemas