{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://github.com/welkaim/ea-codex/schemas/v1/scenario-pack.json",
  "title": "ScenarioPack",
  "description": "Reusable bundle of validation scenarios used by an attractor's validation harness. ScenarioPacks are the human-curated content that BMAD's Double-check stage and the StrongDM-style attractor consume. They are referenced from ArchitecturePackage.act.scenarioPacks, AgentContract.feedback.evaluateOn, and validation pipelines. Each pack is owned by a capability or platform team, versioned, and updated as scenarios are learned from production. ScenarioPacks earn a typed kind because they are referenced across the family, have ownership and lifecycle, and carry operative content (executable scenarios with expected outcomes) that is not present in any EA platform.",
  "type": "object",
  "required": ["apiVersion", "kind", "metadata", "spec"],
  "properties": {
    "apiVersion": { "$ref": "_common.json#/$defs/apiVersion" },
    "kind": { "type": "string", "const": "ScenarioPack" },
    "metadata": { "$ref": "_common.json#/$defs/metadata" },
    "spec": {
      "type": "object",
      "required": ["scope", "scenarios", "convergenceCriteria"],
      "properties": {
        "scope": {
          "type": "object",
          "required": ["appliesTo"],
          "description": "What the pack validates. A pack is scoped either to a capability, to a product line, to a reference architecture instance, or to an agent contract.",
          "properties": {
            "appliesTo": {
              "type": "string",
              "enum": ["capability", "product-line", "reference-architecture", "agent-contract", "data-contract"]
            },
            "capabilityRef": { "type": "string" },
            "productLineRef": { "type": "string" },
            "referenceArchitectureRef": { "type": "string" },
            "agentContractRef": { "type": "string" },
            "dataContractRef": { "type": "string" }
          },
          "additionalProperties": true
        },
        "scenarios": {
          "type": "array",
          "minItems": 1,
          "description": "Scenarios that exercise the artifact under validation. Scenarios should test externally observable behavior, not implementation details.",
          "items": {
            "type": "object",
            "required": ["id", "given", "when", "then"],
            "properties": {
              "id": {
                "$ref": "_common.json#/$defs/identifier",
                "description": "Stable scenario identifier, conventionally SCN-<PACK>-<NUMBER>."
              },
              "title": { "type": "string" },
              "given": {
                "type": "string",
                "description": "Initial conditions. Plain language, structured if needed for execution."
              },
              "when": {
                "type": "string",
                "description": "Action or trigger."
              },
              "then": {
                "type": "string",
                "description": "Expected externally observable outcome."
              },
              "category": {
                "type": "string",
                "enum": ["happy-path", "boundary", "adversarial", "regression", "compliance", "performance", "holdout"],
                "description": "Scenario category. holdout scenarios are reserved from the training/refinement loop and used to validate that the attractor has not overfit."
              },
              "severity": {
                "type": "string",
                "enum": ["blocking", "warning", "advisory"]
              },
              "evidenceRequired": {
                "type": "array",
                "description": "Outputs the scenario must produce as evidence (logs, traces, decision records, etc.).",
                "items": { "type": "string" }
              }
            },
            "additionalProperties": true
          }
        },
        "convergenceCriteria": {
          "type": "object",
          "required": ["metric", "passThreshold"],
          "description": "How the pack determines convergence. Read by attractor loops to decide when iteration stops.",
          "properties": {
            "metric": {
              "type": "string",
              "description": "What is measured (e.g., 'pass-rate', 'severity-weighted-pass-rate', 'p99-latency', 'evidence-completeness')."
            },
            "passThreshold": {
              "type": "string",
              "description": "Minimum value required for convergence (e.g., '>= 0.95', '>= 0.99 on blocking scenarios')."
            },
            "stableForRuns": {
              "type": "integer",
              "description": "Number of consecutive runs the threshold must hold before convergence is declared."
            },
            "blockingFailureMode": {
              "type": "string",
              "enum": ["any-blocking-fail-blocks-merge", "advisory-only", "warn-and-continue"]
            }
          },
          "additionalProperties": true
        },
        "holdoutPolicy": {
          "type": "object",
          "description": "Policy for holdout scenarios: scenarios reserved from the iterative refinement loop and used only for final validation. Holdout scenarios prevent the attractor from overfitting to its training set.",
          "properties": {
            "fraction": {
              "type": "string",
              "description": "Fraction of scenarios reserved as holdout (e.g., '0.2', '20%')."
            },
            "rotationCadence": {
              "type": "string",
              "description": "How often holdouts rotate (e.g., 'monthly', 'per-release', 'never')."
            }
          },
          "additionalProperties": true
        },
        "ownedBy": {
          "type": "string",
          "description": "Team or role accountable for maintaining the pack. Distinct from metadata.owners (which lists the artifact's contributors): ownedBy is the single accountable owner."
        },
        "supersedes": {
          "type": "string",
          "description": "Identifier of an earlier ScenarioPack this one replaces. Allows scenarios to evolve without losing audit trail."
        }
      },
      "additionalProperties": true
    }
  },
  "additionalProperties": false
}
