{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://artifacts.apis.io/flashodds-live/json-schema/flashodds-live-grade-response-schema.json",
  "title": "GradeResponse",
  "x-generated": "2026-10-30",
  "x-method": "derived",
  "x-generator": "derive-json-schema.py",
  "x-source": "openapi/_original/flashodds-live-api-openapi.json#/components/schemas/GradeResponse",
  "type": "object",
  "required": [
    "outcome_id",
    "claim",
    "fair_at_time",
    "fair_close",
    "result",
    "provenance"
  ],
  "properties": {
    "outcome_id": {
      "type": "string"
    },
    "claim": {
      "type": "object",
      "properties": {
        "observed_at": {
          "type": "string",
          "format": "date-time"
        },
        "probability": {
          "type": "number",
          "description": "Your price, normalized to an implied probability."
        },
        "venue": {
          "type": [
            "string",
            "null"
          ]
        }
      }
    },
    "fair_at_time": {
      "$ref": "#/$defs/GradeBenchmarkPoint"
    },
    "fair_close": {
      "$ref": "#/$defs/GradeBenchmarkPoint"
    },
    "edge_at_time_pts": {
      "type": [
        "number",
        "null"
      ],
      "description": "(fair at time - your probability) x 100. Positive means you took the outcome cheaper than the record said it was worth at that moment. Null when the anchor is unavailable; never zero."
    },
    "clv_pts": {
      "type": [
        "number",
        "null"
      ],
      "description": "(Sorqen Close - your probability) x 100. Closing-line value. Null until the close is frozen; never zero."
    },
    "result": {
      "$ref": "#/$defs/GradeResult"
    },
    "provenance": {
      "type": "object",
      "description": "Deterministic: the same claim graded against the same record yields the same hash. No signature field is emitted, because Sorqen does not yet publish a verification key and a cryptographic-looking placeholder would be worse than none.",
      "properties": {
        "grade_method_version": {
          "type": "string"
        },
        "grade_inputs_hash": {
          "type": "string"
        }
      }
    }
  },
  "$defs": {
    "GradeBenchmarkPoint": {
      "type": "object",
      "required": [
        "state"
      ],
      "description": "One anchor. `available` carries the numbers; `pending` means ask again later; `unavailable` means it will never exist. A missing anchor is never reported as zero.",
      "properties": {
        "state": {
          "type": "string",
          "enum": [
            "available",
            "pending",
            "unavailable"
          ]
        },
        "reason": {
          "type": "string",
          "description": "Present when the state is not available."
        },
        "probability": {
          "type": "number",
          "minimum": 0,
          "maximum": 1
        },
        "confidence": {
          "type": [
            "number",
            "null"
          ]
        },
        "dispersion": {
          "type": [
            "number",
            "null"
          ]
        },
        "books": {
          "type": "integer"
        },
        "method_version": {
          "type": "string"
        },
        "observed_at": {
          "type": "string",
          "format": "date-time"
        },
        "frozen_at": {
          "type": "string",
          "format": "date-time",
          "description": "When Sorqen named this observation a benchmark. Close only."
        },
        "policy_version": {
          "type": "string",
          "description": "Which benchmark selection policy chose it. Close only."
        },
        "inputs_hash": {
          "type": "string",
          "description": "Recomputable from the stored benchmark row. Close only."
        }
      }
    },
    "GradeResult": {
      "type": "object",
      "required": [
        "state"
      ],
      "properties": {
        "state": {
          "type": "string",
          "enum": [
            "settled",
            "pending",
            "unavailable"
          ]
        },
        "reason": {
          "type": "string"
        },
        "won": {
          "type": [
            "boolean",
            "null"
          ],
          "description": "Null on a push, where nobody won."
        },
        "push": {
          "type": "boolean"
        },
        "final_score_home": {
          "type": [
            "integer",
            "null"
          ]
        },
        "final_score_away": {
          "type": [
            "integer",
            "null"
          ]
        },
        "settled_at": {
          "type": "string",
          "format": "date-time"
        }
      }
    }
  }
}