{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://cortex.beyond-power.com/skills/voltra-live-stream/references/stream-schema.json",
  "title": "VOLTRA User Live Training Stream",
  "description": "One user-facing NDJSON event emitted by voltra stream.",
  "oneOf": [
    {
      "$ref": "#/$defs/streamStart"
    },
    {
      "$ref": "#/$defs/workoutState"
    },
    {
      "$ref": "#/$defs/rep"
    },
    {
      "$ref": "#/$defs/progress"
    },
    {
      "$ref": "#/$defs/setSummary"
    },
    {
      "$ref": "#/$defs/workoutSummary"
    },
    {
      "$ref": "#/$defs/dataQuality"
    },
    {
      "$ref": "#/$defs/connectionLost"
    },
    {
      "$ref": "#/$defs/reconnected"
    },
    {
      "$ref": "#/$defs/streamEnd"
    }
  ],
  "$defs": {
    "base": {
      "type": "object",
      "required": [
        "event",
        "schema",
        "timestamp",
        "sequence",
        "streamId",
        "deviceId",
        "connectionId"
      ],
      "properties": {
        "event": {
          "type": "string",
          "enum": [
            "streamStart",
            "workoutState",
            "rep",
            "progress",
            "setSummary",
            "workoutSummary",
            "dataQuality",
            "connectionLost",
            "reconnected",
            "streamEnd"
          ]
        },
        "schema": {
          "const": "voltra.training.v7"
        },
        "timestamp": {
          "type": "string",
          "format": "date-time"
        },
        "sequence": {
          "type": "integer",
          "minimum": 0
        },
        "streamId": {
          "type": "string",
          "format": "uuid"
        },
        "deviceId": {
          "type": "string",
          "minLength": 1
        },
        "connectionId": {
          "type": "integer",
          "minimum": 1
        }
      }
    },
    "trainingMode": {
      "type": "string",
      "enum": ["weightTraining", "resistanceBand", "damper", "isokinetic"]
    },
    "units": {
      "type": "object",
      "required": ["weight", "distance", "velocity", "power"],
      "properties": {
        "weight": {
          "type": "string",
          "enum": ["lbs", "kg"]
        },
        "distance": {
          "const": "mm"
        },
        "velocity": {
          "const": "mm/s"
        },
        "power": {
          "const": "W"
        }
      },
      "additionalProperties": false
    },
    "directionMetrics": {
      "type": "object",
      "required": [
        "maxForce",
        "meanForce",
        "maxVelocityMmPerSecond",
        "meanVelocityMmPerSecond",
        "maxPowerWatt",
        "meanPowerWatt"
      ],
      "properties": {
        "maxForce": {
          "type": "number",
          "minimum": 0,
          "multipleOf": 0.01
        },
        "meanForce": {
          "type": "number",
          "minimum": 0,
          "multipleOf": 0.01
        },
        "maxVelocityMmPerSecond": {
          "type": "integer",
          "minimum": 0
        },
        "meanVelocityMmPerSecond": {
          "type": "integer",
          "minimum": 0
        },
        "maxPowerWatt": {
          "type": "integer",
          "minimum": 0
        },
        "meanPowerWatt": {
          "type": "integer",
          "minimum": 0
        }
      },
      "additionalProperties": false
    },
    "streamStart": {
      "allOf": [
        {
          "$ref": "#/$defs/base"
        },
        {
          "type": "object",
          "required": ["event", "trainingMode", "units"],
          "properties": {
            "event": {
              "const": "streamStart"
            },
            "trainingMode": {
              "$ref": "#/$defs/trainingMode",
              "description": "First supported training mode observed by the public stream. If the device starts in an unsupported mode, streamStart is delayed until a supported mode is observed."
            },
            "units": {
              "$ref": "#/$defs/units"
            }
          }
        }
      ],
      "unevaluatedProperties": false
    },
    "workoutState": {
      "allOf": [
        {
          "$ref": "#/$defs/base"
        },
        {
          "type": "object",
          "required": ["event", "trainingMode", "workoutState", "powerEnabled"],
          "properties": {
            "event": {
              "const": "workoutState"
            },
            "trainingMode": {
              "$ref": "#/$defs/trainingMode"
            },
            "workoutState": {
              "type": "string",
              "enum": [
                "idle",
                "waitToBegin",
                "workout",
                "rest",
                "ceasePower",
                "end",
                "unknown"
              ]
            },
            "powerEnabled": {
              "type": "boolean"
            },
            "baseWeight": {
              "type": "number",
              "multipleOf": 0.01
            },
            "chainsWeight": {
              "type": "number",
              "multipleOf": 0.01
            },
            "eccentricWeight": {
              "type": "number",
              "multipleOf": 0.01
            },
            "resistanceBandWeight": {
              "type": "number",
              "minimum": 0,
              "multipleOf": 0.01
            },
            "targetVelocityMmPerSecond": {
              "type": "integer",
              "minimum": 0
            },
            "level": {
              "type": "integer",
              "minimum": 1,
              "maximum": 10
            }
          }
        }
      ],
      "unevaluatedProperties": false
    },
    "rep": {
      "allOf": [
        {
          "$ref": "#/$defs/base"
        },
        {
          "type": "object",
          "required": [
            "event",
            "setIndex",
            "repIndex",
            "direction",
            "valid",
            "distanceMm",
            "peakVelocityMmPerSecond",
            "peakPowerWatt",
            "volume",
            "durationMs"
          ],
          "properties": {
            "event": {
              "const": "rep"
            },
            "setIndex": {
              "type": "integer",
              "minimum": 0
            },
            "repIndex": {
              "type": "integer",
              "minimum": 1
            },
            "direction": {
              "type": "string",
              "enum": ["pull", "recovery"]
            },
            "valid": {
              "type": "boolean"
            },
            "distanceMm": {
              "type": "integer",
              "minimum": 0
            },
            "peakVelocityMmPerSecond": {
              "type": "integer",
              "minimum": 0
            },
            "peakPowerWatt": {
              "type": "integer",
              "minimum": 0
            },
            "meanPowerWatt": {
              "type": "integer",
              "minimum": 0,
              "description": "Device-reported mean power for this directional measurement."
            },
            "totalWorkJ": {
              "type": "integer",
              "minimum": 0,
              "description": "Device-reported total work from the validated V2 work measurement; omitted when unavailable."
            },
            "volume": {
              "type": "number",
              "minimum": 0,
              "multipleOf": 0.01
            },
            "durationMs": {
              "type": "integer",
              "minimum": 0
            },
            "startPosMm": {
              "type": "integer",
              "minimum": 0
            },
            "finishPosMm": {
              "type": "integer",
              "minimum": 0
            }
          }
        }
      ],
      "unevaluatedProperties": false
    },
    "progress": {
      "allOf": [
        {
          "$ref": "#/$defs/base"
        },
        {
          "type": "object",
          "required": [
            "event",
            "setIndex",
            "repIndex",
            "volume",
            "pullDistanceMm",
            "elapsedMs"
          ],
          "properties": {
            "event": {
              "const": "progress"
            },
            "setIndex": {
              "type": "integer",
              "minimum": 0
            },
            "repIndex": {
              "type": "integer",
              "minimum": 0
            },
            "volume": {
              "type": "number",
              "minimum": 0,
              "multipleOf": 0.01
            },
            "pullVolume": {
              "type": "number",
              "minimum": 0,
              "multipleOf": 0.01,
              "description": "Pull-direction training volume when the device provides it."
            },
            "pullDistanceMm": {
              "type": "integer",
              "minimum": 0
            },
            "elapsedMs": {
              "type": "integer",
              "minimum": 0
            }
          }
        }
      ],
      "unevaluatedProperties": false
    },
    "setSummary": {
      "allOf": [
        {
          "$ref": "#/$defs/base"
        },
        {
          "type": "object",
          "required": [
            "event",
            "setIndex",
            "reps",
            "pullDistanceMm",
            "volume",
            "durationMs",
            "restDurationMs",
            "pull",
            "recovery"
          ],
          "properties": {
            "event": {
              "const": "setSummary"
            },
            "setIndex": {
              "type": "integer",
              "minimum": 0
            },
            "reps": {
              "type": "integer",
              "minimum": 0
            },
            "pullDistanceMm": {
              "type": "integer",
              "minimum": 0
            },
            "volume": {
              "type": "number",
              "minimum": 0,
              "multipleOf": 0.01
            },
            "pullVolume": {
              "type": "number",
              "minimum": 0,
              "multipleOf": 0.01,
              "description": "Pull-direction training volume when the device provides it."
            },
            "durationMs": {
              "type": "integer",
              "minimum": 0
            },
            "restDurationMs": {
              "type": "integer",
              "minimum": 0
            },
            "pull": {
              "$ref": "#/$defs/directionMetrics"
            },
            "recovery": {
              "$ref": "#/$defs/directionMetrics"
            }
          }
        }
      ],
      "unevaluatedProperties": false
    },
    "workoutSummary": {
      "allOf": [
        {
          "$ref": "#/$defs/base"
        },
        {
          "type": "object",
          "required": [
            "event",
            "sets",
            "reps",
            "pullDistanceMm",
            "volume",
            "pullVolume",
            "durationMs",
            "restDurationMs",
            "pull",
            "recovery"
          ],
          "properties": {
            "event": {
              "const": "workoutSummary"
            },
            "sets": {
              "type": "integer",
              "minimum": 0
            },
            "reps": {
              "type": "integer",
              "minimum": 0
            },
            "pullDistanceMm": {
              "type": "integer",
              "minimum": 0
            },
            "volume": {
              "type": "number",
              "minimum": 0,
              "multipleOf": 0.01
            },
            "pullVolume": {
              "type": "number",
              "minimum": 0,
              "multipleOf": 0.01,
              "description": "Pull-direction training volume."
            },
            "durationMs": {
              "type": "integer",
              "minimum": 0
            },
            "restDurationMs": {
              "type": "integer",
              "minimum": 0
            },
            "pull": {
              "$ref": "#/$defs/directionMetrics"
            },
            "recovery": {
              "$ref": "#/$defs/directionMetrics"
            }
          }
        }
      ],
      "unevaluatedProperties": false
    },
    "dataQuality": {
      "allOf": [
        {
          "$ref": "#/$defs/base"
        },
        {
          "type": "object",
          "required": ["event", "kind", "count"],
          "properties": {
            "event": {
              "const": "dataQuality"
            },
            "kind": {
              "type": "string",
              "enum": ["droppedData", "decodeError"]
            },
            "count": {
              "type": "integer",
              "minimum": 1
            },
            "dropped": {
              "type": "integer",
              "minimum": 1
            }
          }
        }
      ],
      "unevaluatedProperties": false
    },
    "connectionLost": {
      "allOf": [
        {
          "$ref": "#/$defs/base"
        },
        {
          "type": "object",
          "required": ["event", "reason", "willReconnect"],
          "properties": {
            "event": {
              "const": "connectionLost"
            },
            "reason": {
              "type": "string",
              "minLength": 1
            },
            "willReconnect": {
              "type": "boolean"
            }
          }
        }
      ],
      "unevaluatedProperties": false
    },
    "reconnected": {
      "allOf": [
        {
          "$ref": "#/$defs/base"
        },
        {
          "type": "object",
          "required": ["event", "attempt", "downtimeMs"],
          "properties": {
            "event": {
              "const": "reconnected"
            },
            "attempt": {
              "type": "integer",
              "minimum": 1
            },
            "downtimeMs": {
              "type": "integer",
              "minimum": 0
            }
          }
        }
      ],
      "unevaluatedProperties": false
    },
    "streamEnd": {
      "allOf": [
        {
          "$ref": "#/$defs/base"
        },
        {
          "type": "object",
          "required": [
            "event",
            "reason",
            "complete",
            "droppedEvents",
            "decodeErrors"
          ],
          "properties": {
            "event": {
              "const": "streamEnd"
            },
            "reason": {
              "type": "string",
              "enum": [
                "stopped",
                "daemonEnded",
                "daemonDisconnected",
                "reconnectExhausted"
              ]
            },
            "complete": {
              "type": "boolean"
            },
            "droppedEvents": {
              "type": "integer",
              "minimum": 0
            },
            "decodeErrors": {
              "type": "integer",
              "minimum": 0
            }
          }
        }
      ],
      "unevaluatedProperties": false
    }
  }
}
