{
  "openapi": "3.1.0",
  "info": {
    "title": "Djinn Candidate Analyzer",
    "description": "Aide à la décision de recrutement : scoring explicable, journalisé et minimisé (ADR-028)",
    "version": "0.1.0"
  },
  "paths": {
    "/health": {
      "get": {
        "summary": "Health",
        "description": "Health check, without authentication.",
        "operationId": "health_health_get",
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HealthResponse"
                }
              }
            }
          }
        }
      }
    },
    "/v1/analyze": {
      "post": {
        "summary": "Analyze",
        "description": "Score one candidate against one job: decision support, never a rejection.",
        "operationId": "analyze_v1_analyze_post",
        "parameters": [
          {
            "name": "X-API-Key",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "X-Api-Key"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AnalyzeRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CandidateAnalysis"
                }
              }
            }
          },
          "422": {
            "description": "Requête invalide, ou `no_evaluable_criteria` : le poste et les poids ne laissent aucune dimension évaluable."
          },
          "423": {
            "description": "`scoring_disabled` : arrêt d'urgence activé pour ce client."
          },
          "500": {
            "description": "`audit emission failed` : rien n'a été écrit, réessayer."
          }
        }
      }
    },
    "/v1/analyze/batch": {
      "post": {
        "summary": "Analyze Batch",
        "description": "Score up to 100 candidates against one job, best first.",
        "operationId": "analyze_batch_v1_analyze_batch_post",
        "parameters": [
          {
            "name": "X-API-Key",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "X-Api-Key"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AnalyzeBatchRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AnalyzeBatchResponse"
                }
              }
            }
          },
          "422": {
            "description": "Requête invalide, ou `no_evaluable_criteria` : le poste et les poids ne laissent aucune dimension évaluable."
          },
          "423": {
            "description": "`scoring_disabled` : arrêt d'urgence activé pour ce client."
          },
          "500": {
            "description": "`audit emission failed` : rien n'a été écrit, réessayer."
          }
        }
      }
    },
    "/v1/analyze/competency-file": {
      "post": {
        "summary": "Analyze Competency File",
        "description": "Score a competency file: the job's terms found in the text become the skills.\n\nThe text is read once and never stored or journaled; the other dimensions have\nno input, so those the job sets a criterion for are evaluated with nothing found.",
        "operationId": "analyze_competency_file_v1_analyze_competency_file_post",
        "parameters": [
          {
            "name": "X-API-Key",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "X-Api-Key"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CompetencyFileRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CandidateAnalysis"
                }
              }
            }
          },
          "422": {
            "description": "Requête invalide, ou `no_evaluable_criteria` : le poste et les poids ne laissent aucune dimension évaluable."
          },
          "423": {
            "description": "`scoring_disabled` : arrêt d'urgence activé pour ce client."
          },
          "500": {
            "description": "`audit emission failed` : rien n'a été écrit, réessayer."
          }
        }
      }
    },
    "/v1/hr/analyses/{analysis_id}/decisions": {
      "post": {
        "summary": "Record Decision",
        "description": "Journal a human decision; agreement with the score is computed here.\n\n`review_requested` records a contest (GDPR art. 22(3)), `revised` the new review;\n`supersedes` names the decision_id it replaces. Unknown, purged and other tenants'\nanalyses answer the same 404.",
        "operationId": "record_decision_v1_hr_analyses__analysis_id__decisions_post",
        "parameters": [
          {
            "name": "analysis_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid",
              "title": "Analysis Id"
            }
          },
          {
            "name": "X-API-Key",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "X-Api-Key"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DecisionRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DecisionResponse"
                }
              }
            }
          },
          "404": {
            "description": "`analysis_not_found` : inconnue, purgée ou d'un autre client."
          },
          "503": {
            "description": "Base non configurée."
          },
          "500": {
            "description": "`audit emission failed` : rien n'a été écrit."
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      }
    },
    "/v1/hr/subjects/ref": {
      "post": {
        "summary": "Subject Refs",
        "description": "Pseudonymous reference of a candidate, one per month whose key still exists.\n\nInput of audit-trail's `POST /v1/gdpr/export` (`subject_type=\"resource_id\"`). Each\nreference returned is journaled; Kong rate-limits this route harder.",
        "operationId": "subject_refs_v1_hr_subjects_ref_post",
        "parameters": [
          {
            "name": "X-API-Key",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "X-Api-Key"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SubjectRefRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SubjectRefResponse"
                }
              }
            }
          },
          "503": {
            "description": "Base non configurée."
          },
          "500": {
            "description": "`audit emission failed` : rien n'a été écrit."
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      }
    },
    "/v1/hr/settings": {
      "put": {
        "summary": "Put Settings",
        "description": "Retention (6 to 60 months) and the per-tenant emergency stop, journaled.\n\nLowering the retention purges in the same transaction; raising it does not bring\ndestroyed keys back.",
        "operationId": "put_settings_v1_hr_settings_put",
        "parameters": [
          {
            "name": "X-API-Key",
            "in": "header",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "X-Api-Key"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/HrSettingsUpdate"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HrSettings"
                }
              }
            }
          },
          "503": {
            "description": "Base non configurée."
          },
          "500": {
            "description": "`audit emission failed` : rien n'a été écrit."
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "AnalyzeBatchRequest": {
        "properties": {
          "weights": {
            "$ref": "#/components/schemas/ScoringWeights"
          },
          "anonymize": {
            "type": "boolean",
            "title": "Anonymize",
            "description": "Retire le lieu (profil et expériences) pour tout le lot ; la localisation n'est alors pas évaluée.",
            "default": false
          },
          "as_of": {
            "anyOf": [
              {
                "type": "string",
                "format": "date"
              },
              {
                "type": "null"
              }
            ],
            "title": "As Of",
            "description": "Date de référence du calcul de l'expérience ; défaut : date du jour (UTC), renvoyée dans l'analyse."
          },
          "lang": {
            "type": "string",
            "enum": [
              "fr",
              "en"
            ],
            "title": "Lang",
            "description": "Langue de l'explication.",
            "default": "fr"
          },
          "job": {
            "$ref": "#/components/schemas/JobDescription"
          },
          "candidates": {
            "items": {
              "$ref": "#/components/schemas/CandidateProfile"
            },
            "type": "array",
            "maxItems": 100,
            "minItems": 1,
            "title": "Candidates"
          }
        },
        "type": "object",
        "required": [
          "job",
          "candidates"
        ],
        "title": "AnalyzeBatchRequest",
        "description": "Requête d'analyse de plusieurs candidats (100 au plus)."
      },
      "AnalyzeBatchResponse": {
        "properties": {
          "job_title": {
            "type": "string",
            "title": "Job Title"
          },
          "candidates": {
            "items": {
              "$ref": "#/components/schemas/CandidateAnalysis"
            },
            "type": "array",
            "title": "Candidates"
          },
          "total_analyzed": {
            "type": "integer",
            "title": "Total Analyzed"
          }
        },
        "type": "object",
        "required": [
          "job_title",
          "candidates",
          "total_analyzed"
        ],
        "title": "AnalyzeBatchResponse",
        "description": "Réponse d'analyse batch (triée par score décroissant)."
      },
      "AnalyzeRequest": {
        "properties": {
          "weights": {
            "$ref": "#/components/schemas/ScoringWeights"
          },
          "anonymize": {
            "type": "boolean",
            "title": "Anonymize",
            "description": "Retire le lieu (profil et expériences) pour tout le lot ; la localisation n'est alors pas évaluée.",
            "default": false
          },
          "as_of": {
            "anyOf": [
              {
                "type": "string",
                "format": "date"
              },
              {
                "type": "null"
              }
            ],
            "title": "As Of",
            "description": "Date de référence du calcul de l'expérience ; défaut : date du jour (UTC), renvoyée dans l'analyse."
          },
          "lang": {
            "type": "string",
            "enum": [
              "fr",
              "en"
            ],
            "title": "Lang",
            "description": "Langue de l'explication.",
            "default": "fr"
          },
          "job": {
            "$ref": "#/components/schemas/JobDescription"
          },
          "candidate": {
            "$ref": "#/components/schemas/CandidateProfile"
          }
        },
        "type": "object",
        "required": [
          "job",
          "candidate"
        ],
        "title": "AnalyzeRequest",
        "description": "Requête d'analyse d'un candidat."
      },
      "CandidateAnalysis": {
        "properties": {
          "analysis_id": {
            "type": "string",
            "format": "uuid",
            "title": "Analysis Id"
          },
          "candidate_id": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Candidate Id"
          },
          "scoring_version": {
            "type": "string",
            "title": "Scoring Version"
          },
          "notice_version": {
            "type": "string",
            "title": "Notice Version"
          },
          "as_of": {
            "type": "string",
            "format": "date",
            "title": "As Of"
          },
          "overall_score": {
            "type": "number",
            "maximum": 1.0,
            "minimum": 0.0,
            "title": "Overall Score"
          },
          "fit_level": {
            "type": "string",
            "enum": [
              "excellent",
              "good",
              "moderate",
              "weak"
            ],
            "title": "Fit Level"
          },
          "weights_used": {
            "additionalProperties": {
              "type": "number"
            },
            "propertyNames": {
              "enum": [
                "skills",
                "experience",
                "education",
                "languages",
                "location"
              ]
            },
            "type": "object",
            "title": "Weights Used"
          },
          "dimension_scores": {
            "items": {
              "$ref": "#/components/schemas/DimensionScore"
            },
            "type": "array",
            "title": "Dimension Scores"
          },
          "proxy_criteria": {
            "items": {
              "type": "string",
              "enum": [
                "location",
                "education"
              ]
            },
            "type": "array",
            "title": "Proxy Criteria",
            "description": "Critères indirects (lieu, formation) qui ont pesé : poids > 0 et dimension évaluée."
          },
          "human_review_required": {
            "type": "boolean",
            "const": true,
            "title": "Human Review Required",
            "default": true
          },
          "explanation": {
            "items": {
              "type": "string"
            },
            "type": "array",
            "title": "Explanation"
          },
          "minimization": {
            "$ref": "#/components/schemas/MinimizationReport"
          },
          "strengths": {
            "items": {
              "type": "string"
            },
            "type": "array",
            "title": "Strengths"
          },
          "gaps": {
            "items": {
              "type": "string"
            },
            "type": "array",
            "title": "Gaps"
          },
          "summary": {
            "type": "string",
            "title": "Summary",
            "default": ""
          }
        },
        "type": "object",
        "required": [
          "analysis_id",
          "scoring_version",
          "notice_version",
          "as_of",
          "overall_score",
          "fit_level",
          "weights_used",
          "dimension_scores",
          "explanation",
          "minimization"
        ],
        "title": "CandidateAnalysis",
        "description": "Analyse d'un candidat : aide à la décision, jamais un rejet."
      },
      "CandidateProfile": {
        "properties": {
          "id": {
            "anyOf": [
              {
                "type": "string",
                "maxLength": 200
              },
              {
                "type": "null"
              }
            ],
            "title": "Id",
            "description": "Identifiant opaque du candidat chez le client (ni e-mail, ni entier séquentiel). Pseudonymisé avant journalisation."
          },
          "firstname": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Firstname",
            "description": "Ignoré (minimisation), jamais journalisé ; déprécié.",
            "deprecated": true
          },
          "lastname": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Lastname",
            "description": "Ignoré (minimisation), jamais journalisé ; déprécié.",
            "deprecated": true
          },
          "email": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Email",
            "description": "Ignoré (minimisation), jamais journalisé ; déprécié.",
            "deprecated": true
          },
          "phone": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Phone",
            "description": "Ignoré (minimisation), jamais journalisé ; déprécié.",
            "deprecated": true
          },
          "linkedin": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Linkedin",
            "description": "Ignoré (minimisation), jamais journalisé ; déprécié.",
            "deprecated": true
          },
          "raw_text": {
            "anyOf": [
              {
                "type": "string",
                "maxLength": 500000
              },
              {
                "type": "null"
              }
            ],
            "title": "Raw Text",
            "description": "Ignoré (minimisation), jamais journalisé ; déprécié.",
            "deprecated": true
          },
          "skills": {
            "items": {
              "type": "string"
            },
            "type": "array",
            "title": "Skills"
          },
          "languages": {
            "items": {
              "type": "string"
            },
            "type": "array",
            "title": "Languages"
          },
          "experiences": {
            "items": {
              "$ref": "#/components/schemas/Experience"
            },
            "type": "array",
            "title": "Experiences"
          },
          "diplomas": {
            "items": {
              "$ref": "#/components/schemas/Diploma"
            },
            "type": "array",
            "title": "Diplomas"
          },
          "certifications": {
            "items": {
              "additionalProperties": true,
              "type": "object"
            },
            "type": "array",
            "title": "Certifications"
          },
          "location": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Location"
          }
        },
        "type": "object",
        "title": "CandidateProfile",
        "description": "Profil candidat ; accepte tel quel le `ResumeData` de doc-extract."
      },
      "CompetencyFileRequest": {
        "properties": {
          "weights": {
            "$ref": "#/components/schemas/ScoringWeights"
          },
          "anonymize": {
            "type": "boolean",
            "title": "Anonymize",
            "description": "Retire le lieu (profil et expériences) pour tout le lot ; la localisation n'est alors pas évaluée.",
            "default": false
          },
          "as_of": {
            "anyOf": [
              {
                "type": "string",
                "format": "date"
              },
              {
                "type": "null"
              }
            ],
            "title": "As Of",
            "description": "Date de référence du calcul de l'expérience ; défaut : date du jour (UTC), renvoyée dans l'analyse."
          },
          "lang": {
            "type": "string",
            "enum": [
              "fr",
              "en"
            ],
            "title": "Lang",
            "description": "Langue de l'explication.",
            "default": "fr"
          },
          "job": {
            "$ref": "#/components/schemas/JobDescription"
          },
          "competency_text": {
            "type": "string",
            "maxLength": 500000,
            "minLength": 1,
            "title": "Competency Text"
          }
        },
        "type": "object",
        "required": [
          "job",
          "competency_text"
        ],
        "title": "CompetencyFileRequest",
        "description": "Requête d'analyse d'un dossier de compétences (texte brut, jamais journalisé)."
      },
      "DecisionRequest": {
        "properties": {
          "decision": {
            "type": "string",
            "enum": [
              "shortlisted",
              "not_retained",
              "on_hold",
              "review_requested",
              "revised"
            ],
            "title": "Decision"
          },
          "reviewer_ref": {
            "type": "string",
            "maxLength": 200,
            "minLength": 1,
            "title": "Reviewer Ref",
            "description": "Identifiant opaque du relecteur chez le client ; pseudonymisé avant journalisation."
          },
          "supersedes": {
            "anyOf": [
              {
                "type": "string",
                "format": "uuid"
              },
              {
                "type": "null"
              }
            ],
            "title": "Supersedes",
            "description": "`decision_id` de la décision remplacée."
          }
        },
        "type": "object",
        "required": [
          "decision",
          "reviewer_ref"
        ],
        "title": "DecisionRequest",
        "description": "Décision humaine sur une analyse (spec §4.3)."
      },
      "DecisionResponse": {
        "properties": {
          "decision_id": {
            "type": "string",
            "format": "uuid",
            "title": "Decision Id"
          },
          "agrees_with_score": {
            "type": "boolean",
            "title": "Agrees With Score"
          },
          "seconds_since_scoring": {
            "type": "integer",
            "title": "Seconds Since Scoring"
          }
        },
        "type": "object",
        "required": [
          "decision_id",
          "agrees_with_score",
          "seconds_since_scoring"
        ],
        "title": "DecisionResponse"
      },
      "DimensionScore": {
        "properties": {
          "dimension": {
            "type": "string",
            "enum": [
              "skills",
              "experience",
              "education",
              "languages",
              "location"
            ],
            "title": "Dimension"
          },
          "score": {
            "type": "number",
            "maximum": 1.0,
            "minimum": 0.0,
            "title": "Score"
          },
          "weight": {
            "type": "number",
            "maximum": 1.0,
            "minimum": 0.0,
            "title": "Weight",
            "description": "Poids appliqué, après renormalisation sur les dimensions évaluées."
          },
          "evaluated": {
            "type": "boolean",
            "title": "Evaluated"
          },
          "evidence": {
            "$ref": "#/components/schemas/Evidence"
          },
          "rationale": {
            "type": "string",
            "title": "Rationale"
          },
          "template_id": {
            "type": "string",
            "title": "Template Id"
          },
          "details": {
            "type": "string",
            "title": "Details",
            "description": "Déprécié : reprend `rationale`.",
            "default": "",
            "deprecated": true
          }
        },
        "type": "object",
        "required": [
          "dimension",
          "score",
          "weight",
          "evaluated",
          "rationale",
          "template_id"
        ],
        "title": "DimensionScore",
        "description": "Score d'une dimension, avec ce qui l'explique."
      },
      "Diploma": {
        "properties": {
          "school": {
            "type": "string",
            "title": "School",
            "default": ""
          },
          "degree": {
            "type": "string",
            "title": "Degree",
            "default": ""
          },
          "field_of_study": {
            "type": "string",
            "title": "Field Of Study",
            "default": ""
          },
          "start_date": {
            "type": "string",
            "title": "Start Date",
            "default": ""
          },
          "end_date": {
            "type": "string",
            "title": "End Date",
            "default": ""
          }
        },
        "type": "object",
        "title": "Diploma",
        "description": "Diplôme ; `null` (sortie de doc-extract) vaut chaîne vide."
      },
      "Evidence": {
        "properties": {
          "matched": {
            "items": {
              "type": "string"
            },
            "type": "array",
            "title": "Matched"
          },
          "missing": {
            "items": {
              "type": "string"
            },
            "type": "array",
            "title": "Missing"
          }
        },
        "type": "object",
        "title": "Evidence",
        "description": "Éléments du poste trouvés ou absents dans le profil (jamais d'extrait du CV)."
      },
      "Experience": {
        "properties": {
          "company": {
            "type": "string",
            "title": "Company",
            "default": ""
          },
          "title": {
            "type": "string",
            "title": "Title",
            "default": ""
          },
          "location": {
            "type": "string",
            "title": "Location",
            "default": ""
          },
          "start_date": {
            "type": "string",
            "title": "Start Date",
            "description": "AAAA ou AAAA-MM : premier jour du mois (janvier si l'année seule).",
            "default": ""
          },
          "end_date": {
            "type": "string",
            "title": "End Date",
            "description": "Même format ; vide, « present » ou « en cours » pour un poste en cours.",
            "default": ""
          },
          "description": {
            "type": "string",
            "title": "Description",
            "default": ""
          }
        },
        "type": "object",
        "title": "Experience",
        "description": "Expérience professionnelle ; `null` (sortie de doc-extract) vaut chaîne vide."
      },
      "HTTPValidationError": {
        "properties": {
          "detail": {
            "items": {
              "$ref": "#/components/schemas/ValidationError"
            },
            "type": "array",
            "title": "Detail"
          }
        },
        "type": "object",
        "title": "HTTPValidationError"
      },
      "HealthResponse": {
        "properties": {
          "status": {
            "type": "string",
            "title": "Status",
            "default": "ok"
          },
          "version": {
            "type": "string",
            "title": "Version",
            "default": "0.1.0"
          },
          "scoring_version": {
            "type": "string",
            "title": "Scoring Version",
            "default": "2026.10.1"
          }
        },
        "type": "object",
        "title": "HealthResponse",
        "description": "Response for health check."
      },
      "HrSettings": {
        "properties": {
          "retention_months": {
            "type": "integer",
            "maximum": 60.0,
            "minimum": 6.0,
            "title": "Retention Months",
            "default": 6
          },
          "scoring_enabled": {
            "type": "boolean",
            "title": "Scoring Enabled",
            "default": true
          }
        },
        "type": "object",
        "title": "HrSettings"
      },
      "HrSettingsUpdate": {
        "properties": {
          "retention_months": {
            "type": "integer",
            "maximum": 60.0,
            "minimum": 6.0,
            "title": "Retention Months",
            "description": "Conservation du journal RH, en mois (6 à 60)."
          },
          "scoring_enabled": {
            "type": "boolean",
            "title": "Scoring Enabled",
            "description": "false = arrêt d'urgence : les routes d'analyse répondent 423."
          }
        },
        "type": "object",
        "required": [
          "retention_months",
          "scoring_enabled"
        ],
        "title": "HrSettingsUpdate"
      },
      "JobDescription": {
        "properties": {
          "title": {
            "type": "string",
            "title": "Title"
          },
          "description": {
            "type": "string",
            "title": "Description",
            "default": ""
          },
          "required_skills": {
            "items": {
              "type": "string"
            },
            "type": "array",
            "title": "Required Skills"
          },
          "preferred_skills": {
            "items": {
              "type": "string"
            },
            "type": "array",
            "title": "Preferred Skills"
          },
          "min_experience_years": {
            "anyOf": [
              {
                "type": "integer",
                "maximum": 60.0,
                "minimum": 0.0
              },
              {
                "type": "null"
              }
            ],
            "title": "Min Experience Years"
          },
          "required_languages": {
            "items": {
              "type": "string"
            },
            "type": "array",
            "title": "Required Languages"
          },
          "required_education": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Required Education"
          },
          "location": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Location"
          },
          "remote_policy": {
            "anyOf": [
              {
                "type": "string",
                "enum": [
                  "onsite",
                  "hybrid",
                  "remote"
                ]
              },
              {
                "type": "null"
              }
            ],
            "title": "Remote Policy",
            "description": "onsite | hybrid | remote. Common aliases (e.g. full-remote, télétravail, hybride, présentiel) are normalised; any other value is refused (422). remote: the location dimension is not evaluated."
          }
        },
        "type": "object",
        "required": [
          "title"
        ],
        "title": "JobDescription",
        "description": "Description du poste à pourvoir."
      },
      "MinimizationReport": {
        "properties": {
          "ignored_fields": {
            "items": {
              "type": "string"
            },
            "type": "array",
            "title": "Ignored Fields",
            "description": "Input paths received then dropped before processing (e.g. `email`, `experiences[].location`)."
          },
          "dimensions_not_evaluated": {
            "items": {
              "type": "string"
            },
            "type": "array",
            "title": "Dimensions Not Evaluated",
            "description": "Processing dimensions skipped because of that minimisation."
          }
        },
        "type": "object",
        "title": "MinimizationReport",
        "description": "What a request carried that processing did not use, by name only."
      },
      "ScoringWeights": {
        "properties": {
          "skills": {
            "type": "number",
            "maximum": 1.0,
            "minimum": 0.0,
            "title": "Skills",
            "default": 0.3
          },
          "experience": {
            "type": "number",
            "maximum": 1.0,
            "minimum": 0.0,
            "title": "Experience",
            "default": 0.25
          },
          "education": {
            "type": "number",
            "maximum": 1.0,
            "minimum": 0.0,
            "title": "Education",
            "default": 0.15
          },
          "languages": {
            "type": "number",
            "maximum": 1.0,
            "minimum": 0.0,
            "title": "Languages",
            "default": 0.15
          },
          "location": {
            "type": "number",
            "maximum": 1.0,
            "minimum": 0.0,
            "title": "Location",
            "default": 0.15
          }
        },
        "type": "object",
        "title": "ScoringWeights",
        "description": "Poids configurables pour les 5 dimensions de scoring."
      },
      "SubjectRef": {
        "properties": {
          "period": {
            "type": "string",
            "title": "Period",
            "description": "Mois de la clé, AAAA-MM."
          },
          "subject_ref": {
            "type": "string",
            "title": "Subject Ref"
          }
        },
        "type": "object",
        "required": [
          "period",
          "subject_ref"
        ],
        "title": "SubjectRef"
      },
      "SubjectRefRequest": {
        "properties": {
          "subject_id": {
            "type": "string",
            "maxLength": 200,
            "minLength": 1,
            "title": "Subject Id",
            "description": "Le `CandidateProfile.id` des analyses."
          }
        },
        "type": "object",
        "required": [
          "subject_id"
        ],
        "title": "SubjectRefRequest"
      },
      "SubjectRefResponse": {
        "properties": {
          "subject_refs": {
            "items": {
              "$ref": "#/components/schemas/SubjectRef"
            },
            "type": "array",
            "title": "Subject Refs"
          }
        },
        "type": "object",
        "required": [
          "subject_refs"
        ],
        "title": "SubjectRefResponse"
      },
      "ValidationError": {
        "properties": {
          "loc": {
            "items": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "integer"
                }
              ]
            },
            "type": "array",
            "title": "Location"
          },
          "msg": {
            "type": "string",
            "title": "Message"
          },
          "type": {
            "type": "string",
            "title": "Error Type"
          },
          "input": {
            "title": "Input"
          },
          "ctx": {
            "type": "object",
            "title": "Context"
          }
        },
        "type": "object",
        "required": [
          "loc",
          "msg",
          "type"
        ],
        "title": "ValidationError"
      }
    }
  }
}
