{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://dsolisp.github.io/gavel/schemas/corpus-precision-report.schema.json",
  "title": "Gavel corpus precision report",
  "description": "Machine output of scripts/verify-corpus-precision.js. Irreversible interface (v0.8).",
  "type": "object",
  "additionalProperties": false,
  "required": ["schemaVersion", "generatedAt", "threshold", "tags"],
  "properties": {
    "schemaVersion": {
      "type": "string",
      "enum": ["1.0.0"]
    },
    "generatedAt": {
      "type": "string",
      "description": "ISO-8601 timestamp."
    },
    "threshold": {
      "type": "number",
      "minimum": 0,
      "maximum": 1,
      "description": "Precision floor applied for exit code (0.90 report→warning, 0.95 warning→blocker)."
    },
    "tags": {
      "type": "array",
      "items": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "tag",
          "precision",
          "truePositives",
          "falsePositives",
          "falseNegatives",
          "flagged",
          "languages",
          "pass"
        ],
        "properties": {
          "tag": { "type": "string" },
          "precision": {
            "type": ["number", "null"],
            "description": "TP / flagged. null when flagged=0 (no findings)."
          },
          "truePositives": { "type": "integer", "minimum": 0 },
          "falsePositives": { "type": "integer", "minimum": 0 },
          "falseNegatives": { "type": "integer", "minimum": 0 },
          "fieldMismatches": {
            "type": "integer",
            "minimum": 0,
            "description": "Findings on the right line+tag but with wrong subCase/replaceable/pollingLoop/suggestion (field-lock violations)."
          },
          "flagged": {
            "type": "integer",
            "minimum": 0,
            "description": "Findings for this tag across corpus samples (TP + FP)."
          },
          "languages": {
            "type": "array",
            "items": { "type": "string" }
          },
          "pass": {
            "type": "boolean",
            "description": "true when precision meets threshold (or flagged=0 with zero FN). Always true when pendingScanner."
          },
          "pendingScanner": {
            "type": "boolean",
            "description": "true when the tag has a corpus but no RULES entry yet (contract-first). Precision is null; FNs do not fail."
          },
          "falsePositiveFindings": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": false,
              "required": ["file", "line", "tag"],
              "properties": {
                "file": { "type": "string" },
                "line": { "type": "integer", "minimum": 1 },
                "tag": { "type": "string" }
              }
            }
          },
          "falseNegativeFindings": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": false,
              "required": ["file", "line", "tag"],
              "properties": {
                "file": { "type": "string" },
                "line": { "type": "integer", "minimum": 1 },
                "tag": { "type": "string" }
              }
            }
          },
          "fieldMismatchFindings": {
            "type": "array",
            "description": "Findings that matched an expected line+tag but failed a field lock (subCase/replaceable/pollingLoop/suggestion).",
            "items": {
              "type": "object",
              "additionalProperties": false,
              "required": ["file", "line", "tag", "mismatches"],
              "properties": {
                "file": { "type": "string" },
                "line": { "type": "integer", "minimum": 1 },
                "tag": { "type": "string" },
                "mismatches": {
                  "type": "array",
                  "items": { "type": "string" }
                }
              }
            }
          }
        }
      }
    }
  }
}
