{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "title": "CheckOutcomeView",
  "description": "JSON shape emitted by `pathlint check --json`. Each outcome is rendered as one element of a top-level array.\n\n0.0.15 renamed the discriminator field from `status` to `kind` so it matches doctor / trace / sort / catalog relations. Schema is generated by `cargo run --bin gen_check_schema` and shipped at `schemas/check.schema.json`.",
  "type": "object",
  "required": [
    "avoid",
    "command",
    "kind",
    "matched_sources",
    "prefer",
    "severity"
  ],
  "properties": {
    "avoid": {
      "type": "array",
      "items": {
        "type": "string"
      }
    },
    "command": {
      "type": "string"
    },
    "diagnosis": {
      "anyOf": [
        {
          "$ref": "#/definitions/Diagnosis"
        },
        {
          "type": "null"
        }
      ]
    },
    "kind": {
      "description": "Outcome kind discriminator: `\"ok\"`, `\"ng_wrong_source\"`, `\"ng_unknown_source\"`, `\"ng_not_found\"`, `\"ng_not_executable\"`, `\"skip\"`, `\"not_applicable\"`, or `\"config_error\"`.",
      "allOf": [
        {
          "$ref": "#/definitions/Status"
        }
      ]
    },
    "matched_sources": {
      "type": "array",
      "items": {
        "type": "string"
      }
    },
    "prefer": {
      "type": "array",
      "items": {
        "type": "string"
      }
    },
    "resolved": {
      "type": [
        "string",
        "null"
      ]
    },
    "severity": {
      "description": "Per-rule severity copied from the Outcome. Always emitted (even for `error`, the default) so a downstream consumer gating on severity does not need a fallback for the absent case.",
      "allOf": [
        {
          "$ref": "#/definitions/Severity"
        }
      ]
    }
  },
  "definitions": {
    "Diagnosis": {
      "description": "Pure-data view of *why* an outcome failed. Derived from `Outcome` by `diagnose`; kept separate so the presentation layer renders strings from a structured value rather than from raw `Outcome` fields. `serde::Serialize` so the same value can drive `check --json`.\n\nVariants name the failure mode; the fields are the load-bearing facts callers need: which sources were missed (`prefer_missed`), which `avoid` names were hit (`avoid_hits`), the reason the shape check rejected the file, etc. The struct does *not* carry `command` / `resolved` — those live on `Outcome` and the caller pairs them up.",
      "oneOf": [
        {
          "description": "Resolved path matched some sources, but none of the `prefer` set — or it matched a source listed under `avoid`. `avoid_hits` is the intersection of `matched ∩ avoid`; non-empty means the rule explicitly forbids this source. `prefer_missed` is `prefer` itself (every name the user hoped for); rendering decides whether to show it.",
          "type": "object",
          "required": [
            "avoid_hits",
            "kind",
            "matched",
            "prefer_missed"
          ],
          "properties": {
            "avoid_hits": {
              "type": "array",
              "items": {
                "type": "string"
              }
            },
            "kind": {
              "type": "string",
              "enum": [
                "wrong_source"
              ]
            },
            "matched": {
              "type": "array",
              "items": {
                "type": "string"
              }
            },
            "prefer_missed": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          }
        },
        {
          "description": "Path lies outside every defined `[source.<name>]`. No source name matched at all.",
          "type": "object",
          "required": [
            "kind",
            "prefer"
          ],
          "properties": {
            "kind": {
              "type": "string",
              "enum": [
                "unknown_source"
              ]
            },
            "prefer": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          }
        },
        {
          "description": "Command was not on PATH, and the rule was not optional.",
          "type": "object",
          "required": [
            "kind",
            "prefer"
          ],
          "properties": {
            "kind": {
              "type": "string",
              "enum": [
                "not_found"
              ]
            },
            "prefer": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          }
        },
        {
          "description": "`kind = \"executable\"` shape check rejected the resolved file. `reason` is the short human-readable cause from `lint` (`\"is a directory\"`, `\"broken symlink\"`, …).",
          "type": "object",
          "required": [
            "kind",
            "matched",
            "reason"
          ],
          "properties": {
            "kind": {
              "type": "string",
              "enum": [
                "not_executable"
              ]
            },
            "matched": {
              "type": "array",
              "items": {
                "type": "string"
              }
            },
            "reason": {
              "type": "string"
            }
          }
        },
        {
          "description": "`[[expect]]` referenced a source name that is not defined.",
          "type": "object",
          "required": [
            "kind",
            "message"
          ],
          "properties": {
            "kind": {
              "type": "string",
              "enum": [
                "config"
              ]
            },
            "message": {
              "type": "string"
            }
          }
        }
      ]
    },
    "Severity": {
      "description": "Per-rule severity for `[[expect]]`. Defaults to `Error` so 0.0.x rules behave exactly as before.",
      "oneOf": [
        {
          "description": "NG escalates to exit 1. Default.",
          "type": "string",
          "enum": [
            "error"
          ]
        },
        {
          "description": "NG is reported but does not change the exit code.",
          "type": "string",
          "enum": [
            "warn"
          ]
        }
      ]
    },
    "Status": {
      "oneOf": [
        {
          "type": "string",
          "enum": [
            "ok",
            "ng_wrong_source",
            "ng_unknown_source",
            "ng_not_found",
            "skip",
            "not_applicable"
          ]
        },
        {
          "description": "R2 — resolved path failed `kind` shape check (directory, broken symlink, missing exec bit, etc.). Carries a short human-readable reason.",
          "type": "object",
          "required": [
            "ng_not_executable"
          ],
          "properties": {
            "ng_not_executable": {
              "type": "string"
            }
          },
          "additionalProperties": false
        },
        {
          "type": "object",
          "required": [
            "config_error"
          ],
          "properties": {
            "config_error": {
              "type": "string"
            }
          },
          "additionalProperties": false
        }
      ]
    }
  }
}
