diff --git a/frontend/lib/dashboard-types.ts b/frontend/lib/dashboard-types.ts index c3ccc282..f3a5275d 100644 --- a/frontend/lib/dashboard-types.ts +++ b/frontend/lib/dashboard-types.ts @@ -239,6 +239,7 @@ export interface MarketPrimary { id?: string | null; question?: string | null; slug?: string | null; + market_url?: string | null; condition_id?: string | null; end_date?: string | null; active?: boolean; @@ -266,6 +267,8 @@ export interface MarketScan { available?: boolean; reason?: string | null; primary_market?: MarketPrimary | null; + market_url?: string | null; + primary_market_url?: string | null; selected_date?: string | null; selected_condition_id?: string | null; selected_slug?: string | null; diff --git a/frontend/lib/polymarket-market-links.ts b/frontend/lib/polymarket-market-links.ts index 27c02b8f..20a4d9d4 100644 --- a/frontend/lib/polymarket-market-links.ts +++ b/frontend/lib/polymarket-market-links.ts @@ -98,6 +98,16 @@ export function getTodayPolymarketUrl( detail?: CityDetail | null, locale: Locale = "en-US", ) { + const directMarketUrl = String( + detail?.market_scan?.market_url || + detail?.market_scan?.primary_market_url || + detail?.market_scan?.primary_market?.market_url || + "", + ).trim(); + if (directMarketUrl) { + return directMarketUrl; + } + const cityKey = normalizeCityKey(detail); const citySlug = CITY_TO_MARKET_SLUG[cityKey] || slugifyCityName(cityKey); const dateParts = normalizeDateParts(detail?.local_date); diff --git a/src/data_collection/city_registry.py b/src/data_collection/city_registry.py index c308003e..08cdb0fb 100644 --- a/src/data_collection/city_registry.py +++ b/src/data_collection/city_registry.py @@ -288,7 +288,8 @@ CITY_REGISTRY = { "warning": "海湾冷空气和平流雾常压制机场升温,SFO 与市区体感差异可快速放大。", }, "aurora": { - "name": "Aurora", + "name": "Denver", + "display_name": "Denver", "lat": 39.7017, "lon": -104.7518, "icao": "KBKF", diff --git a/tests/test_web_observability.py b/tests/test_web_observability.py index 806da2d9..c1a59a4f 100644 --- a/tests/test_web_observability.py +++ b/tests/test_web_observability.py @@ -46,6 +46,14 @@ def test_metrics_endpoint_returns_prometheus_payload(): assert 'polyweather_http_requests_total' in response.text +def test_cities_endpoint_uses_denver_display_name_for_aurora_market(): + response = client.get("/api/cities") + assert response.status_code == 200 + payload = response.json() + aurora = next(item for item in payload["cities"] if item["name"] == "aurora") + assert aurora["display_name"] == "Denver" + + def test_payment_runtime_endpoint_returns_shape(): response = client.get('/api/payments/runtime') assert response.status_code == 200 diff --git a/web/analysis_service.py b/web/analysis_service.py index d1437f12..9958af3c 100644 --- a/web/analysis_service.py +++ b/web/analysis_service.py @@ -1451,9 +1451,10 @@ def _analyze(city: str, force_refresh: bool = False) -> Dict[str, Any]: } # ── Assemble result ── + city_meta = CITIES.get(city, {}) or {} result = { "name": city, - "display_name": city.title(), + "display_name": str(city_meta.get("display_name") or city_meta.get("name") or city.title()), "lat": lat, "lon": lon, "temp_symbol": sym, diff --git a/web/routes.py b/web/routes.py index f754b4ae..4bf22e49 100644 --- a/web/routes.py +++ b/web/routes.py @@ -201,11 +201,12 @@ async def list_cities(request: Request): out = [] for name, info in CITIES.items(): risk = CITY_RISK_PROFILES.get(name, {}) + city_meta = CITY_REGISTRY.get(name, {}) or {} settlement_source = str(info.get("settlement_source") or "metar").strip().lower() or "metar" out.append( { "name": name, - "display_name": name.title(), + "display_name": str(city_meta.get("display_name") or city_meta.get("name") or name.title()), "lat": info["lat"], "lon": info["lon"], "risk_level": risk.get("risk_level", "low"), @@ -213,7 +214,7 @@ async def list_cities(request: Request): "airport": risk.get("airport_name", ""), "icao": risk.get("icao", ""), "temp_unit": "fahrenheit" if info["f"] else "celsius", - "is_major": CITY_REGISTRY.get(name, {}).get("is_major", True), + "is_major": city_meta.get("is_major", True), "settlement_source": settlement_source, "settlement_source_label": SETTLEMENT_SOURCE_LABELS.get( settlement_source,