{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://aiir.jacobideji.com/schemas/ai-bom.schema.json",
  "title": "AI Bill of Materials (AI-BOM)",
  "description": "JSON Schema for the AI IR Overlay AI-BOM template (MVO-1 Inventory). One AI-BOM per AI agent in production. The schema enforces the inventory discipline the framework requires for Maturity Roadmap Level 1 (Aware) conformance. See templates/ai-bom.yaml for a worked example and templates/README-ai-bom.md for adoption guidance.",
  "type": "object",
  "required": ["agent", "identity", "model", "tools"],
  "properties": {
    "agent": { "$ref": "#/$defs/agent" },
    "identity": { "$ref": "#/$defs/identity" },
    "model": { "$ref": "#/$defs/model" },
    "tools": {
      "type": "array",
      "minItems": 1,
      "items": { "$ref": "#/$defs/tool" },
      "description": "Every tool the agent can call. Must reflect the runtime tool registry, not desired state. See playbooks/04-tool-design-is-containment.md for tier discipline."
    },
    "retrieval": { "$ref": "#/$defs/retrieval" },
    "memory": { "$ref": "#/$defs/memory" },
    "guardrails": { "$ref": "#/$defs/guardrails" },
    "logging": { "$ref": "#/$defs/logging" },
    "kill_switches": { "$ref": "#/$defs/kill_switches" },
    "evidence_export": { "$ref": "#/$defs/evidence_export" },
    "compliance_tags": {
      "type": "array",
      "items": { "type": "string" },
      "description": "Compliance regimes the agent is in scope for. Empty list by default. Examples: SOC2, ISO_42001 (only after audit), EU_AI_Act_Article_26 (only if EU deployer), HIPAA, GDPR, GLBA. Adopters must not pre-claim regimes that lack a substantive control mapping."
    },
    "incidents_history": {
      "type": "array",
      "items": { "$ref": "#/$defs/incident_record" },
      "description": "Tabletop drills and real incidents. Append-only chronological record. Per playbooks/13-six-metrics.md Metric 6, the M5 success rate is computed from this list."
    }
  },
  "$defs": {
    "agent": {
      "type": "object",
      "required": ["name", "business_owner", "technical_owner", "environment", "deployed_at", "last_reviewed"],
      "properties": {
        "name": {
          "type": "string",
          "pattern": "^[a-z0-9-]+$",
          "description": "Stable identifier for the agent. Lowercase alphanumeric with hyphens."
        },
        "display_name": {
          "type": "string",
          "description": "Human-readable agent name for board reporting and incident notification."
        },
        "business_owner": {
          "type": "string",
          "description": "The business-side owner accountable for the agent's purpose and outcomes. Format: 'Role <email@org>'."
        },
        "technical_owner": {
          "type": "string",
          "description": "The platform-side owner accountable for the agent's runtime and tooling."
        },
        "environment": {
          "enum": ["dev", "staging", "production"],
          "description": "Deployment environment. Conformance discipline applies only to production agents."
        },
        "deployed_at": {
          "type": "string",
          "format": "date-time",
          "description": "Initial production deployment timestamp (RFC 3339)."
        },
        "last_reviewed": {
          "type": "string",
          "format": "date-time",
          "description": "Most recent AI-BOM review timestamp. Per playbooks/13-six-metrics.md Metric 1 (Inventory Currency), must be within 7 days for Maturity Level 1 conformance."
        }
      }
    },
    "identity": {
      "type": "object",
      "required": ["type", "principal", "scopes"],
      "properties": {
        "type": {
          "enum": ["service_account", "delegated_oauth", "impersonation", "shared_token"],
          "description": "Identity class. Each class has different lifecycle and risk profile per playbooks/07-secrets-and-tokens.md."
        },
        "principal": {
          "type": "string",
          "description": "The identity principal (service account email, OAuth grant subject, etc.)."
        },
        "scopes": {
          "type": "array",
          "items": { "type": "string" },
          "minItems": 1,
          "description": "OAuth or platform scopes granted to this identity. Must reflect actual production grant, not desired state."
        },
        "rotation_cadence_days": {
          "type": "integer",
          "minimum": 1,
          "description": "Credential rotation cadence in days. Per playbooks/07-secrets-and-tokens.md Boundary 1: T0 tools <= 90 days, T1 <= 60 days, T2 <= 30 days, break-glass identities rotated quarterly regardless."
        }
      }
    },
    "model": {
      "type": "object",
      "required": ["provider", "model_id"],
      "properties": {
        "provider": {
          "type": "string",
          "description": "Model provider (anthropic, openai, google, vendor name for vendor copilots, etc.)."
        },
        "model_id": {
          "type": "string",
          "description": "Specific model identifier with version where the provider exposes it."
        },
        "version_pinned": {
          "type": "boolean",
          "description": "Whether the model version is contractually or technically pinned. False means the provider can silently swap the model substrate."
        },
        "fallback_provider": { "type": "string" },
        "fallback_model_id": { "type": "string" }
      }
    },
    "tool": {
      "type": "object",
      "required": ["name", "type", "risk_tier"],
      "properties": {
        "name": {
          "type": "string",
          "description": "Stable tool identifier matching the runtime tool registry and the corresponding row in templates/agent-privilege-matrix.csv."
        },
        "type": {
          "enum": ["read", "write"],
          "description": "Read tools cannot change state. Write tools can. The split must be enforced at the tool wrapper, not at the prompt, per playbooks/04-tool-design-is-containment.md."
        },
        "risk_tier": {
          "enum": ["T0", "T1", "T2"],
          "description": "Tier per playbooks/04-tool-design-is-containment.md. T0 = read-only or low risk. T1 = bounded writes. T2 = systems of record. Vocabulary aligned with templates/agent-privilege-matrix.csv."
        },
        "description": { "type": "string" },
        "write_targets": {
          "type": "array",
          "items": { "type": "string" },
          "description": "Required for write tools. Lists downstream systems and object classes the tool can modify (e.g., 'Salesforce.Opportunity', 'M365.Outlook.SentItems')."
        }
      },
      "if": {
        "properties": { "type": { "const": "write" } },
        "required": ["type"]
      },
      "then": {
        "required": ["write_targets"],
        "properties": {
          "write_targets": { "minItems": 1 }
        }
      }
    },
    "retrieval": {
      "type": "object",
      "properties": {
        "enabled": { "type": "boolean" },
        "corpora": {
          "type": "array",
          "items": { "$ref": "#/$defs/corpus" }
        }
      }
    },
    "corpus": {
      "type": "object",
      "required": ["name", "type", "sensitivity"],
      "properties": {
        "name": { "type": "string" },
        "type": {
          "type": "string",
          "description": "Corpus type (e.g., sharepoint, vector_store, knowledge_base, ticket_system)."
        },
        "uri": { "type": "string" },
        "access_scope": { "type": "string" },
        "sensitivity": {
          "type": "string",
          "description": "Sensitivity classification per the customer's data classification scheme. Free-form to allow adopter-specific schemes."
        },
        "refresh_cadence": { "type": "string" }
      }
    },
    "memory": {
      "type": "object",
      "required": ["enabled"],
      "properties": {
        "enabled": { "type": "boolean" },
        "scope": {
          "enum": ["off", "per_user", "shared"],
          "description": "Memory scope. 'shared' is the highest-risk class because of cross-tenant bleed potential. Per playbooks/12-insider-threat-3.md, shared memory is also a sustained-misuse surface."
        },
        "retention_days": { "type": "integer", "minimum": 0 },
        "classification_in_memory": { "type": "string" },
        "pii_allowed": { "type": "boolean" }
      }
    },
    "guardrails": {
      "type": "object",
      "properties": {
        "prompt_injection_detection": { "type": "boolean" },
        "pii_redaction": { "type": "boolean" },
        "external_email_approval": { "type": "boolean" },
        "rate_limit_per_user_per_hour": { "type": "integer", "minimum": 0 }
      }
    },
    "logging": {
      "type": "object",
      "properties": {
        "prompt_response": { "type": "boolean" },
        "prompt_response_retention_days": {
          "type": "integer",
          "minimum": 0,
          "description": "Per evidence/minimum-evidence-set.md Type A, recommended >= 90 days. Model-provider TTLs are often 24 to 72 hours; the customer must extend retention through gateway logging or contracted extension."
        },
        "tool_calls": { "type": "boolean" },
        "tool_call_retention_days": { "type": "integer", "minimum": 0 },
        "retrieval_traces": { "type": "boolean" },
        "retrieval_trace_retention_days": { "type": "integer", "minimum": 0 },
        "config_versioning": { "type": "boolean" }
      }
    },
    "kill_switches": {
      "type": "object",
      "required": ["maturity_target", "m1_read_only", "m2_approvals", "m3_tool_tiering", "m4_full_disable"],
      "properties": {
        "maturity_target": {
          "type": "string",
          "enum": ["level_1_aware", "level_2_containable", "level_3_provable", "level_4_resilient"],
          "description": "The customer's currently-claimed maturity level for this agent per framework/03-maturity-roadmap.md. Determines which Kill-Switch Modes must be implemented. level_1_aware: only inventory required; M1-M4 may have implemented=false during initial adoption. level_2_containable and above: M1-M4 must all be implemented=true and tested within 90 days. The framework rejects ambiguity: customers below Level 2 must explicitly claim Level 1 rather than leave fields blank."
        },
        "m1_read_only": { "$ref": "#/$defs/kill_switch_record" },
        "m2_approvals": { "$ref": "#/$defs/kill_switch_record" },
        "m3_tool_tiering": { "$ref": "#/$defs/kill_switch_record" },
        "m4_full_disable": { "$ref": "#/$defs/kill_switch_record" }
      },
      "description": "Kill-Switch Mode implementation and drill status. Per framework/01-minimum-viable-overlay.md Conformance checklist, M1 through M4 must be implemented and tabletop-tested in the last 90 days for Maturity Level 2 (Containable) conformance. Level 1 (Aware) customers may declare implemented=false on individual modes during initial adoption; the validator's --strict mode enforces conformance for the claimed maturity level.",
      "allOf": [
        {
          "if": {
            "properties": { "maturity_target": { "enum": ["level_2_containable", "level_3_provable", "level_4_resilient"] } }
          },
          "then": {
            "properties": {
              "m1_read_only": { "properties": { "implemented": { "const": true } } },
              "m2_approvals": { "properties": { "implemented": { "const": true } } },
              "m3_tool_tiering": { "properties": { "implemented": { "const": true } } },
              "m4_full_disable": { "properties": { "implemented": { "const": true } } }
            }
          }
        }
      ]
    },
    "kill_switch_record": {
      "type": "object",
      "required": ["implemented", "tested_at", "tta_minutes"],
      "properties": {
        "implemented": {
          "type": "boolean",
          "description": "Whether the mode is implemented in code or configuration, not just in the runbook. May be false only when kill_switches.maturity_target is level_1_aware; conformance to Level 2 (Containable) or higher requires implemented=true (enforced by the schema's allOf rule)."
        },
        "tested_at": {
          "type": ["string", "null"],
          "format": "date",
          "description": "Most recent tabletop or live drill date. Per playbooks/14-testing-for-agent-failure-modes.md, must be within 90 days for Maturity Level 2 conformance. May be null when implemented=false at maturity level_1_aware; the validator's --strict mode enforces the 90-day window on implemented modes."
        },
        "tta_minutes": {
          "type": ["integer", "null"],
          "minimum": 0,
          "maximum": 10,
          "description": "Measured Time-to-Activate in minutes. Per framework/01-minimum-viable-overlay.md and kill-switches/overview.md, must be <= 10 for Tier-1 SOC activation. Drill-measured per framework/01 Measurement Scope section. May be null when implemented=false."
        }
      }
    },
    "evidence_export": {
      "type": "object",
      "required": ["runbook", "emergency_access", "tested_export_minutes"],
      "properties": {
        "runbook": {
          "type": "string",
          "description": "Path or URL to the documented export procedure. Required for Maturity Level 3 conformance."
        },
        "emergency_access": {
          "enum": ["preapproved", "ticketed"],
          "description": "Per evidence/minimum-evidence-set.md, preapproved emergency access is required for the 60-minute SLA. Ticketed access fails the SLA on contact."
        },
        "tested_export_minutes": {
          "type": "integer",
          "minimum": 0,
          "maximum": 60,
          "description": "Most recent drill-measured time to export the full Minimum Evidence Set (A through F). Per framework/01-minimum-viable-overlay.md Measurement Scope, the 60-minute target is drill-measured; live-incident timing is tracked separately under playbooks/13-six-metrics.md Metric 3."
        }
      }
    },
    "incident_record": {
      "type": "object",
      "required": ["date", "summary", "outcome"],
      "properties": {
        "date": { "type": "string", "format": "date" },
        "summary": { "type": "string" },
        "mode_activated": {
          "enum": ["M0", "M1", "M2", "M3", "M4", "M5"],
          "description": "Highest containment mode reached. Per kill-switches/overview.md, M3 has documented variants (M3-RAG, M3-Delegation Cap, M3-Workflow, M3-Vendor) and M4 has corpus-scoped and agent-suspended-for-user variants; all are recorded as their canonical mode here."
        },
        "duration_minutes": { "type": "integer", "minimum": 0 },
        "outcome": {
          "enum": ["passed", "partial", "failed"],
          "description": "Drill or real-incident outcome."
        }
      }
    }
  }
}
