Treat stale observations as weak evidence

City-card fallback reads now stop using stale METAR or official observations as strong live anchors. A stale observation no longer forces high/low revisions, and both backend and browser AI cache keys include the observation fingerprint so updated report times, receipt times, temperatures, or stale status invalidate old AI text.

Constraint: Cached city AI reads must not survive a material observation update

Rejected: Let stale METAR trigger observed-break revisions | stale reports can be older than the active temperature path

Confidence: high

Scope-risk: moderate

Tested: pytest tests/test_web_observability.py -q

Tested: npm run build
This commit is contained in:
2569718930@qq.com
2026-04-28 06:28:29 +08:00
parent 0a3242c6ec
commit 0eab2fe628
4 changed files with 134 additions and 15 deletions
@@ -14,7 +14,7 @@ import type { CityDetail, MarketScan } from "@/lib/dashboard-types";
import { extractStreamingAirportRead } from "./ai-city-stream";
import { normalizeCityKey } from "./decision-utils";
const AI_CITY_FORECAST_CACHE_PREFIX = "polyWeather_aiCityForecast_v5";
const AI_CITY_FORECAST_CACHE_PREFIX = "polyWeather_aiCityForecast_v6";
const AI_CITY_FORECAST_CACHE_TTL_MS = 60 * 60 * 1000;
const AI_CITY_FORECAST_MAX_CONCURRENT_STREAMS = 2;
const CITY_MARKET_SCAN_CACHE_PREFIX = "polyWeather_cityMarketScan_v3";
@@ -447,8 +447,12 @@ export function useAiCityForecast({
observationCurrent.report_time,
observationCurrent.obs_time_epoch,
observationCurrent.obs_time,
observationCurrent.receipt_time,
observationCurrent.temp,
observationCurrent.max_so_far,
observationCurrent.station_code,
detail.metar_status?.stale_for_today,
detail.metar_status?.last_observation_time,
]
.filter((part) => part != null && part !== "")
.join("|");