{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://river-review.the3396.com/schemas/review-artifact.schema.json",
  "title": "River Review Review Artifact",
  "description": "Structured output for a complete River Review run, covering plan, context, findings, and debug info.",
  "type": "object",
  "required": ["version", "timestamp", "phase", "status"],
  "additionalProperties": false,
  "properties": {
    "version": {
      "type": "string",
      "const": "1",
      "description": "Schema version. Always \"1\" for this revision. New schemas should be created as separate files (e.g. review-artifact.v2.schema.json) per the versioning policy in pages/reference/stable-interfaces.md."
    },
    "timestamp": {
      "type": "string",
      "format": "date-time",
      "description": "ISO 8601 timestamp of when the review run completed."
    },
    "phase": {
      "type": "string",
      "enum": ["upstream", "midstream", "downstream"],
      "description": "SDLC phase the review was executed against."
    },
    "status": {
      "type": "string",
      "enum": ["ok", "no-changes", "skipped-by-label", "error"],
      "description": "Terminal status of the review run."
    },
    "plan": {
      "type": "object",
      "description": "Execution plan computed before the review.",
      "additionalProperties": false,
      "properties": {
        "selectedSkills": {
          "type": "array",
          "description": "Skills that were selected for execution.",
          "items": {
            "type": "object",
            "required": ["id", "name"],
            "additionalProperties": false,
            "properties": {
              "id": {
                "type": "string",
                "description": "Unique skill identifier."
              },
              "name": {
                "type": "string",
                "description": "Human-readable skill name."
              },
              "phase": {
                "type": "string",
                "enum": ["upstream", "midstream", "downstream"],
                "description": "Phase the skill targets."
              },
              "modelHint": {
                "type": "string",
                "enum": ["cheap", "balanced", "high-accuracy"],
                "description": "Preferred model tier hint. Mirrors the ModelHintEnum used in src/lib/skillYamlSchema.mjs."
              }
            }
          }
        },
        "skippedSkills": {
          "type": "array",
          "description": "Skills that were excluded from the run and the reasons why.",
          "items": {
            "type": "object",
            "required": ["id", "reasons"],
            "additionalProperties": false,
            "properties": {
              "id": {
                "type": "string",
                "description": "Unique skill identifier."
              },
              "reasons": {
                "type": "array",
                "items": { "type": "string" },
                "description": "List of reasons the skill was skipped."
              }
            }
          }
        },
        "plannerMode": {
          "type": "string",
          "enum": ["off", "order", "prune"],
          "description": "Mode the AI planner was invoked with."
        },
        "plannerReasons": {
          "type": "array",
          "description": "Per-skill reasoning produced by the AI planner.",
          "items": {
            "type": "object",
            "required": ["id", "reason"],
            "additionalProperties": false,
            "properties": {
              "id": {
                "type": "string",
                "description": "Skill identifier."
              },
              "reason": {
                "type": "string",
                "description": "Explanation from the planner."
              }
            }
          }
        },
        "impactTags": {
          "type": "array",
          "items": { "type": "string" },
          "description": "Tags describing the impact area of the changes (e.g. security, performance)."
        }
      }
    },
    "findings": {
      "type": "array",
      "description": "Review findings produced during the run. Each item conforms to the issue schema in output.schema.json.",
      "items": { "$ref": "#/$defs/finding" }
    },
    "context": {
      "type": "object",
      "description": "Repository and diff context captured at review time.",
      "additionalProperties": false,
      "properties": {
        "repoRoot": {
          "type": "string",
          "description": "Absolute path to the repository root."
        },
        "defaultBranch": {
          "type": "string",
          "description": "Default branch name (e.g. main)."
        },
        "mergeBase": {
          "type": "string",
          "description": "Git merge-base commit SHA used for diffing."
        },
        "changedFiles": {
          "type": "array",
          "items": { "type": "string" },
          "description": "List of file paths included in the review diff."
        },
        "tokenEstimate": {
          "type": "number",
          "minimum": 0,
          "description": "Estimated token count of the optimized diff text."
        },
        "rawTokenEstimate": {
          "type": "number",
          "minimum": 0,
          "description": "Estimated token count of the raw (unoptimized) diff text."
        },
        "reduction": {
          "type": "number",
          "minimum": 0,
          "maximum": 100,
          "description": "Percentage of tokens saved by diff optimization (0-100)."
        }
      }
    },
    "debug": {
      "type": "object",
      "additionalProperties": true,
      "description": "Free-form debug information. Structure is not guaranteed across versions.",
      "properties": {
        "execution": {
          "type": "object",
          "additionalProperties": true,
          "description": "Execution-stage diagnostics. Additive over time.",
          "properties": {
            "snapshot": {
              "type": "object",
              "additionalProperties": true,
              "description": "Carry-over context written by buildExecutionPlan and consumed by --plan replay execution (#878 A2-3). Used to avoid context-snapshot drift between plan and replay time. Optional; absent on older artifacts.",
              "properties": {
                "fileTypes": {
                  "type": "array",
                  "items": { "type": "string" },
                  "description": "File-type tags derived at plan creation time."
                },
                "relatedADRs": {
                  "type": "array",
                  "items": { "type": "string" },
                  "description": "Architecture Decision Records related to the change at plan creation time."
                },
                "reviewMode": {
                  "type": "string",
                  "description": "Review mode resolved at plan creation time."
                },
                "riskAssessment": {
                  "type": "object",
                  "additionalProperties": true,
                  "description": "Risk-map evaluation result captured at plan creation time."
                }
              }
            }
          }
        }
      }
    }
  },
  "$defs": {
    "finding": {
      "type": "object",
      "description": "A single review finding. Mirrors the issue schema in output.schema.json so that findings can be cross-validated by both schemas.",
      "required": ["id", "ruleId", "title", "message", "severity", "phase", "file"],
      "additionalProperties": false,
      "properties": {
        "id": {
          "type": "string",
          "description": "Unique identifier for the issue within this run.",
          "minLength": 1
        },
        "ruleId": {
          "type": "string",
          "description": "Identifier of the rule or skill that produced the issue.",
          "minLength": 1
        },
        "title": {
          "type": "string",
          "description": "Short human-readable title for the issue.",
          "minLength": 1
        },
        "message": {
          "type": "string",
          "description": "Detailed explanation of the issue and context.",
          "minLength": 1
        },
        "severity": {
          "type": "string",
          "description": "Severity level assigned to the issue.",
          "enum": ["info", "minor", "major", "critical"]
        },
        "phase": {
          "type": "string",
          "description": "SDLC phase where this issue was found.",
          "enum": ["upstream", "midstream", "downstream"]
        },
        "file": {
          "type": "string",
          "description": "File path or logical name relevant to the issue.",
          "minLength": 1
        },
        "line": {
          "type": "integer",
          "description": "Line number related to the issue when applicable.",
          "minimum": 1
        },
        "lineEnd": {
          "type": "integer",
          "description": "End line number for multi-line issues.",
          "minimum": 1
        },
        "confidence": {
          "type": "string",
          "description": "Confidence level of the finding.",
          "enum": ["high", "medium", "low"]
        },
        "status": {
          "type": "string",
          "description": "Current lifecycle status of the finding.",
          "enum": ["open", "suppressed", "verified"]
        },
        "evidence": {
          "type": "array",
          "description": "Evidence snippets supporting this finding.",
          "items": { "type": "string" }
        },
        "reviewer": {
          "type": "string",
          "description": "Identifier of the skill or agent that produced this finding."
        },
        "suggestion": {
          "type": "string",
          "description": "Optional fix or follow-up hint."
        },
        "sourceKind": {
          "type": "string",
          "description": "Provenance kind for synthesis layers (e.g. Independent Review Synthesis). Optional; absent for findings produced by core skills.",
          "enum": ["ai-review", "human-review", "self-review"]
        },
        "agreement": {
          "type": "array",
          "description": "Auxiliary metadata listing reviewer identifiers that independently raised this finding (after dedup). Synthesis layers MUST NOT use this for majority-vote decisions; severity is decided on evidence quality.",
          "items": { "type": "string", "minLength": 1 },
          "uniqueItems": true
        },
        "validatedStatus": {
          "type": "string",
          "description": "Synthesis verdict for the finding. Distinct from `status` (which tracks lifecycle: open/suppressed/verified).",
          "enum": [
            "confirmed",
            "dismissed-hallucination",
            "dismissed-duplicate",
            "needs-human-judgment"
          ]
        }
      }
    }
  }
}
