Spaces:
Sleeping
Sleeping
| from __future__ import annotations | |
| import math | |
| from collections.abc import Mapping | |
| from datetime import date | |
| from types import MappingProxyType | |
| from typing import Final, final | |
| from pydantic import BaseModel, ConfigDict, Field, field_validator | |
| from redstack.domain.enums import EvidenceKind | |
| from redstack.domain.ids import UnitScore | |
| from redstack.domain.provenance import EvidenceRef | |
| from redstack.domain.source import RawCandidate | |
| from redstack.features.parsing import resolve_path | |
| _VO = ConfigDict( | |
| frozen=True, extra="forbid", str_strip_whitespace=True, validate_default=True | |
| ) | |
| FeatureId = str | |
| CellEmission = tuple[tuple[FeatureId, "FeatureCell"], ...] | |
| # --------------------------------------------------------------------------- # | |
| # Pure numeric helpers (shared normalization vocabulary). # | |
| # --------------------------------------------------------------------------- # | |
| def clamp_unit(value: float) -> float: | |
| """Clamp a finite float into ``[0, 1]``; a non-finite input is a bug → raise.""" | |
| if not math.isfinite(value): | |
| raise ValueError(f"clamp_unit received a non-finite value: {value!r}") | |
| if value <= 0.0: | |
| return 0.0 | |
| if value >= 1.0: | |
| return 1.0 | |
| return float(value) | |
| def unit(value: float) -> UnitScore: | |
| """Construct a ``UnitScore`` from a float, clamping into ``[0, 1]``.""" | |
| return UnitScore(clamp_unit(value)) | |
| def bounded_log_scale(count: float, *, saturation: float) -> float: | |
| """Map a non-negative count onto ``[0, 1]`` with diminishing returns. | |
| ``log1p(count) / log1p(saturation)`` — a count equal to ``saturation`` maps | |
| to ~1.0; growth past it is clamped. Negative counts (sentinels) clamp to 0. | |
| """ | |
| if saturation <= 0.0: | |
| raise ValueError("saturation must be positive") | |
| safe = count if count > 0.0 else 0.0 | |
| return clamp_unit(math.log1p(safe) / math.log1p(saturation)) | |
| def inverse_bounded(value: float, *, scale: float) -> float: | |
| """Map a non-negative magnitude onto ``(0, 1]`` decreasing in ``value``. | |
| ``scale / (scale + value)`` — ``value == 0`` → 1.0, ``value == scale`` → 0.5. | |
| Used for "smaller is better" quantities such as response time in hours. | |
| """ | |
| if scale <= 0.0: | |
| raise ValueError("scale must be positive") | |
| safe = value if value > 0.0 else 0.0 | |
| return clamp_unit(scale / (scale + safe)) | |
| def recency_unit(days_elapsed: float, *, half_life_days: float) -> float: | |
| """Exponential recency in ``[0, 1]``: 1.0 today, 0.5 at one half-life. | |
| A negative ``days_elapsed`` (a future date relative to ``as_of``) is treated | |
| as 0 days (fully recent) here; the *impossibility* of a future date is the | |
| honeypot layer's job, not the normalizer's. | |
| """ | |
| if half_life_days <= 0.0: | |
| raise ValueError("half_life_days must be positive") | |
| safe = days_elapsed if days_elapsed > 0.0 else 0.0 | |
| return clamp_unit(math.pow(0.5, safe / half_life_days)) | |
| def days_between(later: date, earlier: date) -> int: | |
| """Signed day delta ``later - earlier`` (negative if ``later`` precedes).""" | |
| return (later - earlier).days | |
| def mean_of(values: tuple[float, ...]) -> float: | |
| """Arithmetic mean of a non-empty tuple; empty → 0.0 (neutral).""" | |
| if not values: | |
| return 0.0 | |
| return math.fsum(values) / len(values) | |
| def make_evidence( | |
| kind: EvidenceKind, | |
| path: str, | |
| value: str | int | float | bool, | |
| *, | |
| raw: RawCandidate | None = None, | |
| ) -> EvidenceRef: | |
| """Mint an ``EvidenceRef``; ``date`` callers pass ``.isoformat()`` strings. | |
| When ``raw`` is given, ``path`` is verified to resolve inside it before | |
| the ref is minted -- a dangling path (wrong index, renamed field) raises | |
| ``ProvenanceError`` immediately rather than shipping a citation nothing | |
| backs. ``value`` is kept as the caller supplied it (it may be a derived | |
| label, not the literal scalar at ``path``); only existence is checked. | |
| Callers citing a literal ``RawCandidate`` field must pass ``raw``. | |
| ``EvidenceKind.DERIVED`` evidence (and citations of fields on an | |
| already-validated domain profile, where no raw record exists to dangle | |
| against) may omit it. | |
| """ | |
| if raw is not None: | |
| resolve_path(raw, path) | |
| return EvidenceRef(kind=kind, path=path, value=value) | |
| # --------------------------------------------------------------------------- # | |
| # Feature cell. # | |
| # --------------------------------------------------------------------------- # | |
| class FeatureCell(BaseModel): | |
| """One feature's ``(value, confidence, evidence)`` output. | |
| ``value`` carries no range constraint here beyond finiteness — the per-index | |
| bounds in ``FeatureLayout`` are checked when the cell folds into the CQV. | |
| ``evidence`` is non-empty by construction: a feature with no evidence cannot | |
| be cited by Reasoning, so emitting one would be a silent hallucination risk. | |
| """ | |
| model_config = _VO | |
| value: float = Field(allow_inf_nan=False) | |
| confidence: UnitScore = Field(ge=0.0, le=1.0, allow_inf_nan=False) | |
| evidence: tuple[EvidenceRef, ...] = Field(min_length=1) | |
| def _confidence_unit(cls, value: float) -> UnitScore: | |
| return UnitScore(value) | |
| def cell( | |
| value: float, confidence: float, evidence: tuple[EvidenceRef, ...] | |
| ) -> FeatureCell: | |
| """Build a ``FeatureCell``, clamping ``confidence`` into ``[0, 1]``.""" | |
| return FeatureCell(value=value, confidence=unit(confidence), evidence=evidence) | |
| def group_of(feature_id: str) -> str: | |
| """Group prefix (text before the first dot) of a feature id.""" | |
| return feature_id.split(".", 1)[0] | |
| # --------------------------------------------------------------------------- # | |
| # Read-only feature view (Part 9 — the sole engine read surface). # | |
| # --------------------------------------------------------------------------- # | |
| class FeatureView(BaseModel): | |
| """Typed, read-only accessor over one candidate's cells + group confidence. | |
| Engines never touch raw arrays; they resolve features by id through this | |
| view. Construction is via ``from_cells`` (which derives group confidence as | |
| the mean of each group's member-cell confidences). All three accessors are | |
| pure and deterministic. | |
| """ | |
| model_config = _VO | |
| cells: Mapping[FeatureId, FeatureCell] | |
| group_confidences: Mapping[str, float] | |
| importances: Mapping[FeatureId, float] | |
| def _freeze_cells( | |
| cls, value: Mapping[FeatureId, FeatureCell] | |
| ) -> Mapping[FeatureId, FeatureCell]: | |
| return MappingProxyType(dict(value)) | |
| def _freeze_group_conf(cls, value: Mapping[str, float]) -> Mapping[str, float]: | |
| for group, conf in value.items(): | |
| if not (0.0 <= conf <= 1.0): | |
| raise ValueError(f"group_confidence for {group!r} not in [0, 1]") | |
| return MappingProxyType(dict(value)) | |
| def _freeze_importance( | |
| cls, value: Mapping[FeatureId, float] | |
| ) -> Mapping[FeatureId, float]: | |
| for feature_id, weight in value.items(): | |
| if not math.isfinite(weight): | |
| raise ValueError(f"importance for {feature_id!r} is not finite") | |
| return MappingProxyType(dict(value)) | |
| # -- the Part 9 contract --------------------------------------------- # | |
| def get(self, feature_id: FeatureId) -> FeatureCell: | |
| """Resolve a feature's cell. Unknown id → ``KeyError`` (programming error).""" | |
| return self.cells[feature_id] | |
| def group_confidence(self, group: str) -> UnitScore: | |
| """Group-granular confidence. Unknown group → ``KeyError``.""" | |
| return UnitScore(self.group_confidences[group]) | |
| def importance(self, feature_id: FeatureId) -> float: | |
| """Learned importance; a feature with no learned weight returns ``0.0``.""" | |
| return self.importances.get(feature_id, 0.0) | |
| # -- convenience (still read-only) ----------------------------------- # | |
| def has(self, feature_id: FeatureId) -> bool: | |
| """Whether a cell was emitted for ``feature_id``.""" | |
| return feature_id in self.cells | |
| def value_of(self, feature_id: FeatureId, default: float = 0.0) -> float: | |
| """The cell value, or ``default`` if the feature was not emitted.""" | |
| found = self.cells.get(feature_id) | |
| return found.value if found is not None else default | |
| def from_cells( | |
| cls, | |
| cells: Mapping[FeatureId, FeatureCell], | |
| *, | |
| importances: Mapping[FeatureId, float] | None = None, | |
| ) -> FeatureView: | |
| """Assemble a view, deriving group confidence as the per-group mean. | |
| Engines build the full ``{feature_id: FeatureCell}`` map from every | |
| extractor, then hand it here; group confidence is the deterministic mean | |
| of member-cell confidences (Part 7: confidence is stored at group | |
| granularity). | |
| """ | |
| grouped: dict[str, list[float]] = {} | |
| for feature_id, feature_cell in cells.items(): | |
| grouped.setdefault(group_of(feature_id), []).append( | |
| float(feature_cell.confidence) | |
| ) | |
| group_conf = { | |
| group: math.fsum(confs) / len(confs) for group, confs in grouped.items() | |
| } | |
| return cls( | |
| cells=dict(cells), | |
| group_confidences=group_conf, | |
| importances=dict(importances) if importances is not None else {}, | |
| ) | |
| # Saturation / scale constants shared by the extractors (documented once here). | |
| ENDORSEMENT_SATURATION: Final[float] = 50.0 | |
| DURATION_SATURATION_MONTHS: Final[float] = 36.0 | |
| ACTIVITY_HALF_LIFE_DAYS: Final[float] = 90.0 | |
| STALE_HALF_LIFE_DAYS: Final[float] = 180.0 | |
| RESPONSE_TIME_SCALE_HOURS: Final[float] = 24.0 | |
| __all__ = ( | |
| "ACTIVITY_HALF_LIFE_DAYS", | |
| "CellEmission", | |
| "DURATION_SATURATION_MONTHS", | |
| "ENDORSEMENT_SATURATION", | |
| "FeatureCell", | |
| "FeatureId", | |
| "FeatureView", | |
| "RESPONSE_TIME_SCALE_HOURS", | |
| "STALE_HALF_LIFE_DAYS", | |
| "bounded_log_scale", | |
| "cell", | |
| "clamp_unit", | |
| "days_between", | |
| "group_of", | |
| "inverse_bounded", | |
| "make_evidence", | |
| "mean_of", | |
| "recency_unit", | |
| "unit", | |
| ) | |