{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "urn:agent-incident-registry:schema:incident:1",
  "title": "Agent Incident Registry record",
  "description": "One source-linked agent-related security or safety event from the Agent Incident Registry (AIR). Every record carries a fetched supporting source and a verbatim quote. Curation contract: CURATION.md in the corpus repository.",
  "type": "object",
  "required": [
    "public_id",
    "incident_id",
    "date_disclosed",
    "title",
    "class",
    "attack_surface",
    "autonomy_level",
    "impact_realized",
    "primary_sources",
    "verified_quote",
    "confidence",
    "risk_category",
    "eai_domain",
    "eai_category",
    "ai_entity",
    "agency",
    "agency_debatable",
    "agency_reason",
    "vector_family",
    "vector_detail",
    "guardrail_kind",
    "guardrail_outcome",
    "detection_mechanism",
    "agent_framework",
    "model_provider",
    "model_name",
    "tool_access",
    "financial_loss_band",
    "xrefs",
    "primary_asi",
    "asi_curated",
    "asi_scope",
    "asi_provenance",
    "asi_reason",
    "submitted_by"
  ],
  "properties": {
    "public_id": {
      "type": "string",
      "pattern": "^AIR-\\d{4}-\\d{4}$",
      "description": "Stable citable identifier: AIR-YYYY-NNNN (Agent Incident Registry). Minted once, never reused. Permalink: /i/<public_id>/"
    },
    "incident_id": {
      "type": "string",
      "description": "Internal slug, YYYY-MM-<vendor>-<short-name>. Dedupe key; may be renamed (old slugs redirect)."
    },
    "date_disclosed": {
      "type": "string",
      "pattern": "^\\d{4}-\\d{2}(-\\d{2})?$",
      "description": "Public disclosure date. YYYY-MM when the day is unknown."
    },
    "date_occurred": {
      "type": [
        "string",
        "null"
      ],
      "pattern": "^\\d{4}(-\\d{2}(-\\d{2})?)?$",
      "description": "When the event happened, if known and different from disclosure. Variable precision: YYYY, YYYY-MM or YYYY-MM-DD."
    },
    "title": {
      "type": "string",
      "description": "One-line description of what happened."
    },
    "class": {
      "type": "string",
      "enum": [
        "in_the_wild",
        "responsible_disclosure",
        "research_demo",
        "safety_failure"
      ],
      "description": "Disclosure pathway, independent of impact_realized: in_the_wild = observed attack/misuse outside a controlled test; responsible_disclosure = shipped vulnerability or concrete vendor threat mode surfaced through disclosure; research_demo = researcher-led test; safety_failure = failure surfaced without an adversary-supplied trigger."
    },
    "attack_surface": {
      "type": "string",
      "enum": [
        "enterprise_assistant",
        "coding_agent",
        "browser_agent",
        "computer_use_agent",
        "mcp_server",
        "agent_framework",
        "skill_plugin",
        "multi_agent_system",
        "memory_store",
        "consumer_chatbot",
        "autonomous_ops",
        "other"
      ],
      "description": "Which kind of agent system was involved."
    },
    "initial_vector": {
      "type": "string",
      "description": "How the incident started (e.g. indirect_prompt_injection_email, none_autonomous_action). Free vocabulary, not yet normalised."
    },
    "agent_capability_abused": {
      "type": "array",
      "items": {
        "type": "string"
      },
      "description": "Capabilities the agent used or that were turned against it. Free vocabulary."
    },
    "target_product": {
      "type": "string",
      "description": "Product or system involved."
    },
    "target_vendor": {
      "type": [
        "string",
        "null"
      ],
      "description": "Vendor or operator of that product; null when there is no identifiable vendor."
    },
    "autonomy_level": {
      "type": "string",
      "enum": [
        "assistant",
        "copilot_with_approval",
        "semi_autonomous",
        "fully_autonomous"
      ],
      "description": "How much the agent acted without a human approving each step."
    },
    "impact_realized": {
      "type": "boolean",
      "description": "true ONLY if a real party suffered real consequences because of an AI agent. A proof of concept against a live system is false."
    },
    "impact_type": {
      "type": "array",
      "items": {
        "type": "string"
      },
      "description": "Kinds of impact (data_exfiltration, financial_loss, physical_safety…)."
    },
    "blast_radius": {
      "type": "string",
      "description": "Who or what was exposed, in prose."
    },
    "cve": {
      "type": "array",
      "items": {
        "type": "string",
        "pattern": "^(CVE-\\d{4}-\\d{4,}|GHSA-[0-9a-z]{4}-[0-9a-z]{4}-[0-9a-z]{4})$"
      },
      "description": "CVE identifiers, or GitHub Security Advisory (GHSA) ids where no CVE was assigned."
    },
    "taxonomy": {
      "type": "object",
      "properties": {
        "owasp_asi": {
          "type": "array",
          "items": {
            "type": "string",
            "enum": [
              "ASI01",
              "ASI02",
              "ASI03",
              "ASI04",
              "ASI05",
              "ASI06",
              "ASI07",
              "ASI08",
              "ASI09",
              "ASI10"
            ]
          }
        },
        "mitre_atlas": {
          "type": "array",
          "items": {
            "type": "string",
            "pattern": "^AML\\.(T|CS)\\d{4}(\\.\\d{3})?$"
          }
        },
        "labels": {
          "type": "array",
          "items": {
            "type": "string"
          }
        }
      },
      "additionalProperties": true,
      "description": "Framework crosswalk: OWASP Top 10 for Agentic Applications (ASI01–ASI10), MITRE ATLAS technique or case-study IDs, free labels."
    },
    "defense_present": {
      "type": [
        "string",
        "null"
      ],
      "description": "What control was in place, if any. Free text."
    },
    "defense_bypassed": {
      "type": [
        "boolean",
        "null"
      ],
      "description": "Legacy source-extraction flag. It conflates attempted, partial, and successful bypass and MUST NOT be used as a guardrail outcome or efficacy measure."
    },
    "fix_shipped": {
      "type": [
        "string",
        "null"
      ],
      "description": "Remediation, if known."
    },
    "primary_sources": {
      "type": "array",
      "minItems": 1,
      "items": {
        "type": "string",
        "format": "uri"
      },
      "description": "URLs actually fetched during curation. The first one is where verified_quote comes from."
    },
    "verified_quote": {
      "type": "string",
      "description": "Verbatim sentence from the fetched supporting source confirming the report."
    },
    "confidence": {
      "type": "string",
      "enum": [
        "high",
        "medium",
        "unverified"
      ],
      "description": "high = primary source fetched and quoted; medium = secondary coverage only; unverified records are quarantined, not published."
    },
    "notes": {
      "type": "string",
      "description": "Curator notes: disputes, ambiguity, what is not known."
    },
    "risk_category": {
      "type": "string",
      "description": "Legacy (pre-EAI taxonomy): primary risk category (AIR taxonomy, eight categories). Kept for comparability; see eai_category."
    },
    "risk_secondary": {
      "type": "array",
      "items": {
        "type": "string"
      },
      "description": "Legacy (pre-EAI taxonomy): other categories the record also matches."
    },
    "risk_subcategory": {
      "type": "string",
      "description": "Legacy (pre-EAI taxonomy): subcategory within the primary category; 'Unclassified' if no sub-rule fired."
    },
    "risk_sub_secondary": {
      "type": "array",
      "items": {
        "type": "string"
      },
      "description": "Legacy (pre-EAI taxonomy): other subcategories matched."
    },
    "risk_override_reason": {
      "type": "string",
      "description": "Legacy (pre-EAI taxonomy): present when the category was set by curator judgment rather than the rule engine, with the reason."
    },
    "ai_entity": {
      "type": "string",
      "enum": [
        "generative",
        "non_generative_autonomy",
        "not_ai"
      ],
      "description": "generative = an LLM acted or was targeted; non_generative_autonomy = classical perception/planning stack (robotaxis, robots); not_ai = conventional flaw in a product marketed as smart."
    },
    "agency": {
      "type": "string",
      "enum": [
        "agent_acted",
        "human_acted_on_output",
        "ai_as_target",
        "elicitation_only"
      ],
      "description": "Mutually exclusive causal-role stratum: the agent acted; the AI system/integration was a passive target, exposure endpoint, or input recipient; a human acted on its output; or the record is elicitation-only. Agency is not an inclusion flag."
    },
    "agency_debatable": {
      "type": "boolean",
      "description": "true when the agency call is contested; 23% of the corpus."
    },
    "agency_reason": {
      "type": "string",
      "description": "Why the agency value was assigned."
    },
    "eai_domain": {
      "type": "string",
      "enum": [
        "governance",
        "agent_output_quality",
        "tool_misuse",
        "privacy",
        "reliability_and_observability",
        "agent_behaviour",
        "access_control_and_permissions",
        "unmapped"
      ],
      "description": "Internal agent-risk domain (one of 7), derived from eai_category; 'unmapped' when no category applied."
    },
    "eai_category": {
      "type": "string",
      "enum": [
        "goal_misalignment",
        "policy_drift",
        "hallucination",
        "bias_and_toxicity",
        "api_integration",
        "supply_chain_vulnerabilities",
        "uncontrolled_resource_consumption",
        "sensitive_data_exposure",
        "data_exfiltration_channels",
        "data_and_memory_poisoning",
        "opaque_reasoning",
        "human_manipulation",
        "unsafe_actuation",
        "credential_theft",
        "privilege_escalation",
        "confused_deputy",
        "unmapped"
      ],
      "description": "Primary internal agent-risk category (one of 17), each crosswalked to OWASP Agentic threats, MITRE ATLAS, NIST AI RMF, EU AI Act, ISO/IEC and AIUC-1 in data/eai-taxonomy.json. Set by tools/classify_eai.py from the legacy subcategory plus impact/vector rules, with data/eai-overrides.json for judgment."
    },
    "eai_secondary": {
      "type": "array",
      "items": {
        "type": "string"
      },
      "description": "Other internal categories whose impact or vector rule also fired for the record."
    },
    "eai_reason": {
      "type": "string",
      "description": "Which rule or override decided eai_category (audit trail; see data/eai-map-report.md)."
    },
    "is_umbrella": {
      "type": "boolean",
      "description": "true when one catalog row summarizes several findings, flaws, samples, or campaign events."
    },
    "umbrella_constituents": {
      "type": "array",
      "items": {
        "type": "string"
      },
      "description": "incident_id values separately cataloged inside an umbrella record; empty when the underlying items have no separate AIR records."
    },
    "umbrella_reason": {
      "type": "string",
      "description": "Curator rationale for retaining the umbrella and how to interpret without-umbrella sensitivity counts."
    },
    "vector_family": {
      "type": "string",
      "enum": [
        "none_autonomous",
        "indirect_prompt_injection",
        "direct_prompt_injection",
        "malicious_component",
        "conventional_vulnerability",
        "misuse",
        "physical_environment",
        "other"
      ],
      "description": "initial_vector normalised to a family (derived)."
    },
    "vector_detail": {
      "type": "string",
      "description": "Original free-text initial_vector retained alongside the normalized vector_family."
    },
    "guardrail_kind": {
      "type": "array",
      "items": {
        "type": "string",
        "enum": [
          "none",
          "prompt_instruction",
          "input_classifier",
          "output_filter",
          "human_approval",
          "human_supervision",
          "sandbox_isolation",
          "permission_scope",
          "authentication",
          "abuse_detection",
          "physical_safety_system",
          "policy_only",
          "unknown"
        ]
      },
      "description": "Kinds of control recorded in defense_present, normalised: none, prompt_instruction, input_classifier, output_filter, human_approval, human_supervision, sandbox_isolation, permission_scope, authentication, abuse_detection, physical_safety_system, policy_only, unknown."
    },
    "guardrail_outcome": {
      "type": "string",
      "enum": [
        "defeated",
        "held",
        "not_enabled",
        "silent",
        "not_applicable"
      ],
      "description": "Sourced outcome of the recorded control. silent = disclosure does not establish efficacy; not_enabled = relevant control existed but was off; not_applicable = no relevant control existed."
    },
    "detection_mechanism": {
      "type": "string",
      "enum": [
        "external_researcher",
        "vendor_disclosure",
        "operator_monitoring",
        "user_report",
        "press_investigation",
        "regulator_or_court",
        "academic_study",
        "threat_intel",
        "unknown"
      ],
      "description": "Who first surfaced the incident. Rule-proposed with manual overrides; unknown marks unadjudicated or unsupported cases."
    },
    "agent_framework": {
      "type": "string",
      "description": "Agent runtime or framework involved (controlled list in CODEBOOK.md), or unknown."
    },
    "model_provider": {
      "type": "string",
      "description": "Provider of the model in the causal chain; none for classical autonomy; unknown when unnamed."
    },
    "model_name": {
      "type": "string",
      "description": "Model name as stated by the source, if any."
    },
    "tool_access": {
      "type": "string",
      "enum": [
        "none",
        "read_only",
        "write",
        "destructive",
        "unknown"
      ],
      "description": "Highest privilege the agent held in the incident. Manual."
    },
    "financial_loss_band": {
      "type": "string",
      "enum": [
        "none_reported",
        "under_10k",
        "10k_to_100k",
        "100k_to_1m",
        "over_1m",
        "unknown"
      ],
      "description": "Reported financial loss in USD bands. Manual; mostly unknown, which is itself a finding."
    },
    "xrefs": {
      "type": "object",
      "properties": {
        "aiid": {
          "type": "array",
          "items": {
            "type": "integer"
          }
        },
        "atlas": {
          "type": "array",
          "items": {
            "type": "string"
          }
        },
        "cve": {
          "type": "array",
          "items": {
            "type": "string"
          }
        },
        "ghsa": {
          "type": "array",
          "items": {
            "type": "string"
          }
        }
      },
      "description": "Structured cross-references: AI Incident Database ids, MITRE ATLAS ids, CVE, GHSA (derived)."
    },
    "primary_asi": {
      "type": "string",
      "pattern": "^(ASI\\d{2}|none)$",
      "description": "Dominant OWASP Agentic Top 10 mechanism: the first ordered value in taxonomy.owasp_asi, or none when asi_scope is out_of_scope."
    },
    "asi_curated": {
      "type": "array",
      "items": {
        "type": "string",
        "enum": [
          "ASI01",
          "ASI02",
          "ASI03",
          "ASI04",
          "ASI05",
          "ASI06",
          "ASI07",
          "ASI08",
          "ASI09",
          "ASI10"
        ]
      },
      "description": "The taxonomy.owasp_asi codes human curation had assigned before the crosswalk pass first ran, in the order a curator put them. Frozen: the pass computes from this, not from its own previous output."
    },
    "asi_scope": {
      "type": "string",
      "enum": [
        "in_scope",
        "out_of_scope"
      ],
      "description": "Whether any OWASP Agentic Top 10 mechanism can describe the record. out_of_scope marks non-generative embodied autonomy and conventional flaws in products marketed as smart, so an empty taxonomy.owasp_asi never has to be read as 'not yet adjudicated'. See data/owasp-asi.json -> out_of_scope."
    },
    "asi_provenance": {
      "type": "string",
      "enum": [
        "curated",
        "curated_plus_rule",
        "rule",
        "override",
        "out_of_scope"
      ],
      "description": "How the mapping was produced: curated (human, during record curation), curated_plus_rule (human order kept, rule-found codes appended), rule, override (data/owasp-asi-overrides.json), out_of_scope."
    },
    "asi_reason": {
      "type": "string",
      "description": "Which rule, curated value or override produced each code (audit trail; see data/owasp-asi-report.md)."
    },
    "submitted_by": {
      "type": "string",
      "description": "Who submitted the record. 'EAI Internal' for records curated in-house; otherwise the credit the submitter asked for. Attribution only — it says nothing about verification, which is the same for every record regardless of who sent it in. Set by tools/tag_submitter.py from data/submitter-map.json."
    }
  },
  "additionalProperties": true
}
