class AuthorRanking(BaseModel):
"""Ranking entry for a single author combining artifact contributions and AE committee service."""
rank: int = Field(ge=1, description="Ranking position (with ties).")
author_id: int | None = Field(
default=None,
ge=1,
description="Stable integer identifier referencing the canonical author_index.",
)
name: str = Field(description="Full author name including DBLP disambiguation suffix.")
display_name: str = Field(description="Author name without DBLP disambiguation suffix.")
affiliation: str = Field(description="Raw affiliation string from DBLP.")
display_affiliation: str = Field(description="Normalized/cleaned institution name.")
artifacts: int = Field(ge=0, description="Total number of artifacts authored.")
artifact_score: int = Field(
ge=0,
description="Points from artifacts: each artifact scores 1 (available) + 1 (functional) + 1 (reproducible).",
)
artifact_citations: int = Field(ge=0, description="Citation count for artifacts (currently 0).")
citation_score: int = Field(ge=0, description="Points from citations (currently 0).")
total_papers: int = Field(ge=0, description="Total papers published at tracked conferences (from DBLP).")
artifact_rate: float = Field(ge=0, le=100, description="Percentage of papers with artifacts.")
repro_rate: int = Field(ge=0, le=100, description="Percentage of artifacts with a reproducibility badge.")
ae_memberships: int = Field(ge=0, description="Number of AE committee memberships.")
chair_count: int = Field(ge=0, description="Number of AE chair roles.")
ae_score: int = Field(ge=0, description="Points from AE service: memberships * 3 + chairs * 2.")
ae_ratio: float | None = Field(
default=None,
description="Artifact score / AE score ratio. Null if ae_score is 0.",
)
combined_score: int = Field(
ge=3,
description="Total score: artifact_score + citation_score + ae_score. Minimum threshold of 3.",
)
badges_available: int = Field(ge=0, description="Count of 'available' badges.")
badges_functional: int = Field(ge=0, description="Count of 'functional' badges.")
badges_reproducible: int = Field(ge=0, description="Count of 'reproduced' badges.")
conferences: list[str] = Field(description="Conferences where the author has contributed.")
years: dict[str, int] = Field(description="Year-to-activity-count mapping.")
first_year: int | None = Field(default=None, description="Earliest year of activity.")
last_year: int | None = Field(default=None, description="Most recent year of activity.")
model_config = {"extra": "forbid"}