class AuthorProfile(AuthorCore):
"""Unified author profile combining publication record, artifact metrics, and AE committee service."""
ae_memberships: int = Field(
default=0,
ge=0,
description="Total number of AE committee memberships across all conferences and years.",
examples=[4],
)
chair_count: int = Field(
default=0, ge=0, description="Number of times served as AE chair (versus regular member).", examples=[1]
)
ae_conferences: list[AEMembership] = Field(
default_factory=list,
description="AE committee memberships, one per conference-year served. Each entry has conference, year, role.",
)
ae_years: dict[str, int] = Field(
default_factory=dict,
description="Year (as string key, e.g. '2023') → number of AE memberships that year. Example: {'2023': 5, '2024': 3}.",
)
combined_score: int = Field(
ge=0, description="Total combined score: artifact_score + citation_score + ae_score.", examples=[15]
)
artifact_score: int = Field(
ge=0,
description="Points from artifacts: each artifact scores 1 (available) + 1 (functional) + 1 (reproducible).",
examples=[9],
)
citation_score: int = Field(
ge=0, description="Points from artifact citations. Currently 0 for all authors.", examples=[0]
)
ae_score: int = Field(ge=0, description="Points from AE service: memberships * 3 + chairs * 2.", examples=[6])
rank: int | None = Field(
default=None,
ge=1,
description="Ranking position among all author profiles (with ties). Null if unranked.",
examples=[1],
)
@field_validator("conferences", mode="before")
@classmethod
def _coerce_conferences(cls, v: object) -> object:
"""Accept [conf, year, role] tuples and extract conference name strings."""
if isinstance(v, list) and v and isinstance(v[0], (list, tuple)):
seen: set[str] = set()
result: list[str] = []
for item in v:
name = item[0] if isinstance(item, (list, tuple)) else item
if name not in seen:
seen.add(name)
result.append(name)
return result
return v
@field_validator("ae_conferences", mode="before")
@classmethod
def _coerce_ae_conferences(cls, v: object) -> object:
"""Accept both [conf, year, role] lists and {conference, year, role} dicts."""
if isinstance(v, list):
return [
{"conference": item[0], "year": item[1], "role": item[2]} if isinstance(item, (list, tuple)) else item
for item in v
]
return v