{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "urn:cede:schema:monitoring:v0",
  "title": "CEDE monitoring record, v0",
  "description": "One recorded structure and the measurement of its index — the body of POST /structures/{id}/monitoring and of GET /monitoring/{id} (SPEC.md section 3.6). Two halves, and they mean different things. The record is the account holder's own assertion that a structure is in force under a transaction executed entirely outside Cede; Cede did not place it, witness it or take any part in it, and stores the assertion as an assertion. The observation is a measurement computed by analytics software from a pinned public snapshot, carrying the feed id, the vintage, the index value and the distance to attachment as first-class members. A measurement is not a determination: nothing here decides anything about anybody's obligations under any contract, and no part of this document may be presented as though it did.",
  "type": "object",
  "additionalProperties": false,
  "required": [
    "schema_version",
    "id",
    "structure_id",
    "status",
    "recorded_at",
    "in_force",
    "observation",
    "links"
  ],
  "properties": {
    "schema_version": { "type": "string", "pattern": "^[0-9]+\\.[0-9]+\\.[0-9]+$" },
    "id": { "type": "string", "minLength": 1, "description": "Server-assigned identity of this monitoring record." },
    "structure_id": { "type": "string", "minLength": 1 },
    "object_id": { "type": "string", "minLength": 1, "description": "The risk object the structure was cut from, when the structure names one." },
    "status": {
      "type": "string",
      "enum": ["recorded"],
      "description": "What Cede holds. `recorded` is the only value this build writes: the account holder has told Cede that the structure is in force, and Cede is measuring its index. It is a state of the record inside Cede, never a statement about the state of anything outside it."
    },
    "recorded_at": { "type": "string", "minLength": 20, "description": "When the record was created, RFC 3339 in UTC." },
    "reference": { "type": "string", "minLength": 1, "description": "The account holder's own reference for the transaction they assert, echoed verbatim. Cede neither interprets it nor resolves it against anything." },
    "in_force": { "$ref": "#/$defs/in_force" },
    "observation": { "$ref": "#/$defs/observation" },
    "links": {
      "type": "object",
      "additionalProperties": false,
      "required": ["self", "structure"],
      "properties": {
        "self": { "type": "string", "minLength": 1 },
        "structure": { "type": "string", "minLength": 1 },
        "object": { "type": "string", "minLength": 1 }
      }
    }
  },
  "$defs": {
    "model_label": {
      "type": "object",
      "additionalProperties": false,
      "required": ["name", "version"],
      "description": "SPEC.md section 4 P9: every result is labelled with the model and version that produced it. An observation is a computed result exactly as a price and a backtest are, so it carries the same label they do — the name and version of the reader that computed the level (cede.price.engine for a cat-in-a-box magnitude index, cede.price.station_index for a station-measured one). Both members are required here so the label cannot be omitted.",
      "properties": {
        "name": { "type": "string", "minLength": 1 },
        "version": { "type": "string", "minLength": 1 }
      }
    },
    "in_force": {
      "type": "object",
      "additionalProperties": false,
      "required": ["asserted_by", "asserted_at", "assertion"],
      "description": "Whose assertion this is, when it was made, and what it does and does not mean.",
      "properties": {
        "asserted_by": {
          "type": "string",
          "enum": ["account_holder"],
          "description": "The account that made the call. Cede has one source for this fact and it is the caller; there is no second party to it and no verification of it."
        },
        "asserted_at": { "type": "string", "minLength": 20 },
        "assertion": {
          "type": "string",
          "minLength": 1,
          "description": "The fixed sentence stating what recording is: the account holder's assertion about a transaction executed entirely outside Cede. Pinned as a constant in the product (cede.api.monitoring.IN_FORCE_ASSERTION) and asserted by the contract suite, so it cannot be softened response by response."
        }
      }
    },
    "observation": {
      "type": "object",
      "additionalProperties": false,
      "required": [
        "schema_version",
        "observed_at",
        "model",
        "feed",
        "index",
        "index_value",
        "index_unit",
        "attachment_level",
        "distance_to_attachment",
        "distance_basis",
        "attachment_reached",
        "trigger_levels",
        "measurement_window",
        "method",
        "disclosure",
        "limitations"
      ],
      "description": "The measurement, computed at read time. Every read recomputes it from the newest pinned vintage of the feed the structure's trigger names, so nothing here is a stored number that a later correction to the record could leave standing.",
      "properties": {
        "schema_version": { "type": "string", "pattern": "^[0-9]+\\.[0-9]+\\.[0-9]+$" },
        "observed_at": { "type": "string", "minLength": 20 },
        "model": { "$ref": "#/$defs/model_label" },
        "feed": { "$ref": "#/$defs/feed" },
        "index": {
          "type": "object",
          "additionalProperties": true,
          "required": ["name", "version", "variable", "statistic", "unit", "aggregation_window"],
          "description": "The structure's own index, as it was read.",
          "properties": {
            "name": { "type": "string" },
            "version": { "type": "string" },
            "variable": { "type": "string", "minLength": 1 },
            "statistic": { "type": "string", "minLength": 1 },
            "unit": { "type": "string", "minLength": 1 },
            "aggregation_window": { "type": "string", "minLength": 2 }
          }
        },
        "index_value": {
          "type": ["number", "null"],
          "description": "The index level over the measured window, in index_unit. Null when no level could be measured — the snapshot's record does not reach the term yet, or holds no qualifying record — and then unmeasured_reason says which. Null is never a zero: a level of zero is a measurement, and an absence is not."
        },
        "index_unit": { "type": "string", "minLength": 1 },
        "attachment_level": { "type": "number", "description": "The level at which the structure's payout function first pays, in index_unit." },
        "distance_to_attachment": {
          "type": ["number", "null"],
          "description": "attachment_level minus index_value, in index_unit. Negative when the measured level is past the attachment. Null exactly when index_value is null."
        },
        "distance_basis": { "type": "string", "minLength": 1, "description": "The fixed sentence saying how the signed distance is read." },
        "attachment_reached": { "type": "boolean", "description": "Whether the measured level reached the attachment. A statement about a number this software computed, and about nothing else." },
        "trigger_levels": {
          "type": "array",
          "minItems": 1,
          "description": "Every level of the structure's payout function, with the distance from the measured level to it and whether it was reached — SPEC.md section 3.6's index values against trigger levels, and its event flags.",
          "items": {
            "type": "object",
            "additionalProperties": false,
            "required": ["level", "unit", "payout_ratio", "reached", "distance"],
            "properties": {
              "level": { "type": "number" },
              "unit": { "type": "string", "minLength": 1 },
              "payout_ratio": { "type": "number", "description": "The ratio the structure's own function states at this level, echoed from the structure. Not an amount, and not a calculation of one." },
              "reached": { "type": "boolean" },
              "distance": { "type": ["number", "null"] }
            }
          }
        },
        "measurement_window": { "$ref": "#/$defs/measurement_window" },
        "method": {
          "type": "object",
          "additionalProperties": true,
          "required": ["name", "description", "evaluator"],
          "description": "How the level was computed, named and described, so a reader can reproduce it against the same snapshot.",
          "properties": {
            "name": { "type": "string", "minLength": 1 },
            "description": { "type": "string", "minLength": 1 },
            "evaluator": { "type": "string", "minLength": 1 },
            "magnitude_floor": { "type": "number" }
          }
        },
        "unmeasured_reason": { "type": "string", "minLength": 1, "description": "Why no level could be measured, when none could. Present exactly when index_value is null." },
        "occurrences_considered": { "type": "integer", "minimum": 0, "description": "Catalogue indices only: how many occurrences the selection saw in the measured window." },
        "occurrences_at_or_above_attachment": {
          "type": "array",
          "description": "Catalogue indices only: the occurrences that reached the structure's attachment. The whole selection is GET /events/{peril}'s job, not this one's.",
          "items": { "$ref": "#/$defs/occurrence" }
        },
        "largest_occurrence": { "$ref": "#/$defs/occurrence" },
        "disclosure": {
          "type": "string",
          "minLength": 1,
          "description": "The fixed sentence stating what this observation is and is not (SPEC.md section 4, and section 3.6's out-of-scope paragraph). A measurement produced by analytics software; never a determination, a notification, or an instruction to anyone."
        },
        "limitations": {
          "type": "array",
          "minItems": 1,
          "description": "What the measurement does not account for, in plain sentences.",
          "items": { "type": "string", "minLength": 1 }
        }
      }
    },
    "feed": {
      "type": "object",
      "additionalProperties": true,
      "required": ["id", "version", "vintage", "sha256", "links", "vintage_selection"],
      "description": "The one pinned snapshot this observation was computed from. One, never a merge: a level a reader cannot reproduce from a single pinned file is a level nobody can check.",
      "properties": {
        "id": { "type": "string", "minLength": 1 },
        "name": { "type": "string" },
        "publisher": { "type": "string" },
        "kind": { "type": "string" },
        "version": { "type": "string", "minLength": 1 },
        "vintage": { "type": "string", "minLength": 1 },
        "sha256": { "type": "string", "pattern": "^[0-9a-f]{64}$" },
        "licence": { "type": "string" },
        "links": {
          "type": "object",
          "additionalProperties": false,
          "required": ["self", "data"],
          "properties": {
            "self": { "type": "string", "minLength": 1 },
            "data": { "type": "string", "minLength": 1 }
          }
        },
        "vintage_selection": {
          "type": "object",
          "additionalProperties": false,
          "required": ["pinned_version", "read_version", "is_the_pinned_version", "rule"],
          "description": "Which vintage this read used, which one the structure pins, and the rule that chose. Stated on every observation because a level that silently came from a different file than the reader assumes is the failure mode monitoring has.",
          "properties": {
            "pinned_version": { "type": "string", "minLength": 1 },
            "read_version": { "type": "string", "minLength": 1 },
            "is_the_pinned_version": { "type": "boolean" },
            "rule": { "type": "string", "minLength": 1 }
          }
        }
      }
    },
    "measurement_window": {
      "type": "object",
      "additionalProperties": false,
      "required": ["cover_period", "record_ends", "days_measured", "days_not_yet_measured", "basis"],
      "description": "The days the index was measured over: the overlap of the cover period with the snapshot's period of record.",
      "properties": {
        "cover_period": {
          "type": "object",
          "additionalProperties": false,
          "required": ["inception", "expiry", "days"],
          "properties": {
            "inception": { "type": "string", "minLength": 1, "description": "Echoed verbatim from the structure, in the offset it was written in." },
            "expiry": { "type": "string", "minLength": 1 },
            "days": { "type": "integer", "minimum": 1, "description": "Whole days inside the term. The expiry instant ends it, so a term expiring at midnight does not include that day." }
          }
        },
        "measured_from": { "type": "string", "pattern": "^[0-9]{4}-[0-9]{2}-[0-9]{2}$" },
        "measured_to": { "type": "string", "pattern": "^[0-9]{4}-[0-9]{2}-[0-9]{2}$" },
        "record_ends": { "type": "string", "pattern": "^[0-9]{4}-[0-9]{2}-[0-9]{2}$", "description": "The last day the snapshot's period of record holds. Days of the term after it are not measured, and are not read as days in which nothing happened." },
        "days_measured": { "type": "integer", "minimum": 0 },
        "days_not_yet_measured": { "type": "integer", "minimum": 0 },
        "basis": { "type": "string", "minLength": 1 }
      }
    },
    "occurrence": {
      "type": "object",
      "additionalProperties": false,
      "required": ["event_id", "time", "magnitude", "events_in_occurrence"],
      "properties": {
        "event_id": { "type": "string", "minLength": 1 },
        "time": { "type": "string", "minLength": 20 },
        "magnitude": { "type": "number" },
        "events_in_occurrence": { "type": "integer", "minimum": 1 }
      }
    }
  }
}
