{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://oags.dev/schema/oags-v0.1.schema.json",
  "title": "OAGS v0.1 scene payload",
  "description": "Open Agent Graph Standard v0.1. A compact agent-facing graph scene. additionalProperties is true at every level so v0.2 sits on v0.1: unknown keys MUST be preserved, never rejected.",
  "type": "object",
  "required": ["oags", "graph_id", "entry", "blocks", "edges", "declared_losses"],
  "additionalProperties": true,
  "properties": {
    "oags": { "type": "string", "description": "version, e.g. 0.1; self-identifies the payload" },
    "graph_id": { "type": "string", "description": "opaque stable id of the whole graph; MUST NOT be dereferenced by consumers" },
    "site": { "type": "string" },
    "schema": { "type": ["string", "null"], "description": "URL to the OAGS schema/profile; a web surface MUST publish non-null" },
    "conforms_to": { "type": ["string", "array"] },
    "as_of": { "type": "string", "description": "timestamp of the graph state this slice reflects (distinct from served_at)" },
    "graph_version": { "type": "string" },
    "entry": {
      "type": "object",
      "required": ["block_id", "depth"],
      "additionalProperties": true,
      "properties": {
        "block_id": { "type": "string" },
        "depth": { "type": "integer", "minimum": 0 },
        "selector_profile": { "type": "string", "description": "reserved; shape tightens in v0.2" }
      }
    },
    "blocks": {
      "type": "array",
      "items": {
        "type": "object",
        "required": ["block_id"],
        "additionalProperties": true,
        "properties": {
          "block_id": { "type": "string", "pattern": "^[^@].*" },
          "block_class": { "type": "string" },
          "label": { "type": "string" },
          "attachment": { "$ref": "#/$defs/attachment" }
        }
      }
    },
    "edges": {
      "type": "array",
      "items": {
        "type": "object",
        "required": ["from", "to"],
        "additionalProperties": true,
        "properties": {
          "from": { "type": "string" },
          "to": { "type": "string" },
          "op": { "type": "string" },
          "lens": { "type": "string" },
          "polarity": { "enum": ["+", "-", "0"] },
          "id": { "type": "string" },
          "type": { "type": "string" },
          "attachment": { "$ref": "#/$defs/attachment" }
        }
      }
    },
    "lenses": {
      "type": "object",
      "description": "lens_id -> human gloss; the id is the machine token, the gloss is NOT machine-actionable",
      "additionalProperties": { "type": "string" }
    },
    "provenance": {
      "type": "object",
      "additionalProperties": true,
      "description": "flat PROV-O mini-subset, or {claim, document} split for off-origin travel"
    },
    "declared_losses": {
      "type": "array",
      "description": "the confession surface; [] = signable completeness claim within entry.depth",
      "items": {
        "type": "object",
        "required": ["scope"],
        "additionalProperties": true,
        "properties": {
          "scope": {
            "enum": ["depth_limited", "truncated", "hidden_edges", "omitted_nodes", "sampled"],
            "description": "CLOSED enum: what shape of thing is missing"
          },
          "reason": {
            "type": "string",
            "description": "OPEN enum; base policy/rights/rate_limit/timeout/stale/expiry/redacted_by_policy/compact_profile/encoding, or x_*; required only when scope does not self-explain. Unknown reason MUST be surfaced, not dropped."
          },
          "where": {
            "type": "string",
            "description": "a block_id/edge id, or a reserved region: @graph @schema @blocks @edges"
          },
          "count": { "anyOf": [{ "type": "integer", "minimum": 0 }, { "const": "unknown" }] },
          "recoverable": {
            "enum": [true, false, "unknown"],
            "description": "true=follow expand_via, false=gone-do-not-retry, unknown; absent != false"
          },
          "expand_via": {
            "anyOf": [
              { "type": "object", "additionalProperties": true, "properties": { "rel": { "type": "string" }, "from": { "type": "string" }, "depth": { "type": "integer" } } },
              { "type": "null" }
            ]
          },
          "note": { "type": "string", "description": "human gloss; agents MUST NOT derive behavior from it" }
        }
      }
    },
    "negative_space": {
      "type": "array",
      "description": "absence by design; structured objects only (no bare strings); [] is NOT a completeness claim",
      "items": {
        "type": "object",
        "required": ["kind", "claim"],
        "additionalProperties": true,
        "properties": {
          "kind": { "type": "string", "description": "e.g. by_design | asserted_complete" },
          "claim": { "type": "string" },
          "where": { "type": "string" },
          "machine_readable": { "type": "boolean" }
        }
      }
    },
    "expand": {
      "anyOf": [
        { "type": "string", "description": "RFC 6570 URI template; reserved vars from,depth,view,loss,cursor,limit" },
        { "type": "object", "required": ["template"], "additionalProperties": true, "properties": { "template": { "type": "string" }, "params": { "type": "array" }, "rels": { "type": "object" } } }
      ]
    },
    "canon": {
      "anyOf": [
        { "type": "string", "description": "profile id, e.g. jcs-v1 (default)" },
        { "type": "object", "required": ["alg"], "additionalProperties": true, "properties": { "alg": { "type": "string" }, "scope": { "type": "string" }, "sig_excluded": { "type": "array", "items": { "type": "string" } } } }
      ]
    },
    "sig": {
      "type": "object",
      "additionalProperties": true,
      "description": "detached/embedded JWS (RFC 7515) over the canon form; proves the claim was MADE, not that it is true"
    },
    "warnings": {
      "type": "array",
      "description": "conformance/build-state notes; NEVER put build-state in declared_losses",
      "items": { "type": "object", "additionalProperties": true }
    },
    "@context": { "type": ["string", "object", "array"] }
  },
  "$defs": {
    "attachment": {
      "type": "object",
      "description": "reserved opaque latent/embedding payload ref; shape tightens in v0.2",
      "additionalProperties": true,
      "properties": {
        "model": { "type": "string" },
        "projection": { "type": "string" },
        "dims": { "type": "integer" },
        "codec": { "type": "string" },
        "version": { "type": "string" }
      }
    }
  },
  "allOf": [
    {
      "description": "if sig is present, canon MUST be present",
      "if": { "required": ["sig"] },
      "then": { "required": ["canon"] }
    }
  ]
}
