Spaces:
Sleeping
Sleeping
| from __future__ import annotations | |
| from collections.abc import Mapping | |
| from typing import Final, final | |
| from pydantic import BaseModel, ConfigDict | |
| from redstack.config.schema import ScoringPolicy | |
| from redstack.domain.candidate.eligibility import EligibilityReport | |
| from redstack.domain.candidate.integrity import IntegrityReport | |
| from redstack.domain.enums import ScoreComponent | |
| from redstack.domain.errors import ScoreInvariantError | |
| from redstack.domain.ids import CandidateId, Multiplier, Score, UnitScore | |
| from redstack.domain.provenance import EvidenceRef | |
| from redstack.domain.scoring import ( | |
| GateOutcome, | |
| ScoreBreakdown, | |
| ScoredCandidate, | |
| ScoreComponentValue, | |
| ScoringWeights, | |
| ) | |
| _COMPONENT_ORDER: Final[tuple[ScoreComponent, ...]] = tuple(ScoreComponent) | |
| ComponentRaw = tuple[UnitScore, tuple[EvidenceRef, ...]] | |
| class ScoringEngine(BaseModel): | |
| """Stateless, pure scoring engine; weights + policy are injected, immutable.""" | |
| model_config = ConfigDict(frozen=True, extra="forbid", arbitrary_types_allowed=False) | |
| weights: ScoringWeights | |
| policy: ScoringPolicy | |
| def __init__(self, **data: object) -> None: | |
| super().__init__(**data) | |
| # Weight set must equal ScoreComponent exactly (ArtifactContractError is | |
| # raised at load; here we defensively re-assert against silent drift). | |
| missing = set(_COMPONENT_ORDER) - set(self.weights.weights) | |
| if missing: | |
| raise ScoreInvariantError( | |
| f"ScoringWeights missing components: {sorted(c.value for c in missing)}" | |
| ) | |
| # ------------------------------------------------------------------ public | |
| def score( | |
| self, | |
| *, | |
| candidate_id: CandidateId, | |
| components: Mapping[ScoreComponent, ComponentRaw], | |
| integrity: IntegrityReport, | |
| eligibility: EligibilityReport, | |
| behavioral_multiplier: Multiplier, | |
| logistics_multiplier: Multiplier, | |
| archetype_adjustment: float, | |
| confidence: UnitScore, | |
| ) -> ScoredCandidate: | |
| """Produce the ``ScoredCandidate`` with a fully reconstructable breakdown.""" | |
| component_values = self._component_values(components) | |
| base = self._sum_weighted(component_values) | |
| integrity_gate = self._integrity_gate(integrity) | |
| eligibility_gate = self._eligibility_gate(eligibility) | |
| gated = not (integrity_gate.passed and eligibility_gate.passed) | |
| if gated: | |
| final = Score(float(self.policy.floor)) | |
| beh = behavioral_multiplier | |
| log = logistics_multiplier | |
| adjustment = 0.0 # no multipliers/adjustments applied to a floored row | |
| else: | |
| combined = ( | |
| float(base) | |
| * float(behavioral_multiplier) | |
| * float(logistics_multiplier) | |
| + archetype_adjustment | |
| ) | |
| final = Score(self._shrink(combined, confidence)) | |
| beh = behavioral_multiplier | |
| log = logistics_multiplier | |
| adjustment = archetype_adjustment | |
| self._assert_finite(float(base), float(final)) | |
| breakdown = ScoreBreakdown( | |
| components=component_values, | |
| base_relevance=base, | |
| integrity_gate=integrity_gate, | |
| eligibility_gate=eligibility_gate, | |
| behavioral_multiplier=beh, | |
| logistics_multiplier=log, | |
| archetype_adjustment=adjustment, | |
| final_score=final, | |
| ) | |
| if gated and float(final) != float(self.policy.floor): | |
| raise ScoreInvariantError("gated candidate not floored") | |
| return ScoredCandidate( | |
| candidate_id=candidate_id, | |
| final_score=final, | |
| breakdown=breakdown, | |
| tiebreak_key=candidate_id, | |
| ) | |
| # --------------------------------------------------------------- internals | |
| def _component_values( | |
| self, components: Mapping[ScoreComponent, ComponentRaw] | |
| ) -> tuple[ScoreComponentValue, ...]: | |
| values: list[ScoreComponentValue] = [] | |
| for component in _COMPONENT_ORDER: | |
| raw, evidence = components.get( | |
| component, (UnitScore(0.0), ()) | |
| ) | |
| weight = float(self.weights.weights[component]) | |
| weighted = float(raw) * weight | |
| values.append( | |
| ScoreComponentValue( | |
| component=component, | |
| raw=raw, | |
| weight=weight, | |
| weighted=weighted, | |
| evidence=evidence, | |
| ) | |
| ) | |
| return tuple(values) | |
| def _sum_weighted(values: tuple[ScoreComponentValue, ...]) -> Score: | |
| # Summed in ScoreComponent order (values already ordered); float32-stable. | |
| total = 0.0 | |
| for value in values: | |
| total += value.weighted | |
| return Score(total) | |
| def _shrink(self, combined: float, confidence: UnitScore) -> float: | |
| """Shrink ``combined`` toward the neutral prior in proportion to confidence. | |
| ``shrunk = prior + confidence·(combined − prior)``: full confidence keeps the | |
| value, zero confidence collapses to the prior. Monotone in ``combined`` for a | |
| fixed confidence, so ranking order is preserved among equal-confidence rows. | |
| """ | |
| prior = self.policy.neutral_prior | |
| return prior + float(confidence) * (combined - prior) | |
| def _integrity_gate(report: IntegrityReport) -> GateOutcome: | |
| if not report.is_honeypot: | |
| return GateOutcome(passed=True, reason=None) | |
| reason = next( | |
| (f.code for f in report.findings if f.severity.value == "hard"), None | |
| ) | |
| if reason is None and report.findings: | |
| reason = report.findings[0].code | |
| return GateOutcome(passed=False, reason=reason) | |
| def _eligibility_gate(report: EligibilityReport) -> GateOutcome: | |
| if report.is_eligible: | |
| return GateOutcome(passed=True, reason=None) | |
| reason = report.hard_blocks[0].code if report.hard_blocks else None | |
| return GateOutcome(passed=False, reason=reason) | |
| def _assert_finite(base: float, final: float) -> None: | |
| for label, value in (("base_relevance", base), ("final_score", final)): | |
| if value != value or value in (float("inf"), float("-inf")): | |
| raise ScoreInvariantError(f"{label} is non-finite ({value!r})") | |
| __all__: tuple[str, ...] = ("ComponentRaw", "ScoringEngine") |