Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 22 additions & 15 deletions src/benchmark_radar/attention.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

from copy import deepcopy
from datetime import UTC, datetime
from math import isfinite
from typing import Any
from urllib.parse import urlsplit

Expand All @@ -12,6 +13,24 @@
LEGACY_HACKER_NEWS_PRODUCER = "benchmark-social-signal"


def _metrics(values: Any) -> dict[str, float]:
# Public feeds must not turn booleans into measurements or persist Infinity,
# which cannot be read as a JSON number by downstream consumers.
if not isinstance(values, dict):
return {}
normalized = {}
for key, value in values.items():
if type(value) not in (int, float):
continue
try:
numeric = float(value)
except OverflowError:
continue
if isfinite(numeric) and numeric >= 0:
normalized[str(key)] = numeric
return normalized


def _date(value: str | None, *, fallback: datetime) -> datetime:
if not value:
return fallback
Expand Down Expand Up @@ -47,11 +66,7 @@ def _supporting_observations(
"source_id": source_id,
"url": url,
"published_at": str(published_at),
"metrics": {
str(key): float(metric)
for key, metric in (value.get("metrics") or {}).items()
if isinstance(metric, int | float) and metric >= 0
},
"metrics": _metrics(value.get("metrics")),
**(
{"primary_artifact_url": primary}
if (primary := _http_url(value.get("primary_artifact_url")))
Expand Down Expand Up @@ -103,11 +118,7 @@ def _normalize_feed(
event_kind=str(raw.get("event_kind") or "discussed"),
authors=[str(author) for author in raw.get("authors") or []],
primary_artifact_url=_http_url(raw.get("primary_artifact_url")),
metrics={
str(key): float(value)
for key, value in (raw.get("metrics") or {}).items()
if isinstance(value, int | float) and value >= 0
},
metrics=_metrics(raw.get("metrics")),
categories=sorted(
{str(category) for category in raw.get("categories") or [] if category}
),
Expand Down Expand Up @@ -167,11 +178,7 @@ def _restore_previous(
event_kind=str(raw.get("event_kind") or "discussed"),
authors=[str(author) for author in raw.get("authors") or []],
primary_artifact_url=_http_url(raw.get("primary_artifact_url")),
metrics={
str(key): float(value)
for key, value in (raw.get("metrics") or {}).items()
if isinstance(value, int | float) and value >= 0
},
metrics=_metrics(raw.get("metrics")),
categories=[str(value) for value in raw.get("categories") or []],
rationale=[str(value) for value in raw.get("rationale") or []],
supporting_observations=_supporting_observations(
Expand Down
56 changes: 56 additions & 0 deletions tests/test_attention.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import json
from datetime import UTC, datetime

from benchmark_radar.attention import fetch_attention_feeds
Expand Down Expand Up @@ -165,3 +166,58 @@ def test_first_observed_time_survives_reingestion(monkeypatch):
)

assert observations[0].observed_at.isoformat() == first


def test_feed_metrics_preserve_measured_zero_but_cannot_emit_non_json_numbers(monkeypatch):
# A producer's overflowing JSON number became Infinity in the public snapshot;
# booleans also acquired a fabricated numeric measurement of one.
now = datetime(2026, 7, 27, 12, tzinfo=UTC)
invalid = {
"points": float("inf"),
"flag": True,
"zero": 0,
"valid": 2.5,
"nan": float("nan"),
"huge": 10**400,
"negative": -1,
}
raw = local_observation(now)
raw["metrics"] = invalid
raw["supporting_observations"] = [
{
"source_id": "2",
"url": "https://news.ycombinator.com/item?id=2",
"published_at": raw["published_at"],
"metrics": invalid,
}
]
payload = {"schema_version": 1, "producer": "fixture", "observations": [raw], "health": []}
monkeypatch.setattr("benchmark_radar.attention.get_json", lambda url: payload)
observations, health, _, _ = fetch_attention_feeds(
{"feeds": [{"url": "https://example.test/feed.json"}]}, observed_at=now
)
assert health[0].ok
assert observations[0].metrics == {"zero": 0.0, "valid": 2.5}
assert observations[0].supporting_observations[0]["metrics"] == observations[0].metrics
json.dumps(observations[0].to_dict(), allow_nan=False)


def test_failed_collector_sanitizes_metrics_from_legacy_observations(monkeypatch):
now = datetime(2026, 7, 27, 12, tzinfo=UTC)
monkeypatch.setattr(
"benchmark_radar.attention.collect_hacker_news",
lambda *args, **kwargs: ([], {"ok": False, "error": "offline"}),
)
previous = {
**local_observation(now),
"producer": "benchmark-social-signal",
"observation_id": "benchmark-social-signal:hacker-news:1",
"observed_at": now.isoformat(),
"metrics": {"points": float("inf"), "flag": True, "zero": 0},
}
restored, health, _, _ = fetch_attention_feeds(
LOCAL_CONFIG, observed_at=now, previous_observations=[previous]
)
assert not health[0].ok
assert restored[0].metrics == {"zero": 0.0}
json.dumps(restored[0].to_dict(), allow_nan=False)
Loading