☰ Contents
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" }
        }
      }
    }
  }
}