Route-level statistics collector with persistent storage.
| 268 | |
| 269 | |
| 270 | class RouteStats: |
| 271 | """Route-level statistics collector with persistent storage.""" |
| 272 | |
| 273 | def __init__( |
| 274 | self, |
| 275 | storage: RouteStatsStorage | None = None, |
| 276 | now_fn: Any = None, |
| 277 | ) -> None: |
| 278 | self._storage = storage or FileRouteStatsStorage() |
| 279 | self._now = now_fn or time.time |
| 280 | self._records: list[RouteRecord] = [] |
| 281 | self._load() |
| 282 | |
| 283 | def record(self, rec: RouteRecord) -> None: |
| 284 | rec.tier = _normalize_tier_label(rec.tier) |
| 285 | rec.decision_tier = _normalize_tier_label(rec.decision_tier) if rec.decision_tier else "" |
| 286 | rec.served_quality = _normalize_served_quality(rec.served_quality) |
| 287 | rec.served_quality_target = _normalize_served_quality(rec.served_quality_target) |
| 288 | rec.served_quality_floor = _normalize_served_quality(rec.served_quality_floor) |
| 289 | rec.capability_lane = str(rec.capability_lane or "").strip().lower() |
| 290 | rec.feedback_from_tier = _normalize_tier_label(rec.feedback_from_tier) if rec.feedback_from_tier else "" |
| 291 | rec.feedback_to_tier = _normalize_tier_label(rec.feedback_to_tier) if rec.feedback_to_tier else "" |
| 292 | self._records.append(rec) |
| 293 | self._cleanup() |
| 294 | self._save() |
| 295 | |
| 296 | def record_feedback( |
| 297 | self, |
| 298 | request_id: str, |
| 299 | *, |
| 300 | signal: str, |
| 301 | ok: bool, |
| 302 | action: str, |
| 303 | from_tier: str = "", |
| 304 | to_tier: str = "", |
| 305 | reason: str = "", |
| 306 | ) -> bool: |
| 307 | for record in reversed(self._records): |
| 308 | if record.request_id != request_id: |
| 309 | continue |
| 310 | record.feedback_signal = signal |
| 311 | record.feedback_ok = ok |
| 312 | record.feedback_action = action |
| 313 | record.feedback_from_tier = _normalize_tier_label(from_tier) if from_tier else "" |
| 314 | record.feedback_to_tier = _normalize_tier_label(to_tier) if to_tier else "" |
| 315 | record.feedback_reason = reason |
| 316 | record.feedback_submitted_at = self._now() |
| 317 | self._save() |
| 318 | return True |
| 319 | return False |
| 320 | |
| 321 | def history(self, limit: int | None = None) -> list[RouteRecord]: |
| 322 | records = list(reversed(self._records)) |
| 323 | return records[:limit] if limit else records |
| 324 | |
| 325 | def export_records(self, limit: int | None = None) -> list[dict[str, Any]]: |
| 326 | records = self.history(limit=limit) |
| 327 | return [_record_payload(record) for record in records] |
no outgoing calls