{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://getzero.dev/contracts/zero.setup_lifecycle.v1.schema.json",
  "title": "Setup Lifecycle Snapshot v1",
  "description": "Unified view of the Runtime's 'what's forming' surfaces. Folds approaching.json, near_misses*.jsonl, rejections.jsonl, and trades.jsonl into one record per (coin, direction) tuple over a configurable window. Produced by zero/setup_lifecycle.py:build_snapshot(); persisted at bus/setup_lifecycles.json; exposed at GET /v2/setup-lifecycles.",
  "type": "object",
  "required": ["schema", "built_at", "window_hours", "count", "lifecycles"],
  "properties": {
    "schema": {
      "type": "string",
      "const": "zero.setup_lifecycle.v1"
    },
    "built_at": {
      "type": ["string", "null"],
      "format": "date-time"
    },
    "window_hours": {
      "type": "number",
      "minimum": 0
    },
    "count": {
      "type": "integer",
      "minimum": 0
    },
    "lifecycles": {
      "type": "array",
      "items": {
        "type": "object",
        "required": [
          "coin", "direction", "window_hours", "stage", "terminal",
          "approaching_count", "signal_count", "near_miss_count",
          "rejection_count", "rejection_reasons", "opened_count",
          "closed_count", "realized_pnl_usd",
          "first_event_at", "last_event_at",
          "most_recent_rejection_reason"
        ],
        "properties": {
          "coin": {"type": "string"},
          "direction": {
            "type": "string",
            "enum": ["LONG", "SHORT", "UNKNOWN"]
          },
          "window_hours": {"type": "number"},
          "stage": {
            "type": "string",
            "enum": [
              "approaching",
              "signal_fired",
              "near_miss",
              "rejected",
              "opened",
              "closed_win",
              "closed_loss",
              "unknown"
            ],
            "description": "Most-advanced stage reached in this window. Severity order: closed_{win,loss} > opened > {near_miss, rejected} > signal_fired > approaching > unknown."
          },
          "terminal": {
            "type": "boolean",
            "description": "True when stage is closed_win or closed_loss."
          },
          "approaching_count": {"type": "integer", "minimum": 0},
          "signal_count": {"type": "integer", "minimum": 0},
          "near_miss_count": {"type": "integer", "minimum": 0},
          "rejection_count": {"type": "integer", "minimum": 0},
          "rejection_reasons": {
            "type": "array",
            "items": {"type": "string"},
            "description": "Distinct reasons observed in this window."
          },
          "opened_count": {"type": "integer", "minimum": 0},
          "closed_count": {"type": "integer", "minimum": 0},
          "realized_pnl_usd": {"type": "number"},
          "first_event_at": {"type": ["string", "null"], "format": "date-time"},
          "last_event_at": {"type": ["string", "null"], "format": "date-time"},
          "most_recent_rejection_reason": {"type": ["string", "null"]}
        }
      }
    }
  }
}
