{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://golfsga.com/sga-ois/schema/0.1/notice.schema.json",
  "title": "SGA-OIS notice",
  "description": "The engine telling someone something they can act on, or need to know is affecting their record. Delivered to participants that asked for the pseudo-field sga.notice in their wants, so it needs no separate transport and a device that does not care never sees one.",
  "type": "object",
  "required": [
    "type",
    "code",
    "severity",
    "audience"
  ],
  "additionalProperties": false,
  "properties": {
    "sga_kind": {
      "const": "notice",
      "description": "Document type discriminator. Always notice. Optional on the wire -- a consumer that already knows what it asked for does not need it -- but present in stored and exchanged documents so a file on its own can say what it is."
    },
    "type": {
      "const": "notice.post",
      "description": "Message type discriminator. Always notice.post: every notice, from the engine or from a device, travels as one."
    },
    "code": {
      "$ref": "common.schema.json#/$defs/noticeCode"
    },
    "severity": {
      "enum": [
        "info",
        "warning",
        "blocked"
      ],
      "description": "blocked means play cannot proceed under the current ruleset -- reserved for pre-round settings divergence. Mid-round problems flag; they never halt."
    },
    "audience": {
      "$ref": "common.schema.json#/$defs/noticeAudience"
    },
    "slot": {
      "$ref": "common.schema.json#/$defs/slot"
    },
    "urgency": {
      "$ref": "common.schema.json#/$defs/noticeUrgency"
    },
    "id": {
      "type": "string",
      "minLength": 1,
      "maxLength": 64,
      "description": "Identifies this notice within the session. The engine assigns it; a notice.response names it in notice_id, and a notice that clears this one (resolved: true) repeats it."
    },
    "from": {
      "$ref": "common.schema.json#/$defs/sgaId",
      "description": "Present when a PARTICIPANT raised this rather than the engine. A device may address only a slot it is bound to or the active one, never the round or the operator, and never at interrupt urgency -- interrupting a golfer is the engine's alone."
    },
    "choices": {
      "type": "array",
      "maxItems": 6,
      "description": "Turns a notice into a question. A swing monitor asking how that one felt, a tournament system asking whether a player is ready. Answering is always optional: an unanswered prompt expires and nothing waits on it.",
      "items": {
        "type": "object",
        "required": [
          "id",
          "label"
        ],
        "additionalProperties": false,
        "properties": {
          "id": {
            "type": "string",
            "maxLength": 32,
            "description": "Stable identifier for this choice, echoed verbatim in the NOTICE_RESPONSE. Never localized and never renumbered."
          },
          "label": {
            "type": "string",
            "maxLength": 60,
            "description": "The text shown to the person. Localized, and free to change in any release -- nothing keys on it."
          }
        },
        "patternProperties": {
          "^x-[a-z0-9_-]+\\.": {}
        }
      }
    },
    "expires_ms": {
      "type": "integer",
      "minimum": 0,
      "description": "How long an answer is still useful. A swing rating is worthless three holes later; a readiness check may hold for minutes."
    },
    "actionable": {
      "type": "boolean",
      "description": "Can somebody in the bay fix this right now? 'Put a club back' is actionable; 'your firmware is two versions old' is not. Only actionable notices should interrupt play -- everything else waits for a natural break, or for the round summary."
    },
    "text": {
      "type": "string",
      "maxLength": 300,
      "description": "English fallback for a surface with no app to localize it. Apps render from code and detail instead."
    },
    "detail": {
      "type": "object",
      "additionalProperties": true,
      "description": "Structured context specific to the notice code: the device that failed, the field that went missing, the threshold that was crossed. A consumer that does not recognize the code MUST still render the notice rather than swallow it."
    },
    "resolved": {
      "type": "boolean",
      "description": "The follow-up saying the condition has cleared. This is half the value of the channel and the half most systems forget: a warning that never resolves teaches people to ignore warnings."
    },
    "session_epoch": {
      "$ref": "common.schema.json#/$defs/sessionEpoch"
    },
    "t_ms": {
      "$ref": "common.schema.json#/$defs/monotonicMs"
    }
  },
  "patternProperties": {
    "^x-[a-z0-9_-]+\\.": {}
  }
}
