{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://yarramate.org/schema/interrogation-report/v1",
  "title": "YarraMate interrogation report",
  "type": "object",
  "additionalProperties": false,
  "required": [
    "format",
    "workspace",
    "catalogue",
    "semantics",
    "inputs",
    "summary",
    "waves"
  ],
  "properties": {
    "format": {
      "const": "yarramate/interrogation-report/v1"
    },
    "workspace": {
      "type": "string",
      "minLength": 1
    },
    "catalogue": {
      "type": "string",
      "minLength": 1
    },
    "catalogues": {
      "description": "Every catalogue that contributed, as id@version, base first (#345, ADR 0129). Present only when more than one did. OPTIONAL, and `catalogue` keeps naming the base with its existing value shape, because turning that field into an array would break every reader: an optional additive field is free for readers and does not force constructors. Question ids in this report are qualified as catalogue#question and carry NO version, so a catalogue version bump strands no stored judgment keyed on them; the versions live here instead.",
      "type": "array",
      "minItems": 1,
      "items": {
        "type": "string",
        "minLength": 1
      }
    },
    "semantics": {
      "type": "string",
      "minLength": 1,
      "description": "The version of condition evaluation that produced this report, as distinct from the package version. It changes only when an existing question's answer can change for an unchanged model, so a consumer holding stored answers can tell an engine change from a model change. Absent on reports produced before yarramate 1.1.0."
    },
    "inputs": {
      "description": "Which optional inputs the evaluation was given (#450). A condition that reads one it was not given stays quiet, which is correct - the caller did not look, so the answer is unknown rather than negative - but a quiet condition and a satisfied one are both open:false. Without this a host summing closed questions reads \"nothing was supplied\" as \"nothing is missing\", and for an absence question the silent direction is \"the interview is satisfied\". This says the same thing asked:false says one level up, for inputs rather than for subjects. Every key is present on every report, so a consumer reads a boolean rather than testing for presence.",
      "type": "object",
      "additionalProperties": false,
      "required": [
        "profileContext",
        "evidence",
        "patternMemberships",
        "patternVacancies"
      ],
      "properties": {
        "profileContext": {
          "description": "Resolved profile context. Without it `unconstrained-kind` never holds.",
          "type": "boolean"
        },
        "evidence": {
          "description": "Evidence overlay observations. Without them `unchallenged-evidence` never holds.",
          "type": "boolean"
        },
        "patternMemberships": {
          "description": "Pattern memberships from the compilation. Without them `fills-pattern-slot` never holds.",
          "type": "boolean"
        },
        "patternVacancies": {
          "description": "Pattern vacancies from the compilation. Without them `missing-part` never holds.",
          "type": "boolean"
        }
      }
    },
    "summary": {
      "type": "object",
      "additionalProperties": false,
      "required": [
        "questions",
        "openQuestions",
        "open"
      ],
      "properties": {
        "questions": {
          "type": "integer",
          "minimum": 0
        },
        "openQuestions": {
          "type": "integer",
          "minimum": 0
        },
        "open": {
          "type": "integer",
          "minimum": 0
        }
      }
    },
    "waves": {
      "type": "array",
      "items": {
        "$ref": "#/$defs/wave"
      }
    }
  },
  "$defs": {
    "wave": {
      "type": "object",
      "additionalProperties": false,
      "required": [
        "id",
        "name",
        "opened",
        "questions"
      ],
      "properties": {
        "id": {
          "type": "string",
          "minLength": 1
        },
        "name": {
          "type": "string",
          "minLength": 1
        },
        "opened": {
          "description": "Whether this wave's gate is met (#334, ADR 0125). A wave with no `opensWhen` is always true. A wave reported false asks nothing and carries no questions: they are premature rather than answered, which is the third state a progress rail needs so a closed wave is not counted as done. Its questions are excluded from `summary` for the same reason.",
          "type": "boolean"
        },
        "questions": {
          "type": "array",
          "items": {
            "$ref": "#/$defs/question"
          }
        }
      }
    },
    "question": {
      "type": "object",
      "additionalProperties": false,
      "required": [
        "id",
        "scope",
        "authority",
        "open",
        "question",
        "materiality",
        "resolution",
        "trigger"
      ],
      "properties": {
        "id": {
          "type": "string",
          "minLength": 1
        },
        "scope": {
          "enum": [
            "workspace",
            "subject"
          ]
        },
        "authority": {
          "enum": [
            "human",
            "agent",
            "either"
          ]
        },
        "open": {
          "type": "boolean"
        },
        "asked": {
          "type": "boolean",
          "description": "Whether the question was asked at all (#375, ADR 0132). Absent means true; only a subject-scoped question whose selector matched no subject carries asked: false. Without it, never-asked and answered were byte-identical (open: false), and a host summing closed questions read an empty model as a satisfied interview."
        },
        "question": {
          "type": "string",
          "minLength": 1
        },
        "materiality": {
          "type": "string",
          "minLength": 1
        },
        "resolution": {
          "type": "string",
          "minLength": 1
        },
        "trigger": {
          "description": "The catalogue trigger, verbatim: the conditions that opened this question, i.e. its machine-readable answer shape.",
          "type": "array",
          "minItems": 1,
          "items": {
            "$ref": "#/$defs/condition"
          }
        },
        "since": {
          "type": "string"
        },
        "subjects": {
          "type": "array",
          "minItems": 1,
          "items": {
            "$ref": "#/$defs/openSubject"
          }
        }
      }
    },
    "openSubject": {
      "type": "object",
      "additionalProperties": false,
      "required": [
        "id",
        "question"
      ],
      "properties": {
        "id": {
          "type": "string",
          "minLength": 1
        },
        "name": {
          "type": "string",
          "minLength": 1
        },
        "question": {
          "type": "string",
          "minLength": 1
        }
      }
    },
    "condition": {
      "description": "One deterministic trigger condition. All conditions in a trigger must hold (AND) for the question to be open.",
      "oneOf": [
        {
          "type": "object",
          "additionalProperties": false,
          "required": [
            "condition",
            "predicate"
          ],
          "properties": {
            "condition": {
              "const": "missing-claim"
            },
            "predicate": {
              "$ref": "#/$defs/claimPredicate"
            }
          }
        },
        {
          "type": "object",
          "additionalProperties": false,
          "required": [
            "condition",
            "kinds",
            "direction"
          ],
          "properties": {
            "condition": {
              "const": "missing-relationship"
            },
            "kinds": {
              "type": "array",
              "minItems": 1,
              "uniqueItems": true,
              "items": {
                "$ref": "#/$defs/qualifiedKind"
              }
            },
            "direction": {
              "enum": [
                "incoming",
                "outgoing",
                "any"
              ]
            },
            "kindMatching": {
              "enum": [
                "exact",
                "descendants"
              ]
            }
          }
        },
        {
          "type": "object",
          "additionalProperties": false,
          "required": [
            "condition"
          ],
          "properties": {
            "condition": {
              "const": "isolated"
            }
          }
        },
        {
          "type": "object",
          "additionalProperties": false,
          "required": [
            "condition",
            "kinds"
          ],
          "properties": {
            "condition": {
              "const": "no-subject-of-kind"
            },
            "kinds": {
              "type": "array",
              "minItems": 1,
              "uniqueItems": true,
              "items": {
                "$ref": "#/$defs/qualifiedKind"
              }
            },
            "kindMatching": {
              "enum": [
                "exact",
                "descendants"
              ],
              "default": "descendants"
            }
          }
        },
        {
          "type": "object",
          "additionalProperties": false,
          "required": [
            "condition",
            "kinds"
          ],
          "properties": {
            "condition": {
              "const": "has-subject-of-kind"
            },
            "kinds": {
              "type": "array",
              "minItems": 1,
              "uniqueItems": true,
              "items": {
                "$ref": "#/$defs/qualifiedKind"
              }
            },
            "kindMatching": {
              "enum": [
                "exact",
                "descendants"
              ],
              "default": "descendants"
            }
          }
        },
        {
          "type": "object",
          "additionalProperties": false,
          "required": [
            "condition",
            "kinds",
            "atLeast"
          ],
          "properties": {
            "condition": {
              "const": "below-subject-count"
            },
            "kinds": {
              "type": "array",
              "minItems": 1,
              "uniqueItems": true,
              "items": {
                "$ref": "#/$defs/qualifiedKind"
              }
            },
            "atLeast": {
              "description": "The floor the kind's population must reach. At least 2: atLeast 1 is no-subject-of-kind under another name, and the engine refuses it (YM918).",
              "type": "integer",
              "minimum": 1
            },
            "kindMatching": {
              "enum": [
                "exact",
                "descendants"
              ],
              "default": "descendants"
            }
          }
        },
        {
          "type": "object",
          "additionalProperties": false,
          "required": [
            "condition"
          ],
          "properties": {
            "condition": {
              "const": "no-state-defined"
            }
          }
        },
        {
          "type": "object",
          "additionalProperties": false,
          "required": [
            "condition",
            "kinds",
            "direction",
            "counterpartKinds"
          ],
          "properties": {
            "condition": {
              "const": "missing-linkage"
            },
            "kinds": {
              "type": "array",
              "minItems": 1,
              "uniqueItems": true,
              "items": {
                "$ref": "#/$defs/qualifiedKind"
              }
            },
            "direction": {
              "enum": [
                "outgoing",
                "incoming"
              ]
            },
            "counterpartKinds": {
              "type": "array",
              "minItems": 1,
              "uniqueItems": true,
              "items": {
                "$ref": "#/$defs/qualifiedKind"
              }
            },
            "kindMatching": {
              "enum": [
                "exact",
                "descendants"
              ],
              "default": "descendants"
            }
          }
        },
        {
          "type": "object",
          "additionalProperties": false,
          "required": [
            "condition",
            "kinds",
            "direction",
            "counterpartKinds"
          ],
          "properties": {
            "condition": {
              "const": "has-linkage"
            },
            "kinds": {
              "type": "array",
              "minItems": 1,
              "uniqueItems": true,
              "items": {
                "$ref": "#/$defs/qualifiedKind"
              }
            },
            "direction": {
              "enum": [
                "outgoing",
                "incoming",
                "either"
              ]
            },
            "counterpartKinds": {
              "type": "array",
              "minItems": 1,
              "uniqueItems": true,
              "items": {
                "$ref": "#/$defs/qualifiedKind"
              }
            },
            "kindMatching": {
              "enum": [
                "exact",
                "descendants"
              ],
              "default": "descendants"
            }
          }
        },
        {
          "type": "object",
          "additionalProperties": false,
          "required": [
            "condition",
            "kinds",
            "direction",
            "counterpartKinds"
          ],
          "properties": {
            "condition": {
              "const": "exists-linkage"
            },
            "kinds": {
              "type": "array",
              "minItems": 1,
              "uniqueItems": true,
              "items": {
                "$ref": "#/$defs/qualifiedKind"
              }
            },
            "direction": {
              "enum": [
                "outgoing",
                "incoming",
                "either"
              ]
            },
            "counterpartKinds": {
              "type": "array",
              "minItems": 1,
              "uniqueItems": true,
              "items": {
                "$ref": "#/$defs/qualifiedKind"
              }
            },
            "kindMatching": {
              "enum": [
                "exact",
                "descendants"
              ],
              "default": "descendants"
            }
          }
        },
        {
          "type": "object",
          "additionalProperties": false,
          "required": [
            "condition",
            "kinds",
            "direction",
            "counterpartKinds"
          ],
          "properties": {
            "condition": {
              "const": "no-linkage-exists"
            },
            "kinds": {
              "type": "array",
              "minItems": 1,
              "uniqueItems": true,
              "items": {
                "$ref": "#/$defs/qualifiedKind"
              }
            },
            "direction": {
              "enum": [
                "outgoing",
                "incoming",
                "either"
              ]
            },
            "counterpartKinds": {
              "type": "array",
              "minItems": 1,
              "uniqueItems": true,
              "items": {
                "$ref": "#/$defs/qualifiedKind"
              }
            },
            "kindMatching": {
              "enum": [
                "exact",
                "descendants"
              ],
              "default": "descendants"
            }
          }
        },
        {
          "type": "object",
          "additionalProperties": false,
          "required": [
            "condition",
            "kinds"
          ],
          "properties": {
            "condition": {
              "const": "missing-constraint"
            },
            "kinds": {
              "type": "array",
              "minItems": 1,
              "uniqueItems": true,
              "items": {
                "$ref": "#/$defs/qualifiedKind"
              }
            },
            "kindMatching": {
              "enum": [
                "exact",
                "descendants"
              ],
              "default": "descendants"
            }
          }
        },
        {
          "type": "object",
          "additionalProperties": false,
          "description": "The subject is an endpoint of at least one flow relationship that has no yarramate/flow/content claim.",
          "required": [
            "condition"
          ],
          "properties": {
            "condition": {
              "const": "missing-flow-content"
            }
          }
        },
        {
          "type": "object",
          "additionalProperties": false,
          "required": [
            "condition",
            "predicate",
            "direction"
          ],
          "properties": {
            "condition": {
              "const": "missing-reference"
            },
            "predicate": {
              "$ref": "#/$defs/claimPredicate"
            },
            "direction": {
              "enum": [
                "outgoing",
                "incoming"
              ]
            }
          }
        },
        {
          "type": "object",
          "additionalProperties": false,
          "required": [
            "condition",
            "topic"
          ],
          "properties": {
            "condition": {
              "const": "missing-attestation"
            },
            "topic": {
              "type": "string",
              "pattern": "^[a-z][a-z0-9-]*$"
            }
          }
        },
        {
          "type": "object",
          "additionalProperties": false,
          "description": "The subject resembles another subject of the same kind closely enough to be the same thing under two names, and no yarramate/identity/distinct-from claim dismisses the pair. Deterministic and lexical; the algorithm and thresholds are stated in ADR 0077. Questions using it may interpolate {counterparts}.",
          "required": [
            "condition"
          ],
          "properties": {
            "condition": {
              "const": "near-duplicate"
            }
          }
        },
        {
          "type": "object",
          "additionalProperties": false,
          "description": "The subject's kind is never tested by anything the compiler can check: it participates in no relationship whose kind pins the aspect at the subject's end, so reclassifying it to any other kind of any other aspect would still compile. The kind is a label rather than a constraint (ADR 0083).",
          "required": [
            "condition"
          ],
          "properties": {
            "condition": {
              "const": "unconstrained-kind"
            }
          }
        },
        {
          "type": "object",
          "additionalProperties": false,
          "description": "The subject supersedes a predecessor that is still current, and does not say in what respect. A succession that replaced its predecessor outright says so by the predecessor being gone; one where both remain is usually partial, and the respect is the part a reader needs (ADR 0109).",
          "required": [
            "condition"
          ],
          "properties": {
            "condition": {
              "const": "unscoped-succession"
            }
          }
        },
        {
          "type": "object",
          "additionalProperties": false,
          "description": "The workspace holds at least one concept (#334, ADR 0125). The guard a late wave needs to say \"only once the model has substance\": an empty model is not an architecture at rest, it has not started, and asking it how the planned architecture becomes real greets someone ahead of question one.",
          "required": [
            "condition"
          ],
          "properties": {
            "condition": {
              "const": "has-any-subject"
            }
          }
        },
        {
          "type": "object",
          "additionalProperties": false,
          "description": "The workspace's evidence overlay records observations and every one is a frictionless confirmation: no contradicted, unknown, or not-observed result, and no recorded search (ADR 0107). A discovery that never records anything but success never tested a claim it might fail. The one condition that reads the evidence overlay rather than the compiled graph; where the evaluating consumer supplies no overlay it stays quiet (ADR 0120).",
          "required": [
            "condition"
          ],
          "properties": {
            "condition": {
              "const": "unchallenged-evidence"
            }
          }
        }
      ]
    },
    "claimPredicate": {
      "type": "string",
      "pattern": "^[a-z][a-z0-9/@.#-]*$"
    },
    "qualifiedKind": {
      "type": "string",
      "pattern": "^[a-z][a-z0-9/-]*@[0-9][0-9A-Za-z.-]*#[A-Za-z][A-Za-z0-9-]*$"
    }
  }
}
