{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://www.anguskit.com/schema/anguscopilot/1.0.0/safety.json",
  "title": "Safety Configuration",
  "description": "SecurityGate 策略配置块。包括 Prompt Injection 防御、RBAC、SafetyClass 强制、数据出境合规、内容审核。W12 增量字段：promptInjection / rbac.engine / safetyClass.approval / dataResidency.crossBorderAllowed / contentSafety.providers。",
  "type": "object",
  "properties": {

    "inputFilter": {
      "description": "输入过滤等级，对应 PromptInjectionGate 行为。 [stable]",
      "type": "string",
      "enum": ["off", "basic", "strict"],
      "default": "basic"
    },
    "outputReview": {
      "description": "输出审查策略。 [stable]",
      "type": "string",
      "enum": ["off", "pii-redact", "content-safety", "pii-redact+content-safety"],
      "default": "pii-redact"
    },

    "promptInjection": {
      "description": "Prompt Injection 多层检测（W12 新增；与 §4.4 对齐）。 [beta]",
      "type": "object",
      "properties": {
        "enabled": { "type": "boolean", "default": true },
        "layers": {
          "description": "启用的检测层。任一命中即终止。 [beta]",
          "type": "array",
          "items": {
            "type": "string",
            "enum": ["rule", "classifier", "llm-judge"]
          },
          "uniqueItems": true,
          "default": ["rule"]
        },
        "rule": {
          "description": "正则 / 关键词字典层（layers 含 rule 时使用）。 [beta]",
          "type": "object",
          "properties": {
            "ruleSets": {
              "type": "array",
              "items": { "type": "string", "minLength": 1 },
              "uniqueItems": true,
              "default": ["builtin"]
            },
            "customRulesRef": { "$ref": "common.json#/$defs/SecretRef" }
          },
          "patternProperties": { "^x-": true },
          "unevaluatedProperties": false
        },
        "classifier": {
          "description": "本地分类模型层（layers 含 classifier 时必填 modelRef + threshold ∈ (0,1)，E2 约束）。 [beta]",
          "type": "object",
          "properties": {
            "modelRef": {
              "description": "本地分类模型引用。 [beta]",
              "type": "string",
              "minLength": 1
            },
            "threshold": {
              "description": "命中阈值，必须 ∈ (0,1)。 [beta]",
              "type": "number",
              "exclusiveMinimum": 0,
              "exclusiveMaximum": 1
            }
          },
          "patternProperties": { "^x-": true },
          "unevaluatedProperties": false
        },
        "llmJudge": {
          "description": "LLM Judge 兜底层（layers 含 llm-judge 时必填 modelRef，E1 约束）。 [beta]",
          "type": "object",
          "properties": {
            "modelRef": {
              "description": "LLM Judge 调用的模型引用。 [beta]",
              "type": "string",
              "minLength": 1
            },
            "triggerScoreRange": {
              "description": "Layer 2 分数处于该区间时才触发 LLM Judge（避免成本失控）。 [beta]",
              "type": "array",
              "items": { "type": "number", "minimum": 0, "maximum": 1 },
              "minItems": 2,
              "maxItems": 2
            }
          },
          "patternProperties": { "^x-": true },
          "unevaluatedProperties": false
        }
      },
      "patternProperties": { "^x-": true },
      "$comment": "E1/E2 跨字段约束：layers 含 llm-judge 时必须 llmJudge.modelRef；含 classifier 时必须 classifier.modelRef + threshold。",
      "allOf": [
        {
          "if": {
            "properties": {
              "layers": {
                "type": "array",
                "contains": { "const": "llm-judge" }
              }
            },
            "required": ["layers"]
          },
          "then": {
            "required": ["llmJudge"],
            "properties": {
              "llmJudge": {
                "required": ["modelRef"]
              }
            }
          }
        },
        {
          "if": {
            "properties": {
              "layers": {
                "type": "array",
                "contains": { "const": "classifier" }
              }
            },
            "required": ["layers"]
          },
          "then": {
            "required": ["classifier"],
            "properties": {
              "classifier": {
                "required": ["modelRef", "threshold"]
              }
            }
          }
        }
      ],
      "unevaluatedProperties": false
    },

    "rbac": {
      "description": "RBAC 策略（W12 增强：新增 engine + opaBundleUrl + policy 字段）。 [beta]",
      "type": "object",
      "properties": {
        "enabled": { "type": "boolean", "default": false },
        "engine": {
          "description": "RBAC 引擎选型（W12 新增）。 [beta]",
          "type": "string",
          "enum": ["casbin", "opa"]
        },
        "policy": {
          "description": "Casbin 策略文本（engine=casbin 时必填，E4 约束）。 [beta]",
          "type": "string"
        },
        "opaBundleUrl": {
          "description": "OPA Bundle URL（engine=opa 时必填，E3 约束）。 [beta]",
          "type": "string",
          "format": "uri"
        },
        "allowedRoles": {
          "type": "array",
          "items": { "type": "string" },
          "uniqueItems": true
        },
        "deniedRoles": {
          "type": "array",
          "items": { "type": "string" },
          "uniqueItems": true
        }
      },
      "patternProperties": { "^x-": true },
      "$comment": "E3/E4 跨字段约束：engine=opa 必须 opaBundleUrl；engine=casbin 必须 policy。",
      "allOf": [
        {
          "if": {
            "properties": { "engine": { "const": "opa" } },
            "required": ["engine"]
          },
          "then": {
            "required": ["opaBundleUrl"]
          }
        },
        {
          "if": {
            "properties": { "engine": { "const": "casbin" } },
            "required": ["engine"]
          },
          "then": {
            "required": ["policy"]
          }
        }
      ],
      "unevaluatedProperties": false
    },

    "safetyClass": {
      "description": "SafetyClass 强制策略。destructive 操作默认强制 Human-in-Loop。W12 增强：approval 多审批人聚合。 [beta]",
      "type": "object",
      "properties": {
        "destructiveRequiresApproval": { "type": "boolean", "default": true },
        "sensitiveRequiresApproval": { "type": "boolean", "default": false },
        "approvalChannel": {
          "type": "string",
          "enum": ["web", "slack", "lark", "dingtalk", "email"]
        },
        "approval": {
          "description": "审批流程详细配置（W12 新增；与 §4.6 对齐）。 [beta]",
          "type": "object",
          "properties": {
            "channel": {
              "type": "string",
              "enum": ["web", "slack", "lark", "dingtalk", "email"]
            },
            "timeout": { "$ref": "common.json#/$defs/Duration", "default": "30m" },
            "aggregation": {
              "description": "多审批人聚合策略。 [beta]",
              "type": "string",
              "enum": ["any", "all", "quorum-N"],
              "default": "any"
            },
            "quorumN": {
              "description": "aggregation=quorum-N 时必填，且必须 ≥ 2（E5 约束）。 [beta]",
              "type": "integer",
              "minimum": 2
            },
            "approvers": {
              "type": "array",
              "items": { "type": "string" },
              "minItems": 1,
              "uniqueItems": true
            },
            "autoApproveBelow": {
              "description": "小额自动批准阈值（如 amount < 100USD）。 [beta]",
              "type": "object",
              "additionalProperties": true
            }
          },
          "patternProperties": { "^x-": true },
          "$comment": "E5 跨字段约束：aggregation=quorum-N 时必须 quorumN ≥ 2（minimum 已保证）。",
          "if": {
            "properties": { "aggregation": { "const": "quorum-N" } },
            "required": ["aggregation"]
          },
          "then": {
            "required": ["quorumN"]
          },
          "unevaluatedProperties": false
        }
      },
      "patternProperties": { "^x-": true },
      "unevaluatedProperties": false
    },

    "dataResidency": {
      "description": "数据出境合规策略。W12 增强：crossBorderAllowed[] 显式允许列表。 [beta]",
      "type": "object",
      "properties": {
        "region": {
          "type": "string",
          "enum": ["cn", "eu", "us", "global"]
        },
        "sensitiveDataPolicy": {
          "type": "string",
          "enum": ["allow", "redact", "route-to-private", "deny"]
        },
        "privateLlmModel": {
          "description": "敏感数据强制路由到的私有 LLM。 [beta]",
          "type": "string"
        },
        "crossBorderAllowed": {
          "description": "允许跨境流转的目的地与法律基础（W12 新增；与 §4.7.5 对齐）。 [beta]",
          "type": "array",
          "items": {
            "type": "object",
            "required": ["to", "legalBasis"],
            "properties": {
              "to": {
                "description": "目的地区域。 [beta]",
                "type": "string",
                "enum": ["cn", "eu", "us", "uk", "jp", "kr", "sg", "ca", "au", "global"]
              },
              "legalBasis": {
                "description": "法律基础（E7 约束）。 [beta]",
                "type": "string",
                "enum": ["SCC", "BCR", "ConsentGiven", "DataSubjectRequest", "Adequacy"]
              },
              "dataSubjects": {
                "type": "array",
                "items": {
                  "type": "string",
                  "enum": ["INTERNAL", "PII", "PHI", "PCI", "TRADE_SECRET", "GOV_SECRET"]
                },
                "uniqueItems": true
              }
            },
            "patternProperties": { "^x-": true },
            "unevaluatedProperties": false
          },
          "uniqueItems": true
        }
      },
      "$comment": "E6 跨字段约束：region=cn 且 sensitiveDataPolicy=route-to-private 时必须 privateLlmModel。",
      "allOf": [
        {
          "if": {
            "properties": {
              "region": { "const": "cn" },
              "sensitiveDataPolicy": { "const": "route-to-private" }
            },
            "required": ["region", "sensitiveDataPolicy"]
          },
          "then": {
            "required": ["privateLlmModel"]
          }
        },
        {
          "$comment": "保留旧约束：sensitiveDataPolicy=route-to-private 时 privateLlmModel 必填（不分 region）。",
          "if": {
            "properties": { "sensitiveDataPolicy": { "const": "route-to-private" } },
            "required": ["sensitiveDataPolicy"]
          },
          "then": {
            "required": ["privateLlmModel"]
          }
        }
      ],
      "patternProperties": { "^x-": true },
      "unevaluatedProperties": false
    },

    "contentSafety": {
      "description": "内容审核服务集成。W12 增强：多 provider + ensemble 模式。 [beta]",
      "type": "object",
      "properties": {
        "provider": {
          "description": "[deprecated W12] 旧字段；建议改用 providers[]。 [stable]",
          "type": "string",
          "enum": ["off", "aliyun", "aws-comprehend", "azure", "custom"]
        },
        "providers": {
          "description": "多提供商列表（W12 新增；ensemble 模式下要求 ≥ 2，E8 约束）。 [beta]",
          "type": "array",
          "items": {
            "type": "object",
            "required": ["name"],
            "properties": {
              "name": {
                "type": "string",
                "enum": ["aliyun", "aws-comprehend", "azure", "google-perspective", "local-small-model", "custom"]
              },
              "credentialRef": { "$ref": "common.json#/$defs/SecretRef" },
              "weight": {
                "type": "number",
                "minimum": 0,
                "maximum": 1,
                "default": 1.0
              }
            },
            "patternProperties": { "^x-": true },
            "unevaluatedProperties": false
          },
          "uniqueItems": true
        },
        "mode": {
          "description": "组合模式（W12 新增）。 [beta]",
          "type": "string",
          "enum": ["primary", "fallback", "ensemble"],
          "default": "primary"
        },
        "threshold": {
          "description": "ensemble 模式下加权分数阈值。 [beta]",
          "type": "number",
          "minimum": 0,
          "maximum": 1
        },
        "credentialRef": { "$ref": "common.json#/$defs/SecretRef" },
        "blockOn": {
          "type": "array",
          "items": {
            "type": "string",
            "enum": ["porn", "violence", "politics", "ad", "abuse", "pii", "hate", "self-harm"]
          },
          "uniqueItems": true
        }
      },
      "patternProperties": { "^x-": true },
      "$comment": "E8 跨字段约束：mode=ensemble 时 providers 必须 ≥ 2。",
      "if": {
        "properties": { "mode": { "const": "ensemble" } },
        "required": ["mode"]
      },
      "then": {
        "required": ["providers"],
        "properties": {
          "providers": { "minItems": 2 }
        }
      },
      "unevaluatedProperties": false
    },

    "allowedDomains": {
      "description": "允许调用的业务域白名单（HTTP 调用、知识库 namespace）。 [stable]",
      "type": "array",
      "items": { "type": "string" },
      "uniqueItems": true
    },

    "deniedDomains": {
      "description": "禁止调用的域名黑名单。 [stable]",
      "type": "array",
      "items": { "type": "string" },
      "uniqueItems": true
    }
  },
  "patternProperties": {
    "^x-": true
  },
  "unevaluatedProperties": false
}
