{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://ayagmar.github.io/llm-usage-metrics/report-blocks.v1.schema.json",
  "title": "llm-usage-metrics blocks report output (v1)",
  "description": "Envelope and payload for blocks --json output: estimated 5-hour usage blocks per source, across machines.",
  "type": "object",
  "allOf": [
    {
      "$ref": "https://ayagmar.github.io/llm-usage-metrics/report-common.v1.schema.json#/$defs/envelope"
    }
  ],
  "properties": {
    "report": { "const": "blocks" },
    "data": {
      "description": "Estimated blocks in the window, and the blocks containing now.",
      "type": "object",
      "properties": {
        "estimated": {
          "description": "Always true: blocks follow a community convention, not data from the provider.",
          "const": true
        },
        "blockHours": {
          "description": "Length of a block in hours.",
          "type": "integer",
          "minimum": 1
        },
        "timezone": {
          "description": "IANA timezone of the date window.",
          "type": "string"
        },
        "since": {
          "description": "First day of the window (YYYY-MM-DD); null for the full history.",
          "type": ["string", "null"]
        },
        "until": {
          "description": "Last day of the window (YYYY-MM-DD); null when open-ended.",
          "type": ["string", "null"]
        },
        "top": {
          "description": "With --top: the number of blocks asked for and what ranked them; null otherwise.",
          "oneOf": [
            { "type": "null" },
            {
              "type": "object",
              "properties": {
                "count": { "type": "integer", "minimum": 1 },
                "rankedBy": { "enum": ["cost", "tokens"] }
              },
              "required": ["count", "rankedBy"],
              "additionalProperties": false
            }
          ]
        },
        "blockCount": {
          "description": "Blocks in the window before --top.",
          "type": "integer",
          "minimum": 0
        },
        "blocks": {
          "description": "Blocks in time order, or by rank with --top.",
          "type": "array",
          "items": { "$ref": "#/$defs/block" }
        },
        "activeBlocks": {
          "description": "Blocks containing now, whether or not --top shows them; empty when the window ended before today.",
          "type": "array",
          "items": { "$ref": "#/$defs/block" }
        }
      },
      "required": [
        "estimated",
        "blockHours",
        "timezone",
        "since",
        "until",
        "top",
        "blockCount",
        "blocks",
        "activeBlocks"
      ],
      "additionalProperties": false
    }
  },
  "$defs": {
    "modelBreakdown": {
      "type": "object",
      "description": "Usage of one model within the block.",
      "allOf": [
        {
          "$ref": "https://ayagmar.github.io/llm-usage-metrics/report-common.v1.schema.json#/$defs/usageTotals"
        }
      ],
      "properties": {
        "model": { "description": "Normalized model name.", "type": "string" }
      },
      "required": ["model"],
      "unevaluatedProperties": false
    },
    "burnRate": {
      "type": "object",
      "description": "Usage per hour since the block started (at least one minute), for the block containing now.",
      "properties": {
        "remainingMinutes": {
          "description": "Whole minutes until the block ends, rounded up.",
          "type": "integer",
          "minimum": 1
        },
        "tokensPerHour": { "type": "integer", "minimum": 0 },
        "costUsdPerHour": {
          "description": "Omitted when no event of the block has a cost.",
          "type": "number",
          "minimum": 0
        },
        "costIncomplete": {
          "description": "True when the block's cost is incomplete, so the cost rate is a lower bound.",
          "type": "boolean"
        }
      },
      "required": ["remainingMinutes", "tokensPerHour"],
      "additionalProperties": false
    },
    "block": {
      "type": "object",
      "description": "One estimated block: it starts at the UTC hour of the source's first event at or after the previous block's end and lasts blockHours.",
      "allOf": [
        {
          "$ref": "https://ayagmar.github.io/llm-usage-metrics/report-common.v1.schema.json#/$defs/usageTotals"
        }
      ],
      "properties": {
        "source": {
          "description": "Source id; one stream per source across machines.",
          "type": "string"
        },
        "start": { "description": "ISO timestamp of the block start.", "type": "string" },
        "end": { "description": "ISO timestamp of the block end (exclusive).", "type": "string" },
        "startUncertain": {
          "description": "True when usage before the days read may have started the chain earlier, so the start may differ.",
          "type": "boolean"
        },
        "firstEventAt": {
          "description": "ISO timestamp of the block's first event.",
          "type": "string"
        },
        "lastEventAt": {
          "description": "ISO timestamp of the block's last event.",
          "type": "string"
        },
        "eventCount": { "type": "integer", "minimum": 1 },
        "models": {
          "description": "Models used in the block, most tokens first.",
          "type": "array",
          "items": { "type": "string" }
        },
        "modelBreakdown": {
          "type": "array",
          "items": { "$ref": "#/$defs/modelBreakdown" }
        },
        "active": {
          "description": "The burn rate when the block contains now; null otherwise.",
          "oneOf": [{ "type": "null" }, { "$ref": "#/$defs/burnRate" }]
        }
      },
      "required": [
        "source",
        "start",
        "end",
        "startUncertain",
        "firstEventAt",
        "lastEventAt",
        "eventCount",
        "models",
        "modelBreakdown",
        "active"
      ],
      "unevaluatedProperties": false
    }
  }
}
