{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://openspatials.com/developers/spec/0.5/status.schema.json",
  "title": "OpenSpatials connector status object, version 0.2-draft",
  "description": "Spec: docs/package/04-INTERFACE-SPECS.md section 6. Read-only. On the web a frozen copy at window.openspatials.status; in Godot the status property, also printed as one JSON line. Field names are the same in every engine so one conformance runner can compare engines. Unknown fields are allowed. Connectors may add fields (the web core adds game, ladder, itemUses and focus). receipt (the arrival's Universal Manifest v0.4 evaluation receipt) and profileReceipt (the sending game's signed profile) are defined here; the receipt is the full Universal Manifest receipt and replaces the separate ownership field.",
  "type": "object",
  "required": [
    "state"
  ],
  "properties": {
    "state": {
      "enum": [
        "idle",
        "ready",
        "loading",
        "arrived",
        "refused",
        "no-arrival"
      ]
    },
    "mode": {
      "description": "openspatials for an OpenSpatials crossing link of any version, vibejam for a Vibe Jam arrival.",
      "anyOf": [
        {
          "enum": [
            "openspatials",
            "vibejam"
          ]
        },
        {
          "type": "null"
        }
      ]
    },
    "arrival": {
      "description": "The raw link parameters.",
      "anyOf": [
        {
          "type": "object",
          "additionalProperties": {
            "type": "string"
          }
        },
        {
          "type": "null"
        }
      ]
    },
    "character": {
      "anyOf": [
        {
          "$ref": "#/$defs/character"
        },
        {
          "type": "null"
        }
      ]
    },
    "rung": {
      "anyOf": [
        {
          "enum": [
            1,
            2,
            3,
            4
          ]
        },
        {
          "type": "null"
        }
      ]
    },
    "look": {
      "anyOf": [
        {
          "enum": [
            "vrm",
            "gltf",
            "simple",
            "sprite",
            "portrait",
            "nametag"
          ]
        },
        {
          "type": "null"
        }
      ]
    },
    "lookAttempts": {
      "type": "array",
      "items": {
        "type": "object",
        "required": [
          "look"
        ],
        "properties": {
          "look": {
            "type": "string"
          },
          "url": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ]
          },
          "ok": {
            "type": "boolean"
          },
          "reason": {
            "anyOf": [
              {
                "$ref": "#/$defs/reasonCode"
              },
              {
                "type": "null"
              }
            ]
          },
          "rung": {
            "anyOf": [
              {
                "enum": [
                  1,
                  2,
                  3,
                  4
                ]
              },
              {
                "type": "null"
              }
            ]
          },
          "detail": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ]
          }
        }
      }
    },
    "acceptedItems": {
      "type": "array",
      "items": {
        "type": "string"
      }
    },
    "refusedItems": {
      "type": "array",
      "items": {
        "type": "object",
        "required": [
          "id",
          "reason"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "reason": {
            "$ref": "#/$defs/reasonCode"
          },
          "message": {
            "type": "string"
          }
        }
      }
    },
    "integrity": {
      "description": "checked: the link's hash matches. mismatch: it does not, and the arrival is refused (tampered-link). record-changed: it does not, but the file is a signed avatar record that its issuing game's listed key confirms, for the link's character (CROSSING-AND-RETURN.md section 3 step 4): it arrives, with warning record-changed. missing: the link has no hash. n/a: a Vibe Jam arrival.",
      "anyOf": [
        {
          "enum": [
            "checked",
            "missing",
            "mismatch",
            "record-changed",
            "n/a"
          ]
        },
        {
          "type": "null"
        }
      ]
    },
    "returnUrl": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ]
    },
    "reason": {
      "anyOf": [
        {
          "$ref": "#/$defs/reasonCode"
        },
        {
          "type": "null"
        }
      ]
    },
    "errors": {
      "type": "array",
      "items": {
        "type": "string"
      }
    },
    "warnings": {
      "type": "array",
      "items": {
        "type": "string"
      }
    },
    "log": {
      "type": "array"
    },
    "lastDepartLink": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ]
    },
    "arrivalMs": {
      "anyOf": [
        {
          "type": "number",
          "minimum": 0
        },
        {
          "type": "null"
        }
      ]
    },
    "receipt": {
      "description": "The arrival's Universal Manifest v0.4 evaluation receipt (AVATAR-RECORD.md section 1.2; STATUS-REASONS-AND-TEST-INTERFACE.md section 1.2): the avatar record's own check, the status of every facet this game projected, the outcome, and records, each linked ownership record's own receipt. It replaces the separate ownership field. null until a character file is read as a record (no arrival, a Vibe Jam arrival, or a refusal before the file was read). A refused arrival keeps it, with outcome rejected.",
      "anyOf": [
        {
          "allOf": [
            {
              "$ref": "#/$defs/receipt"
            },
            {
              "required": [
                "form",
                "version",
                "records"
              ]
            }
          ]
        },
        {
          "type": "null"
        }
      ]
    },
    "profileReceipt": {
      "description": "The arrival's view of the sending game's profile, read by the issuer-key lookup (APP-PROFILE-AND-DIRECTORY.md section 1.5): the same receipt shape as receipt (with no records), with subject the address of the sender's openspatials-world.json. null when no sender profile was read.",
      "anyOf": [
        {
          "allOf": [
            {
              "$ref": "#/$defs/receipt"
            },
            {
              "required": [
                "form",
                "version"
              ]
            }
          ]
        },
        {
          "type": "null"
        }
      ]
    },
    "permissionsSource": {
      "description": "Where item rights came from, for example 'none' (show-only), 'universal-manifest' or 'unreadable'.",
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ]
    },
    "spec": {
      "description": "The spec version the connector writes.",
      "type": "string"
    },
    "message": {
      "description": "The plain sentence for reason.",
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ]
    }
  },
  "$defs": {
    "reasonCode": {
      "description": "A reason code from 04 section 2, including prefix codes such as game-policy:tool-not-accepted and unknown-kind:wand.",
      "type": "string",
      "pattern": "^[a-z][a-z0-9-]*(?::[a-z0-9-]+)?$"
    },
    "character": {
      "type": "object",
      "properties": {
        "id": {
          "type": "string"
        },
        "name": {
          "type": "string"
        },
        "color": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ]
        },
        "looks": {
          "description": "Look names (a list) or look name -> URL (an object).",
          "anyOf": [
            {
              "type": "array",
              "items": {
                "type": "string"
              }
            },
            {
              "type": "object",
              "additionalProperties": {
                "anyOf": [
                  {
                    "type": "string"
                  },
                  {
                    "type": "null"
                  }
                ]
              }
            }
          ]
        },
        "items": {
          "type": "array",
          "items": {
            "type": "object",
            "required": [
              "id"
            ],
            "properties": {
              "id": {
                "type": "string"
              },
              "name": {
                "type": "string"
              },
              "kind": {
                "type": "string"
              }
            }
          }
        },
        "lookUrls": {
          "type": "object",
          "additionalProperties": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ]
          }
        }
      }
    },
    "issuer": {
      "description": "The game that issued a verified record. url: where its profile was found. name: the profile's name, or null when that is not a string of at most 64 characters. keyId: the signingKeys id whose key checked the signature.",
      "type": "object",
      "required": [
        "url",
        "name",
        "keyId"
      ],
      "properties": {
        "url": {
          "type": "string",
          "minLength": 1,
          "maxLength": 2048
        },
        "name": {
          "anyOf": [
            {
              "type": "string",
              "maxLength": 64
            },
            {
              "type": "null"
            }
          ]
        },
        "keyId": {
          "type": "string",
          "pattern": "^[A-Za-z0-9._-]{1,64}$"
        }
      }
    },
    "receipt": {
      "description": "A Universal Manifest v0.4 evaluation receipt (Base sections 3.1.5; 3.1.6 and 3.3.1; CONFORMANCE item 5) for one document: an avatar record (status.receipt, AVATAR-RECORD.md section 1.2) or an app profile (status.profileReceipt and the destination check, APP-PROFILE-AND-DIRECTORY.md section 1.5). @type includes um:Receipt. form: signed (a Universal Manifest document was read) or plain. version: the document's core version (openspatials), or null. manifestId and subject: the signed document's @id and subject, else null. outcome: accepted, accepted-with-warnings, accepted-partial or rejected. signatureCheck and freshnessCheck: how far those checks got (not-evaluated when a stage did not run). keyRefResolution: resolved or unresolved when the signature's keyRef was looked at, else null. trust: issuer (a key the issuing game lists checked a fresh document), unverified (it still loads or arrives), or null (refused before a trust answer). why: why it is unverified, else null. issuer: set only when trust is issuer. facetStatuses: each processed or withheld facet with its Universal Manifest status. records: on status.receipt only, the receipt of each ownership record the character links.",
      "type": "object",
      "required": [
        "@type",
        "manifestId",
        "subject",
        "outcome",
        "signatureCheck",
        "freshnessCheck",
        "keyRefResolution",
        "trust",
        "why",
        "issuer",
        "facetStatuses"
      ],
      "properties": {
        "@type": {
          "type": "array",
          "minItems": 1,
          "items": {
            "type": "string"
          },
          "contains": {
            "const": "um:Receipt"
          }
        },
        "form": {
          "enum": [
            "signed",
            "plain"
          ]
        },
        "version": {
          "anyOf": [
            {
              "type": "string",
              "minLength": 1,
              "maxLength": 64
            },
            {
              "type": "null"
            }
          ]
        },
        "manifestId": {
          "anyOf": [
            {
              "type": "string",
              "minLength": 1,
              "maxLength": 2048
            },
            {
              "type": "null"
            }
          ]
        },
        "subject": {
          "anyOf": [
            {
              "type": "string",
              "minLength": 1,
              "maxLength": 2048
            },
            {
              "type": "null"
            }
          ]
        },
        "outcome": {
          "$ref": "#/$defs/outcome"
        },
        "signatureCheck": {
          "enum": [
            "valid",
            "invalid",
            "unsupported-profile",
            "not-evaluated"
          ]
        },
        "freshnessCheck": {
          "enum": [
            "fresh",
            "expired",
            "stale",
            "not-evaluated"
          ]
        },
        "keyRefResolution": {
          "anyOf": [
            {
              "enum": [
                "resolved",
                "unresolved"
              ]
            },
            {
              "type": "null"
            }
          ]
        },
        "trust": {
          "anyOf": [
            {
              "enum": [
                "issuer",
                "unverified"
              ]
            },
            {
              "type": "null"
            }
          ]
        },
        "why": {
          "description": "Avatar records: unsigned, expired, not-yet-valid, or the ownership why values (issuer-profile-unverified: the issuing game's profile names a signed form that did not confirm it). App profiles: no-signed-profile, signed-profile-unreachable, subject-mismatch, unsigned, expired, not-yet-valid, issuer-key-not-listed, cannot-check.",
          "anyOf": [
            {
              "enum": [
                "unsigned",
                "expired",
                "not-yet-valid",
                "no-issuer",
                "issuer-unreachable",
                "issuer-timeout",
                "issuer-no-keys",
                "issuer-key-not-listed",
                "cannot-check",
                "issuer-profile-unverified",
                "no-signed-profile",
                "signed-profile-unreachable",
                "subject-mismatch"
              ]
            },
            {
              "type": "null"
            }
          ]
        },
        "issuer": {
          "anyOf": [
            {
              "$ref": "#/$defs/issuer"
            },
            {
              "type": "null"
            }
          ]
        },
        "facetStatuses": {
          "type": "array",
          "maxItems": 33,
          "items": {
            "$ref": "#/$defs/facetStatus"
          }
        },
        "records": {
          "description": "The receipt of each ownership record the character links, in link order after equal addresses are fetched once: one record, or one to eight. Empty when none is linked (the record's own consents, or no rights record, decide).",
          "type": "array",
          "maxItems": 8,
          "items": {
            "$ref": "#/$defs/recordReceipt"
          }
        }
      },
      "allOf": [
        {
          "description": "trust issuer means a listed key checked the signature of a fresh document: issuer is set, why is null.",
          "if": {
            "required": [
              "trust"
            ],
            "properties": {
              "trust": {
                "const": "issuer"
              }
            }
          },
          "then": {
            "properties": {
              "form": {
                "const": "signed"
              },
              "why": {
                "type": "null"
              },
              "issuer": {
                "$ref": "#/$defs/issuer"
              },
              "signatureCheck": {
                "const": "valid"
              },
              "freshnessCheck": {
                "const": "fresh"
              }
            }
          }
        },
        {
          "description": "trust unverified always says why.",
          "if": {
            "required": [
              "trust"
            ],
            "properties": {
              "trust": {
                "const": "unverified"
              }
            }
          },
          "then": {
            "properties": {
              "why": {
                "type": "string"
              },
              "issuer": {
                "type": "null"
              }
            }
          }
        },
        {
          "description": "A plain document carries no signature and no Universal Manifest envelope.",
          "if": {
            "required": [
              "form"
            ],
            "properties": {
              "form": {
                "const": "plain"
              }
            }
          },
          "then": {
            "properties": {
              "manifestId": {
                "type": "null"
              },
              "trust": {
                "const": "unverified"
              },
              "signatureCheck": {
                "const": "not-evaluated"
              },
              "keyRefResolution": {
                "type": "null"
              }
            }
          }
        },
        {
          "description": "accepted means every facet was processed by a confirmed document: trust is issuer.",
          "if": {
            "required": [
              "outcome"
            ],
            "properties": {
              "outcome": {
                "const": "accepted"
              }
            }
          },
          "then": {
            "properties": {
              "trust": {
                "const": "issuer"
              }
            }
          }
        }
      ]
    },
    "outcome": {
      "description": "Base section 3.1.5. accepted: every projected facet processed, every use asked allowed, and the document confirmed by its issuer's key. accepted-with-warnings: the same, with a non-critical condition noted (not confirmed by an issuer key, or shown only). accepted-partial: some facet withheld or some use asked refused. rejected: a mandatory check failed, or the arrival was refused after the document was read.",
      "enum": [
        "accepted",
        "accepted-with-warnings",
        "accepted-partial",
        "rejected"
      ]
    },
    "facetStatus": {
      "description": "One facet's status (Base section 3.3.1). facetId: the facet's @id (an avatar record's character facet is its subject or id; an item facet is <subject>#item-<item id>; an app profile's facet is its subject). status: processed (shown), consent-denied (a governing consent refused it: withdrawn, expired, a condition, the scope or the purpose), consent-missing (no consent that counts governs it: none is listed, or the record that would carry it was not accepted); the other Universal Manifest statuses are not written by this core. reason: the core's reason code for that answer, or null. why (a facet shown only): why no issuer key confirmed the record that decided it. uses (items): the other uses the game asked about, as status.itemUses gives them.",
      "type": "object",
      "required": [
        "facetId",
        "status",
        "reason"
      ],
      "properties": {
        "facetId": {
          "type": "string",
          "minLength": 1,
          "maxLength": 2200
        },
        "status": {
          "enum": [
            "processed",
            "opaque",
            "consent-denied",
            "consent-missing",
            "trustTierUnsupported",
            "assuranceInsufficient",
            "not-projected",
            "written"
          ]
        },
        "name": {
          "type": "string"
        },
        "reason": {
          "anyOf": [
            {
              "$ref": "#/$defs/reasonCode"
            },
            {
              "type": "null"
            }
          ]
        },
        "why": {
          "description": "A facet shown only: why no issuer key this game accepts confirmed the record that decided it (the ownership answer's why).",
          "enum": [
            "no-issuer",
            "issuer-unreachable",
            "issuer-timeout",
            "issuer-no-keys",
            "issuer-key-not-listed",
            "cannot-check",
            "issuer-profile-unverified",
            "issuer-not-accepted"
          ]
        },
        "uses": {
          "type": "object",
          "propertyNames": {
            "enum": [
              "use",
              "copy"
            ]
          },
          "additionalProperties": {
            "type": "object",
            "required": [
              "allowed",
              "reason"
            ],
            "properties": {
              "allowed": {
                "type": "boolean"
              },
              "reason": {
                "$ref": "#/$defs/reasonCode"
              }
            }
          }
        }
      }
    },
    "recordReceipt": {
      "description": "The receipt of one ownership record the character links (ownership-bridge.js recordReceipt). url: where it was read from. reason: null when the issuer's key confirmed it, ownership-unverified or ownership-self-made when it is shown only, else the record problem (ownership-unreadable, ownership-bad-signature, ownership-expired, ownership-not-yet-valid, ownership-wrong-character). trust, why and issuer: as the ownership check gave them (issuer only when trust is issuer). facetStatuses: what this record alone answers for showing each facet of this character it names (empty when it was not read). outcome: rejected when it was not read or has a whole-record problem; accepted-partial when a facet it names is withheld; accepted-with-warnings when it is shown only; accepted when its issuer's key confirmed it and it shows every facet it names.",
      "type": "object",
      "required": [
        "@type",
        "url",
        "manifestId",
        "subject",
        "outcome",
        "signatureCheck",
        "freshnessCheck",
        "keyRefResolution",
        "trust",
        "why",
        "issuer",
        "reason",
        "facetStatuses"
      ],
      "properties": {
        "@type": {
          "type": "array",
          "minItems": 1,
          "items": {
            "type": "string"
          },
          "contains": {
            "const": "um:Receipt"
          }
        },
        "url": {
          "anyOf": [
            {
              "type": "string",
              "minLength": 1,
              "maxLength": 2048
            },
            {
              "type": "null"
            }
          ]
        },
        "manifestId": {
          "anyOf": [
            {
              "type": "string",
              "minLength": 1,
              "maxLength": 2048
            },
            {
              "type": "null"
            }
          ]
        },
        "subject": {
          "anyOf": [
            {
              "type": "string",
              "minLength": 1,
              "maxLength": 2048
            },
            {
              "type": "null"
            }
          ]
        },
        "outcome": {
          "$ref": "#/$defs/outcome"
        },
        "signatureCheck": {
          "enum": [
            "valid",
            "invalid",
            "unsupported-profile",
            "not-evaluated"
          ]
        },
        "freshnessCheck": {
          "enum": [
            "fresh",
            "expired",
            "stale",
            "not-evaluated"
          ]
        },
        "keyRefResolution": {
          "anyOf": [
            {
              "enum": [
                "resolved",
                "unresolved"
              ]
            },
            {
              "type": "null"
            }
          ]
        },
        "trust": {
          "description": "issuer: the issuer key that keyRef names checked the signature. self-made: the player signed it with the did:key that is its subject. unverified: no issuer key this game accepts confirmed it. null: the check stopped before the signature step.",
          "anyOf": [
            {
              "enum": [
                "issuer",
                "self-made",
                "unverified"
              ]
            },
            {
              "type": "null"
            }
          ]
        },
        "why": {
          "description": "Why no issuer key confirmed the record. issuer-profile-unverified: the issuer's profile names a signed form that did not confirm it (APP-PROFILE-AND-DIRECTORY.md section 1.5). issuer-not-accepted: this game's accepts.issuers leaves the issuer out.",
          "anyOf": [
            {
              "enum": [
                "no-issuer",
                "issuer-unreachable",
                "issuer-timeout",
                "issuer-no-keys",
                "issuer-key-not-listed",
                "cannot-check",
                "issuer-profile-unverified",
                "issuer-not-accepted"
              ]
            },
            {
              "type": "null"
            }
          ]
        },
        "issuer": {
          "anyOf": [
            {
              "$ref": "#/$defs/issuer"
            },
            {
              "type": "null"
            }
          ]
        },
        "reason": {
          "anyOf": [
            {
              "$ref": "#/$defs/reasonCode"
            },
            {
              "type": "null"
            }
          ]
        },
        "facetStatuses": {
          "type": "array",
          "maxItems": 33,
          "items": {
            "$ref": "#/$defs/facetStatus"
          }
        }
      },
      "allOf": [
        {
          "description": "An issuer is named only when its key checked the record.",
          "if": {
            "not": {
              "required": [
                "trust"
              ],
              "properties": {
                "trust": {
                  "const": "issuer"
                }
              }
            }
          },
          "then": {
            "properties": {
              "issuer": {
                "type": "null"
              }
            }
          }
        },
        {
          "description": "accepted: the issuer's key confirmed a fresh record for this character.",
          "if": {
            "required": [
              "outcome"
            ],
            "properties": {
              "outcome": {
                "const": "accepted"
              }
            }
          },
          "then": {
            "properties": {
              "trust": {
                "const": "issuer"
              },
              "reason": {
                "type": "null"
              },
              "issuer": {
                "$ref": "#/$defs/issuer"
              },
              "signatureCheck": {
                "const": "valid"
              },
              "freshnessCheck": {
                "const": "fresh"
              }
            }
          }
        },
        {
          "description": "A record that was not read has no facet statuses.",
          "if": {
            "required": [
              "manifestId"
            ],
            "properties": {
              "manifestId": {
                "type": "null"
              }
            }
          },
          "then": {
            "properties": {
              "facetStatuses": {
                "maxItems": 0
              }
            }
          }
        }
      ]
    }
  }
}
