{
  "$defs": {
    "DtmfStep": {
      "additionalProperties": true,
      "properties": {
        "type": {
          "const": "dtmf",
          "default": "dtmf",
          "title": "Type",
          "type": "string"
        },
        "digits": {
          "title": "Digits",
          "type": "string"
        }
      },
      "required": [
        "digits"
      ],
      "title": "DtmfStep",
      "type": "object"
    },
    "EnvironmentPlan": {
      "additionalProperties": true,
      "description": "How the scenario runs in one environment (key of ``Scenario.environments``).\n\nThe top-level ``schedule``, ``timezone`` and ``call_window`` are the plan of the\norganization's default environment; an entry here overrides them for that environment.",
      "properties": {
        "enabled": {
          "default": true,
          "description": "Run the scenario in this environment (schedule included).",
          "title": "Enabled",
          "type": "boolean"
        },
        "schedule": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "Cron expression or 'every day at 09:00'. None: no schedule.",
          "title": "Schedule"
        },
        "timezone": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "IANA time zone of `schedule` in this environment. Default UTC.",
          "examples": [
            "Europe/Paris"
          ],
          "title": "Timezone"
        },
        "call_window": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "'HH:MM-HH:MM Area/City'.",
          "title": "Call Window"
        }
      },
      "title": "EnvironmentPlan",
      "type": "object"
    },
    "ExpectStep": {
      "additionalProperties": true,
      "properties": {
        "type": {
          "const": "expect",
          "default": "expect",
          "title": "Type",
          "type": "string"
        },
        "text": {
          "description": "What the target should say (semantic match, not exact).",
          "title": "Text",
          "type": "string"
        },
        "timeout_s": {
          "default": 15.0,
          "exclusiveMinimum": 0,
          "maximum": 300,
          "title": "Timeout S",
          "type": "number"
        }
      },
      "required": [
        "text"
      ],
      "title": "ExpectStep",
      "type": "object"
    },
    "GoalReached": {
      "additionalProperties": true,
      "properties": {
        "id": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "Stable id, reused across runs for trends.",
          "title": "Id"
        },
        "severity": {
          "default": "fail",
          "enum": [
            "fail",
            "warn"
          ],
          "title": "Severity",
          "type": "string"
        },
        "type": {
          "const": "goal_reached",
          "default": "goal_reached",
          "title": "Type",
          "type": "string"
        }
      },
      "title": "GoalReached",
      "type": "object"
    },
    "Limits": {
      "additionalProperties": true,
      "properties": {
        "max_duration_s": {
          "default": 300,
          "exclusiveMinimum": 0,
          "maximum": 1800,
          "title": "Max Duration S",
          "type": "integer"
        },
        "silence_timeout_s": {
          "default": 20,
          "exclusiveMinimum": 0,
          "maximum": 300,
          "title": "Silence Timeout S",
          "type": "integer"
        },
        "ring_timeout_s": {
          "default": 45,
          "exclusiveMinimum": 0,
          "maximum": 120,
          "title": "Ring Timeout S",
          "type": "integer"
        }
      },
      "title": "Limits",
      "type": "object"
    },
    "LlmCheck": {
      "additionalProperties": true,
      "properties": {
        "id": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "Stable id, reused across runs for trends.",
          "title": "Id"
        },
        "severity": {
          "default": "fail",
          "enum": [
            "fail",
            "warn"
          ],
          "title": "Severity",
          "type": "string"
        },
        "type": {
          "const": "llm_check",
          "default": "llm_check",
          "title": "Type",
          "type": "string"
        },
        "question": {
          "description": "Yes/no question answered by the judge from the transcript.",
          "title": "Question",
          "type": "string"
        }
      },
      "required": [
        "question"
      ],
      "title": "LlmCheck",
      "type": "object"
    },
    "MaxDuration": {
      "additionalProperties": true,
      "properties": {
        "id": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "Stable id, reused across runs for trends.",
          "title": "Id"
        },
        "severity": {
          "default": "fail",
          "enum": [
            "fail",
            "warn"
          ],
          "title": "Severity",
          "type": "string"
        },
        "type": {
          "const": "max_duration_s",
          "default": "max_duration_s",
          "title": "Type",
          "type": "string"
        },
        "value": {
          "exclusiveMinimum": 0,
          "title": "Value",
          "type": "integer"
        }
      },
      "required": [
        "value"
      ],
      "title": "MaxDuration",
      "type": "object"
    },
    "MaxInterruptions": {
      "additionalProperties": true,
      "properties": {
        "id": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "Stable id, reused across runs for trends.",
          "title": "Id"
        },
        "severity": {
          "default": "fail",
          "enum": [
            "fail",
            "warn"
          ],
          "title": "Severity",
          "type": "string"
        },
        "type": {
          "const": "max_interruptions",
          "default": "max_interruptions",
          "title": "Type",
          "type": "string"
        },
        "value": {
          "description": "Times the target talked over the caller.",
          "minimum": 0,
          "title": "Value",
          "type": "integer"
        }
      },
      "required": [
        "value"
      ],
      "title": "MaxInterruptions",
      "type": "object"
    },
    "MaxLatency": {
      "additionalProperties": true,
      "properties": {
        "id": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "Stable id, reused across runs for trends.",
          "title": "Id"
        },
        "severity": {
          "default": "fail",
          "enum": [
            "fail",
            "warn"
          ],
          "title": "Severity",
          "type": "string"
        },
        "type": {
          "const": "max_latency_ms",
          "default": "max_latency_ms",
          "title": "Type",
          "type": "string"
        },
        "value": {
          "description": "Per turn, end of caller speech to start of target speech.",
          "exclusiveMinimum": 0,
          "title": "Value",
          "type": "integer"
        },
        "percentile": {
          "default": "p95",
          "enum": [
            "p50",
            "p95",
            "max"
          ],
          "title": "Percentile",
          "type": "string"
        }
      },
      "required": [
        "value"
      ],
      "title": "MaxLatency",
      "type": "object"
    },
    "MustInclude": {
      "additionalProperties": true,
      "properties": {
        "id": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "Stable id, reused across runs for trends.",
          "title": "Id"
        },
        "severity": {
          "default": "fail",
          "enum": [
            "fail",
            "warn"
          ],
          "title": "Severity",
          "type": "string"
        },
        "type": {
          "const": "must_include",
          "default": "must_include",
          "title": "Type",
          "type": "string"
        },
        "text": {
          "description": "Behaviour the agent must show, judged semantically.",
          "title": "Text",
          "type": "string"
        }
      },
      "required": [
        "text"
      ],
      "title": "MustInclude",
      "type": "object"
    },
    "MustNot": {
      "additionalProperties": true,
      "properties": {
        "id": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "Stable id, reused across runs for trends.",
          "title": "Id"
        },
        "severity": {
          "default": "fail",
          "enum": [
            "fail",
            "warn"
          ],
          "title": "Severity",
          "type": "string"
        },
        "type": {
          "const": "must_not",
          "default": "must_not",
          "title": "Type",
          "type": "string"
        },
        "text": {
          "title": "Text",
          "type": "string"
        }
      },
      "required": [
        "text"
      ],
      "title": "MustNot",
      "type": "object"
    },
    "Persona": {
      "additionalProperties": true,
      "properties": {
        "description": {
          "description": "Who the caller is and how they behave.",
          "title": "Description",
          "type": "string"
        },
        "voice": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "TTS voice id; provider default if empty.",
          "title": "Voice"
        },
        "accent": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Accent"
        },
        "speaking_rate": {
          "default": 1.0,
          "maximum": 2.0,
          "minimum": 0.5,
          "title": "Speaking Rate",
          "type": "number"
        },
        "patience": {
          "default": "normal",
          "enum": [
            "low",
            "normal",
            "high"
          ],
          "title": "Patience",
          "type": "string"
        },
        "interrupts": {
          "default": false,
          "description": "If true the caller barges in while the agent speaks.",
          "title": "Interrupts",
          "type": "boolean"
        }
      },
      "required": [
        "description"
      ],
      "title": "Persona",
      "type": "object"
    },
    "SayStep": {
      "additionalProperties": true,
      "properties": {
        "type": {
          "const": "say",
          "default": "say",
          "title": "Type",
          "type": "string"
        },
        "text": {
          "title": "Text",
          "type": "string"
        }
      },
      "required": [
        "text"
      ],
      "title": "SayStep",
      "type": "object"
    },
    "Target": {
      "additionalProperties": true,
      "properties": {
        "phone": {
          "description": "Number to call, E.164 (e.g. +15550123456).",
          "title": "Phone",
          "type": "string"
        },
        "kind": {
          "$ref": "#/$defs/TargetKind",
          "default": "unknown"
        },
        "platform": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "Free text: vapi, retell, bland, livekit, twilio, genesys...",
          "title": "Platform"
        },
        "language": {
          "default": "en-US",
          "description": "BCP-47 language the call is held in.",
          "title": "Language",
          "type": "string"
        }
      },
      "required": [
        "phone"
      ],
      "title": "Target",
      "type": "object"
    },
    "TargetKind": {
      "enum": [
        "ai_agent",
        "ivr",
        "iva",
        "human",
        "unknown"
      ],
      "title": "TargetKind",
      "type": "string"
    },
    "TranscriptRegex": {
      "additionalProperties": true,
      "properties": {
        "id": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "Stable id, reused across runs for trends.",
          "title": "Id"
        },
        "severity": {
          "default": "fail",
          "enum": [
            "fail",
            "warn"
          ],
          "title": "Severity",
          "type": "string"
        },
        "type": {
          "const": "transcript_regex",
          "default": "transcript_regex",
          "title": "Type",
          "type": "string"
        },
        "pattern": {
          "title": "Pattern",
          "type": "string"
        },
        "speaker": {
          "default": "target",
          "enum": [
            "target",
            "caller",
            "any"
          ],
          "title": "Speaker",
          "type": "string"
        },
        "expect_match": {
          "default": true,
          "title": "Expect Match",
          "type": "boolean"
        }
      },
      "required": [
        "pattern"
      ],
      "title": "TranscriptRegex",
      "type": "object"
    },
    "Variant": {
      "additionalProperties": true,
      "description": "A derived test run (#1..#N on the landing). Overrides the base scenario.",
      "properties": {
        "title": {
          "title": "Title",
          "type": "string"
        },
        "source": {
          "default": "manual",
          "enum": [
            "auto",
            "manual"
          ],
          "title": "Source",
          "type": "string"
        },
        "persona": {
          "anyOf": [
            {
              "$ref": "#/$defs/Persona"
            },
            {
              "type": "null"
            }
          ],
          "default": null
        },
        "goal": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Goal"
        },
        "instructions": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "Extra guidance for this run.",
          "title": "Instructions"
        },
        "test_data": {
          "anyOf": [
            {
              "additionalProperties": true,
              "type": "object"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Test Data"
        },
        "assertions": {
          "anyOf": [
            {
              "items": {
                "discriminator": {
                  "mapping": {
                    "goal_reached": "#/$defs/GoalReached",
                    "llm_check": "#/$defs/LlmCheck",
                    "max_duration_s": "#/$defs/MaxDuration",
                    "max_interruptions": "#/$defs/MaxInterruptions",
                    "max_latency_ms": "#/$defs/MaxLatency",
                    "must_include": "#/$defs/MustInclude",
                    "must_not": "#/$defs/MustNot",
                    "transcript_regex": "#/$defs/TranscriptRegex"
                  },
                  "propertyName": "type"
                },
                "oneOf": [
                  {
                    "$ref": "#/$defs/MustInclude"
                  },
                  {
                    "$ref": "#/$defs/MustNot"
                  },
                  {
                    "$ref": "#/$defs/MaxLatency"
                  },
                  {
                    "$ref": "#/$defs/MaxDuration"
                  },
                  {
                    "$ref": "#/$defs/GoalReached"
                  },
                  {
                    "$ref": "#/$defs/MaxInterruptions"
                  },
                  {
                    "$ref": "#/$defs/TranscriptRegex"
                  },
                  {
                    "$ref": "#/$defs/LlmCheck"
                  }
                ]
              },
              "type": "array"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "Appended to the base assertions.",
          "title": "Assertions"
        },
        "enabled": {
          "default": true,
          "title": "Enabled",
          "type": "boolean"
        }
      },
      "required": [
        "title"
      ],
      "title": "Variant",
      "type": "object"
    },
    "WaitStep": {
      "additionalProperties": true,
      "properties": {
        "type": {
          "const": "wait",
          "default": "wait",
          "title": "Type",
          "type": "string"
        },
        "seconds": {
          "exclusiveMinimum": 0,
          "maximum": 600,
          "title": "Seconds",
          "type": "number"
        }
      },
      "required": [
        "seconds"
      ],
      "title": "WaitStep",
      "type": "object"
    }
  },
  "additionalProperties": true,
  "properties": {
    "schema_version": {
      "default": 1,
      "title": "Schema Version",
      "type": "integer"
    },
    "name": {
      "title": "Name",
      "type": "string"
    },
    "target": {
      "$ref": "#/$defs/Target"
    },
    "persona": {
      "$ref": "#/$defs/Persona"
    },
    "goal": {
      "title": "Goal",
      "type": "string"
    },
    "test_data": {
      "additionalProperties": true,
      "title": "Test Data",
      "type": "object"
    },
    "steps": {
      "description": "Optional IVR navigation hints.",
      "items": {
        "discriminator": {
          "mapping": {
            "dtmf": "#/$defs/DtmfStep",
            "expect": "#/$defs/ExpectStep",
            "say": "#/$defs/SayStep",
            "wait": "#/$defs/WaitStep"
          },
          "propertyName": "type"
        },
        "oneOf": [
          {
            "$ref": "#/$defs/SayStep"
          },
          {
            "$ref": "#/$defs/DtmfStep"
          },
          {
            "$ref": "#/$defs/ExpectStep"
          },
          {
            "$ref": "#/$defs/WaitStep"
          }
        ]
      },
      "title": "Steps",
      "type": "array"
    },
    "assertions": {
      "items": {
        "discriminator": {
          "mapping": {
            "goal_reached": "#/$defs/GoalReached",
            "llm_check": "#/$defs/LlmCheck",
            "max_duration_s": "#/$defs/MaxDuration",
            "max_interruptions": "#/$defs/MaxInterruptions",
            "max_latency_ms": "#/$defs/MaxLatency",
            "must_include": "#/$defs/MustInclude",
            "must_not": "#/$defs/MustNot",
            "transcript_regex": "#/$defs/TranscriptRegex"
          },
          "propertyName": "type"
        },
        "oneOf": [
          {
            "$ref": "#/$defs/MustInclude"
          },
          {
            "$ref": "#/$defs/MustNot"
          },
          {
            "$ref": "#/$defs/MaxLatency"
          },
          {
            "$ref": "#/$defs/MaxDuration"
          },
          {
            "$ref": "#/$defs/GoalReached"
          },
          {
            "$ref": "#/$defs/MaxInterruptions"
          },
          {
            "$ref": "#/$defs/TranscriptRegex"
          },
          {
            "$ref": "#/$defs/LlmCheck"
          }
        ]
      },
      "title": "Assertions",
      "type": "array"
    },
    "limits": {
      "$ref": "#/$defs/Limits"
    },
    "variants": {
      "items": {
        "$ref": "#/$defs/Variant"
      },
      "title": "Variants",
      "type": "array"
    },
    "tags": {
      "items": {
        "type": "string"
      },
      "title": "Tags",
      "type": "array"
    },
    "schedule": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "Cron expression, UTC unless timezone.",
      "title": "Schedule"
    },
    "timezone": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "IANA time zone of `schedule` (e.g. `Europe/Paris`). Default UTC. Local wall-clock time: 8:00 stays 8:00 across daylight saving changes.",
      "examples": [
        "Europe/Paris",
        "America/New_York"
      ],
      "title": "Timezone"
    },
    "call_window": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "'HH:MM-HH:MM Area/City'.",
      "title": "Call Window"
    },
    "environments": {
      "anyOf": [
        {
          "additionalProperties": {
            "$ref": "#/$defs/EnvironmentPlan"
          },
          "type": "object"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "Per environment plan, keyed by environment slug (`staging`): whether the scenario runs there, with its own `schedule`, `timezone` and `call_window`. The top-level fields stay the plan of the default environment.",
      "examples": [
        {
          "staging": {
            "schedule": "every hour",
            "timezone": "Europe/Paris"
          }
        }
      ],
      "title": "Environments"
    }
  },
  "required": [
    "name",
    "target",
    "persona",
    "goal"
  ],
  "title": "Scenario",
  "type": "object"
}