AISA v2.0 / Technical documentation / product.schema.json
product.schema.json
JSON · 421 lines · 15,257 bytes · wiki path 10 Architecture/20 Configuration/contracts/product.schema.json · download the raw file · cited from Delivery · Stage S1 — Normalization · Contracts
Same folder: validate_product.py
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://ablera.dev/aisa-next/contracts/product.schema.json",
"title": "Whitelabel product specification",
"description": "S1 Normalization's output; the contract S2-S5 read. See aisa-next/10 Architecture/20 Configuration/Stage Normalization.md, the WS-n sections. Structural validation only - the reconciliation and layer-count rules are semantic and are enforced by validate_product.py, not by this schema.",
"type": "object",
"required": ["schema_version", "meta", "covers", "factors", "reconciliation", "unresolved"],
"additionalProperties": false,
"$defs": {
"source": {
"type": "string",
"minLength": 3,
"description": "Provenance. file!sheet range, a clause reference, or a message id. An element without one is a guess."
},
"money": {
"type": "object",
"required": ["amount", "currency"],
"additionalProperties": false,
"properties": {
"amount": { "type": "number" },
"currency": { "type": "string", "pattern": "^[A-Z]{3}$" }
}
},
"reconciliationEntry": {
"type": "object",
"required": ["claimed_in_source", "in_model", "evidence"],
"additionalProperties": false,
"properties": {
"claimed_in_source": { "type": "integer", "minimum": 0 },
"in_model": { "type": "integer", "minimum": 0 },
"evidence": { "$ref": "#/$defs/source" }
}
}
},
"properties": {
"_comment": { "type": "string", "description": "free note; permitted so fixtures can explain themselves" },
"schema_version": { "const": "1" },
"meta": {
"type": "object",
"required": ["code", "names", "lob", "valid_from", "sources"],
"additionalProperties": false,
"properties": {
"code": { "type": "string", "minLength": 1 },
"names": {
"type": "object",
"required": ["bg"],
"additionalProperties": { "type": "string" },
"properties": { "bg": { "type": "string" }, "en": { "type": "string" } }
},
"lob": { "type": "string" },
"class": { "type": "string" },
"valid_from": { "type": "string", "format": "date" },
"business_line": { "type": "string" },
"derived_from_product": { "type": ["string", "null"] },
"sources": {
"type": "array",
"minItems": 1,
"items": {
"type": "object",
"required": ["file", "role"],
"additionalProperties": false,
"properties": {
"file": { "type": "string" },
"role": { "enum": ["structure", "tariff", "requirements", "terms", "correspondence"] }
}
}
}
}
},
"objects": {
"type": "array",
"items": {
"type": "object",
"required": ["code", "source"],
"additionalProperties": false,
"properties": {
"code": { "type": "string" },
"status": { "enum": ["M", "O"] },
"one_only": { "type": "boolean" },
"source": { "$ref": "#/$defs/source" }
}
}
},
"covers": {
"type": "array",
"minItems": 1,
"items": {
"type": "object",
"required": ["key", "names", "type", "source"],
"additionalProperties": false,
"properties": {
"key": { "type": "string", "minLength": 1 },
"names": { "type": "object", "required": ["bg"], "additionalProperties": { "type": "string" } },
"type": { "enum": ["COV", "OPT"] },
"object": { "type": "string" },
"order": { "type": "integer" },
"risks": { "type": "array", "items": { "type": "string" } },
"events": { "type": "array", "items": { "type": "string" } },
"definitions": {
"type": "array",
"items": {
"type": "object",
"required": ["var", "source"],
"additionalProperties": false,
"properties": {
"var": { "enum": ["LIMIT", "DEDUCTIBLE"] },
"dim": { "enum": ["V", "P"] },
"from": { "type": "number" },
"to": { "type": "number" },
"currency": { "type": "string", "pattern": "^[A-Z]{3}$" },
"list": { "type": ["array", "null"], "items": { "type": "number" } },
"source": { "$ref": "#/$defs/source" }
}
}
},
"source": { "$ref": "#/$defs/source" }
}
}
},
"ld": {
"type": "array",
"items": {
"type": "object",
"required": ["code", "type", "sign", "scope", "source"],
"additionalProperties": false,
"properties": {
"code": { "type": "string", "maxLength": 20, "description": "PPA_PRODUCT_LD.LD_CODE is VARCHAR2(20)" },
"type": { "enum": ["LD", "TAX", "SR"] },
"sign": { "enum": [1, -1] },
"scope": { "type": "string", "pattern": "^(product|cover:[^@]+(@.+)?)$" },
"rate_dim": { "enum": ["P", "V", "M"] },
"rate": { "type": "number" },
"rate_base": { "enum": ["BP", "IV", "FINAL_PREMIUM"] },
"combination": { "enum": ["SUM", "MULT", "SEQUENTIAL_LAST"] },
"order": { "type": "integer" },
"rule": { "type": "string", "description": "prose, as written in the source" },
"source": { "$ref": "#/$defs/source" }
}
}
},
"ancillary_premiums": {
"type": "array",
"items": {
"type": "object",
"required": ["code", "amount", "currency", "source"],
"additionalProperties": false,
"properties": {
"code": { "type": "string" },
"name_bg": { "type": "string" },
"amount": { "type": "number" },
"currency": { "type": "string", "pattern": "^[A-Z]{3}$" },
"source": { "$ref": "#/$defs/source" }
}
}
},
"tariff_constraints": {
"type": "array",
"items": {
"type": "object",
"required": ["code", "kind", "source"],
"additionalProperties": false,
"properties": {
"code": { "type": "string" },
"kind": { "enum": ["premium_min", "sufficient_premium", "discount_prc_max", "ld_conflict", "calculation_order"] },
"amount": { "type": "number" },
"currency": { "type": "string", "pattern": "^[A-Z]{3}$" },
"rule": { "type": "string" },
"affects": { "type": "array", "items": { "type": "string" } },
"source": { "$ref": "#/$defs/source" }
}
}
},
"factors": {
"type": "array",
"items": {
"type": "object",
"required": ["code", "datatype", "level", "source"],
"additionalProperties": false,
"properties": {
"code": { "type": "string", "minLength": 1 },
"datatype": {
"enum": ["BOOLEAN", "IV", "TEXT", "TEXTAREA", "NUMBER", "FORMULA", "DATE", "IVLIST", "LIST", "CURRENCY"],
"description": "The ten the Angular field generator implements. IV_COV/IV_COVLIST are bucketed but have no case in the generator - see Stage IPAL, PF-8."
},
"level": { "enum": ["policy", "object"] },
"object": { "type": "string" },
"answered_by": {
"enum": ["operator", "object_attribute", "backend_operation", "constant"],
"description": "Maps to VALUE_SOURCE, which is the extraction dispatch key - not POLICY_TABLE."
},
"rating_axis": {
"type": "boolean",
"description": "True if a rating grid keys on it. Forces SALE_STAGE=POL and QT_REQUIRED=Y."
},
"required": { "type": "boolean" },
"default": { "type": ["string", "number", "boolean", "null"] },
"depends_on": { "type": ["string", "null"] },
"ui": {
"type": "object",
"additionalProperties": false,
"properties": {
"group": { "type": "string" },
"order": { "type": "integer" },
"visible": { "type": "boolean" }
}
},
"values": {
"type": "array",
"items": {
"type": "object",
"required": ["value"],
"additionalProperties": false,
"properties": {
"value": { "type": "string" },
"name": { "type": "string" },
"default": { "type": "boolean" }
}
}
},
"source": { "$ref": "#/$defs/source" }
}
}
},
"tariff": {
"type": "object",
"required": ["template", "versions", "cover_rates"],
"additionalProperties": false,
"properties": {
"template": { "type": "string" },
"versions": {
"type": "array",
"minItems": 1,
"items": {
"type": "object",
"required": ["effective_from"],
"additionalProperties": false,
"properties": {
"effective_from": { "type": "string", "format": "date" },
"ld_rule": { "enum": ["SUM", "MULT"] }
}
}
},
"layer_model": {
"type": "object",
"description": "REQUIRED when the source repeats its rate tables under more than one qualifier. Each axis carries its cardinality so the layer product is computable - see validate_product.py.",
"required": ["axes", "why"],
"additionalProperties": false,
"properties": {
"axes": {
"type": "array",
"minItems": 1,
"items": {
"type": "object",
"required": ["name", "cardinality", "carried_by"],
"additionalProperties": false,
"properties": {
"name": { "type": "string" },
"cardinality": { "type": "integer", "minimum": 1 },
"carried_by": { "type": "string", "description": "what carries this axis in the document" }
}
}
},
"grid_axes": { "type": "array", "items": { "type": "string" } },
"why": { "type": "string", "description": "what a linear read would miss" }
}
},
"cover_rates": {
"type": "array",
"items": {
"type": "object",
"required": ["cover", "shape", "source"],
"additionalProperties": false,
"properties": {
"cover": { "type": "string" },
"shape": { "enum": ["flat", "conditional", "grid"] },
"base": { "type": "string" },
"rate_dim": { "enum": ["P", "V", "M"] },
"grid": {
"type": "object",
"additionalProperties": false,
"properties": {
"row_factor": { "type": "string" },
"column_factor": { "type": "string" },
"row_labels": { "type": "array" },
"column_labels": { "type": "array" },
"rates": { "type": "array", "items": { "type": "array" } }
}
},
"conditions": { "type": "array" },
"min": { "type": ["number", "null"] },
"cap": { "type": ["number", "null"] },
"source": { "$ref": "#/$defs/source" }
}
}
}
}
},
"offers": {
"type": "array",
"items": {
"type": "object",
"required": ["code", "covers", "source"],
"additionalProperties": false,
"properties": {
"code": { "type": "string" },
"segment": { "type": "string" },
"object": { "type": "string" },
"covers": {
"type": "array",
"minItems": 1,
"items": {
"type": "object",
"required": ["cover", "extent"],
"additionalProperties": false,
"properties": {
"cover": { "type": "string" },
"extent": { "enum": ["M", "R", "O"] },
"values": {
"type": "array",
"items": {
"type": "object",
"required": ["var", "amount"],
"additionalProperties": false,
"properties": { "var": { "type": "string" }, "amount": { "type": "number" } }
}
}
}
}
},
"restrictions": { "type": "array" },
"dependencies": { "type": "array" },
"conflicts": { "type": "array" },
"source": { "$ref": "#/$defs/source" }
}
}
},
"requirements": {
"type": "array",
"items": {
"type": "object",
"required": ["source", "rule", "confidence"],
"additionalProperties": false,
"properties": {
"source": { "$ref": "#/$defs/source" },
"rule": { "type": "string" },
"maps_to": { "type": "string" },
"confidence": { "enum": ["high", "medium", "low"] }
}
}
},
"contradictions": {
"type": "array",
"description": "Two sources disagreeing. Never resolved by rule - every entry is a question to the user at H1 (decision 01.09.2026).",
"items": {
"type": "object",
"required": ["subject", "readings"],
"additionalProperties": false,
"properties": {
"subject": { "type": "string" },
"readings": {
"type": "array",
"minItems": 2,
"items": {
"type": "object",
"required": ["quote", "source", "consequence"],
"additionalProperties": false,
"properties": {
"quote": { "type": "string" },
"source": { "$ref": "#/$defs/source" },
"consequence": { "type": "string" }
}
}
},
"resolved_by_user": { "type": ["string", "null"] }
}
}
},
"reconciliation": {
"type": "object",
"required": ["covers", "factors"],
"additionalProperties": false,
"properties": {
"covers": { "$ref": "#/$defs/reconciliationEntry" },
"ld": { "$ref": "#/$defs/reconciliationEntry" },
"factors": { "$ref": "#/$defs/reconciliationEntry" },
"tariff_layers": { "$ref": "#/$defs/reconciliationEntry" },
"rate_cells": { "$ref": "#/$defs/reconciliationEntry" }
}
},
"unresolved": {
"type": "array",
"description": "A deliverable, not a failure. Blocking entries hold H1.",
"items": {
"type": "object",
"required": ["what", "why", "blocking"],
"additionalProperties": false,
"properties": {
"what": { "type": "string" },
"why": { "type": "string", "description": "which configuration step it blocks" },
"expected_in": { "type": "string" },
"blocking": { "type": "boolean" }
}
}
}
}
}