{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://artifacts.apis.io/infersports-dev/json-schema/infersports-dev-compare-prob-result-schema.json",
  "title": "CompareProbResult",
  "description": "Is an external probability good vs our sharp de-vigged fair line? DETECTION ONLY (read-only).\n\n``status``: ``ok`` (fair line found, edge computed), ``no_line`` (no sharp fair for that\nmarket/period — can't judge), ``ambiguous`` (alternatives + ask_user; never guessed), or\n``not_found``. ``edge_pp = (fair_prob − external_prob)·100`` (positive ⇒ the external YES price is\ncheap vs the sharp fair). The caller owns the prediction-market→probability mapping; ``caveats``\nflags the traps (1x2 regulation/draw, AH push mass, staleness).",
  "x-generated": "2026-11-12",
  "x-method": "derived",
  "x-generator": "derive-json-schema.py",
  "x-source": "openapi/infersports-dev-openapi.json#/components/schemas/CompareProbResult",
  "properties": {
    "status": {
      "type": "string",
      "title": "Status"
    },
    "query": {
      "type": "string",
      "title": "Query"
    },
    "summary": {
      "type": "string",
      "title": "Summary"
    },
    "match": {
      "anyOf": [
        {
          "$ref": "#/$defs/MatchSummary"
        },
        {
          "type": "null"
        }
      ]
    },
    "market_type": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "title": "Market Type"
    },
    "period": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "title": "Period"
    },
    "outcome": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "title": "Outcome"
    },
    "line": {
      "anyOf": [
        {
          "type": "number"
        },
        {
          "type": "null"
        }
      ],
      "title": "Line",
      "description": "Consensus line used (AH/totals; null for 1x2)."
    },
    "fair_prob": {
      "anyOf": [
        {
          "type": "number"
        },
        {
          "type": "null"
        }
      ],
      "title": "Fair Prob",
      "description": "Sharp de-vigged fair probability for `outcome` (0–1)."
    },
    "fair_decimal": {
      "anyOf": [
        {
          "type": "number"
        },
        {
          "type": "null"
        }
      ],
      "title": "Fair Decimal",
      "description": "Same fair value as decimal odds."
    },
    "fair_from": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "title": "Fair From",
      "description": "Bookmaker key the fair line was de-vigged from."
    },
    "external_prob": {
      "anyOf": [
        {
          "type": "number"
        },
        {
          "type": "null"
        }
      ],
      "title": "External Prob"
    },
    "external_label": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "title": "External Label"
    },
    "edge_pp": {
      "anyOf": [
        {
          "type": "number"
        },
        {
          "type": "null"
        }
      ],
      "title": "Edge Pp",
      "description": "(fair_prob − external_prob)·100, in percentage points. Positive ⇒ external YES is cheap."
    },
    "ev_roi": {
      "anyOf": [
        {
          "type": "number"
        },
        {
          "type": "null"
        }
      ],
      "title": "Ev Roi",
      "description": "Expected ROI buying YES at external_prob = edge/external_prob."
    },
    "verdict": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "title": "Verdict",
      "description": "good | marginal | no_edge (vs a market-shape noise floor)."
    },
    "devig_method": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "title": "Devig Method",
      "description": "proportional | power (power for 3-way 1x2)."
    },
    "as_of": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "title": "As Of"
    },
    "stale": {
      "anyOf": [
        {
          "type": "boolean"
        },
        {
          "type": "null"
        }
      ],
      "title": "Stale"
    },
    "caveats": {
      "items": {
        "type": "string"
      },
      "type": "array",
      "title": "Caveats",
      "description": "Mapping/freshness traps to respect before acting."
    },
    "alternatives": {
      "items": {
        "$ref": "#/$defs/MatchAlternative"
      },
      "type": "array",
      "title": "Alternatives"
    },
    "ask_user": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "title": "Ask User"
    }
  },
  "type": "object",
  "required": [
    "status",
    "query",
    "summary"
  ],
  "$defs": {
    "MatchAlternative": {
      "properties": {
        "event_id": {
          "type": "string",
          "title": "Event Id"
        },
        "label": {
          "type": "string",
          "title": "Label",
          "description": "'Home vs Away' label for disambiguation."
        },
        "confidence": {
          "type": "number",
          "title": "Confidence"
        }
      },
      "type": "object",
      "required": [
        "event_id",
        "label",
        "confidence"
      ],
      "title": "MatchAlternative",
      "description": "A runner-up fixture when a query is ambiguous."
    },
    "MatchSummary": {
      "properties": {
        "event_id": {
          "type": "string",
          "title": "Event Id",
          "description": "Canonical event id (evt_…); pass to get_match_odds / compare_lines."
        },
        "sport": {
          "type": "string",
          "title": "Sport",
          "description": "football | basketball"
        },
        "league": {
          "type": "string",
          "title": "League",
          "description": "League name, e.g. 'English Premier League'."
        },
        "home_team": {
          "type": "string",
          "title": "Home Team"
        },
        "away_team": {
          "type": "string",
          "title": "Away Team"
        },
        "scheduled_at": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "title": "Scheduled At",
          "description": "Kickoff, ISO-8601 UTC."
        },
        "scheduled_at_local": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "title": "Scheduled At Local",
          "description": "Kickoff in the requested timezone (ISO-8601); null when no timezone was given."
        },
        "status": {
          "type": "string",
          "title": "Status",
          "description": "scheduled | live | finished"
        },
        "score": {
          "anyOf": [
            {
              "$ref": "#/$defs/Score"
            },
            {
              "type": "null"
            }
          ],
          "description": "Current score when live, else null."
        },
        "red_cards": {
          "anyOf": [
            {
              "$ref": "#/$defs/Score"
            },
            {
              "type": "null"
            }
          ],
          "description": "Red cards per side; null when not tracked by upstream."
        },
        "clock": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "title": "Clock",
          "description": "Match clock when live, humanized for display: e.g. '1st half 25'', '2nd half 47'' (the real minute, not estimated) or 'half-time'; null pre-match or when the feed omits it. Basketball clocks (e.g. 'Q2 4:12') pass through as-is."
        },
        "confidence": {
          "anyOf": [
            {
              "type": "number"
            },
            {
              "type": "null"
            }
          ],
          "title": "Confidence",
          "description": "Fuzzy-match confidence 0–1 (find_match only; null elsewhere)."
        },
        "summary": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "title": "Summary",
          "description": "One-line human-readable status, e.g. \"Man City vs Arsenal — LIVE 1h 23 2-1.\" or \"… — Kicks off 18:00 UTC on Jun 01.\" — ready to read to a user."
        }
      },
      "type": "object",
      "required": [
        "event_id",
        "sport",
        "league",
        "home_team",
        "away_team",
        "status"
      ],
      "title": "MatchSummary",
      "description": "A fixture flattened for agent consumption (teams as names, optional live score)."
    },
    "Score": {
      "properties": {
        "home": {
          "type": "integer",
          "title": "Home"
        },
        "away": {
          "type": "integer",
          "title": "Away"
        }
      },
      "type": "object",
      "required": [
        "home",
        "away"
      ],
      "title": "Score"
    }
  }
}