{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://situational-awareness-study-game.ayaki-tokugawa.chatgpt.site/proof/outcome-event-schema.json",
  "title": "Pocket Thesis local outcome envelope",
  "description": "Version 1 local-only outcome data. Learner answer text is intentionally absent and rejected as an additional property. A private recall attempt records completion without a score or correctness claim.",
  "type": "object",
  "additionalProperties": false,
  "required": ["schemaVersion", "installationId", "events", "recallQueue"],
  "properties": {
    "schemaVersion": { "const": 1 },
    "installationId": { "$ref": "#/$defs/id" },
    "events": {
      "type": "array",
      "maxItems": 5000,
      "items": { "$ref": "#/$defs/event" }
    },
    "recallQueue": {
      "type": "array",
      "maxItems": 1000,
      "items": { "$ref": "#/$defs/recallQueueItem" }
    }
  },
  "$defs": {
    "id": {
      "type": "string",
      "minLength": 1,
      "maxLength": 128,
      "pattern": "^[A-Za-z0-9][A-Za-z0-9._:-]*$"
    },
    "baseEvent": {
      "type": "object",
      "required": ["schemaVersion", "id", "sessionId", "at", "type"],
      "properties": {
        "schemaVersion": { "const": 1 },
        "id": { "$ref": "#/$defs/id" },
        "sessionId": { "$ref": "#/$defs/id" },
        "at": { "type": "integer", "minimum": 0 },
        "type": {
          "enum": [
            "session_started",
            "session_heartbeat",
            "session_ended",
            "card_opened",
            "learn_completed",
            "source_reopened",
            "recall_attempted",
            "recall_graded",
            "scenario_completed"
          ]
        }
      }
    },
    "event": {
      "oneOf": [
        {
          "allOf": [
            { "$ref": "#/$defs/baseEvent" },
            {
              "type": "object",
              "additionalProperties": false,
              "required": ["schemaVersion", "id", "sessionId", "at", "type"],
              "properties": {
                "schemaVersion": { "const": 1 },
                "id": { "$ref": "#/$defs/id" },
                "sessionId": { "$ref": "#/$defs/id" },
                "at": { "type": "integer", "minimum": 0 },
                "type": { "const": "session_started" },
                "deckId": { "$ref": "#/$defs/id" }
              }
            }
          ]
        },
        {
          "type": "object",
          "additionalProperties": false,
          "required": [
            "schemaVersion",
            "id",
            "sessionId",
            "at",
            "type",
            "deckId",
            "cardId",
            "horizon",
            "mode",
            "aided"
          ],
          "properties": {
            "schemaVersion": { "const": 1 },
            "id": { "$ref": "#/$defs/id" },
            "sessionId": { "$ref": "#/$defs/id" },
            "at": { "type": "integer", "minimum": 0 },
            "type": { "const": "recall_attempted" },
            "deckId": { "$ref": "#/$defs/id" },
            "cardId": { "$ref": "#/$defs/id" },
            "horizon": { "enum": ["immediate", "1-day", "7-day"] },
            "mode": { "enum": ["typed", "aloud"] },
            "aided": { "type": "boolean" }
          }
        },
        {
          "type": "object",
          "additionalProperties": false,
          "required": ["schemaVersion", "id", "sessionId", "at", "type"],
          "properties": {
            "schemaVersion": { "const": 1 },
            "id": { "$ref": "#/$defs/id" },
            "sessionId": { "$ref": "#/$defs/id" },
            "at": { "type": "integer", "minimum": 0 },
            "type": { "const": "session_heartbeat" }
          }
        },
        {
          "type": "object",
          "additionalProperties": false,
          "required": ["schemaVersion", "id", "sessionId", "at", "type", "reason"],
          "properties": {
            "schemaVersion": { "const": 1 },
            "id": { "$ref": "#/$defs/id" },
            "sessionId": { "$ref": "#/$defs/id" },
            "at": { "type": "integer", "minimum": 0 },
            "type": { "const": "session_ended" },
            "reason": { "enum": ["manual", "idle", "clock-change"] }
          }
        },
        {
          "type": "object",
          "additionalProperties": false,
          "required": ["schemaVersion", "id", "sessionId", "at", "type", "deckId", "cardId"],
          "properties": {
            "schemaVersion": { "const": 1 },
            "id": { "$ref": "#/$defs/id" },
            "sessionId": { "$ref": "#/$defs/id" },
            "at": { "type": "integer", "minimum": 0 },
            "type": { "enum": ["card_opened", "learn_completed", "source_reopened"] },
            "deckId": { "$ref": "#/$defs/id" },
            "cardId": { "$ref": "#/$defs/id" }
          }
        },
        {
          "type": "object",
          "additionalProperties": false,
          "required": [
            "schemaVersion",
            "id",
            "sessionId",
            "at",
            "type",
            "deckId",
            "cardId",
            "horizon",
            "result",
            "verification",
            "grader",
            "rubricVersion"
          ],
          "properties": {
            "schemaVersion": { "const": 1 },
            "id": { "$ref": "#/$defs/id" },
            "sessionId": { "$ref": "#/$defs/id" },
            "at": { "type": "integer", "minimum": 0 },
            "type": { "const": "recall_graded" },
            "deckId": { "$ref": "#/$defs/id" },
            "cardId": { "$ref": "#/$defs/id" },
            "horizon": { "enum": ["immediate", "1-day", "7-day"] },
            "result": { "enum": ["pass", "partial", "retry"] },
            "verification": { "enum": ["verified", "unverified"] },
            "grader": { "enum": ["semantic", "human", "self-check"] },
            "rubricVersion": { "$ref": "#/$defs/id" }
          },
          "allOf": [
            {
              "if": {
                "properties": { "grader": { "const": "self-check" } },
                "required": ["grader"]
              },
              "then": { "properties": { "verification": { "const": "unverified" } } }
            }
          ]
        },
        {
          "type": "object",
          "additionalProperties": false,
          "required": [
            "schemaVersion",
            "id",
            "sessionId",
            "at",
            "type",
            "deckId",
            "scenarioId",
            "result"
          ],
          "properties": {
            "schemaVersion": { "const": 1 },
            "id": { "$ref": "#/$defs/id" },
            "sessionId": { "$ref": "#/$defs/id" },
            "at": { "type": "integer", "minimum": 0 },
            "type": { "const": "scenario_completed" },
            "deckId": { "$ref": "#/$defs/id" },
            "scenarioId": { "$ref": "#/$defs/id" },
            "result": { "enum": ["calibrated", "developing", "completed"] }
          }
        }
      ]
    },
    "recallQueueItem": {
      "type": "object",
      "additionalProperties": false,
      "required": [
        "schemaVersion",
        "id",
        "deckId",
        "cardId",
        "horizon",
        "scheduledAt",
        "dueAt",
        "status"
      ],
      "properties": {
        "schemaVersion": { "const": 1 },
        "id": { "$ref": "#/$defs/id" },
        "deckId": { "$ref": "#/$defs/id" },
        "cardId": { "$ref": "#/$defs/id" },
        "horizon": { "enum": ["1-day", "7-day"] },
        "scheduledAt": { "type": "integer", "minimum": 0 },
        "dueAt": { "type": "integer", "minimum": 0 },
        "status": { "enum": ["pending", "completed"] },
        "completedAt": { "type": "integer", "minimum": 0 },
        "gradeEventId": { "$ref": "#/$defs/id" },
        "attemptEventId": { "$ref": "#/$defs/id" }
      },
      "allOf": [
        {
          "if": { "properties": { "status": { "const": "completed" } } },
          "then": {
            "required": ["completedAt"],
            "oneOf": [
              {
                "required": ["gradeEventId"],
                "not": { "required": ["attemptEventId"] }
              },
              {
                "required": ["attemptEventId"],
                "not": { "required": ["gradeEventId"] }
              }
            ]
          },
          "else": {
            "allOf": [
              { "not": { "required": ["completedAt"] } },
              { "not": { "required": ["gradeEventId"] } },
              { "not": { "required": ["attemptEventId"] } }
            ]
          }
        }
      ]
    }
  }
}
