Spaces:
Sleeping
Sleeping
| from __future__ import annotations | |
| from collections.abc import Mapping | |
| from datetime import date | |
| from types import MappingProxyType | |
| from typing import Any, final | |
| from pydantic import ( | |
| BaseModel, | |
| ConfigDict, | |
| Field, | |
| ValidationError, | |
| field_serializer, | |
| field_validator, | |
| ) | |
| from redstack.domain.enums import ( | |
| CompanySize, | |
| InstitutionTier, | |
| LanguageProficiency, | |
| Proficiency, | |
| WorkMode, | |
| ) | |
| from redstack.domain.errors import SchemaError | |
| from redstack.domain.ids import CandidateId, LpaAmount, Months, SkillName | |
| _STRICT = ConfigDict( | |
| frozen=True, extra="forbid", str_strip_whitespace=True, validate_default=True | |
| ) | |
| class RawProfile(BaseModel): | |
| """Top-level profile facts.""" | |
| model_config = _STRICT | |
| anonymized_name: str = Field(min_length=1) | |
| headline: str | |
| summary: str | |
| location: str | |
| country: str | |
| years_of_experience: float = Field(ge=0.0, le=50.0, allow_inf_nan=False) | |
| current_title: str | |
| current_company: str | |
| current_company_size: CompanySize | |
| current_industry: str | |
| class RawPosition(BaseModel): | |
| """One career-history position, mirrored verbatim.""" | |
| model_config = _STRICT | |
| company: str | |
| title: str | |
| start_date: date | |
| end_date: date | None | |
| duration_months: Months = Field(ge=0) | |
| is_current: bool | |
| industry: str | |
| company_size: CompanySize | |
| description: str | |
| class RawEducation(BaseModel): | |
| """One education record.""" | |
| model_config = _STRICT | |
| institution: str | |
| degree: str | |
| field_of_study: str | |
| start_year: int | |
| end_year: int | |
| grade: str | None | |
| tier: InstitutionTier | |
| class RawSkill(BaseModel): | |
| """One claimed skill.""" | |
| model_config = _STRICT | |
| name: SkillName | |
| proficiency: Proficiency | |
| endorsements: int = Field(ge=0) | |
| duration_months: Months | None = Field(default=None, ge=0) | |
| class RawCertification(BaseModel): | |
| """One certification.""" | |
| model_config = _STRICT | |
| name: str | |
| issuer: str | |
| year: int | |
| class RawLanguage(BaseModel): | |
| """One spoken language.""" | |
| model_config = _STRICT | |
| language: str | |
| proficiency: LanguageProficiency | |
| class RawSalaryRange(BaseModel): | |
| """Expected salary range (INR lpa); inversion preserved, never corrected. | |
| Field names mirror the source JSON verbatim (``{"min": ..., "max": ...}``), | |
| not the ``*_lpa``-suffixed names used by downstream domain models. | |
| """ | |
| model_config = _STRICT | |
| min: LpaAmount = Field(ge=0.0, allow_inf_nan=False) | |
| max: LpaAmount = Field(ge=0.0, allow_inf_nan=False) | |
| class RawSignals(BaseModel): | |
| """The 23 ``redrob_signals``, typed exactly; sentinels preserved as-is.""" | |
| model_config = _STRICT | |
| profile_completeness_score: float = Field(ge=0.0, le=100.0, allow_inf_nan=False) | |
| signup_date: date | |
| last_active_date: date | |
| open_to_work_flag: bool | |
| profile_views_received_30d: int = Field(ge=0) | |
| applications_submitted_30d: int = Field(ge=0) | |
| recruiter_response_rate: float = Field(ge=0.0, le=1.0, allow_inf_nan=False) | |
| avg_response_time_hours: float = Field(ge=0.0, allow_inf_nan=False) | |
| skill_assessment_scores: Mapping[str, float] | |
| connection_count: int = Field(ge=0) | |
| endorsements_received: int = Field(ge=0) | |
| notice_period_days: int = Field(ge=0, le=180) | |
| expected_salary_range_inr_lpa: RawSalaryRange | |
| preferred_work_mode: WorkMode | |
| willing_to_relocate: bool | |
| github_activity_score: float = Field(ge=-1.0, le=100.0, allow_inf_nan=False) | |
| search_appearance_30d: int = Field(ge=0) | |
| saved_by_recruiters_30d: int = Field(ge=0) | |
| interview_completion_rate: float = Field(ge=0.0, le=1.0, allow_inf_nan=False) | |
| offer_acceptance_rate: float = Field(ge=-1.0, le=1.0, allow_inf_nan=False) | |
| verified_email: bool | |
| verified_phone: bool | |
| linkedin_connected: bool | |
| def _freeze_scores(cls, value: Mapping[str, float]) -> Mapping[str, float]: | |
| for score in value.values(): | |
| if not (0.0 <= score <= 100.0): | |
| raise ValueError("skill_assessment_scores out of range [0, 100]") | |
| return MappingProxyType(dict(value)) | |
| def _dump_scores(self, value: Mapping[str, float]) -> dict[str, float]: | |
| # ``MappingProxyType`` is not natively serializable; project the | |
| # read-only view back to a plain ``dict`` so ``RawCandidate`` round-trips | |
| # to JSON losslessly (provenance depends on this, §P). | |
| return dict(value) | |
| class RawCandidate(BaseModel): | |
| """Aggregate of raw facts — the canonical evidence source.""" | |
| model_config = _STRICT | |
| candidate_id: CandidateId = Field(pattern=r"^CAND_[0-9]{7}$") | |
| profile: RawProfile | |
| career_history: tuple[RawPosition, ...] = Field(min_length=1, max_length=10) | |
| education: tuple[RawEducation, ...] = Field(max_length=5) | |
| skills: tuple[RawSkill, ...] | |
| certifications: tuple[RawCertification, ...] | |
| languages: tuple[RawLanguage, ...] | |
| redrob_signals: RawSignals | |
| def from_mapping(cls, data: Mapping[str, Any]) -> RawCandidate: | |
| """Validate and narrow a raw mapping — the sole ``Any`` boundary. | |
| Type/shape violations are re-raised as ``SchemaError``; semantic | |
| contradictions are intentionally preserved for downstream detection. | |
| """ | |
| try: | |
| return cls.model_validate(data) | |
| except ValidationError as exc: | |
| raise SchemaError(str(exc)) from exc | |
| __all__: tuple[str, ...] = ( | |
| "RawCandidate", | |
| "RawCertification", | |
| "RawEducation", | |
| "RawLanguage", | |
| "RawPosition", | |
| "RawProfile", | |
| "RawSalaryRange", | |
| "RawSignals", | |
| "RawSkill", | |
| ) |