{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://airevops.io/templates/enrichment-scoring-output.schema.json",
  "title": "Lead enrichment + scoring output",
  "description": "Structured-output contract for the LLM step in Lesson 5. Force your model to return JSON matching this schema, then validate before writing to the CRM. It is strict on purpose: additionalProperties is false and every field is required, so a malformed or hallucinated response fails closed and routes to a human instead of writing garbage.",
  "type": "object",
  "additionalProperties": false,
  "required": ["company", "fit_score", "routing", "reasoning", "confidence"],
  "properties": {
    "company": {
      "type": "object",
      "additionalProperties": false,
      "required": ["industry", "employee_band", "summary"],
      "properties": {
        "industry": {
          "type": "string",
          "description": "Normalized industry. Use one of your CRM's industry picklist values, not free text."
        },
        "employee_band": {
          "type": "string",
          "enum": ["1-10", "11-50", "51-200", "201-1000", "1001-5000", "5000+", "unknown"],
          "description": "Coarse size band. 'unknown' is a valid answer — do not let the model guess."
        },
        "summary": {
          "type": "string",
          "maxLength": 240,
          "description": "One-line company summary written from the scraped site, for the enrichment_summary field."
        }
      }
    },
    "fit_score": {
      "type": "integer",
      "minimum": 0,
      "maximum": 100,
      "description": "Fit against your ICP rubric. Pair with a threshold in your flow (e.g. >= 70 routes to sales)."
    },
    "routing": {
      "type": "string",
      "enum": ["tier_1", "tier_2", "tier_3", "disqualify", "needs_human"],
      "description": "Decision. 'needs_human' is the fallback when the model is unsure — always offer it as an option."
    },
    "reasoning": {
      "type": "string",
      "maxLength": 600,
      "description": "Why the model scored and routed this way. Store it in score_reasoning so the decision is auditable."
    },
    "confidence": {
      "type": "number",
      "minimum": 0,
      "maximum": 1,
      "description": "Model's self-reported confidence. Route anything below your floor (e.g. < 0.6) to needs_human regardless of fit_score."
    },
    "disqualifiers": {
      "type": "array",
      "items": { "type": "string" },
      "description": "Optional: any hard-stop reasons found (competitor, personal email domain, unsupported region)."
    }
  }
}
