{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://law.arxo.io/schema/package-questions.schema.json",
  "title": "Arxo package question catalog 0.1",
  "description": "Authoring input for the question catalog: which queries are provided for the package and what verifies them. A card is a parameterized query template with a stable id, not an \"answer\": a card's presence does not mean a positive answer on the case, completeness of the law, or sufficiency of the facts submitted. Metadata, not semantics: not lowered into CLIR, not included in the package hash. The schema is closed; substantive links (the predicate is declared and derivable, the test executes exactly this template, the boundary is named in the package info) are held by a repository gate.",
  "$comment": "analysis/questions.json; SPEC §172; SPEC §209; package-info.json; DECISION-0190; verify/ci/gates/coverage/check_package_questions.py",
  "type": "object",
  "additionalProperties": false,
  "required": [
    "format",
    "package",
    "tasks",
    "questions",
    "boundaries",
    "internal"
  ],
  "properties": {
    "$comment": {
      "type": "string"
    },
    "format": {
      "const": "law.package-questions/0.1"
    },
    "package": {
      "type": "string",
      "minLength": 1,
      "description": "Package name from law.toml [package].name."
    },
    "tasks": {
      "type": "array",
      "minItems": 1,
      "items": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "id",
          "title",
          "source_units"
        ],
        "properties": {
          "id": {
            "$ref": "#/$defs/Id"
          },
          "title": {
            "type": "string",
            "minLength": 1
          },
          "source_units": {
            "$ref": "#/$defs/SourceUnits"
          }
        }
      }
    },
    "questions": {
      "type": "array",
      "minItems": 1,
      "items": {
        "$ref": "#/$defs/Question"
      }
    },
    "boundaries": {
      "type": "array",
      "items": {
        "$ref": "#/$defs/Boundary"
      }
    },
    "internal": {
      "type": "array",
      "description": "Derivable predicates without their own card — listed by name, with a reason. A wildcard for \"everything else internal\" is not provided.",
      "items": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "predicate",
          "reason"
        ],
        "properties": {
          "predicate": {
            "$ref": "#/$defs/Name"
          },
          "reason": {
            "type": "string",
            "minLength": 1
          }
        }
      }
    },
    "language": {
      "description": "Language of the QUESTIONS.md wrapper: ru by default. Packages published as a separate repository do not carry a second language (en).",
      "enum": [
        "ru",
        "en"
      ]
    }
  },
  "$defs": {
    "Id": {
      "type": "string",
      "pattern": "^[a-z0-9][a-z0-9-]*$"
    },
    "Name": {
      "type": "string",
      "pattern": "^[A-Za-z_][A-Za-z0-9_]*$"
    },
    "NormName": {
      "type": "string",
      "description": "Short norm template name; expand instances add path segments (`InsurerMustPayWithinTerm/duty/norm`).",
      "pattern": "^[A-Za-z_][A-Za-z0-9_]*(/[A-Za-z_][A-Za-z0-9_]*)*$"
    },
    "SourceUnits": {
      "type": "array",
      "minItems": 1,
      "items": {
        "type": "string",
        "pattern": "^[A-Z][A-Z0-9_]*$"
      },
      "description": "Identifiers of sources.law fragments (CLIR `fragment` nodes) without a namespace."
    },
    "Parameter": {
      "type": "object",
      "additionalProperties": false,
      "required": [
        "name",
        "type",
        "role"
      ],
      "properties": {
        "name": {
          "$ref": "#/$defs/Name"
        },
        "type": {
          "type": "string",
          "minLength": 1,
          "description": "Short type name of the declaration (after `#`)."
        },
        "role": {
          "enum": [
            "bound",
            "collected"
          ],
          "description": "bound — supplied by the asker; collected — gathered by the answer (only for kind=collect)."
        }
      }
    },
    "Question": {
      "type": "object",
      "additionalProperties": false,
      "required": [
        "id",
        "task",
        "question",
        "kind",
        "template",
        "tests"
      ],
      "properties": {
        "id": {
          "$ref": "#/$defs/Id"
        },
        "task": {
          "$ref": "#/$defs/Id"
        },
        "question": {
          "type": "string",
          "minLength": 1,
          "description": "The question in Russian, phrased as an insurer, injured party, or agent would ask it."
        },
        "kind": {
          "enum": [
            "truth",
            "why_not",
            "collect",
            "positions"
          ]
        },
        "predicate": {
          "$ref": "#/$defs/Name"
        },
        "norms": {
          "type": "array",
          "minItems": 1,
          "items": {
            "$ref": "#/$defs/NormName"
          }
        },
        "parameters": {
          "type": "array",
          "items": {
            "$ref": "#/$defs/Parameter"
          }
        },
        "template": {
          "type": "string",
          "minLength": 1,
          "description": "The query template in `evaluate …;` form with `<name>` placeholders for bound parameters; for positions — `evaluate positions();` and the expected form `position(<norm>, <status>)`.",
          "$comment": "SPEC §267.2"
        },
        "branches": {
          "type": "array",
          "minItems": 1,
          "items": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "summary",
              "rule"
            ],
            "properties": {
              "summary": {
                "type": "string",
                "minLength": 1
              },
              "rule": {
                "type": "string",
                "minLength": 1,
                "description": "Name of the package rule whose head is this predicate (or norm)."
              }
            }
          }
        },
        "tests": {
          "type": "array",
          "items": {
            "type": "string",
            "minLength": 1
          },
          "description": "Titles of `test \"…\"` in the package's tests/**/*.lawtest that execute a query of this template."
        },
        "cases": {
          "type": "array",
          "items": {
            "$ref": "#/$defs/Name"
          },
          "description": "Names of `[[cases]]` cases in the teaching packages examples/*/law.toml."
        },
        "queries": {
          "type": "array",
          "items": {
            "type": "string",
            "minLength": 1
          },
          "description": "Files examples/*/queries/<name>.json of the same kind and predicate."
        },
        "evidence": {
          "type": "array",
          "minItems": 1,
          "items": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "file",
              "contains"
            ],
            "properties": {
              "file": {
                "type": "string",
                "minLength": 1,
                "description": "Path from the package root."
              },
              "contains": {
                "type": "string",
                "minLength": 1,
                "description": "The exact substring by which the file executes this template (e.g. the collect line in check.py)."
              }
            }
          }
        },
        "source_units": {
          "$ref": "#/$defs/SourceUnits"
        },
        "related_boundaries": {
          "type": "array",
          "minItems": 1,
          "items": {
            "$ref": "#/$defs/Id"
          }
        },
        "notes": {
          "type": "string",
          "minLength": 1
        }
      },
      "allOf": [
        {
          "if": {
            "properties": {
              "kind": {
                "const": "positions"
              }
            }
          },
          "then": {
            "required": [
              "norms"
            ],
            "not": {
              "required": [
                "predicate"
              ]
            }
          },
          "else": {
            "required": [
              "predicate",
              "parameters"
            ],
            "not": {
              "required": [
                "norms"
              ]
            }
          }
        },
        {
          "if": {
            "properties": {
              "kind": {
                "const": "collect"
              }
            }
          },
          "then": {
            "properties": {
              "parameters": {
                "contains": {
                  "properties": {
                    "role": {
                      "const": "collected"
                    }
                  }
                }
              }
            }
          },
          "else": {
            "properties": {
              "parameters": {
                "items": {
                  "properties": {
                    "role": {
                      "const": "bound"
                    }
                  }
                }
              }
            }
          }
        }
      ]
    },
    "Boundary": {
      "type": "object",
      "additionalProperties": false,
      "required": [
        "id",
        "task",
        "question",
        "reason_kind",
        "limitation",
        "source_units"
      ],
      "properties": {
        "id": {
          "$ref": "#/$defs/Id"
        },
        "task": {
          "$ref": "#/$defs/Id"
        },
        "question": {
          "type": "string",
          "minLength": 1,
          "description": "A question the package does NOT answer."
        },
        "reason_kind": {
          "enum": [
            "source_delegates",
            "not_formalized",
            "engine_limit",
            "case_data",
            "open_reading"
          ],
          "description": "source_delegates — the source delegates elsewhere; not_formalized — the norm exists in the text but has no rules yet; engine_limit — a limitation of the language or engine; case_data — data is needed that the case does not carry; open_reading — an open interpretation question with an adopted reading."
        },
        "limitation": {
          "type": "string",
          "minLength": 1,
          "description": "Verbatim string from the package's package-info.json `limitations`: a single limitation text, not a third copy."
        },
        "source_units": {
          "$ref": "#/$defs/SourceUnits"
        },
        "input": {
          "$ref": "#/$defs/Name",
          "description": "The empirical predicate through which the missing piece is supplied as a case fact."
        },
        "related_question": {
          "$ref": "#/$defs/Id"
        },
        "notes": {
          "type": "string",
          "minLength": 1
        }
      }
    }
  }
}
