{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://getzero.dev/contracts/zero.runtime_safety.v1.schema.json",
  "title": "RuntimeSafetyState v1",
  "description": "Aggregated read-only view of the engine's safety signals. Joins risk.json, circuit_breaker.json, md_heartbeat.json, heartbeat.json, immune_risk.json into one contract with freshness metadata. Consumers (Admin UI, MCP tools, public Runtime status) read this once instead of reconciling 5+ files by hand. Pure aggregator: no business logic. Produced by zero/runtime_safety.py:compute_runtime_safety_state and exposed at GET /v2/runtime-safety.",
  "type": "object",
  "required": [
    "schema",
    "checked_at",
    "overall_status",
    "overall_reasons",
    "account",
    "risk",
    "circuit_breaker",
    "market_data",
    "immune",
    "heartbeats"
  ],
  "properties": {
    "schema": {
      "type": "string",
      "const": "zero.runtime_safety.v1"
    },
    "checked_at": {
      "type": "string",
      "format": "date-time",
      "description": "ISO-8601 UTC timestamp when this snapshot was computed."
    },
    "overall_status": {
      "type": "string",
      "enum": ["ok", "degraded", "halted"],
      "description": "halted = any explicit halt or active circuit breaker; degraded = freshness violation or component missing; ok = everything fresh and unhalted."
    },
    "overall_reasons": {
      "type": "array",
      "items": {"type": "string"},
      "description": "Empty when overall_status=ok. Lists every contributing reason for the degraded/halted status."
    },
    "account": {
      "type": "object",
      "properties": {
        "value_usd": {"type": ["number", "null"]},
        "open_positions": {"type": ["integer", "null"]},
        "freshness_s": {"type": ["number", "null"], "description": "Age in seconds since md_account.json was updated."},
        "source": {"type": ["string", "null"], "description": "rest:clearinghouseState | websocket | etc."},
        "missing": {"type": "boolean"},
        "stale": {"type": "boolean"}
      },
      "required": ["freshness_s", "missing", "stale"]
    },
    "risk": {
      "type": "object",
      "properties": {
        "global_halt": {"type": "boolean"},
        "halted": {"type": "boolean"},
        "halt_reason": {"type": ["string", "null"]},
        "halt_until": {"type": ["string", "null"]},
        "daily_pnl_usd": {"type": ["number", "null"]},
        "daily_loss_usd": {"type": ["number", "null"]},
        "drawdown_pct": {"type": ["number", "null"]},
        "peak_equity": {"type": ["number", "null"]},
        "capital_floor_hit": {"type": "boolean"},
        "stop_failure_halt": {"type": "boolean"},
        "management_liveness_halt": {"type": "boolean"},
        "open_count": {"type": ["integer", "null"]},
        "freshness_s": {"type": ["number", "null"]},
        "missing": {"type": "boolean"},
        "stale": {"type": "boolean"}
      },
      "required": ["global_halt", "halted", "freshness_s", "missing", "stale"]
    },
    "circuit_breaker": {
      "type": "object",
      "properties": {
        "paused": {"type": "boolean"},
        "halted": {"type": "boolean"},
        "active": {"type": "boolean", "description": "paused OR halted"},
        "freshness_s": {"type": ["number", "null"]},
        "missing": {"type": "boolean"},
        "stale": {"type": "boolean", "description": "Only true if CB state file > 24h old (durable state)"}
      },
      "required": ["paused", "halted", "active", "missing", "stale"]
    },
    "market_data": {
      "type": "object",
      "properties": {
        "alive": {"type": "boolean"},
        "ws_connected": {"type": "boolean"},
        "fail_count": {"type": "integer"},
        "cycle": {"type": ["integer", "null"]},
        "freshness_s": {"type": ["number", "null"]},
        "missing": {"type": "boolean"},
        "stale": {"type": "boolean"}
      },
      "required": ["alive", "ws_connected", "freshness_s", "missing", "stale"]
    },
    "immune": {
      "type": "object",
      "properties": {
        "alive": {"type": "boolean", "description": "Derived from heartbeat.json[immune] freshness, not from immune_risk.json which is known to lag."},
        "heartbeat_freshness_s": {"type": ["number", "null"]},
        "risk_snapshot_freshness_s": {"type": ["number", "null"], "description": "immune_risk.json mtime — known to lag the immune heartbeat. Don't use this as the alive signal."},
        "risk_snapshot_missing": {"type": "boolean"},
        "risk_snapshot_stale": {"type": "boolean"}
      },
      "required": ["alive", "risk_snapshot_missing", "risk_snapshot_stale"]
    },
    "data_plane": {
      "type": "object",
      "description": "Latest Hyperliquid data-plane divergence state plus zero.hl_data_plane.v1 provenance for live-signing freshness gates.",
      "properties": {
        "age_s": {"type": ["number", "null"]},
        "reason": {"type": ["string", "null"]},
        "result": {
          "type": "object",
          "properties": {
            "status": {
              "type": "string",
              "enum": ["match", "minor_drift", "major_drift", "unchecked"]
            },
            "comparisons": {"type": "array"}
          }
        },
        "provenance": {
          "type": "object",
          "required": [
            "schema",
            "checked_at",
            "source",
            "fallback_used",
            "freshness_budgets_ms",
            "ages_ms",
            "public_api_divergence_status"
          ],
          "properties": {
            "schema": {"type": "string", "const": "zero.hl_data_plane.v1"},
            "checked_at": {"type": "string", "format": "date-time"},
            "source": {
              "type": "object",
              "required": ["source_id", "kind", "network", "info_url", "exchange_url", "ws_url"],
              "properties": {
                "source_id": {"type": "string"},
                "kind": {
                  "type": "string",
                  "enum": [
                    "public_hl_api",
                    "foundation_nonvalidating_node",
                    "self_hosted_node_api",
                    "managed_private_endpoint"
                  ]
                },
                "network": {"type": "string", "enum": ["mainnet", "testnet"]},
                "info_url": {"type": "string"},
                "exchange_url": {"type": "string"},
                "ws_url": {"type": "string"}
              }
            },
            "fallback_used": {"type": "boolean"},
            "fallback_reason": {"type": ["string", "null"]},
            "freshness_budgets_ms": {"$ref": "#/$defs/data_plane_age_budget_map"},
            "ages_ms": {"$ref": "#/$defs/data_plane_age_observation_map"},
            "public_api_divergence_status": {
              "type": "string",
              "enum": ["match", "minor_drift", "major_drift", "unchecked"]
            }
          }
        }
      }
    },
    "heartbeats": {
      "type": "object",
      "description": "Per-daemon freshness map. Key = daemon name (controller, immune, market_data, runner_lens_*, hl_truth_reconciler, close_reconciler, introspector, tick_manager, cloud_feed, etc).",
      "additionalProperties": {
        "type": "object",
        "properties": {
          "freshness_s": {"type": ["number", "null"]},
          "stale": {"type": "boolean"}
        },
        "required": ["freshness_s", "stale"]
      }
    }
  },
  "$defs": {
    "data_plane_age_budget_map": {
      "type": "object",
      "required": ["account_state", "open_orders", "fills", "book"],
      "properties": {
        "account_state": {"type": "integer", "minimum": 0},
        "open_orders": {"type": "integer", "minimum": 0},
        "fills": {"type": "integer", "minimum": 0},
        "book": {"type": "integer", "minimum": 0}
      }
    },
    "data_plane_age_observation_map": {
      "type": "object",
      "required": ["account_state", "open_orders", "fills", "book"],
      "properties": {
        "account_state": {"type": ["integer", "null"], "minimum": 0},
        "open_orders": {"type": ["integer", "null"], "minimum": 0},
        "fills": {"type": ["integer", "null"], "minimum": 0},
        "book": {"type": ["integer", "null"], "minimum": 0}
      }
    }
  }
}
