{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "$id": "https://clean-slop.vercel.app/docs/schema/scan-result.schema.json",
  "title": "clean-slop ScanResult",
  "description": "The shape of clean-slop's --reporter json output. Stable across patch/minor releases; a breaking shape change will be called out in CHANGELOG.md under a major version bump.",
  "type": "object",
  "required": ["root", "timestamp", "version", "files", "issues", "score", "durationMs"],
  "properties": {
    "root": { "type": "string", "description": "Absolute path of the scanned project root" },
    "timestamp": { "type": "string", "format": "date-time", "description": "ISO timestamp of the scan" },
    "version": { "type": "string", "description": "clean-slop version that produced this result" },
    "durationMs": { "type": "number" },
    "files": {
      "type": "array",
      "items": {
        "type": "object",
        "required": ["file", "issues"],
        "properties": {
          "file": { "type": "string" },
          "issues": { "type": "array", "items": { "$ref": "#/definitions/issue" } },
          "parseError": { "type": "string" },
          "skipped": { "type": "boolean" },
          "skipReason": { "type": "string" }
        }
      }
    },
    "issues": { "type": "array", "items": { "$ref": "#/definitions/issue" } },
    "score": {
      "type": "object",
      "required": ["overall", "categories", "grade", "productionReady", "partialCoverage", "coveragePercent"],
      "properties": {
        "overall": { "type": "number", "minimum": 0, "maximum": 100 },
        "grade": { "type": "string", "enum": ["A", "B", "C", "D", "F"] },
        "productionReady": {
          "type": "boolean",
          "description": "The hard pass/fail gate (score >= failThreshold AND maxIssues satisfied). Tracked separately from `overall` so the two can never contradict each other."
        },
        "partialCoverage": {
          "type": "boolean",
          "description": "True when one or more files failed to parse and were excluded from scoring."
        },
        "coveragePercent": {
          "type": "number",
          "minimum": 0,
          "maximum": 100,
          "description": "Percentage of discovered files that were actually scanned."
        },
        "categories": {
          "type": "array",
          "items": {
            "type": "object",
            "required": ["category", "score", "issueCount"],
            "properties": {
              "category": {
                "type": "string",
                "enum": ["ai-slop", "security", "reliability", "maintainability", "production-readiness"]
              },
              "score": { "type": "number", "minimum": 0, "maximum": 100 },
              "issueCount": { "type": "integer" },
              "criticalCount": { "type": "integer" },
              "highCount": { "type": "integer" },
              "mediumCount": { "type": "integer" },
              "lowCount": { "type": "integer" }
            }
          }
        }
      }
    }
  },
  "definitions": {
    "issue": {
      "type": "object",
      "required": ["ruleId", "ruleName", "category", "severity", "confidence", "message", "explanation", "impact", "location"],
      "properties": {
        "ruleId": { "type": "string", "description": "e.g. \"security/sql-injection\"" },
        "ruleName": { "type": "string" },
        "category": {
          "type": "string",
          "enum": ["ai-slop", "security", "reliability", "maintainability", "production-readiness"]
        },
        "severity": { "type": "string", "enum": ["critical", "high", "medium", "low", "info"] },
        "confidence": { "type": "string", "enum": ["certain", "high", "medium", "low"] },
        "message": { "type": "string" },
        "explanation": { "type": "string" },
        "impact": { "type": "string" },
        "docsUrl": { "type": "string", "format": "uri" },
        "snippet": { "type": "string" },
        "location": {
          "type": "object",
          "required": ["file", "line"],
          "properties": {
            "file": { "type": "string" },
            "line": { "type": "integer" },
            "column": { "type": "integer" },
            "endLine": { "type": "integer" },
            "endColumn": { "type": "integer" }
          }
        },
        "fix": {
          "type": "object",
          "properties": {
            "description": { "type": "string" },
            "code": { "type": "string" }
          }
        }
      }
    }
  }
}
