Compact scan runway history payload

This commit is contained in:
2569718930@qq.com
2026-06-01 01:03:33 +08:00
parent ff2a3da100
commit 2424b68532
2 changed files with 58 additions and 3 deletions
+36 -1
View File
@@ -6,6 +6,7 @@ from web.scan_terminal_payloads import (
build_stale_scan_terminal_payload,
)
from web.scan_terminal_ranker import build_ranked_scan_terminal_result
from web.scan_terminal_city_row import _build_quick_row
from web.routers.scan import router as scan_router
@@ -137,6 +138,41 @@ def test_scan_terminal_snapshot_id_is_stable_for_same_ranked_inputs():
assert first.startswith("scan-")
def test_scan_terminal_quick_row_compacts_runway_history_for_list_payload():
raw_history = {
"35R": [
{"time": "2026-05-31T00:00:00+00:00", "temp": 22.11},
{"time": "2026-05-31T00:01:00+00:00", "temp": 22.22},
{"time": "2026-05-31T00:02:00+00:00", "temp": 22.33},
{"time": "2026-05-31T00:10:00+00:00", "temp": 23.44},
{"time": "2026-05-31T00:11:00+00:00", "temp": 23.55},
]
}
row = _build_quick_row(
city="shanghai",
data={
"display_name": "Shanghai",
"local_date": "2026-05-31",
"local_time": "2026-05-31T08:11:00+08:00",
"temp_symbol": "°C",
"current": {"temp": 22.3, "max_so_far": 23.0},
"risk": {"airport": "Shanghai Pudong", "level": "medium"},
"deb": {"prediction": 24.0},
"probabilities": {"distribution": []},
"multi_model": {},
"runway_plate_history": raw_history,
},
)
compact_history = row["runway_plate_history"]["35R"]
assert len(compact_history) == 2
assert compact_history[0]["temp"] == 22.3
assert compact_history[1]["temp"] == 23.6
assert len(str(row["runway_plate_history"])) < len(str(raw_history))
def test_metar_gate_vetoes_yes_when_observed_breaks_above_bucket():
row = {
"id": "yes-row",
@@ -158,4 +194,3 @@ def test_metar_gate_vetoes_yes_when_observed_breaks_above_bucket():
assert row["v4_metar_decision"] == "veto"
assert row["ai_decision"] == "veto"
assert "越过目标桶上沿" in row["ai_reason_zh"]
+22 -2
View File
@@ -11,6 +11,22 @@ from web.scan_terminal_filters import (
market_region_from_tz_offset as _market_region_from_tz_offset,
safe_int as _safe_int,
)
from web.services.city_payloads import aggregate_runway_history
SCAN_ROW_RUNWAY_HISTORY_RESOLUTION = "10m"
SCAN_ROW_MAX_RUNWAY_POINTS = 144
def _compact_runway_plate_history_for_scan(raw_history: Any) -> Dict[str, List[Dict[str, Any]]]:
if not isinstance(raw_history, dict) or not raw_history:
return {}
compacted = aggregate_runway_history(raw_history, SCAN_ROW_RUNWAY_HISTORY_RESOLUTION)
return {
str(runway): points[-SCAN_ROW_MAX_RUNWAY_POINTS:]
for runway, points in compacted.items()
if isinstance(points, list) and points
}
def _resolve_time_range_dates(data: Dict[str, Any], time_range: str) -> List[str]:
@@ -132,7 +148,9 @@ def _build_terminal_row(
"amos": data.get("amos") or None,
"top_buckets": scan.get("top_buckets") or [],
"all_buckets": scan.get("all_buckets") or [],
"runway_plate_history": data.get("runway_plate_history") or {},
"runway_plate_history": _compact_runway_plate_history_for_scan(
data.get("runway_plate_history")
),
}
@@ -232,7 +250,9 @@ def _build_quick_row(
"is_primary_signal": True,
"accepting_orders": False,
"row_id": row_id,
"runway_plate_history": data.get("runway_plate_history") or {},
"runway_plate_history": _compact_runway_plate_history_for_scan(
data.get("runway_plate_history")
),
}
# Compute a simple edge: model top probability vs neutral
best_model_prob = max(