From 95c0c452f1de3083c2191fcc4686204569f2f4b7 Mon Sep 17 00:00:00 2001 From: "2569718930@qq.com" <2569718930@qq.com> Date: Thu, 2 Apr 2026 23:24:38 +0800 Subject: [PATCH] Finalize SQLite defaults and refresh calibration artifacts --- .env.example | 2 +- README.md | 6 +- README_ZH.md | 6 +- .../probability_calibration/default.json | 174 +- .../evaluation_report.json | 261 +-- .../shadow_report.json | 1306 +++----------- .../training_samples.json | 1600 +++++------------ docs/TECH_DEBT.md | 13 +- docs/TECH_DEBT_ZH.md | 13 +- docs/deep-research-report.md | 11 +- scripts/backfill_daily_record_model_gaps.py | 13 +- .../backfill_probability_shadow_history.py | 3 +- ...ackfill_recent_daily_actuals_from_metar.py | 3 +- scripts/build_probability_shadow_report.py | 3 +- scripts/evaluate_probability_calibration.py | 3 +- .../export_probability_training_dataset.py | 6 +- scripts/fit_probability_calibration.py | 25 +- src/bot/analysis/deb_analysis_service.py | 7 +- src/models/lgbm_features.py | 42 +- 19 files changed, 1055 insertions(+), 2442 deletions(-) diff --git a/.env.example b/.env.example index cdf80bcb..ab9b0389 100644 --- a/.env.example +++ b/.env.example @@ -17,7 +17,7 @@ OPEN_METEO_DISK_CACHE_PATH=/var/lib/polyweather/open_meteo_cache.json # Windows / macOS can usually keep the defaults. UID=1000 GID=1000 -POLYWEATHER_STATE_STORAGE_MODE=dual +POLYWEATHER_STATE_STORAGE_MODE=sqlite POLYWEATHER_PROMETHEUS_PORT=9090 POLYWEATHER_ALERTMANAGER_PORT=9093 POLYWEATHER_ALERT_RELAY_PORT=9099 diff --git a/README.md b/README.md index db63d475..d3949111 100644 --- a/README.md +++ b/README.md @@ -25,7 +25,7 @@ Public docs center: `/docs/intro` on the main site (bilingual product documentat - Auto-reconciliation live: event listener + periodic confirm loop. - Ops dashboard live: `/ops` for memberships, leaderboard, manual point grants, and payment incident triage. - Lightweight observability live: `/healthz`, `/api/system/status`, `/metrics`. -- Runtime state supports gradual SQLite migration (`file / dual / sqlite`). +- Runtime state, cache, and core offline training/backfill flows now use SQLite as the primary path; legacy JSON/JSONL files remain only for migration, export, and explicit fallback input. - EMOS/CRPS pipeline is integrated in `shadow` mode with rollout gating. - Intraday structural signal is now peak-window aware and bilingual (`zh-CN` / `en-US`). - Non-Hong Kong airport cities now ingest `TAF` and parse `FM / TEMPO / BECMG / PROB30/40`. @@ -101,7 +101,8 @@ npm run dev ## Recent Highlights -- Taipei settlement is aligned to `NOAA RCTP` and rounded whole-degree Celsius logic. +- Taipei settlement is aligned to `Wunderground RCSS` with whole-degree Celsius resolution logic. +- Shenzhen settlement is aligned to `Wunderground ZGSZ`. - Hong Kong keeps `HKO` official readings in dashboard and history, without falling back to airport METAR lines. - Intraday analysis now separates: - `Surface Structure` @@ -117,6 +118,7 @@ Use external runtime storage to avoid SQLite/git conflicts: ```env POLYWEATHER_RUNTIME_DATA_DIR=/var/lib/polyweather POLYWEATHER_DB_PATH=/var/lib/polyweather/polyweather.db +POLYWEATHER_STATE_STORAGE_MODE=sqlite ``` ## Ops Verification diff --git a/README_ZH.md b/README_ZH.md index ebf142ba..8d8159d3 100644 --- a/README_ZH.md +++ b/README_ZH.md @@ -24,7 +24,7 @@ - 已上线轻量运营后台:`/ops`(会员、周榜、补分、支付异常单)。 - 已上线轻量可观测性:`/healthz`、`/api/system/status`、`/metrics`。 - 已补最小外部监控栈:Prometheus + Alertmanager + Grafana + Telegram 告警 relay。 -- 运行态状态与缓存已支持 SQLite 渐进迁移:`file / dual / sqlite`。 +- 运行态状态、缓存与核心离线训练/回填链路已完成 SQLite 主路径收口;legacy JSON/JSONL 仅保留给迁移、导出与显式回退输入。 - 已接入 EMOS/CRPS 校准链路,但当前仍保持 `emos_shadow`。 ## 许可证与商用边界(重要) @@ -64,7 +64,7 @@ flowchart LR ANA --> PAY["支付状态(Intent + Event + Confirm Loop)"] ANA --> PM["Polymarket 只读层"] API --> OBS["healthz / system status / metrics"] - ANA --> STATE["SQLite runtime state + dual fallback"] + ANA --> STATE["SQLite runtime state
legacy files only for migration/export fallback"] ``` ## 监控城市(30) @@ -98,7 +98,7 @@ npm run dev ```env POLYWEATHER_RUNTIME_DATA_DIR=/var/lib/polyweather POLYWEATHER_DB_PATH=/var/lib/polyweather/polyweather.db -POLYWEATHER_STATE_STORAGE_MODE=dual +POLYWEATHER_STATE_STORAGE_MODE=sqlite ``` ## 运维验收 diff --git a/artifacts/probability_calibration/default.json b/artifacts/probability_calibration/default.json index 281fbf86..390b241d 100644 --- a/artifacts/probability_calibration/default.json +++ b/artifacts/probability_calibration/default.json @@ -1,20 +1,20 @@ { - "version": "emos-20260320132525", - "trained_at": "2026-03-20T13:25:25.836021+00:00", + "version": "emos-20260402151301", + "trained_at": "2026-04-02T15:13:01.073253+00:00", "global": { "mu": { - "intercept": -1.57406048, - "raw_mu_coef": 2.80583627, - "deb_coef": -0.06819634, - "ens_median_coef": -1.81560215, - "max_so_far_gap_coef": 0.0 + "intercept": 1.52725527, + "raw_mu_coef": 2.96318139, + "deb_coef": -1.54490032, + "ens_median_coef": -0.71820793, + "max_so_far_gap_coef": 10.22802132 }, "sigma": { - "intercept": 0.67509915, - "raw_sigma_coef": 0.14431833, - "spread_coef": 0.14431833, - "peak_flag_coef": 0.0, - "max_so_far_gap_coef": 0.0 + "intercept": 0.67227661, + "raw_sigma_coef": 0.69444674, + "spread_coef": 0.09134583, + "peak_flag_coef": -0.58201761, + "max_so_far_gap_coef": -0.81482466 } }, "sigma_constraints": { @@ -30,143 +30,59 @@ }, "blending": { "alpha_mu": 0.0, - "alpha_sigma": 0.0 + "alpha_sigma": 0.45 }, "cities": { "ankara": { - "samples": 7, - "mu_bias": 0.566273, - "sigma_scale": 2.0, - "confidence": 0.875 - }, - "london": { - "samples": 6, - "mu_bias": 0.489961, - "sigma_scale": 2.0, - "confidence": 0.75 - }, - "new york": { - "samples": 4, - "mu_bias": 1.852451, - "sigma_scale": 0.830444, - "confidence": 0.5 - }, - "paris": { - "samples": 7, - "mu_bias": 0.308599, - "sigma_scale": 2.0, - "confidence": 0.875 - }, - "seoul": { - "samples": 6, - "mu_bias": -1.486024, - "sigma_scale": 1.569585, - "confidence": 0.75 - }, - "toronto": { - "samples": 5, - "mu_bias": -0.734395, - "sigma_scale": 1.656751, - "confidence": 0.625 - }, - "buenos aires": { - "samples": 5, - "mu_bias": -1.753334, - "sigma_scale": 1.831739, - "confidence": 0.625 - }, - "wellington": { - "samples": 6, - "mu_bias": 0.350757, - "sigma_scale": 1.377974, - "confidence": 0.75 - }, - "chicago": { - "samples": 4, - "mu_bias": 3.01062, - "sigma_scale": 0.825575, - "confidence": 0.5 - }, - "sao paulo": { - "samples": 5, - "mu_bias": 1.632457, - "sigma_scale": 2.0, - "confidence": 0.625 - }, - "dallas": { - "samples": 4, - "mu_bias": 3.77714, - "sigma_scale": 0.796874, - "confidence": 0.5 - }, - "miami": { - "samples": 5, - "mu_bias": -4.868741, - "sigma_scale": 2.0, - "confidence": 0.625 - }, - "atlanta": { - "samples": 5, - "mu_bias": -7.648823, - "sigma_scale": 2.0, - "confidence": 0.625 - }, - "seattle": { - "samples": 4, - "mu_bias": 4.058619, - "sigma_scale": 2.0, - "confidence": 0.5 - }, - "lucknow": { - "samples": 4, - "mu_bias": 3.257609, - "sigma_scale": 2.0, - "confidence": 0.5 - }, - "munich": { - "samples": 6, - "mu_bias": -0.780811, - "sigma_scale": 2.0, - "confidence": 0.75 + "samples": 3, + "mu_bias": 1.283918, + "sigma_scale": 1.484056, + "confidence": 0.375 }, "hong kong": { + "samples": 4, + "mu_bias": 1.329042, + "sigma_scale": 1.045379, + "confidence": 0.5 + }, + "milan": { "samples": 3, - "mu_bias": -0.492675, + "mu_bias": -3.932299, + "sigma_scale": 2.0, + "confidence": 0.375 + }, + "shanghai": { + "samples": 3, + "mu_bias": 1.827618, "sigma_scale": 2.0, "confidence": 0.375 }, "taipei": { "samples": 3, - "mu_bias": 1.462462, - "sigma_scale": 1.132834, - "confidence": 0.375 - }, - "milan": { - "samples": 3, - "mu_bias": -2.729203, + "mu_bias": 3.387896, "sigma_scale": 2.0, "confidence": 0.375 }, "warsaw": { "samples": 3, - "mu_bias": 0.349319, - "sigma_scale": 1.337949, + "mu_bias": -0.614031, + "sigma_scale": 1.252706, "confidence": 0.375 } }, "metrics": { - "sample_count": 105, - "mean_crps": 2.923823, - "legacy_mean_crps": 2.793938, - "legacy_mean_mae": 2.721143, - "legacy_bucket_hit_rate": 0.695238, - "legacy_bucket_brier": 0.775463, - "selected_mean_crps": 2.700275, - "selected_mean_mae": 2.721143, - "selected_bucket_hit_rate": 0.695238, - "selected_bucket_brier": 0.765459, - "selected_score": 4.003626, - "legacy_score": 4.104792, + "sample_count": 54, + "mean_crps": 3.78558, + "legacy_mean_crps": 4.326547, + "legacy_mean_mae": 4.528889, + "legacy_bucket_hit_rate": 0.518519, + "legacy_bucket_brier": 0.83496, + "selected_mean_crps": 4.239815, + "selected_mean_mae": 4.528889, + "selected_bucket_hit_rate": 0.537037, + "selected_bucket_brier": 0.853485, + "selected_score": 6.027262, + "legacy_score": 6.127879, "filled_actual_from_history": 2, "settlement_history_city_count": 30 }, diff --git a/artifacts/probability_calibration/evaluation_report.json b/artifacts/probability_calibration/evaluation_report.json index f3b787d1..faea812f 100644 --- a/artifacts/probability_calibration/evaluation_report.json +++ b/artifacts/probability_calibration/evaluation_report.json @@ -1,190 +1,199 @@ { "summary": { - "sample_count": 105, + "sample_count": 54, "filled_actual_from_history": 2, "legacy": { - "mean_crps": 2.793938, - "mean_mae": 2.721143, - "bucket_hit_rate": 0.695238 + "mean_crps": 4.287017, + "mean_mae": 4.488148, + "bucket_hit_rate": 0.537037 }, "emos": { - "mean_crps": 2.700275, - "mean_mae": 2.721143, - "bucket_hit_rate": 0.695238 + "mean_crps": 4.201116, + "mean_mae": 4.488148, + "bucket_hit_rate": 0.537037 }, "delta": { - "crps": -0.093663, + "crps": -0.085901, "mae": 0.0, "bucket_hit_rate": 0.0 } }, "by_city": { "ankara": { - "samples": 7, - "legacy_mean_crps": 2.023242, - "emos_mean_crps": 2.023242, - "legacy_mean_mae": 1.984286, - "emos_mean_mae": 1.984286, - "legacy_bucket_hit_rate": 0.714286, - "emos_bucket_hit_rate": 0.714286 + "samples": 3, + "legacy_mean_crps": 0.327701, + "emos_mean_crps": 0.439705, + "legacy_mean_mae": 0.066667, + "emos_mean_mae": 0.066667, + "legacy_bucket_hit_rate": 1.0, + "emos_bucket_hit_rate": 1.0 }, "atlanta": { - "samples": 5, - "legacy_mean_crps": 12.792034, - "emos_mean_crps": 12.694543, - "legacy_mean_mae": 12.806, - "emos_mean_mae": 12.806, - "legacy_bucket_hit_rate": 0.6, - "emos_bucket_hit_rate": 0.6 + "samples": 2, + "legacy_mean_crps": 30.449382, + "emos_mean_crps": 30.578432, + "legacy_mean_mae": 32.015, + "emos_mean_mae": 32.015, + "legacy_bucket_hit_rate": 0.0, + "emos_bucket_hit_rate": 0.0 }, "buenos aires": { - "samples": 5, - "legacy_mean_crps": 3.846144, - "emos_mean_crps": 3.846144, - "legacy_mean_mae": 4.168, - "emos_mean_mae": 4.168, - "legacy_bucket_hit_rate": 0.6, - "emos_bucket_hit_rate": 0.6 + "samples": 2, + "legacy_mean_crps": 9.113412, + "emos_mean_crps": 8.759954, + "legacy_mean_mae": 10.27, + "emos_mean_mae": 10.27, + "legacy_bucket_hit_rate": 0.0, + "emos_bucket_hit_rate": 0.0 }, "chicago": { - "samples": 4, - "legacy_mean_crps": 1.346667, - "emos_mean_crps": 0.601765, + "samples": 1, + "legacy_mean_crps": 1.250268, + "emos_mean_crps": 0.701085, "legacy_mean_mae": 0.0, "emos_mean_mae": 0.0, "legacy_bucket_hit_rate": 1.0, "emos_bucket_hit_rate": 1.0 }, "dallas": { - "samples": 4, - "legacy_mean_crps": 1.256111, - "emos_mean_crps": 0.651425, + "samples": 1, + "legacy_mean_crps": 2.173363, + "emos_mean_crps": 0.701085, "legacy_mean_mae": 0.0, "emos_mean_mae": 0.0, "legacy_bucket_hit_rate": 1.0, "emos_bucket_hit_rate": 1.0 }, "hong kong": { - "samples": 3, - "legacy_mean_crps": 0.261027, - "emos_mean_crps": 0.261027, - "legacy_mean_mae": 0.1, - "emos_mean_mae": 0.1, + "samples": 4, + "legacy_mean_crps": 0.29509, + "emos_mean_crps": 0.387946, + "legacy_mean_mae": 0.075, + "emos_mean_mae": 0.075, "legacy_bucket_hit_rate": 1.0, - "emos_bucket_hit_rate": 0.666667 + "emos_bucket_hit_rate": 0.75 }, "london": { - "samples": 6, - "legacy_mean_crps": 2.079624, - "emos_mean_crps": 2.079624, - "legacy_mean_mae": 2.451667, - "emos_mean_mae": 2.451667, - "legacy_bucket_hit_rate": 0.166667, - "emos_bucket_hit_rate": 0.166667 + "samples": 2, + "legacy_mean_crps": 3.885033, + "emos_mean_crps": 3.866915, + "legacy_mean_mae": 4.135, + "emos_mean_mae": 4.135, + "legacy_bucket_hit_rate": 0.0, + "emos_bucket_hit_rate": 0.0 }, "lucknow": { - "samples": 4, - "legacy_mean_crps": 1.468528, - "emos_mean_crps": 1.468528, - "legacy_mean_mae": 1.6025, - "emos_mean_mae": 1.6025, - "legacy_bucket_hit_rate": 0.5, - "emos_bucket_hit_rate": 0.5 + "samples": 2, + "legacy_mean_crps": 2.487193, + "emos_mean_crps": 2.342342, + "legacy_mean_mae": 3.205, + "emos_mean_mae": 3.205, + "legacy_bucket_hit_rate": 0.0, + "emos_bucket_hit_rate": 0.0 }, "madrid": { "samples": 2, "legacy_mean_crps": 6.27726, - "emos_mean_crps": 6.27726, + "emos_mean_crps": 5.967277, "legacy_mean_mae": 7.33, "emos_mean_mae": 7.33, "legacy_bucket_hit_rate": 0.0, "emos_bucket_hit_rate": 0.0 }, "miami": { - "samples": 5, - "legacy_mean_crps": 11.665378, - "emos_mean_crps": 11.665378, - "legacy_mean_mae": 12.07, - "emos_mean_mae": 12.07, - "legacy_bucket_hit_rate": 0.6, - "emos_bucket_hit_rate": 0.6 + "samples": 2, + "legacy_mean_crps": 28.637631, + "emos_mean_crps": 28.482516, + "legacy_mean_mae": 30.175, + "emos_mean_mae": 30.175, + "legacy_bucket_hit_rate": 0.0, + "emos_bucket_hit_rate": 0.0 }, "milan": { "samples": 3, "legacy_mean_crps": 4.401392, - "emos_mean_crps": 3.928883, + "emos_mean_crps": 3.858031, "legacy_mean_mae": 4.06, "emos_mean_mae": 4.06, "legacy_bucket_hit_rate": 0.666667, "emos_bucket_hit_rate": 0.666667 }, "munich": { - "samples": 6, - "legacy_mean_crps": 2.988583, - "emos_mean_crps": 2.988583, - "legacy_mean_mae": 3.143333, - "emos_mean_mae": 3.143333, + "samples": 2, + "legacy_mean_crps": 3.145192, + "emos_mean_crps": 3.011312, + "legacy_mean_mae": 3.64, + "emos_mean_mae": 3.64, + "legacy_bucket_hit_rate": 0.0, + "emos_bucket_hit_rate": 0.0 + }, + "new york": { + "samples": 1, + "legacy_mean_crps": 3.692845, + "emos_mean_crps": 3.407357, + "legacy_mean_mae": 4.94, + "emos_mean_mae": 4.94, + "legacy_bucket_hit_rate": 0.0, + "emos_bucket_hit_rate": 0.0 + }, + "paris": { + "samples": 2, + "legacy_mean_crps": 4.013782, + "emos_mean_crps": 3.979293, + "legacy_mean_mae": 4.265, + "emos_mean_mae": 4.265, "legacy_bucket_hit_rate": 0.5, "emos_bucket_hit_rate": 0.5 }, - "new york": { - "samples": 4, - "legacy_mean_crps": 1.861101, - "emos_mean_crps": 1.409393, - "legacy_mean_mae": 1.3725, - "emos_mean_mae": 1.3725, - "legacy_bucket_hit_rate": 0.75, - "emos_bucket_hit_rate": 0.75 - }, - "paris": { - "samples": 7, - "legacy_mean_crps": 2.430082, - "emos_mean_crps": 2.430082, - "legacy_mean_mae": 2.518571, - "emos_mean_mae": 2.518571, - "legacy_bucket_hit_rate": 0.571429, - "emos_bucket_hit_rate": 0.571429 - }, "sao paulo": { - "samples": 5, - "legacy_mean_crps": 2.454756, - "emos_mean_crps": 2.454756, - "legacy_mean_mae": 2.628, - "emos_mean_mae": 2.628, - "legacy_bucket_hit_rate": 0.6, - "emos_bucket_hit_rate": 0.6 + "samples": 2, + "legacy_mean_crps": 5.540967, + "emos_mean_crps": 5.272063, + "legacy_mean_mae": 6.57, + "emos_mean_mae": 6.57, + "legacy_bucket_hit_rate": 0.0, + "emos_bucket_hit_rate": 0.0 }, "seattle": { - "samples": 4, - "legacy_mean_crps": 0.531656, - "emos_mean_crps": 0.452784, + "samples": 1, + "legacy_mean_crps": 0.315488, + "emos_mean_crps": 0.425909, "legacy_mean_mae": 0.0, "emos_mean_mae": 0.0, "legacy_bucket_hit_rate": 1.0, "emos_bucket_hit_rate": 1.0 }, "seoul": { - "samples": 6, - "legacy_mean_crps": 0.328088, - "emos_mean_crps": 0.328088, - "legacy_mean_mae": 0.2, - "emos_mean_mae": 0.2, + "samples": 2, + "legacy_mean_crps": 0.313754, + "emos_mean_crps": 0.412831, + "legacy_mean_mae": 0.15, + "emos_mean_mae": 0.15, "legacy_bucket_hit_rate": 1.0, "emos_bucket_hit_rate": 1.0 }, "shanghai": { - "samples": 2, - "legacy_mean_crps": 0.250034, - "emos_mean_crps": 0.250034, - "legacy_mean_mae": 0.15, - "emos_mean_mae": 0.15, + "samples": 3, + "legacy_mean_crps": 0.299116, + "emos_mean_crps": 0.394855, + "legacy_mean_mae": 0.1, + "emos_mean_mae": 0.1, + "legacy_bucket_hit_rate": 1.0, + "emos_bucket_hit_rate": 1.0 + }, + "shenzhen": { + "samples": 1, + "legacy_mean_crps": 0.063696, + "emos_mean_crps": 0.073016, + "legacy_mean_mae": 0.1, + "emos_mean_mae": 0.1, "legacy_bucket_hit_rate": 1.0, "emos_bucket_hit_rate": 1.0 }, "singapore": { "samples": 2, "legacy_mean_crps": 0.281993, - "emos_mean_crps": 0.281993, + "emos_mean_crps": 0.37264, "legacy_mean_mae": 0.15, "emos_mean_mae": 0.15, "legacy_bucket_hit_rate": 1.0, @@ -193,16 +202,16 @@ "taipei": { "samples": 3, "legacy_mean_crps": 0.356996, - "emos_mean_crps": 0.356996, + "emos_mean_crps": 0.472738, "legacy_mean_mae": 0.1, "emos_mean_mae": 0.1, - "legacy_bucket_hit_rate": 1.0, - "emos_bucket_hit_rate": 1.0 + "legacy_bucket_hit_rate": 0.666667, + "emos_bucket_hit_rate": 0.666667 }, "tel aviv": { "samples": 2, "legacy_mean_crps": 0.446758, - "emos_mean_crps": 0.446758, + "emos_mean_crps": 0.578006, "legacy_mean_mae": 0.3, "emos_mean_mae": 0.3, "legacy_bucket_hit_rate": 1.0, @@ -211,36 +220,36 @@ "tokyo": { "samples": 2, "legacy_mean_crps": 0.450128, - "emos_mean_crps": 0.450128, + "emos_mean_crps": 0.582151, "legacy_mean_mae": 0.25, "emos_mean_mae": 0.25, "legacy_bucket_hit_rate": 0.5, "emos_bucket_hit_rate": 1.0 }, "toronto": { - "samples": 5, - "legacy_mean_crps": 2.647861, - "emos_mean_crps": 2.566068, - "legacy_mean_mae": 2.532, - "emos_mean_mae": 2.532, - "legacy_bucket_hit_rate": 0.6, - "emos_bucket_hit_rate": 0.6 + "samples": 2, + "legacy_mean_crps": 5.497916, + "emos_mean_crps": 5.240552, + "legacy_mean_mae": 6.33, + "emos_mean_mae": 6.33, + "legacy_bucket_hit_rate": 0.0, + "emos_bucket_hit_rate": 0.0 }, "warsaw": { "samples": 3, "legacy_mean_crps": 1.618875, - "emos_mean_crps": 1.618875, + "emos_mean_crps": 1.553232, "legacy_mean_mae": 2.056667, "emos_mean_mae": 2.056667, "legacy_bucket_hit_rate": 0.333333, "emos_bucket_hit_rate": 0.333333 }, "wellington": { - "samples": 6, - "legacy_mean_crps": 0.266349, - "emos_mean_crps": 0.266349, - "legacy_mean_mae": 0.2, - "emos_mean_mae": 0.2, + "samples": 2, + "legacy_mean_crps": 0.364919, + "emos_mean_crps": 0.475875, + "legacy_mean_mae": 0.15, + "emos_mean_mae": 0.15, "legacy_bucket_hit_rate": 1.0, "emos_bucket_hit_rate": 1.0 } diff --git a/artifacts/probability_calibration/shadow_report.json b/artifacts/probability_calibration/shadow_report.json index 9a200d12..f1a1f574 100644 --- a/artifacts/probability_calibration/shadow_report.json +++ b/artifacts/probability_calibration/shadow_report.json @@ -1,439 +1,355 @@ { - "generated_at": "2026-03-20T13:03:15.168560Z", + "generated_at": "2026-04-02T15:13:02.010825Z", "summary": { - "samples": 103, - "legacy_mean_mae": 1.839223, - "shadow_mean_mae": 1.851931, - "legacy_bucket_hit_rate": 0.669903, - "shadow_bucket_hit_rate": 0.679612, - "legacy_bucket_brier": 0.462814, - "shadow_bucket_brier": 0.756649, - "delta_mae": 0.012708, - "delta_bucket_hit_rate": 0.009709, - "delta_bucket_brier": 0.293835 + "samples": 48, + "legacy_mean_mae": 3.04125, + "shadow_mean_mae": 3.04125, + "legacy_bucket_hit_rate": 0.479167, + "shadow_bucket_hit_rate": 0.520833, + "legacy_bucket_brier": 0.688077, + "shadow_bucket_brier": 0.811329, + "delta_mae": 0.0, + "delta_bucket_hit_rate": 0.041666, + "delta_bucket_brier": 0.123252 }, "by_city": { "ankara": { - "samples": 7, - "legacy_mean_mae": 1.984286, - "shadow_mean_mae": 1.977721, - "legacy_bucket_hit_rate": 0.714286, - "shadow_bucket_hit_rate": 0.714286, - "legacy_bucket_brier": 0.484311, - "shadow_bucket_brier": 0.793303, - "delta_mae": -0.006565, + "samples": 2, + "legacy_mean_mae": 0.1, + "shadow_mean_mae": 0.1, + "legacy_bucket_hit_rate": 1.0, + "shadow_bucket_hit_rate": 1.0, + "legacy_bucket_brier": 0.494847, + "shadow_bucket_brier": 0.654648, + "delta_mae": 0.0, "delta_bucket_hit_rate": 0.0, - "delta_bucket_brier": 0.308992 + "delta_bucket_brier": 0.159801 }, "atlanta": { - "samples": 4, - "legacy_mean_mae": 4.265, - "shadow_mean_mae": 4.558028, - "legacy_bucket_hit_rate": 0.75, - "shadow_bucket_hit_rate": 0.5, - "legacy_bucket_brier": 0.257274, - "shadow_bucket_brier": 0.858699, - "delta_mae": 0.293028, - "delta_bucket_hit_rate": -0.25, - "delta_bucket_brier": 0.601425 + "samples": 1, + "legacy_mean_mae": 17.06, + "shadow_mean_mae": 17.06, + "legacy_bucket_hit_rate": 0.0, + "shadow_bucket_hit_rate": 0.0, + "legacy_bucket_brier": 1.029097, + "shadow_bucket_brier": 1.064101, + "delta_mae": 0.0, + "delta_bucket_hit_rate": 0.0, + "delta_bucket_brier": 0.035004 }, "buenos aires": { - "samples": 5, - "legacy_mean_mae": 4.168, - "shadow_mean_mae": 4.086663, - "legacy_bucket_hit_rate": 0.6, - "shadow_bucket_hit_rate": 0.6, - "legacy_bucket_brier": 0.501444, - "shadow_bucket_brier": 0.820713, - "delta_mae": -0.081337, + "samples": 2, + "legacy_mean_mae": 10.27, + "shadow_mean_mae": 10.27, + "legacy_bucket_hit_rate": 0.0, + "shadow_bucket_hit_rate": 0.0, + "legacy_bucket_brier": 1.117726, + "shadow_bucket_brier": 1.116732, + "delta_mae": 0.0, "delta_bucket_hit_rate": 0.0, - "delta_bucket_brier": 0.319269 + "delta_bucket_brier": -0.000994 }, "chicago": { - "samples": 4, + "samples": 1, "legacy_mean_mae": 0.0, - "shadow_mean_mae": 0.075265, + "shadow_mean_mae": 0.0, "legacy_bucket_hit_rate": 1.0, "shadow_bucket_hit_rate": 1.0, "legacy_bucket_brier": 0.0, - "shadow_bucket_brier": 0.746156, - "delta_mae": 0.075265, + "shadow_bucket_brier": 0.791878, + "delta_mae": 0.0, "delta_bucket_hit_rate": 0.0, - "delta_bucket_brier": 0.746156 + "delta_bucket_brier": 0.791878 }, "dallas": { - "samples": 4, + "samples": 1, "legacy_mean_mae": 0.0, - "shadow_mean_mae": 0.114807, + "shadow_mean_mae": 0.0, "legacy_bucket_hit_rate": 1.0, "shadow_bucket_hit_rate": 1.0, "legacy_bucket_brier": 0.0, - "shadow_bucket_brier": 0.778678, - "delta_mae": 0.114807, + "shadow_bucket_brier": 0.792585, + "delta_mae": 0.0, "delta_bucket_hit_rate": 0.0, - "delta_bucket_brier": 0.778678 + "delta_bucket_brier": 0.792585 }, "hong kong": { "samples": 3, "legacy_mean_mae": 0.1, - "shadow_mean_mae": 0.174879, + "shadow_mean_mae": 0.1, "legacy_bucket_hit_rate": 0.333333, "shadow_bucket_hit_rate": 0.666667, "legacy_bucket_brier": 0.882203, - "shadow_bucket_brier": 0.463809, - "delta_mae": 0.074879, + "shadow_bucket_brier": 0.437187, + "delta_mae": 0.0, "delta_bucket_hit_rate": 0.333334, - "delta_bucket_brier": -0.418394 + "delta_bucket_brier": -0.445016 }, "london": { - "samples": 6, - "legacy_mean_mae": 2.451667, - "shadow_mean_mae": 2.327304, - "legacy_bucket_hit_rate": 0.166667, - "shadow_bucket_hit_rate": 0.333333, - "legacy_bucket_brier": 0.988538, - "shadow_bucket_brier": 0.879058, - "delta_mae": -0.124363, - "delta_bucket_hit_rate": 0.166666, - "delta_bucket_brier": -0.10948 + "samples": 2, + "legacy_mean_mae": 4.135, + "shadow_mean_mae": 4.135, + "legacy_bucket_hit_rate": 0.0, + "shadow_bucket_hit_rate": 0.0, + "legacy_bucket_brier": 0.929652, + "shadow_bucket_brier": 1.039551, + "delta_mae": 0.0, + "delta_bucket_hit_rate": 0.0, + "delta_bucket_brier": 0.109899 }, "lucknow": { - "samples": 4, - "legacy_mean_mae": 1.6025, - "shadow_mean_mae": 1.682697, - "legacy_bucket_hit_rate": 0.5, - "shadow_bucket_hit_rate": 0.5, - "legacy_bucket_brier": 0.836804, - "shadow_bucket_brier": 0.832969, - "delta_mae": 0.080197, + "samples": 2, + "legacy_mean_mae": 3.205, + "shadow_mean_mae": 3.205, + "legacy_bucket_hit_rate": 0.0, + "shadow_bucket_hit_rate": 0.0, + "legacy_bucket_brier": 1.673607, + "shadow_bucket_brier": 0.96272, + "delta_mae": 0.0, "delta_bucket_hit_rate": 0.0, - "delta_bucket_brier": -0.003835 + "delta_bucket_brier": -0.710887 }, "madrid": { "samples": 2, "legacy_mean_mae": 7.33, - "shadow_mean_mae": 7.141649, + "shadow_mean_mae": 7.33, "legacy_bucket_hit_rate": 0.0, "shadow_bucket_hit_rate": 0.0, "legacy_bucket_brier": 1.148213, - "shadow_bucket_brier": 1.131778, - "delta_mae": -0.188351, + "shadow_bucket_brier": 1.133888, + "delta_mae": 0.0, "delta_bucket_hit_rate": 0.0, - "delta_bucket_brier": -0.016435 + "delta_bucket_brier": -0.014325 }, "miami": { - "samples": 4, - "legacy_mean_mae": 2.76, - "shadow_mean_mae": 3.001559, - "legacy_bucket_hit_rate": 0.75, - "shadow_bucket_hit_rate": 0.25, - "legacy_bucket_brier": 0.295651, - "shadow_bucket_brier": 0.773896, - "delta_mae": 0.241559, - "delta_bucket_hit_rate": -0.5, - "delta_bucket_brier": 0.478245 + "samples": 1, + "legacy_mean_mae": 11.04, + "shadow_mean_mae": 11.04, + "legacy_bucket_hit_rate": 0.0, + "shadow_bucket_hit_rate": 0.0, + "legacy_bucket_brier": 1.182605, + "shadow_bucket_brier": 1.067257, + "delta_mae": 0.0, + "delta_bucket_hit_rate": 0.0, + "delta_bucket_brier": -0.115348 }, "milan": { "samples": 3, "legacy_mean_mae": 4.06, - "shadow_mean_mae": 3.942288, + "shadow_mean_mae": 4.06, "legacy_bucket_hit_rate": 0.666667, "shadow_bucket_hit_rate": 0.666667, "legacy_bucket_brier": 0.587548, - "shadow_bucket_brier": 0.761128, - "delta_mae": -0.117712, + "shadow_bucket_brier": 0.78616, + "delta_mae": 0.0, "delta_bucket_hit_rate": 0.0, - "delta_bucket_brier": 0.17358 + "delta_bucket_brier": 0.198612 }, "munich": { - "samples": 6, - "legacy_mean_mae": 3.143333, - "shadow_mean_mae": 3.126482, - "legacy_bucket_hit_rate": 0.5, - "shadow_bucket_hit_rate": 0.5, - "legacy_bucket_brier": 0.531206, - "shadow_bucket_brier": 0.756931, - "delta_mae": -0.016851, + "samples": 2, + "legacy_mean_mae": 3.64, + "shadow_mean_mae": 3.64, + "legacy_bucket_hit_rate": 0.0, + "shadow_bucket_hit_rate": 0.0, + "legacy_bucket_brier": 0.918378, + "shadow_bucket_brier": 0.945234, + "delta_mae": 0.0, "delta_bucket_hit_rate": 0.0, - "delta_bucket_brier": 0.225725 + "delta_bucket_brier": 0.026856 }, "new york": { - "samples": 4, - "legacy_mean_mae": 1.3725, - "shadow_mean_mae": 1.369301, - "legacy_bucket_hit_rate": 0.75, - "shadow_bucket_hit_rate": 0.75, - "legacy_bucket_brier": 0.410198, - "shadow_bucket_brier": 0.856962, - "delta_mae": -0.003199, + "samples": 1, + "legacy_mean_mae": 4.94, + "shadow_mean_mae": 4.94, + "legacy_bucket_hit_rate": 0.0, + "shadow_bucket_hit_rate": 0.0, + "legacy_bucket_brier": 1.111711, + "shadow_bucket_brier": 1.099556, + "delta_mae": 0.0, "delta_bucket_hit_rate": 0.0, - "delta_bucket_brier": 0.446764 + "delta_bucket_brier": -0.012155 }, "paris": { - "samples": 7, - "legacy_mean_mae": 2.518571, - "shadow_mean_mae": 2.48437, - "legacy_bucket_hit_rate": 0.571429, - "shadow_bucket_hit_rate": 0.571429, - "legacy_bucket_brier": 0.630706, - "shadow_bucket_brier": 0.859044, - "delta_mae": -0.034201, + "samples": 2, + "legacy_mean_mae": 4.265, + "shadow_mean_mae": 4.265, + "legacy_bucket_hit_rate": 0.5, + "shadow_bucket_hit_rate": 0.5, + "legacy_bucket_brier": 0.90186, + "shadow_bucket_brier": 0.9967, + "delta_mae": 0.0, "delta_bucket_hit_rate": 0.0, - "delta_bucket_brier": 0.228338 + "delta_bucket_brier": 0.09484 }, "sao paulo": { - "samples": 5, - "legacy_mean_mae": 2.628, - "shadow_mean_mae": 2.689909, - "legacy_bucket_hit_rate": 0.6, - "shadow_bucket_hit_rate": 0.6, - "legacy_bucket_brier": 0.505595, - "shadow_bucket_brier": 0.869029, - "delta_mae": 0.061909, + "samples": 2, + "legacy_mean_mae": 6.57, + "shadow_mean_mae": 6.57, + "legacy_bucket_hit_rate": 0.0, + "shadow_bucket_hit_rate": 0.0, + "legacy_bucket_brier": 1.263988, + "shadow_bucket_brier": 1.159352, + "delta_mae": 0.0, "delta_bucket_hit_rate": 0.0, - "delta_bucket_brier": 0.363434 + "delta_bucket_brier": -0.104636 }, "seattle": { - "samples": 4, + "samples": 1, "legacy_mean_mae": 0.0, - "shadow_mean_mae": 0.11262, + "shadow_mean_mae": 0.0, "legacy_bucket_hit_rate": 1.0, "shadow_bucket_hit_rate": 1.0, "legacy_bucket_brier": 0.0, - "shadow_bucket_brier": 0.692003, - "delta_mae": 0.11262, + "shadow_bucket_brier": 0.61609, + "delta_mae": 0.0, "delta_bucket_hit_rate": 0.0, - "delta_bucket_brier": 0.692003 + "delta_bucket_brier": 0.61609 }, "seoul": { - "samples": 6, - "legacy_mean_mae": 0.2, - "shadow_mean_mae": 0.246659, + "samples": 2, + "legacy_mean_mae": 0.15, + "shadow_mean_mae": 0.15, "legacy_bucket_hit_rate": 1.0, "shadow_bucket_hit_rate": 1.0, - "legacy_bucket_brier": 0.22618, - "shadow_bucket_brier": 0.58261, - "delta_mae": 0.046659, + "legacy_bucket_brier": 0.258977, + "shadow_bucket_brier": 0.548485, + "delta_mae": 0.0, "delta_bucket_hit_rate": 0.0, - "delta_bucket_brier": 0.35643 + "delta_bucket_brier": 0.289508 }, "shanghai": { "samples": 2, "legacy_mean_mae": 0.15, - "shadow_mean_mae": 0.204362, + "shadow_mean_mae": 0.15, "legacy_bucket_hit_rate": 1.0, "shadow_bucket_hit_rate": 1.0, "legacy_bucket_brier": 0.1156, - "shadow_bucket_brier": 0.500523, - "delta_mae": 0.054362, + "shadow_bucket_brier": 0.501323, + "delta_mae": 0.0, "delta_bucket_hit_rate": 0.0, - "delta_bucket_brier": 0.384923 + "delta_bucket_brier": 0.385723 }, "singapore": { "samples": 2, "legacy_mean_mae": 0.15, - "shadow_mean_mae": 0.070547, + "shadow_mean_mae": 0.15, "legacy_bucket_hit_rate": 1.0, "shadow_bucket_hit_rate": 1.0, "legacy_bucket_brier": 0.306527, - "shadow_bucket_brier": 0.546477, - "delta_mae": -0.079453, + "shadow_bucket_brier": 0.553647, + "delta_mae": 0.0, "delta_bucket_hit_rate": 0.0, - "delta_bucket_brier": 0.23995 + "delta_bucket_brier": 0.24712 }, "taipei": { "samples": 3, "legacy_mean_mae": 0.1, - "shadow_mean_mae": 0.084784, - "legacy_bucket_hit_rate": 0.333333, + "shadow_mean_mae": 0.1, + "legacy_bucket_hit_rate": 0.666667, "shadow_bucket_hit_rate": 0.666667, - "legacy_bucket_brier": 0.884594, - "shadow_bucket_brier": 0.633789, - "delta_mae": -0.015216, - "delta_bucket_hit_rate": 0.333334, - "delta_bucket_brier": -0.250805 + "legacy_bucket_brier": 0.217927, + "shadow_bucket_brier": 0.640998, + "delta_mae": 0.0, + "delta_bucket_hit_rate": 0.0, + "delta_bucket_brier": 0.423071 }, "tel aviv": { "samples": 2, "legacy_mean_mae": 0.3, - "shadow_mean_mae": 0.196589, + "shadow_mean_mae": 0.3, "legacy_bucket_hit_rate": 1.0, "shadow_bucket_hit_rate": 1.0, "legacy_bucket_brier": 0.257895, - "shadow_bucket_brier": 0.693539, - "delta_mae": -0.103411, + "shadow_bucket_brier": 0.697774, + "delta_mae": 0.0, "delta_bucket_hit_rate": 0.0, - "delta_bucket_brier": 0.435644 + "delta_bucket_brier": 0.439879 }, "tokyo": { "samples": 2, "legacy_mean_mae": 0.25, - "shadow_mean_mae": 0.100782, + "shadow_mean_mae": 0.25, "legacy_bucket_hit_rate": 0.5, "shadow_bucket_hit_rate": 1.0, "legacy_bucket_brier": 0.284759, - "shadow_bucket_brier": 0.691981, - "delta_mae": -0.149218, + "shadow_bucket_brier": 0.69701, + "delta_mae": 0.0, "delta_bucket_hit_rate": 0.5, - "delta_bucket_brier": 0.407222 + "delta_bucket_brier": 0.412251 }, "toronto": { - "samples": 5, - "legacy_mean_mae": 2.532, - "shadow_mean_mae": 2.535078, - "legacy_bucket_hit_rate": 0.6, - "shadow_bucket_hit_rate": 0.6, - "legacy_bucket_brier": 0.502694, - "shadow_bucket_brier": 0.947846, - "delta_mae": 0.003078, + "samples": 2, + "legacy_mean_mae": 6.33, + "shadow_mean_mae": 6.33, + "legacy_bucket_hit_rate": 0.0, + "shadow_bucket_hit_rate": 0.0, + "legacy_bucket_brier": 1.256736, + "shadow_bucket_brier": 1.221422, + "delta_mae": 0.0, "delta_bucket_hit_rate": 0.0, - "delta_bucket_brier": 0.445152 + "delta_bucket_brier": -0.035314 }, "warsaw": { "samples": 3, "legacy_mean_mae": 2.056667, - "shadow_mean_mae": 1.942917, + "shadow_mean_mae": 2.056667, "legacy_bucket_hit_rate": 0.333333, "shadow_bucket_hit_rate": 0.333333, "legacy_bucket_brier": 0.86425, - "shadow_bucket_brier": 0.734939, - "delta_mae": -0.11375, + "shadow_bucket_brier": 0.750985, + "delta_mae": 0.0, "delta_bucket_hit_rate": 0.0, - "delta_bucket_brier": -0.129311 + "delta_bucket_brier": -0.113265 }, "wellington": { - "samples": 6, - "legacy_mean_mae": 0.2, - "shadow_mean_mae": 0.205623, + "samples": 2, + "legacy_mean_mae": 0.15, + "shadow_mean_mae": 0.15, "legacy_bucket_hit_rate": 1.0, "shadow_bucket_hit_rate": 1.0, - "legacy_bucket_brier": 0.126496, - "shadow_bucket_brier": 0.466977, - "delta_mae": 0.005623, + "legacy_bucket_brier": 0.095481, + "shadow_bucket_brier": 0.604684, + "delta_mae": 0.0, "delta_bucket_hit_rate": 0.0, - "delta_bucket_brier": 0.340481 + "delta_bucket_brier": 0.509203 } }, "by_date": { - "2026-03-07": { - "samples": 13, - "legacy_mean_mae": 0.096154, - "shadow_mean_mae": 0.204611, - "legacy_bucket_hit_rate": 0.923077, - "shadow_bucket_hit_rate": 0.846154, - "legacy_bucket_brier": 0.131914, - "shadow_bucket_brier": 0.656071, - "delta_mae": 0.108457, - "delta_bucket_hit_rate": -0.076923, - "delta_bucket_brier": 0.524157 - }, - "2026-03-08": { - "samples": 16, - "legacy_mean_mae": 0.189375, - "shadow_mean_mae": 0.318263, - "legacy_bucket_hit_rate": 0.9375, - "shadow_bucket_hit_rate": 0.9375, - "legacy_bucket_brier": 0.093386, - "shadow_bucket_brier": 0.686836, - "delta_mae": 0.128888, - "delta_bucket_hit_rate": 0.0, - "delta_bucket_brier": 0.59345 - }, - "2026-03-09": { - "samples": 16, - "legacy_mean_mae": 0.026875, - "shadow_mean_mae": 0.167204, - "legacy_bucket_hit_rate": 1.0, - "shadow_bucket_hit_rate": 0.875, - "legacy_bucket_brier": 0.034156, - "shadow_bucket_brier": 0.620235, - "delta_mae": 0.140329, - "delta_bucket_hit_rate": -0.125, - "delta_bucket_brier": 0.586079 - }, - "2026-03-10": { - "samples": 6, - "legacy_mean_mae": 3.346667, - "shadow_mean_mae": 3.295706, - "legacy_bucket_hit_rate": 0.333333, - "shadow_bucket_hit_rate": 0.333333, - "legacy_bucket_brier": 1.004838, - "shadow_bucket_brier": 1.025975, - "delta_mae": -0.050961, - "delta_bucket_hit_rate": 0.0, - "delta_bucket_brier": 0.021137 - }, - "2026-03-11": { - "samples": 1, - "legacy_mean_mae": 12.27, - "shadow_mean_mae": 12.106368, - "legacy_bucket_hit_rate": 0.0, - "shadow_bucket_hit_rate": 0.0, - "legacy_bucket_brier": 1.101949, - "shadow_bucket_brier": 1.143139, - "delta_mae": -0.163632, - "delta_bucket_hit_rate": 0.0, - "delta_bucket_brier": 0.04119 - }, - "2026-03-12": { - "samples": 2, - "legacy_mean_mae": 3.05, - "shadow_mean_mae": 3.027162, - "legacy_bucket_hit_rate": 0.5, - "shadow_bucket_hit_rate": 0.5, - "legacy_bucket_brier": 0.674081, - "shadow_bucket_brier": 0.94215, - "delta_mae": -0.022838, - "delta_bucket_hit_rate": 0.0, - "delta_bucket_brier": 0.268069 - }, - "2026-03-13": { - "samples": 1, - "legacy_mean_mae": 0.3, - "shadow_mean_mae": 0.329081, - "legacy_bucket_hit_rate": 1.0, - "shadow_bucket_hit_rate": 1.0, - "legacy_bucket_brier": 0.407401, - "shadow_bucket_brier": 0.704589, - "delta_mae": 0.029081, - "delta_bucket_hit_rate": 0.0, - "delta_bucket_brier": 0.297188 - }, "2026-03-17": { "samples": 4, "legacy_mean_mae": 0.15, - "shadow_mean_mae": 0.176549, - "legacy_bucket_hit_rate": 0.75, - "shadow_bucket_hit_rate": 0.75, - "legacy_bucket_brier": 0.601543, - "shadow_bucket_brier": 0.654372, - "delta_mae": 0.026549, - "delta_bucket_hit_rate": 0.0, - "delta_bucket_brier": 0.052829 + "shadow_mean_mae": 0.15, + "legacy_bucket_hit_rate": 1.0, + "shadow_bucket_hit_rate": 0.5, + "legacy_bucket_brier": 0.101543, + "shadow_bucket_brier": 0.6636, + "delta_mae": 0.0, + "delta_bucket_hit_rate": -0.5, + "delta_bucket_brier": 0.562057 }, "2026-03-18": { "samples": 25, "legacy_mean_mae": 2.5476, - "shadow_mean_mae": 2.476214, + "shadow_mean_mae": 2.5476, "legacy_bucket_hit_rate": 0.52, "shadow_bucket_hit_rate": 0.56, "legacy_bucket_brier": 0.657516, - "shadow_bucket_brier": 0.735089, - "delta_mae": -0.071386, + "shadow_bucket_brier": 0.74574, + "delta_mae": 0.0, "delta_bucket_hit_rate": 0.04, - "delta_bucket_brier": 0.077573 + "delta_bucket_brier": 0.088224 }, "2026-03-19": { "samples": 19, "legacy_mean_mae": 4.299474, - "shadow_mean_mae": 4.181363, + "shadow_mean_mae": 4.299474, "legacy_bucket_hit_rate": 0.315789, "shadow_bucket_hit_rate": 0.473684, "legacy_bucket_brier": 0.85177, - "shadow_bucket_brier": 0.926854, - "delta_mae": -0.118111, + "shadow_bucket_brier": 0.928731, + "delta_mae": 0.0, "delta_bucket_hit_rate": 0.157895, - "delta_bucket_brier": 0.075084 + "delta_bucket_brier": 0.076961 } }, "recent_observations": [ @@ -443,10 +359,10 @@ "actual_high": 18.0, "actual_bucket": 18, "legacy_mu": 18.3, - "shadow_mu": 18.273, + "shadow_mu": 18.3, "legacy_top_bucket": 18, "shadow_top_bucket": 18, - "calibration_version": "emos-20260320130109", + "calibration_version": "emos-20260320130245", "calibration_mode": "emos_shadow" }, { @@ -455,10 +371,10 @@ "actual_high": 7.0, "actual_bucket": 7, "legacy_mu": 12.03, - "shadow_mu": 11.887, + "shadow_mu": 12.03, "legacy_top_bucket": 12, "shadow_top_bucket": 12, - "calibration_version": "emos-20260320130109", + "calibration_version": "emos-20260320130245", "calibration_mode": "emos_shadow" }, { @@ -467,10 +383,10 @@ "actual_high": -2.0, "actual_bucket": -2, "legacy_mu": 5.67, - "shadow_mu": 5.487, + "shadow_mu": 5.67, "legacy_top_bucket": 6, - "shadow_top_bucket": 5, - "calibration_version": "emos-20260320130109", + "shadow_top_bucket": 6, + "calibration_version": "emos-20260320130245", "calibration_mode": "emos_shadow" }, { @@ -479,10 +395,10 @@ "actual_high": 16.0, "actual_bucket": 16, "legacy_mu": 16.5, - "shadow_mu": 16.171, + "shadow_mu": 16.5, "legacy_top_bucket": 17, "shadow_top_bucket": 16, - "calibration_version": "emos-20260320130109", + "calibration_version": "emos-20260320130245", "calibration_mode": "emos_shadow" }, { @@ -491,10 +407,10 @@ "actual_high": 21.0, "actual_bucket": 21, "legacy_mu": 21.3, - "shadow_mu": 21.158, + "shadow_mu": 21.3, "legacy_top_bucket": 21, "shadow_top_bucket": 21, - "calibration_version": "emos-20260320130109", + "calibration_version": "emos-20260320130245", "calibration_mode": "emos_shadow" }, { @@ -503,10 +419,10 @@ "actual_high": 21.4, "actual_bucket": 21, "legacy_mu": 21.7, - "shadow_mu": 21.601, + "shadow_mu": 21.7, "legacy_top_bucket": 22, "shadow_top_bucket": 21, - "calibration_version": "emos-20260320130109", + "calibration_version": "emos-20260320130245", "calibration_mode": "emos_shadow" }, { @@ -515,10 +431,10 @@ "actual_high": 32.0, "actual_bucket": 32, "legacy_mu": 32.3, - "shadow_mu": 32.116, + "shadow_mu": 32.3, "legacy_top_bucket": 32, "shadow_top_bucket": 32, - "calibration_version": "emos-20260320130109", + "calibration_version": "emos-20260320130245", "calibration_mode": "emos_shadow" }, { @@ -527,10 +443,10 @@ "actual_high": 12.0, "actual_bucket": 12, "legacy_mu": 12.3, - "shadow_mu": 12.279, + "shadow_mu": 12.3, "legacy_top_bucket": 12, "shadow_top_bucket": 12, - "calibration_version": "emos-20260320130109", + "calibration_version": "emos-20260320130245", "calibration_mode": "emos_shadow" }, { @@ -539,10 +455,10 @@ "actual_high": 10.0, "actual_bucket": 10, "legacy_mu": 10.3, - "shadow_mu": 10.498, + "shadow_mu": 10.3, "legacy_top_bucket": 10, "shadow_top_bucket": 10, - "calibration_version": "emos-20260320130109", + "calibration_version": "emos-20260320130245", "calibration_mode": "emos_shadow" }, { @@ -551,10 +467,10 @@ "actual_high": 21.0, "actual_bucket": 21, "legacy_mu": 26.5, - "shadow_mu": 26.372, + "shadow_mu": 26.5, "legacy_top_bucket": 26, "shadow_top_bucket": 26, - "calibration_version": "emos-20260320130109", + "calibration_version": "emos-20260320130245", "calibration_mode": "emos_shadow" }, { @@ -563,10 +479,10 @@ "actual_high": 8.0, "actual_bucket": 8, "legacy_mu": 16.06, - "shadow_mu": 15.91, + "shadow_mu": 16.06, "legacy_top_bucket": 16, "shadow_top_bucket": 16, - "calibration_version": "emos-20260320130109", + "calibration_version": "emos-20260320130245", "calibration_mode": "emos_shadow" }, { @@ -575,10 +491,10 @@ "actual_high": 5.0, "actual_bucket": 5, "legacy_mu": 11.62, - "shadow_mu": 11.451, + "shadow_mu": 11.62, "legacy_top_bucket": 12, - "shadow_top_bucket": 11, - "calibration_version": "emos-20260320130109", + "shadow_top_bucket": 12, + "calibration_version": "emos-20260320130245", "calibration_mode": "emos_shadow" }, { @@ -587,10 +503,10 @@ "actual_high": 5.0, "actual_bucket": 5, "legacy_mu": 16.58, - "shadow_mu": 16.346, + "shadow_mu": 16.58, "legacy_top_bucket": 17, - "shadow_top_bucket": 16, - "calibration_version": "emos-20260320130109", + "shadow_top_bucket": 17, + "calibration_version": "emos-20260320130245", "calibration_mode": "emos_shadow" }, { @@ -599,10 +515,10 @@ "actual_high": 8.0, "actual_bucket": 8, "legacy_mu": 18.23, - "shadow_mu": 18.028, + "shadow_mu": 18.23, "legacy_top_bucket": 18, "shadow_top_bucket": 18, - "calibration_version": "emos-20260320130109", + "calibration_version": "emos-20260320130245", "calibration_mode": "emos_shadow" }, { @@ -611,10 +527,10 @@ "actual_high": 30.0, "actual_bucket": 30, "legacy_mu": 35.3, - "shadow_mu": 35.222, + "shadow_mu": 35.3, "legacy_top_bucket": 35, "shadow_top_bucket": 35, - "calibration_version": "emos-20260320130109", + "calibration_version": "emos-20260320130245", "calibration_mode": "emos_shadow" }, { @@ -623,10 +539,10 @@ "actual_high": 8.0, "actual_bucket": 8, "legacy_mu": 15.71, - "shadow_mu": 15.58, + "shadow_mu": 15.71, "legacy_top_bucket": 16, "shadow_top_bucket": 16, - "calibration_version": "emos-20260320130109", + "calibration_version": "emos-20260320130245", "calibration_mode": "emos_shadow" }, { @@ -635,10 +551,10 @@ "actual_high": 27.3, "actual_bucket": 27, "legacy_mu": 27.6, - "shadow_mu": 27.65, + "shadow_mu": 27.6, "legacy_top_bucket": 28, "shadow_top_bucket": 27, - "calibration_version": "emos-20260320130109", + "calibration_version": "emos-20260320130245", "calibration_mode": "emos_shadow" }, { @@ -647,10 +563,10 @@ "actual_high": 16.0, "actual_bucket": 16, "legacy_mu": 27.39, - "shadow_mu": 27.105, + "shadow_mu": 27.39, "legacy_top_bucket": 27, "shadow_top_bucket": 27, - "calibration_version": "emos-20260320130109", + "calibration_version": "emos-20260320130245", "calibration_mode": "emos_shadow" }, { @@ -659,10 +575,10 @@ "actual_high": 11.0, "actual_bucket": 11, "legacy_mu": 11.0, - "shadow_mu": 10.989, + "shadow_mu": 11.0, "legacy_top_bucket": 11, "shadow_top_bucket": 11, - "calibration_version": "emos-20260320130109", + "calibration_version": "emos-20260320130245", "calibration_mode": "emos_shadow" }, { @@ -671,10 +587,10 @@ "actual_high": 21.0, "actual_bucket": 21, "legacy_mu": 21.0, - "shadow_mu": 21.031, + "shadow_mu": 21.0, "legacy_top_bucket": 21, "shadow_top_bucket": 21, - "calibration_version": "emos-20260320130109", + "calibration_version": "emos-20260320130245", "calibration_mode": "emos_shadow" }, { @@ -683,10 +599,10 @@ "actual_high": 13.0, "actual_bucket": 13, "legacy_mu": 13.84, - "shadow_mu": 13.682, + "shadow_mu": 13.84, "legacy_top_bucket": 14, "shadow_top_bucket": 14, - "calibration_version": "emos-20260320130109", + "calibration_version": "emos-20260320130245", "calibration_mode": "emos_shadow" }, { @@ -695,10 +611,10 @@ "actual_high": -6.0, "actual_bucket": -6, "legacy_mu": -1.01, - "shadow_mu": -1.101, + "shadow_mu": -1.01, "legacy_top_bucket": -1, "shadow_top_bucket": -1, - "calibration_version": "emos-20260320130109", + "calibration_version": "emos-20260320130245", "calibration_mode": "emos_shadow" }, { @@ -707,10 +623,10 @@ "actual_high": 17.0, "actual_bucket": 17, "legacy_mu": 17.0, - "shadow_mu": 16.969, + "shadow_mu": 17.0, "legacy_top_bucket": 17, "shadow_top_bucket": 17, - "calibration_version": "emos-20260320130109", + "calibration_version": "emos-20260320130245", "calibration_mode": "emos_shadow" }, { @@ -719,10 +635,10 @@ "actual_high": 30.0, "actual_bucket": 30, "legacy_mu": 30.3, - "shadow_mu": 30.235, + "shadow_mu": 30.3, "legacy_top_bucket": 30, "shadow_top_bucket": 30, - "calibration_version": "emos-20260320130109", + "calibration_version": "emos-20260320130245", "calibration_mode": "emos_shadow" }, { @@ -731,10 +647,10 @@ "actual_high": 29.0, "actual_bucket": 29, "legacy_mu": 29.0, - "shadow_mu": 28.978, + "shadow_mu": 29.0, "legacy_top_bucket": 29, - "shadow_top_bucket": 28, - "calibration_version": "emos-20260320130109", + "shadow_top_bucket": 29, + "calibration_version": "emos-20260320130245", "calibration_mode": "emos_shadow" }, { @@ -743,10 +659,10 @@ "actual_high": 32.0, "actual_bucket": 32, "legacy_mu": 32.0, - "shadow_mu": 31.975, + "shadow_mu": 32.0, "legacy_top_bucket": 32, "shadow_top_bucket": 32, - "calibration_version": "emos-20260320130109", + "calibration_version": "emos-20260320130245", "calibration_mode": "emos_shadow" }, { @@ -755,10 +671,10 @@ "actual_high": 13.0, "actual_bucket": 13, "legacy_mu": 13.0, - "shadow_mu": 12.87, + "shadow_mu": 13.0, "legacy_top_bucket": 13, "shadow_top_bucket": 13, - "calibration_version": "emos-20260320130109", + "calibration_version": "emos-20260320130245", "calibration_mode": "emos_shadow" }, { @@ -767,10 +683,10 @@ "actual_high": 8.0, "actual_bucket": 8, "legacy_mu": 8.0, - "shadow_mu": 7.891, + "shadow_mu": 8.0, "legacy_top_bucket": 8, "shadow_top_bucket": 8, - "calibration_version": "emos-20260320130109", + "calibration_version": "emos-20260320130245", "calibration_mode": "emos_shadow" }, { @@ -779,10 +695,10 @@ "actual_high": 55.9, "actual_bucket": 56, "legacy_mu": 55.9, - "shadow_mu": 55.705, + "shadow_mu": 55.9, "legacy_top_bucket": 56, "shadow_top_bucket": 56, - "calibration_version": "emos-20260320130109", + "calibration_version": "emos-20260320130245", "calibration_mode": "emos_shadow" }, { @@ -791,10 +707,10 @@ "actual_high": 22.0, "actual_bucket": 22, "legacy_mu": 29.64, - "shadow_mu": 29.517, + "shadow_mu": 29.64, "legacy_top_bucket": 30, "shadow_top_bucket": 30, - "calibration_version": "emos-20260320130109", + "calibration_version": "emos-20260320130245", "calibration_mode": "emos_shadow" }, { @@ -803,10 +719,10 @@ "actual_high": 14.0, "actual_bucket": 14, "legacy_mu": 14.47, - "shadow_mu": 14.319, + "shadow_mu": 14.47, "legacy_top_bucket": 14, "shadow_top_bucket": 14, - "calibration_version": "emos-20260320130109", + "calibration_version": "emos-20260320130245", "calibration_mode": "emos_shadow" }, { @@ -815,10 +731,10 @@ "actual_high": 32.0, "actual_bucket": 32, "legacy_mu": 36.94, - "shadow_mu": 36.759, + "shadow_mu": 36.94, "legacy_top_bucket": 37, "shadow_top_bucket": 37, - "calibration_version": "emos-20260320130109", + "calibration_version": "emos-20260320130245", "calibration_mode": "emos_shadow" }, { @@ -827,10 +743,10 @@ "actual_high": 10.0, "actual_bucket": 10, "legacy_mu": 10.66, - "shadow_mu": 10.516, + "shadow_mu": 10.66, "legacy_top_bucket": 11, "shadow_top_bucket": 11, - "calibration_version": "emos-20260320130109", + "calibration_version": "emos-20260320130245", "calibration_mode": "emos_shadow" }, { @@ -839,10 +755,10 @@ "actual_high": 14.0, "actual_bucket": 14, "legacy_mu": 14.3, - "shadow_mu": 14.162, + "shadow_mu": 14.3, "legacy_top_bucket": 14, "shadow_top_bucket": 14, - "calibration_version": "emos-20260320130109", + "calibration_version": "emos-20260320130245", "calibration_mode": "emos_shadow" }, { @@ -851,10 +767,10 @@ "actual_high": 59.0, "actual_bucket": 59, "legacy_mu": 70.04, - "shadow_mu": 69.507, + "shadow_mu": 70.04, "legacy_top_bucket": 70, "shadow_top_bucket": 70, - "calibration_version": "emos-20260320130109", + "calibration_version": "emos-20260320130245", "calibration_mode": "emos_shadow" }, { @@ -863,10 +779,10 @@ "actual_high": 14.0, "actual_bucket": 14, "legacy_mu": 18.43, - "shadow_mu": 18.255, + "shadow_mu": 18.43, "legacy_top_bucket": 18, "shadow_top_bucket": 18, - "calibration_version": "emos-20260320130109", + "calibration_version": "emos-20260320130245", "calibration_mode": "emos_shadow" }, { @@ -875,10 +791,10 @@ "actual_high": 34.0, "actual_bucket": 34, "legacy_mu": 35.11, - "shadow_mu": 35.025, + "shadow_mu": 35.11, "legacy_top_bucket": 35, "shadow_top_bucket": 35, - "calibration_version": "emos-20260320130109", + "calibration_version": "emos-20260320130245", "calibration_mode": "emos_shadow" }, { @@ -887,10 +803,10 @@ "actual_high": 16.0, "actual_bucket": 16, "legacy_mu": 16.56, - "shadow_mu": 16.414, + "shadow_mu": 16.56, "legacy_top_bucket": 17, - "shadow_top_bucket": 16, - "calibration_version": "emos-20260320130109", + "shadow_top_bucket": 17, + "calibration_version": "emos-20260320130245", "calibration_mode": "emos_shadow" }, { @@ -899,10 +815,10 @@ "actual_high": 27.8, "actual_bucket": 27, "legacy_mu": 27.8, - "shadow_mu": 27.878, + "shadow_mu": 27.8, "legacy_top_bucket": 28, "shadow_top_bucket": 27, - "calibration_version": "emos-20260320130109", + "calibration_version": "emos-20260320130245", "calibration_mode": "emos_shadow" }, { @@ -911,10 +827,10 @@ "actual_high": 73.9, "actual_bucket": 74, "legacy_mu": 73.9, - "shadow_mu": 73.578, + "shadow_mu": 73.9, "legacy_top_bucket": 74, "shadow_top_bucket": 74, - "calibration_version": "emos-20260320130109", + "calibration_version": "emos-20260320130245", "calibration_mode": "emos_shadow" }, { @@ -923,10 +839,10 @@ "actual_high": 46.0, "actual_bucket": 46, "legacy_mu": 46.0, - "shadow_mu": 45.992, + "shadow_mu": 46.0, "legacy_top_bucket": 46, "shadow_top_bucket": 46, - "calibration_version": "emos-20260320130109", + "calibration_version": "emos-20260320130245", "calibration_mode": "emos_shadow" }, { @@ -935,10 +851,10 @@ "actual_high": 17.0, "actual_bucket": 17, "legacy_mu": 26.15, - "shadow_mu": 25.927, + "shadow_mu": 26.15, "legacy_top_bucket": 26, "shadow_top_bucket": 26, - "calibration_version": "emos-20260320130109", + "calibration_version": "emos-20260320130245", "calibration_mode": "emos_shadow" }, { @@ -947,10 +863,10 @@ "actual_high": 37.0, "actual_bucket": 37, "legacy_mu": 54.06, - "shadow_mu": 53.706, + "shadow_mu": 54.06, "legacy_top_bucket": 54, "shadow_top_bucket": 54, - "calibration_version": "emos-20260320130109", + "calibration_version": "emos-20260320130245", "calibration_mode": "emos_shadow" }, { @@ -959,10 +875,10 @@ "actual_high": 15.0, "actual_bucket": 15, "legacy_mu": 15.2, - "shadow_mu": 15.032, + "shadow_mu": 15.2, "legacy_top_bucket": 15, "shadow_top_bucket": 15, - "calibration_version": "emos-20260320130109", + "calibration_version": "emos-20260320130245", "calibration_mode": "emos_shadow" }, { @@ -971,22 +887,22 @@ "actual_high": 11.0, "actual_bucket": 11, "legacy_mu": 11.3, - "shadow_mu": 11.259, + "shadow_mu": 11.3, "legacy_top_bucket": 11, "shadow_top_bucket": 11, - "calibration_version": "emos-20260320130109", + "calibration_version": "emos-20260320130245", "calibration_mode": "emos_shadow" }, { "city": "taipei", "date": "2026-03-17", "actual_high": 26.7, - "actual_bucket": 26, + "actual_bucket": 27, "legacy_mu": 26.7, - "shadow_mu": 26.669, + "shadow_mu": 26.7, "legacy_top_bucket": 27, "shadow_top_bucket": 26, - "calibration_version": "emos-20260320130109", + "calibration_version": "emos-20260320130245", "calibration_mode": "emos_shadow" }, { @@ -995,10 +911,10 @@ "actual_high": 17.0, "actual_bucket": 17, "legacy_mu": 17.3, - "shadow_mu": 17.319, + "shadow_mu": 17.3, "legacy_top_bucket": 17, "shadow_top_bucket": 17, - "calibration_version": "emos-20260320130109", + "calibration_version": "emos-20260320130245", "calibration_mode": "emos_shadow" }, { @@ -1007,634 +923,10 @@ "actual_high": 24.0, "actual_bucket": 24, "legacy_mu": 24.0, - "shadow_mu": 23.903, + "shadow_mu": 24.0, "legacy_top_bucket": 24, "shadow_top_bucket": 23, - "calibration_version": "emos-20260320130109", - "calibration_mode": "emos_shadow" - }, - { - "city": "seoul", - "date": "2026-03-13", - "actual_high": 11.0, - "actual_bucket": 11, - "legacy_mu": 11.3, - "shadow_mu": 11.329, - "legacy_top_bucket": 11, - "shadow_top_bucket": 11, - "calibration_version": "emos-20260320130109", - "calibration_mode": "emos_shadow" - }, - { - "city": "wellington", - "date": "2026-03-12", - "actual_high": 21.0, - "actual_bucket": 21, - "legacy_mu": 21.3, - "shadow_mu": 21.396, - "legacy_top_bucket": 21, - "shadow_top_bucket": 21, - "calibration_version": "emos-20260320130109", - "calibration_mode": "emos_shadow" - }, - { - "city": "paris", - "date": "2026-03-12", - "actual_high": 7.0, - "actual_bucket": 7, - "legacy_mu": 12.8, - "shadow_mu": 12.658, - "legacy_top_bucket": 13, - "shadow_top_bucket": 13, - "calibration_version": "emos-20260320130109", - "calibration_mode": "emos_shadow" - }, - { - "city": "ankara", - "date": "2026-03-11", - "actual_high": 1.0, - "actual_bucket": 1, - "legacy_mu": 13.27, - "shadow_mu": 13.106, - "legacy_top_bucket": 13, - "shadow_top_bucket": 13, - "calibration_version": "emos-20260320130109", - "calibration_mode": "emos_shadow" - }, - { - "city": "wellington", - "date": "2026-03-10", - "actual_high": 16.0, - "actual_bucket": 16, - "legacy_mu": 16.3, - "shadow_mu": 16.228, - "legacy_top_bucket": 16, - "shadow_top_bucket": 16, - "calibration_version": "emos-20260320130109", - "calibration_mode": "emos_shadow" - }, - { - "city": "seoul", - "date": "2026-03-10", - "actual_high": 7.0, - "actual_bucket": 7, - "legacy_mu": 7.3, - "shadow_mu": 7.362, - "legacy_top_bucket": 7, - "shadow_top_bucket": 7, - "calibration_version": "emos-20260320130109", - "calibration_mode": "emos_shadow" - }, - { - "city": "paris", - "date": "2026-03-10", - "actual_high": 12.0, - "actual_bucket": 12, - "legacy_mu": 15.3, - "shadow_mu": 15.175, - "legacy_top_bucket": 15, - "shadow_top_bucket": 15, - "calibration_version": "emos-20260320130109", - "calibration_mode": "emos_shadow" - }, - { - "city": "munich", - "date": "2026-03-10", - "actual_high": 4.0, - "actual_bucket": 4, - "legacy_mu": 15.58, - "shadow_mu": 15.4, - "legacy_top_bucket": 16, - "shadow_top_bucket": 15, - "calibration_version": "emos-20260320130109", - "calibration_mode": "emos_shadow" - }, - { - "city": "london", - "date": "2026-03-10", - "actual_high": 10.0, - "actual_bucket": 10, - "legacy_mu": 13.18, - "shadow_mu": 13.058, - "legacy_top_bucket": 13, - "shadow_top_bucket": 13, - "calibration_version": "emos-20260320130109", - "calibration_mode": "emos_shadow" - }, - { - "city": "ankara", - "date": "2026-03-10", - "actual_high": 11.0, - "actual_bucket": 11, - "legacy_mu": 9.58, - "shadow_mu": 9.45, - "legacy_top_bucket": 10, - "shadow_top_bucket": 9, - "calibration_version": "emos-20260320130109", - "calibration_mode": "emos_shadow" - }, - { - "city": "wellington", - "date": "2026-03-09", - "actual_high": 18.0, - "actual_bucket": 18, - "legacy_mu": 18.0, - "shadow_mu": 17.94, - "legacy_top_bucket": 18, - "shadow_top_bucket": 18, - "calibration_version": "emos-20260320130109", - "calibration_mode": "emos_shadow" - }, - { - "city": "toronto", - "date": "2026-03-09", - "actual_high": 19.0, - "actual_bucket": 19, - "legacy_mu": 19.0, - "shadow_mu": 18.951, - "legacy_top_bucket": 19, - "shadow_top_bucket": 19, - "calibration_version": "emos-20260320130109", - "calibration_mode": "emos_shadow" - }, - { - "city": "seoul", - "date": "2026-03-09", - "actual_high": 8.0, - "actual_bucket": 8, - "legacy_mu": 8.0, - "shadow_mu": 7.995, - "legacy_top_bucket": 8, - "shadow_top_bucket": 8, - "calibration_version": "emos-20260320130109", - "calibration_mode": "emos_shadow" - }, - { - "city": "seattle", - "date": "2026-03-09", - "actual_high": 45.0, - "actual_bucket": 45, - "legacy_mu": 45.0, - "shadow_mu": 44.84, - "legacy_top_bucket": 45, - "shadow_top_bucket": 45, - "calibration_version": "emos-20260320130109", - "calibration_mode": "emos_shadow" - }, - { - "city": "sao paulo", - "date": "2026-03-09", - "actual_high": 22.0, - "actual_bucket": 22, - "legacy_mu": 22.0, - "shadow_mu": 21.746, - "legacy_top_bucket": 22, - "shadow_top_bucket": 22, - "calibration_version": "emos-20260320130109", - "calibration_mode": "emos_shadow" - }, - { - "city": "paris", - "date": "2026-03-09", - "actual_high": 18.0, - "actual_bucket": 18, - "legacy_mu": 18.0, - "shadow_mu": 17.922, - "legacy_top_bucket": 18, - "shadow_top_bucket": 18, - "calibration_version": "emos-20260320130109", - "calibration_mode": "emos_shadow" - }, - { - "city": "new york", - "date": "2026-03-09", - "actual_high": 71.1, - "actual_bucket": 71, - "legacy_mu": 71.1, - "shadow_mu": 71.203, - "legacy_top_bucket": 71, - "shadow_top_bucket": 71, - "calibration_version": "emos-20260320130109", - "calibration_mode": "emos_shadow" - }, - { - "city": "munich", - "date": "2026-03-09", - "actual_high": 15.0, - "actual_bucket": 15, - "legacy_mu": 15.0, - "shadow_mu": 14.882, - "legacy_top_bucket": 15, - "shadow_top_bucket": 15, - "calibration_version": "emos-20260320130109", - "calibration_mode": "emos_shadow" - }, - { - "city": "miami", - "date": "2026-03-09", - "actual_high": 84.0, - "actual_bucket": 84, - "legacy_mu": 84.0, - "shadow_mu": 83.451, - "legacy_top_bucket": 84, - "shadow_top_bucket": 83, - "calibration_version": "emos-20260320130109", - "calibration_mode": "emos_shadow" - }, - { - "city": "lucknow", - "date": "2026-03-09", - "actual_high": 34.0, - "actual_bucket": 34, - "legacy_mu": 34.0, - "shadow_mu": 33.816, - "legacy_top_bucket": 34, - "shadow_top_bucket": 34, - "calibration_version": "emos-20260320130109", - "calibration_mode": "emos_shadow" - }, - { - "city": "london", - "date": "2026-03-09", - "actual_high": 15.0, - "actual_bucket": 15, - "legacy_mu": 15.13, - "shadow_mu": 14.987, - "legacy_top_bucket": 15, - "shadow_top_bucket": 15, - "calibration_version": "emos-20260320130109", - "calibration_mode": "emos_shadow" - }, - { - "city": "dallas", - "date": "2026-03-09", - "actual_high": 84.0, - "actual_bucket": 84, - "legacy_mu": 84.0, - "shadow_mu": 83.964, - "legacy_top_bucket": 84, - "shadow_top_bucket": 84, - "calibration_version": "emos-20260320130109", - "calibration_mode": "emos_shadow" - }, - { - "city": "chicago", - "date": "2026-03-09", - "actual_high": 72.0, - "actual_bucket": 72, - "legacy_mu": 72.0, - "shadow_mu": 71.829, - "legacy_top_bucket": 72, - "shadow_top_bucket": 72, - "calibration_version": "emos-20260320130109", - "calibration_mode": "emos_shadow" - }, - { - "city": "buenos aires", - "date": "2026-03-09", - "actual_high": 27.0, - "actual_bucket": 27, - "legacy_mu": 27.3, - "shadow_mu": 27.165, - "legacy_top_bucket": 27, - "shadow_top_bucket": 27, - "calibration_version": "emos-20260320130109", - "calibration_mode": "emos_shadow" - }, - { - "city": "atlanta", - "date": "2026-03-09", - "actual_high": 77.0, - "actual_bucket": 77, - "legacy_mu": 77.0, - "shadow_mu": 76.347, - "legacy_top_bucket": 77, - "shadow_top_bucket": 76, - "calibration_version": "emos-20260320130109", - "calibration_mode": "emos_shadow" - }, - { - "city": "ankara", - "date": "2026-03-09", - "actual_high": 8.0, - "actual_bucket": 8, - "legacy_mu": 8.0, - "shadow_mu": 7.924, - "legacy_top_bucket": 8, - "shadow_top_bucket": 8, - "calibration_version": "emos-20260320130109", - "calibration_mode": "emos_shadow" - }, - { - "city": "wellington", - "date": "2026-03-08", - "actual_high": 19.0, - "actual_bucket": 19, - "legacy_mu": 19.3, - "shadow_mu": 19.244, - "legacy_top_bucket": 19, - "shadow_top_bucket": 19, - "calibration_version": "emos-20260320130109", - "calibration_mode": "emos_shadow" - }, - { - "city": "toronto", - "date": "2026-03-08", - "actual_high": 13.0, - "actual_bucket": 13, - "legacy_mu": 13.0, - "shadow_mu": 12.912, - "legacy_top_bucket": 13, - "shadow_top_bucket": 13, - "calibration_version": "emos-20260320130109", - "calibration_mode": "emos_shadow" - }, - { - "city": "seoul", - "date": "2026-03-08", - "actual_high": 4.0, - "actual_bucket": 4, - "legacy_mu": 4.3, - "shadow_mu": 4.177, - "legacy_top_bucket": 4, - "shadow_top_bucket": 4, - "calibration_version": "emos-20260320130109", - "calibration_mode": "emos_shadow" - }, - { - "city": "seattle", - "date": "2026-03-08", - "actual_high": 53.1, - "actual_bucket": 53, - "legacy_mu": 53.1, - "shadow_mu": 53.122, - "legacy_top_bucket": 53, - "shadow_top_bucket": 53, - "calibration_version": "emos-20260320130109", - "calibration_mode": "emos_shadow" - }, - { - "city": "sao paulo", - "date": "2026-03-08", - "actual_high": 28.0, - "actual_bucket": 28, - "legacy_mu": 28.0, - "shadow_mu": 27.864, - "legacy_top_bucket": 28, - "shadow_top_bucket": 28, - "calibration_version": "emos-20260320130109", - "calibration_mode": "emos_shadow" - }, - { - "city": "paris", - "date": "2026-03-08", - "actual_high": 16.0, - "actual_bucket": 16, - "legacy_mu": 16.0, - "shadow_mu": 15.854, - "legacy_top_bucket": 16, - "shadow_top_bucket": 16, - "calibration_version": "emos-20260320130109", - "calibration_mode": "emos_shadow" - }, - { - "city": "new york", - "date": "2026-03-08", - "actual_high": 68.0, - "actual_bucket": 68, - "legacy_mu": 68.0, - "shadow_mu": 67.777, - "legacy_top_bucket": 68, - "shadow_top_bucket": 68, - "calibration_version": "emos-20260320130109", - "calibration_mode": "emos_shadow" - }, - { - "city": "munich", - "date": "2026-03-08", - "actual_high": 14.0, - "actual_bucket": 14, - "legacy_mu": 14.0, - "shadow_mu": 13.81, - "legacy_top_bucket": 14, - "shadow_top_bucket": 14, - "calibration_version": "emos-20260320130109", - "calibration_mode": "emos_shadow" - }, - { - "city": "miami", - "date": "2026-03-08", - "actual_high": 84.0, - "actual_bucket": 84, - "legacy_mu": 84.0, - "shadow_mu": 83.563, - "legacy_top_bucket": 84, - "shadow_top_bucket": 84, - "calibration_version": "emos-20260320130109", - "calibration_mode": "emos_shadow" - }, - { - "city": "lucknow", - "date": "2026-03-08", - "actual_high": 32.0, - "actual_bucket": 32, - "legacy_mu": 32.0, - "shadow_mu": 31.701, - "legacy_top_bucket": 32, - "shadow_top_bucket": 32, - "calibration_version": "emos-20260320130109", - "calibration_mode": "emos_shadow" - }, - { - "city": "london", - "date": "2026-03-08", - "actual_high": 9.0, - "actual_bucket": 9, - "legacy_mu": 11.43, - "shadow_mu": 11.335, - "legacy_top_bucket": 11, - "shadow_top_bucket": 11, - "calibration_version": "emos-20260320130109", - "calibration_mode": "emos_shadow" - }, - { - "city": "dallas", - "date": "2026-03-08", - "actual_high": 75.0, - "actual_bucket": 75, - "legacy_mu": 75.0, - "shadow_mu": 75.041, - "legacy_top_bucket": 75, - "shadow_top_bucket": 75, - "calibration_version": "emos-20260320130109", - "calibration_mode": "emos_shadow" - }, - { - "city": "chicago", - "date": "2026-03-08", - "actual_high": 62.1, - "actual_bucket": 62, - "legacy_mu": 62.1, - "shadow_mu": 62.035, - "legacy_top_bucket": 62, - "shadow_top_bucket": 62, - "calibration_version": "emos-20260320130109", - "calibration_mode": "emos_shadow" - }, - { - "city": "buenos aires", - "date": "2026-03-08", - "actual_high": 27.0, - "actual_bucket": 27, - "legacy_mu": 27.0, - "shadow_mu": 26.817, - "legacy_top_bucket": 27, - "shadow_top_bucket": 27, - "calibration_version": "emos-20260320130109", - "calibration_mode": "emos_shadow" - }, - { - "city": "atlanta", - "date": "2026-03-08", - "actual_high": 69.1, - "actual_bucket": 69, - "legacy_mu": 69.1, - "shadow_mu": 68.643, - "legacy_top_bucket": 69, - "shadow_top_bucket": 69, - "calibration_version": "emos-20260320130109", - "calibration_mode": "emos_shadow" - }, - { - "city": "ankara", - "date": "2026-03-08", - "actual_high": 8.0, - "actual_bucket": 8, - "legacy_mu": 8.0, - "shadow_mu": 7.952, - "legacy_top_bucket": 8, - "shadow_top_bucket": 8, - "calibration_version": "emos-20260320130109", - "calibration_mode": "emos_shadow" - }, - { - "city": "toronto", - "date": "2026-03-07", - "actual_high": 17.0, - "actual_bucket": 17, - "legacy_mu": 17.0, - "shadow_mu": 16.847, - "legacy_top_bucket": 17, - "shadow_top_bucket": 17, - "calibration_version": "emos-20260320130109", - "calibration_mode": "emos_shadow" - }, - { - "city": "seattle", - "date": "2026-03-07", - "actual_high": 54.0, - "actual_bucket": 54, - "legacy_mu": 54.0, - "shadow_mu": 53.926, - "legacy_top_bucket": 54, - "shadow_top_bucket": 54, - "calibration_version": "emos-20260320130109", - "calibration_mode": "emos_shadow" - }, - { - "city": "sao paulo", - "date": "2026-03-07", - "actual_high": 27.0, - "actual_bucket": 27, - "legacy_mu": 27.0, - "shadow_mu": 26.831, - "legacy_top_bucket": 27, - "shadow_top_bucket": 27, - "calibration_version": "emos-20260320130109", - "calibration_mode": "emos_shadow" - }, - { - "city": "paris", - "date": "2026-03-07", - "actual_high": 17.0, - "actual_bucket": 17, - "legacy_mu": 17.0, - "shadow_mu": 16.896, - "legacy_top_bucket": 17, - "shadow_top_bucket": 17, - "calibration_version": "emos-20260320130109", - "calibration_mode": "emos_shadow" - }, - { - "city": "new york", - "date": "2026-03-07", - "actual_high": 46.9, - "actual_bucket": 47, - "legacy_mu": 47.45, - "shadow_mu": 47.292, - "legacy_top_bucket": 47, - "shadow_top_bucket": 47, - "calibration_version": "emos-20260320130109", - "calibration_mode": "emos_shadow" - }, - { - "city": "munich", - "date": "2026-03-07", - "actual_high": 16.0, - "actual_bucket": 16, - "legacy_mu": 16.0, - "shadow_mu": 15.916, - "legacy_top_bucket": 16, - "shadow_top_bucket": 16, - "calibration_version": "emos-20260320130109", - "calibration_mode": "emos_shadow" - }, - { - "city": "miami", - "date": "2026-03-07", - "actual_high": 82.0, - "actual_bucket": 82, - "legacy_mu": 82.0, - "shadow_mu": 81.486, - "legacy_top_bucket": 82, - "shadow_top_bucket": 81, - "calibration_version": "emos-20260320130109", - "calibration_mode": "emos_shadow" - }, - { - "city": "london", - "date": "2026-03-07", - "actual_high": 9.0, - "actual_bucket": 9, - "legacy_mu": 9.7, - "shadow_mu": 9.565, - "legacy_top_bucket": 10, - "shadow_top_bucket": 10, - "calibration_version": "emos-20260320130109", - "calibration_mode": "emos_shadow" - }, - { - "city": "dallas", - "date": "2026-03-07", - "actual_high": 75.0, - "actual_bucket": 75, - "legacy_mu": 75.0, - "shadow_mu": 74.939, - "legacy_top_bucket": 75, - "shadow_top_bucket": 75, - "calibration_version": "emos-20260320130109", - "calibration_mode": "emos_shadow" - }, - { - "city": "chicago", - "date": "2026-03-07", - "actual_high": 64.9, - "actual_bucket": 65, - "legacy_mu": 64.9, - "shadow_mu": 64.843, - "legacy_top_bucket": 65, - "shadow_top_bucket": 65, - "calibration_version": "emos-20260320130109", + "calibration_version": "emos-20260320130245", "calibration_mode": "emos_shadow" } ] diff --git a/artifacts/probability_calibration/training_samples.json b/artifacts/probability_calibration/training_samples.json index f9991ffa..b2fe4ac9 100644 --- a/artifacts/probability_calibration/training_samples.json +++ b/artifacts/probability_calibration/training_samples.json @@ -1,73 +1,22 @@ { - "sample_count": 105, - "snapshot_sample_count": 0, - "daily_record_sample_count": 105, + "sample_count": 54, + "snapshot_sample_count": 1, + "daily_record_sample_count": 53, "filled_actual_from_history": 2, "samples": [ { - "city": "ankara", - "date": "2026-03-07", - "actual_high": 7.0, - "raw_mu": 7.0, - "raw_sigma": 1.5499999999999998, - "deb_prediction": 6.5, - "ens_median": 5.9, - "ensemble_spread": 1.5499999999999998, - "max_so_far_gap": null, - "peak_flag": 0.0, - "sample_source": "daily_record" - }, - { - "city": "ankara", - "date": "2026-03-08", - "actual_high": 8.0, - "raw_mu": 8.0, - "raw_sigma": 1.75, - "deb_prediction": 7.8, - "ens_median": 7.6, - "ensemble_spread": 1.75, - "max_so_far_gap": null, - "peak_flag": 0.0, - "sample_source": "daily_record" - }, - { - "city": "ankara", - "date": "2026-03-09", - "actual_high": 8.0, - "raw_mu": 8.0, - "raw_sigma": 1.5499999999999998, - "deb_prediction": 8.0, - "ens_median": 7.9, - "ensemble_spread": 1.5499999999999998, - "max_so_far_gap": null, - "peak_flag": 0.0, - "sample_source": "daily_record" - }, - { - "city": "ankara", - "date": "2026-03-10", - "actual_high": 11.0, - "raw_mu": 9.58, - "raw_sigma": 0.8500000000000005, - "deb_prediction": 9.9, - "ens_median": 10.0, - "ensemble_spread": 0.8500000000000005, - "max_so_far_gap": null, - "peak_flag": 0.0, - "sample_source": "daily_record" - }, - { - "city": "ankara", - "date": "2026-03-11", - "actual_high": 1.0, - "raw_mu": 13.27, - "raw_sigma": 1.75, - "deb_prediction": 13.5, - "ens_median": 13.9, - "ensemble_spread": 1.75, - "max_so_far_gap": null, - "peak_flag": 0.0, - "sample_source": "daily_record" + "city": "shenzhen", + "date": "2026-03-25", + "timestamp": "2026-03-25T08:57:11.783182+00:00", + "actual_high": 29.0, + "raw_mu": 26.7, + "raw_sigma": 0.18016764322916676, + "deb_prediction": 28.1, + "ens_median": 31.4, + "ensemble_spread": 0.5078125000000002, + "max_so_far_gap": 1.4000000000000021, + "peak_flag": 1.0, + "sample_source": "snapshot" }, { "city": "ankara", @@ -96,785 +45,18 @@ "sample_source": "daily_record" }, { - "city": "london", - "date": "2026-03-07", - "actual_high": 9.0, - "raw_mu": 9.7, - "raw_sigma": 0.9000000000000004, - "deb_prediction": 9.8, - "ens_median": 10.1, - "ensemble_spread": 0.9000000000000004, - "max_so_far_gap": null, - "peak_flag": 0.0, - "sample_source": "daily_record" - }, - { - "city": "london", - "date": "2026-03-08", - "actual_high": 9.0, - "raw_mu": 11.43, - "raw_sigma": 2.1500000000000004, - "deb_prediction": 9.4, - "ens_median": 11.4, - "ensemble_spread": 2.1500000000000004, - "max_so_far_gap": null, - "peak_flag": 0.0, - "sample_source": "daily_record" - }, - { - "city": "london", - "date": "2026-03-09", - "actual_high": 15.0, - "raw_mu": 15.13, - "raw_sigma": 0.6, - "deb_prediction": 14.9, - "ens_median": 15.4, - "ensemble_spread": 0.6, - "max_so_far_gap": null, - "peak_flag": 0.0, - "sample_source": "daily_record" - }, - { - "city": "london", - "date": "2026-03-10", + "city": "ankara", + "date": "2026-03-29", "actual_high": 10.0, - "raw_mu": 13.18, - "raw_sigma": 0.9500000000000002, - "deb_prediction": 13.1, - "ens_median": 13.3, - "ensemble_spread": 0.9500000000000002, - "max_so_far_gap": null, - "peak_flag": 0.0, - "sample_source": "daily_record" - }, - { - "city": "london", - "date": "2026-03-18", - "actual_high": 16.0, - "raw_mu": 16.56, - "raw_sigma": 1.299999999999999, - "deb_prediction": 16.5, - "ens_median": 16.8, - "ensemble_spread": 1.299999999999999, - "max_so_far_gap": null, - "peak_flag": 0.0, - "sample_source": "daily_record" - }, - { - "city": "london", - "date": "2026-03-19", - "actual_high": 8.0, - "raw_mu": 15.71, - "raw_sigma": 0.6, - "deb_prediction": 15.9, - "ens_median": 15.8, - "ensemble_spread": 0.6, - "max_so_far_gap": null, - "peak_flag": 0.0, - "sample_source": "daily_record" - }, - { - "city": "new york", - "date": "2026-03-07", - "actual_high": 46.9, - "raw_mu": 47.45, - "raw_sigma": 9.7, - "deb_prediction": 50.1, - "ens_median": 46.7, - "ensemble_spread": 9.7, - "max_so_far_gap": null, - "peak_flag": 0.0, - "sample_source": "daily_record" - }, - { - "city": "new york", - "date": "2026-03-08", - "actual_high": 68.0, - "raw_mu": 68.0, - "raw_sigma": 2.1499999999999986, - "deb_prediction": 67.6, - "ens_median": 67.2, - "ensemble_spread": 2.1499999999999986, - "max_so_far_gap": null, - "peak_flag": 0.0, - "sample_source": "daily_record" - }, - { - "city": "new york", - "date": "2026-03-09", - "actual_high": 71.1, - "raw_mu": 71.1, - "raw_sigma": 4.149999999999999, - "deb_prediction": 69.8, - "ens_median": 66.6, - "ensemble_spread": 4.149999999999999, - "max_so_far_gap": null, - "peak_flag": 0.0, - "sample_source": "daily_record" - }, - { - "city": "new york", - "date": "2026-03-18", - "actual_high": 32.0, - "raw_mu": 36.94, - "raw_sigma": 2.25, - "deb_prediction": 36.8, - "ens_median": 37.0, - "ensemble_spread": 2.25, - "max_so_far_gap": null, - "peak_flag": 0.0, - "sample_source": "daily_record" - }, - { - "city": "paris", - "date": "2026-03-07", - "actual_high": 17.0, - "raw_mu": 17.0, - "raw_sigma": 0.7000000000000011, - "deb_prediction": 16.9, - "ens_median": 16.7, - "ensemble_spread": 0.7000000000000011, - "max_so_far_gap": null, - "peak_flag": 0.0, - "sample_source": "daily_record" - }, - { - "city": "paris", - "date": "2026-03-08", - "actual_high": 16.0, - "raw_mu": 16.0, - "raw_sigma": 1.5999999999999996, - "deb_prediction": 16.0, - "ens_median": 16.2, - "ensemble_spread": 1.5999999999999996, - "max_so_far_gap": null, - "peak_flag": 0.0, - "sample_source": "daily_record" - }, - { - "city": "paris", - "date": "2026-03-09", - "actual_high": 18.0, - "raw_mu": 18.0, - "raw_sigma": 0.6999999999999993, - "deb_prediction": 17.2, - "ens_median": 17.4, - "ensemble_spread": 0.6999999999999993, - "max_so_far_gap": null, - "peak_flag": 0.0, - "sample_source": "daily_record" - }, - { - "city": "paris", - "date": "2026-03-10", - "actual_high": 12.0, - "raw_mu": 15.3, - "raw_sigma": 0.6, - "deb_prediction": 15.2, - "ens_median": 15.3, - "ensemble_spread": 0.6, - "max_so_far_gap": null, - "peak_flag": 0.0, - "sample_source": "daily_record" - }, - { - "city": "paris", - "date": "2026-03-12", - "actual_high": 7.0, - "raw_mu": 12.8, - "raw_sigma": 0.8499999999999996, - "deb_prediction": 12.7, - "ens_median": 13.1, - "ensemble_spread": 0.8499999999999996, - "max_so_far_gap": null, - "peak_flag": 0.0, - "sample_source": "daily_record" - }, - { - "city": "paris", - "date": "2026-03-18", - "actual_high": 14.0, - "raw_mu": 14.47, + "raw_mu": 10.0, "raw_sigma": 0.9000000000000004, - "deb_prediction": 14.2, - "ens_median": 14.8, + "deb_prediction": 9.7, + "ens_median": 10.0, "ensemble_spread": 0.9000000000000004, "max_so_far_gap": null, "peak_flag": 0.0, "sample_source": "daily_record" }, - { - "city": "paris", - "date": "2026-03-19", - "actual_high": 8.0, - "raw_mu": 16.06, - "raw_sigma": 0.6, - "deb_prediction": 16.2, - "ens_median": 16.3, - "ensemble_spread": 0.6, - "max_so_far_gap": null, - "peak_flag": 0.0, - "sample_source": "daily_record" - }, - { - "city": "seoul", - "date": "2026-03-08", - "actual_high": 4.0, - "raw_mu": 4.3, - "raw_sigma": 0.7999999999999998, - "deb_prediction": 4.0, - "ens_median": 4.0, - "ensemble_spread": 0.7999999999999998, - "max_so_far_gap": null, - "peak_flag": 0.0, - "sample_source": "daily_record" - }, - { - "city": "seoul", - "date": "2026-03-09", - "actual_high": 8.0, - "raw_mu": 8.0, - "raw_sigma": 1.4, - "deb_prediction": 6.2, - "ens_median": 6.3, - "ensemble_spread": 1.4, - "max_so_far_gap": null, - "peak_flag": 0.0, - "sample_source": "daily_record" - }, - { - "city": "seoul", - "date": "2026-03-10", - "actual_high": 7.0, - "raw_mu": 7.3, - "raw_sigma": 1.35, - "deb_prediction": 5.3, - "ens_median": 4.9, - "ensemble_spread": 1.35, - "max_so_far_gap": null, - "peak_flag": 0.0, - "sample_source": "daily_record" - }, - { - "city": "seoul", - "date": "2026-03-13", - "actual_high": 11.0, - "raw_mu": 11.3, - "raw_sigma": 1.7999999999999998, - "deb_prediction": 9.0, - "ens_median": 9.1, - "ensemble_spread": 1.7999999999999998, - "max_so_far_gap": null, - "peak_flag": 0.0, - "sample_source": "daily_record" - }, - { - "city": "seoul", - "date": "2026-03-18", - "actual_high": 8.0, - "raw_mu": 8.0, - "raw_sigma": 0.7999999999999998, - "deb_prediction": 7.4, - "ens_median": 7.4, - "ensemble_spread": 0.7999999999999998, - "max_so_far_gap": null, - "peak_flag": 0.0, - "sample_source": "daily_record" - }, - { - "city": "seoul", - "date": "2026-03-19", - "actual_high": 10.0, - "raw_mu": 10.3, - "raw_sigma": 1.7999999999999998, - "deb_prediction": 7.6, - "ens_median": 6.3, - "ensemble_spread": 1.7999999999999998, - "max_so_far_gap": null, - "peak_flag": 0.0, - "sample_source": "daily_record" - }, - { - "city": "toronto", - "date": "2026-03-07", - "actual_high": 17.0, - "raw_mu": 17.0, - "raw_sigma": 2.8500000000000005, - "deb_prediction": 15.4, - "ens_median": 16.9, - "ensemble_spread": 2.8500000000000005, - "max_so_far_gap": null, - "peak_flag": 0.0, - "sample_source": "daily_record" - }, - { - "city": "toronto", - "date": "2026-03-08", - "actual_high": 13.0, - "raw_mu": 13.0, - "raw_sigma": 2.0, - "deb_prediction": 12.7, - "ens_median": 12.3, - "ensemble_spread": 2.0, - "max_so_far_gap": null, - "peak_flag": 0.0, - "sample_source": "daily_record" - }, - { - "city": "toronto", - "date": "2026-03-09", - "actual_high": 19.0, - "raw_mu": 19.0, - "raw_sigma": 4.75, - "deb_prediction": 19.0, - "ens_median": 17.6, - "ensemble_spread": 4.75, - "max_so_far_gap": null, - "peak_flag": 0.0, - "sample_source": "daily_record" - }, - { - "city": "toronto", - "date": "2026-03-18", - "actual_high": -6.0, - "raw_mu": -1.01, - "raw_sigma": 0.8, - "deb_prediction": -0.6, - "ens_median": -1.1, - "ensemble_spread": 0.8, - "max_so_far_gap": null, - "peak_flag": 0.0, - "sample_source": "daily_record" - }, - { - "city": "toronto", - "date": "2026-03-19", - "actual_high": -2.0, - "raw_mu": 5.67, - "raw_sigma": 2.1500000000000004, - "deb_prediction": 6.4, - "ens_median": 6.3, - "ensemble_spread": 2.1500000000000004, - "max_so_far_gap": null, - "peak_flag": 0.0, - "sample_source": "daily_record" - }, - { - "city": "buenos aires", - "date": "2026-03-07", - "actual_high": 28.0, - "raw_mu": 28.0, - "raw_sigma": 1.3999999999999986, - "deb_prediction": 25.4, - "ens_median": 26.0, - "ensemble_spread": 1.3999999999999986, - "max_so_far_gap": null, - "peak_flag": 0.0, - "sample_source": "daily_record" - }, - { - "city": "buenos aires", - "date": "2026-03-08", - "actual_high": 27.0, - "raw_mu": 27.0, - "raw_sigma": 1.200000000000001, - "deb_prediction": 26.7, - "ens_median": 26.4, - "ensemble_spread": 1.200000000000001, - "max_so_far_gap": null, - "peak_flag": 0.0, - "sample_source": "daily_record" - }, - { - "city": "buenos aires", - "date": "2026-03-09", - "actual_high": 27.0, - "raw_mu": 27.3, - "raw_sigma": 1.5999999999999996, - "deb_prediction": 25.8, - "ens_median": 26.2, - "ensemble_spread": 1.5999999999999996, - "max_so_far_gap": null, - "peak_flag": 0.0, - "sample_source": "daily_record" - }, - { - "city": "buenos aires", - "date": "2026-03-18", - "actual_high": 17.0, - "raw_mu": 26.15, - "raw_sigma": 2.0, - "deb_prediction": 26.4, - "ens_median": 26.0, - "ensemble_spread": 2.0, - "max_so_far_gap": null, - "peak_flag": 0.0, - "sample_source": "daily_record" - }, - { - "city": "buenos aires", - "date": "2026-03-19", - "actual_high": 16.0, - "raw_mu": 27.39, - "raw_sigma": 2.0999999999999996, - "deb_prediction": 26.8, - "ens_median": 27.9, - "ensemble_spread": 2.0999999999999996, - "max_so_far_gap": null, - "peak_flag": 0.0, - "sample_source": "daily_record" - }, - { - "city": "wellington", - "date": "2026-03-08", - "actual_high": 19.0, - "raw_mu": 19.3, - "raw_sigma": 0.6, - "deb_prediction": 18.3, - "ens_median": 18.4, - "ensemble_spread": 0.6, - "max_so_far_gap": null, - "peak_flag": 0.0, - "sample_source": "daily_record" - }, - { - "city": "wellington", - "date": "2026-03-09", - "actual_high": 18.0, - "raw_mu": 18.0, - "raw_sigma": 0.6, - "deb_prediction": 17.1, - "ens_median": 17.2, - "ensemble_spread": 0.6, - "max_so_far_gap": null, - "peak_flag": 0.0, - "sample_source": "daily_record" - }, - { - "city": "wellington", - "date": "2026-03-10", - "actual_high": 16.0, - "raw_mu": 16.3, - "raw_sigma": 0.9000000000000004, - "deb_prediction": 15.4, - "ens_median": 15.7, - "ensemble_spread": 0.9000000000000004, - "max_so_far_gap": null, - "peak_flag": 0.0, - "sample_source": "daily_record" - }, - { - "city": "wellington", - "date": "2026-03-12", - "actual_high": 21.0, - "raw_mu": 21.3, - "raw_sigma": 1.049999999999999, - "deb_prediction": 18.7, - "ens_median": 18.7, - "ensemble_spread": 1.049999999999999, - "max_so_far_gap": null, - "peak_flag": 0.0, - "sample_source": "daily_record" - }, - { - "city": "wellington", - "date": "2026-03-18", - "actual_high": 21.0, - "raw_mu": 21.0, - "raw_sigma": 0.9500000000000011, - "deb_prediction": 19.2, - "ens_median": 19.1, - "ensemble_spread": 0.9500000000000011, - "max_so_far_gap": null, - "peak_flag": 0.0, - "sample_source": "daily_record" - }, - { - "city": "wellington", - "date": "2026-03-19", - "actual_high": 18.0, - "raw_mu": 18.3, - "raw_sigma": 2.0999999999999996, - "deb_prediction": 17.9, - "ens_median": 17.1, - "ensemble_spread": 2.0999999999999996, - "max_so_far_gap": null, - "peak_flag": 0.0, - "sample_source": "daily_record" - }, - { - "city": "chicago", - "date": "2026-03-07", - "actual_high": 64.9, - "raw_mu": 64.9, - "raw_sigma": 1.3000000000000007, - "deb_prediction": 62.3, - "ens_median": 62.8, - "ensemble_spread": 1.3000000000000007, - "max_so_far_gap": null, - "peak_flag": 0.0, - "sample_source": "daily_record" - }, - { - "city": "chicago", - "date": "2026-03-08", - "actual_high": 62.1, - "raw_mu": 62.1, - "raw_sigma": 5.600000000000001, - "deb_prediction": 62.4, - "ens_median": 60.1, - "ensemble_spread": 5.600000000000001, - "max_so_far_gap": null, - "peak_flag": 0.0, - "sample_source": "daily_record" - }, - { - "city": "chicago", - "date": "2026-03-09", - "actual_high": 72.0, - "raw_mu": 72.0, - "raw_sigma": 10.799999999999997, - "deb_prediction": 70.8, - "ens_median": 70.8, - "ensemble_spread": 10.799999999999997, - "max_so_far_gap": null, - "peak_flag": 0.0, - "sample_source": "daily_record" - }, - { - "city": "chicago", - "date": "2026-03-18", - "actual_high": 46.0, - "raw_mu": 46.0, - "raw_sigma": 5.350000000000001, - "deb_prediction": 42.7, - "ens_median": 44.2, - "ensemble_spread": 5.350000000000001, - "max_so_far_gap": null, - "peak_flag": 0.0, - "sample_source": "daily_record" - }, - { - "city": "sao paulo", - "date": "2026-03-07", - "actual_high": 27.0, - "raw_mu": 27.0, - "raw_sigma": 1.5, - "deb_prediction": 26.9, - "ens_median": 27.4, - "ensemble_spread": 1.5, - "max_so_far_gap": null, - "peak_flag": 0.0, - "sample_source": "daily_record" - }, - { - "city": "sao paulo", - "date": "2026-03-08", - "actual_high": 28.0, - "raw_mu": 28.0, - "raw_sigma": 2.1999999999999993, - "deb_prediction": 27.9, - "ens_median": 28.0, - "ensemble_spread": 2.1999999999999993, - "max_so_far_gap": null, - "peak_flag": 0.0, - "sample_source": "daily_record" - }, - { - "city": "sao paulo", - "date": "2026-03-09", - "actual_high": 22.0, - "raw_mu": 22.0, - "raw_sigma": 1.4000000000000004, - "deb_prediction": 23.4, - "ens_median": 23.5, - "ensemble_spread": 1.4000000000000004, - "max_so_far_gap": null, - "peak_flag": 0.0, - "sample_source": "daily_record" - }, - { - "city": "sao paulo", - "date": "2026-03-18", - "actual_high": 22.0, - "raw_mu": 29.64, - "raw_sigma": 2.450000000000001, - "deb_prediction": 30.0, - "ens_median": 29.4, - "ensemble_spread": 2.450000000000001, - "max_so_far_gap": null, - "peak_flag": 0.0, - "sample_source": "daily_record" - }, - { - "city": "sao paulo", - "date": "2026-03-19", - "actual_high": 21.0, - "raw_mu": 26.5, - "raw_sigma": 1.200000000000001, - "deb_prediction": 25.5, - "ens_median": 26.5, - "ensemble_spread": 1.200000000000001, - "max_so_far_gap": null, - "peak_flag": 0.0, - "sample_source": "daily_record" - }, - { - "city": "dallas", - "date": "2026-03-07", - "actual_high": 75.0, - "raw_mu": 75.0, - "raw_sigma": 2.1499999999999986, - "deb_prediction": 72.9, - "ens_median": 72.7, - "ensemble_spread": 2.1499999999999986, - "max_so_far_gap": null, - "peak_flag": 0.0, - "sample_source": "daily_record" - }, - { - "city": "dallas", - "date": "2026-03-08", - "actual_high": 75.0, - "raw_mu": 75.0, - "raw_sigma": 6.200000000000003, - "deb_prediction": 75.1, - "ens_median": 71.5, - "ensemble_spread": 6.200000000000003, - "max_so_far_gap": null, - "peak_flag": 0.0, - "sample_source": "daily_record" - }, - { - "city": "dallas", - "date": "2026-03-09", - "actual_high": 84.0, - "raw_mu": 84.0, - "raw_sigma": 3.8500000000000014, - "deb_prediction": 82.9, - "ens_median": 81.0, - "ensemble_spread": 3.8500000000000014, - "max_so_far_gap": null, - "peak_flag": 0.0, - "sample_source": "daily_record" - }, - { - "city": "dallas", - "date": "2026-03-18", - "actual_high": 73.9, - "raw_mu": 73.9, - "raw_sigma": 9.299999999999997, - "deb_prediction": 75.2, - "ens_median": 74.4, - "ensemble_spread": 9.299999999999997, - "max_so_far_gap": null, - "peak_flag": 0.0, - "sample_source": "daily_record" - }, - { - "city": "miami", - "date": "2026-03-07", - "actual_high": 82.0, - "raw_mu": 82.0, - "raw_sigma": 1.3999999999999986, - "deb_prediction": 81.8, - "ens_median": 81.6, - "ensemble_spread": 1.3999999999999986, - "max_so_far_gap": null, - "peak_flag": 0.0, - "sample_source": "daily_record" - }, - { - "city": "miami", - "date": "2026-03-08", - "actual_high": 84.0, - "raw_mu": 84.0, - "raw_sigma": 1.5500000000000043, - "deb_prediction": 83.0, - "ens_median": 82.7, - "ensemble_spread": 1.5500000000000043, - "max_so_far_gap": null, - "peak_flag": 0.0, - "sample_source": "daily_record" - }, - { - "city": "miami", - "date": "2026-03-09", - "actual_high": 84.0, - "raw_mu": 84.0, - "raw_sigma": 1.5499999999999972, - "deb_prediction": 84.0, - "ens_median": 83.9, - "ensemble_spread": 1.5499999999999972, - "max_so_far_gap": null, - "peak_flag": 0.0, - "sample_source": "daily_record" - }, - { - "city": "miami", - "date": "2026-03-18", - "actual_high": 59.0, - "raw_mu": 70.04, - "raw_sigma": 2.8999999999999986, - "deb_prediction": 69.1, - "ens_median": 70.4, - "ensemble_spread": 2.8999999999999986, - "max_so_far_gap": null, - "peak_flag": 0.0, - "sample_source": "daily_record" - }, - { - "city": "miami", - "date": "2026-03-19", - "actual_high": 24.6, - "raw_mu": 73.91, - "raw_sigma": 2.5500000000000043, - "deb_prediction": 74.2, - "ens_median": 74.0, - "ensemble_spread": 2.5500000000000043, - "max_so_far_gap": null, - "peak_flag": 0.0, - "sample_source": "daily_record" - }, - { - "city": "atlanta", - "date": "2026-03-07", - "actual_high": 82.0, - "raw_mu": 82.0, - "raw_sigma": 4.600000000000001, - "deb_prediction": 78.3, - "ens_median": 79.7, - "ensemble_spread": 4.600000000000001, - "max_so_far_gap": null, - "peak_flag": 0.0, - "sample_source": "daily_record" - }, - { - "city": "atlanta", - "date": "2026-03-08", - "actual_high": 69.1, - "raw_mu": 69.1, - "raw_sigma": 5.899999999999999, - "deb_prediction": 68.3, - "ens_median": 67.7, - "ensemble_spread": 5.899999999999999, - "max_so_far_gap": null, - "peak_flag": 0.0, - "sample_source": "daily_record" - }, - { - "city": "atlanta", - "date": "2026-03-09", - "actual_high": 77.0, - "raw_mu": 77.0, - "raw_sigma": 2.6000000000000014, - "deb_prediction": 76.7, - "ens_median": 77.4, - "ensemble_spread": 2.6000000000000014, - "max_so_far_gap": null, - "peak_flag": 0.0, - "sample_source": "daily_record" - }, { "city": "atlanta", "date": "2026-03-18", @@ -902,183 +84,53 @@ "sample_source": "daily_record" }, { - "city": "seattle", - "date": "2026-03-07", - "actual_high": 54.0, - "raw_mu": 54.0, - "raw_sigma": 1.3999999999999986, - "deb_prediction": 52.5, - "ens_median": 52.8, - "ensemble_spread": 1.3999999999999986, - "max_so_far_gap": null, - "peak_flag": 0.0, - "sample_source": "daily_record" - }, - { - "city": "seattle", - "date": "2026-03-08", - "actual_high": 53.1, - "raw_mu": 53.1, - "raw_sigma": 4.350000000000001, - "deb_prediction": 51.1, - "ens_median": 50.9, - "ensemble_spread": 4.350000000000001, - "max_so_far_gap": null, - "peak_flag": 0.0, - "sample_source": "daily_record" - }, - { - "city": "seattle", - "date": "2026-03-09", - "actual_high": 45.0, - "raw_mu": 45.0, + "city": "buenos aires", + "date": "2026-03-18", + "actual_high": 17.0, + "raw_mu": 26.15, "raw_sigma": 2.0, - "deb_prediction": 44.4, - "ens_median": 45.1, + "deb_prediction": 26.4, + "ens_median": 26.0, "ensemble_spread": 2.0, "max_so_far_gap": null, "peak_flag": 0.0, "sample_source": "daily_record" }, { - "city": "seattle", - "date": "2026-03-18", - "actual_high": 55.9, - "raw_mu": 55.9, - "raw_sigma": 1.3500000000000014, - "deb_prediction": 55.8, - "ens_median": 55.9, - "ensemble_spread": 1.3500000000000014, - "max_so_far_gap": null, - "peak_flag": 0.0, - "sample_source": "daily_record" - }, - { - "city": "lucknow", - "date": "2026-03-08", - "actual_high": 32.0, - "raw_mu": 32.0, - "raw_sigma": 1.8500000000000014, - "deb_prediction": 33.4, - "ens_median": 33.9, - "ensemble_spread": 1.8500000000000014, - "max_so_far_gap": null, - "peak_flag": 0.0, - "sample_source": "daily_record" - }, - { - "city": "lucknow", - "date": "2026-03-09", - "actual_high": 34.0, - "raw_mu": 34.0, - "raw_sigma": 2.0, - "deb_prediction": 34.0, - "ens_median": 34.6, - "ensemble_spread": 2.0, - "max_so_far_gap": null, - "peak_flag": 0.0, - "sample_source": "daily_record" - }, - { - "city": "lucknow", - "date": "2026-03-18", - "actual_high": 34.0, - "raw_mu": 35.11, - "raw_sigma": 1.3000000000000007, - "deb_prediction": 34.3, - "ens_median": 34.6, - "ensemble_spread": 1.3000000000000007, - "max_so_far_gap": null, - "peak_flag": 0.0, - "sample_source": "daily_record" - }, - { - "city": "lucknow", + "city": "buenos aires", "date": "2026-03-19", - "actual_high": 30.0, - "raw_mu": 35.3, - "raw_sigma": 1.75, - "deb_prediction": 34.5, - "ens_median": 34.7, - "ensemble_spread": 1.75, - "max_so_far_gap": null, - "peak_flag": 0.0, - "sample_source": "daily_record" - }, - { - "city": "munich", - "date": "2026-03-07", "actual_high": 16.0, - "raw_mu": 16.0, - "raw_sigma": 1.6000000000000005, - "deb_prediction": 14.5, - "ens_median": 15.1, - "ensemble_spread": 1.6000000000000005, + "raw_mu": 27.39, + "raw_sigma": 2.0999999999999996, + "deb_prediction": 26.8, + "ens_median": 27.9, + "ensemble_spread": 2.0999999999999996, "max_so_far_gap": null, "peak_flag": 0.0, "sample_source": "daily_record" }, { - "city": "munich", - "date": "2026-03-08", - "actual_high": 14.0, - "raw_mu": 14.0, - "raw_sigma": 0.9000000000000004, - "deb_prediction": 14.0, - "ens_median": 14.3, - "ensemble_spread": 0.9000000000000004, - "max_so_far_gap": null, - "peak_flag": 0.0, - "sample_source": "daily_record" - }, - { - "city": "munich", - "date": "2026-03-09", - "actual_high": 15.0, - "raw_mu": 15.0, - "raw_sigma": 0.8999999999999995, - "deb_prediction": 14.2, - "ens_median": 14.5, - "ensemble_spread": 0.8999999999999995, - "max_so_far_gap": null, - "peak_flag": 0.0, - "sample_source": "daily_record" - }, - { - "city": "munich", - "date": "2026-03-10", - "actual_high": 4.0, - "raw_mu": 15.58, - "raw_sigma": 1.2999999999999998, - "deb_prediction": 15.6, - "ens_median": 15.7, - "ensemble_spread": 1.2999999999999998, - "max_so_far_gap": null, - "peak_flag": 0.0, - "sample_source": "daily_record" - }, - { - "city": "munich", + "city": "chicago", "date": "2026-03-18", - "actual_high": 10.0, - "raw_mu": 10.66, - "raw_sigma": 0.6, - "deb_prediction": 10.6, - "ens_median": 10.6, - "ensemble_spread": 0.6, + "actual_high": 46.0, + "raw_mu": 46.0, + "raw_sigma": 5.350000000000001, + "deb_prediction": 42.7, + "ens_median": 44.2, + "ensemble_spread": 5.350000000000001, "max_so_far_gap": null, "peak_flag": 0.0, "sample_source": "daily_record" }, { - "city": "munich", - "date": "2026-03-19", - "actual_high": 5.0, - "raw_mu": 11.62, - "raw_sigma": 1.3000000000000007, - "deb_prediction": 11.5, - "ens_median": 11.8, - "ensemble_spread": 1.3000000000000007, + "city": "dallas", + "date": "2026-03-18", + "actual_high": 73.9, + "raw_mu": 73.9, + "raw_sigma": 9.299999999999997, + "deb_prediction": 75.2, + "ens_median": 74.4, + "ensemble_spread": 9.299999999999997, "max_so_far_gap": null, "peak_flag": 0.0, "sample_source": "daily_record" @@ -1123,40 +175,118 @@ "sample_source": "daily_record" }, { - "city": "taipei", - "date": "2026-03-17", - "actual_high": 26.7, - "raw_mu": 26.7, - "raw_sigma": 2.25, - "deb_prediction": 24.9, - "ens_median": 25.4, - "ensemble_spread": 2.25, + "city": "hong kong", + "date": "2026-03-23", + "actual_high": 27.4, + "raw_mu": 27.4, + "raw_sigma": 1.6999999999999993, + "deb_prediction": 25.2, + "ens_median": 25.1, + "ensemble_spread": 1.6999999999999993, "max_so_far_gap": null, "peak_flag": 0.0, "sample_source": "daily_record" }, { - "city": "taipei", + "city": "london", "date": "2026-03-18", - "actual_high": 29.0, - "raw_mu": 29.0, - "raw_sigma": 1.0500000000000007, - "deb_prediction": 27.2, - "ens_median": 27.5, - "ensemble_spread": 1.0500000000000007, + "actual_high": 16.0, + "raw_mu": 16.56, + "raw_sigma": 1.299999999999999, + "deb_prediction": 16.5, + "ens_median": 16.8, + "ensemble_spread": 1.299999999999999, "max_so_far_gap": null, "peak_flag": 0.0, "sample_source": "daily_record" }, { - "city": "taipei", + "city": "london", "date": "2026-03-19", - "actual_high": 21.4, - "raw_mu": 21.7, - "raw_sigma": 1.1500000000000004, - "deb_prediction": 21.5, - "ens_median": 21.3, - "ensemble_spread": 1.1500000000000004, + "actual_high": 8.0, + "raw_mu": 15.71, + "raw_sigma": 0.6, + "deb_prediction": 15.9, + "ens_median": 15.8, + "ensemble_spread": 0.6, + "max_so_far_gap": null, + "peak_flag": 0.0, + "sample_source": "daily_record" + }, + { + "city": "lucknow", + "date": "2026-03-18", + "actual_high": 34.0, + "raw_mu": 35.11, + "raw_sigma": 1.3000000000000007, + "deb_prediction": 34.3, + "ens_median": 34.6, + "ensemble_spread": 1.3000000000000007, + "max_so_far_gap": null, + "peak_flag": 0.0, + "sample_source": "daily_record" + }, + { + "city": "lucknow", + "date": "2026-03-19", + "actual_high": 30.0, + "raw_mu": 35.3, + "raw_sigma": 1.75, + "deb_prediction": 34.5, + "ens_median": 34.7, + "ensemble_spread": 1.75, + "max_so_far_gap": null, + "peak_flag": 0.0, + "sample_source": "daily_record" + }, + { + "city": "madrid", + "date": "2026-03-18", + "actual_high": 14.0, + "raw_mu": 18.43, + "raw_sigma": 1.8499999999999996, + "deb_prediction": 18.3, + "ens_median": 18.7, + "ensemble_spread": 1.8499999999999996, + "max_so_far_gap": null, + "peak_flag": 0.0, + "sample_source": "daily_record" + }, + { + "city": "madrid", + "date": "2026-03-19", + "actual_high": 8.0, + "raw_mu": 18.23, + "raw_sigma": 1.8999999999999995, + "deb_prediction": 18.4, + "ens_median": 18.8, + "ensemble_spread": 1.8999999999999995, + "max_so_far_gap": null, + "peak_flag": 0.0, + "sample_source": "daily_record" + }, + { + "city": "miami", + "date": "2026-03-18", + "actual_high": 59.0, + "raw_mu": 70.04, + "raw_sigma": 2.8999999999999986, + "deb_prediction": 69.1, + "ens_median": 70.4, + "ensemble_spread": 2.8999999999999986, + "max_so_far_gap": null, + "peak_flag": 0.0, + "sample_source": "daily_record" + }, + { + "city": "miami", + "date": "2026-03-19", + "actual_high": 24.6, + "raw_mu": 73.91, + "raw_sigma": 2.5500000000000043, + "deb_prediction": 74.2, + "ens_median": 74.0, + "ensemble_spread": 2.5500000000000043, "max_so_far_gap": null, "peak_flag": 0.0, "sample_source": "daily_record" @@ -1200,6 +330,318 @@ "peak_flag": 0.0, "sample_source": "daily_record" }, + { + "city": "munich", + "date": "2026-03-18", + "actual_high": 10.0, + "raw_mu": 10.66, + "raw_sigma": 0.6, + "deb_prediction": 10.6, + "ens_median": 10.6, + "ensemble_spread": 0.6, + "max_so_far_gap": null, + "peak_flag": 0.0, + "sample_source": "daily_record" + }, + { + "city": "munich", + "date": "2026-03-19", + "actual_high": 5.0, + "raw_mu": 11.62, + "raw_sigma": 1.3000000000000007, + "deb_prediction": 11.5, + "ens_median": 11.8, + "ensemble_spread": 1.3000000000000007, + "max_so_far_gap": null, + "peak_flag": 0.0, + "sample_source": "daily_record" + }, + { + "city": "new york", + "date": "2026-03-18", + "actual_high": 32.0, + "raw_mu": 36.94, + "raw_sigma": 2.25, + "deb_prediction": 36.8, + "ens_median": 37.0, + "ensemble_spread": 2.25, + "max_so_far_gap": null, + "peak_flag": 0.0, + "sample_source": "daily_record" + }, + { + "city": "paris", + "date": "2026-03-18", + "actual_high": 14.0, + "raw_mu": 14.47, + "raw_sigma": 0.9000000000000004, + "deb_prediction": 14.2, + "ens_median": 14.8, + "ensemble_spread": 0.9000000000000004, + "max_so_far_gap": null, + "peak_flag": 0.0, + "sample_source": "daily_record" + }, + { + "city": "paris", + "date": "2026-03-19", + "actual_high": 8.0, + "raw_mu": 16.06, + "raw_sigma": 0.6, + "deb_prediction": 16.2, + "ens_median": 16.3, + "ensemble_spread": 0.6, + "max_so_far_gap": null, + "peak_flag": 0.0, + "sample_source": "daily_record" + }, + { + "city": "sao paulo", + "date": "2026-03-18", + "actual_high": 22.0, + "raw_mu": 29.64, + "raw_sigma": 2.450000000000001, + "deb_prediction": 30.0, + "ens_median": 29.4, + "ensemble_spread": 2.450000000000001, + "max_so_far_gap": null, + "peak_flag": 0.0, + "sample_source": "daily_record" + }, + { + "city": "sao paulo", + "date": "2026-03-19", + "actual_high": 21.0, + "raw_mu": 26.5, + "raw_sigma": 1.200000000000001, + "deb_prediction": 25.5, + "ens_median": 26.5, + "ensemble_spread": 1.200000000000001, + "max_so_far_gap": null, + "peak_flag": 0.0, + "sample_source": "daily_record" + }, + { + "city": "seattle", + "date": "2026-03-18", + "actual_high": 55.9, + "raw_mu": 55.9, + "raw_sigma": 1.3500000000000014, + "deb_prediction": 55.8, + "ens_median": 55.9, + "ensemble_spread": 1.3500000000000014, + "max_so_far_gap": null, + "peak_flag": 0.0, + "sample_source": "daily_record" + }, + { + "city": "seoul", + "date": "2026-03-18", + "actual_high": 8.0, + "raw_mu": 8.0, + "raw_sigma": 0.7999999999999998, + "deb_prediction": 7.4, + "ens_median": 7.4, + "ensemble_spread": 0.7999999999999998, + "max_so_far_gap": null, + "peak_flag": 0.0, + "sample_source": "daily_record" + }, + { + "city": "seoul", + "date": "2026-03-19", + "actual_high": 10.0, + "raw_mu": 10.3, + "raw_sigma": 1.7999999999999998, + "deb_prediction": 7.6, + "ens_median": 6.3, + "ensemble_spread": 1.7999999999999998, + "max_so_far_gap": null, + "peak_flag": 0.0, + "sample_source": "daily_record" + }, + { + "city": "shanghai", + "date": "2026-03-18", + "actual_high": 13.0, + "raw_mu": 13.0, + "raw_sigma": 1.1500000000000004, + "deb_prediction": 13.2, + "ens_median": 13.0, + "ensemble_spread": 1.1500000000000004, + "max_so_far_gap": null, + "peak_flag": 0.0, + "sample_source": "daily_record" + }, + { + "city": "shanghai", + "date": "2026-03-19", + "actual_high": 12.0, + "raw_mu": 12.3, + "raw_sigma": 0.7999999999999998, + "deb_prediction": 10.7, + "ens_median": 11.2, + "ensemble_spread": 0.7999999999999998, + "max_so_far_gap": null, + "peak_flag": 0.0, + "sample_source": "daily_record" + }, + { + "city": "shanghai", + "date": "2026-03-29", + "actual_high": 18.0, + "raw_mu": 18.0, + "raw_sigma": 1.6999999999999993, + "deb_prediction": 18.4, + "ens_median": 17.6, + "ensemble_spread": 1.6999999999999993, + "max_so_far_gap": null, + "peak_flag": 0.0, + "sample_source": "daily_record" + }, + { + "city": "singapore", + "date": "2026-03-18", + "actual_high": 32.0, + "raw_mu": 32.0, + "raw_sigma": 0.9500000000000011, + "deb_prediction": 30.2, + "ens_median": 30.1, + "ensemble_spread": 0.9500000000000011, + "max_so_far_gap": null, + "peak_flag": 0.0, + "sample_source": "daily_record" + }, + { + "city": "singapore", + "date": "2026-03-19", + "actual_high": 32.0, + "raw_mu": 32.3, + "raw_sigma": 1.3499999999999996, + "deb_prediction": 31.5, + "ens_median": 32.1, + "ensemble_spread": 1.3499999999999996, + "max_so_far_gap": null, + "peak_flag": 0.0, + "sample_source": "daily_record" + }, + { + "city": "taipei", + "date": "2026-03-17", + "actual_high": 26.7, + "raw_mu": 26.7, + "raw_sigma": 2.25, + "deb_prediction": 24.9, + "ens_median": 25.4, + "ensemble_spread": 2.25, + "max_so_far_gap": null, + "peak_flag": 0.0, + "sample_source": "daily_record" + }, + { + "city": "taipei", + "date": "2026-03-18", + "actual_high": 29.0, + "raw_mu": 29.0, + "raw_sigma": 1.0500000000000007, + "deb_prediction": 27.2, + "ens_median": 27.5, + "ensemble_spread": 1.0500000000000007, + "max_so_far_gap": null, + "peak_flag": 0.0, + "sample_source": "daily_record" + }, + { + "city": "taipei", + "date": "2026-03-19", + "actual_high": 21.4, + "raw_mu": 21.7, + "raw_sigma": 1.1500000000000004, + "deb_prediction": 21.5, + "ens_median": 21.3, + "ensemble_spread": 1.1500000000000004, + "max_so_far_gap": null, + "peak_flag": 0.0, + "sample_source": "daily_record" + }, + { + "city": "tel aviv", + "date": "2026-03-18", + "actual_high": 30.0, + "raw_mu": 30.3, + "raw_sigma": 2.1500000000000004, + "deb_prediction": 29.0, + "ens_median": 28.9, + "ensemble_spread": 2.1500000000000004, + "max_so_far_gap": null, + "peak_flag": 0.0, + "sample_source": "daily_record" + }, + { + "city": "tel aviv", + "date": "2026-03-19", + "actual_high": 21.0, + "raw_mu": 21.3, + "raw_sigma": 1.5, + "deb_prediction": 20.7, + "ens_median": 21.1, + "ensemble_spread": 1.5, + "max_so_far_gap": null, + "peak_flag": 0.0, + "sample_source": "daily_record" + }, + { + "city": "tokyo", + "date": "2026-03-18", + "actual_high": 17.0, + "raw_mu": 17.0, + "raw_sigma": 1.5499999999999998, + "deb_prediction": 15.4, + "ens_median": 15.8, + "ensemble_spread": 1.5499999999999998, + "max_so_far_gap": null, + "peak_flag": 0.0, + "sample_source": "daily_record" + }, + { + "city": "tokyo", + "date": "2026-03-19", + "actual_high": 16.0, + "raw_mu": 16.5, + "raw_sigma": 2.0999999999999996, + "deb_prediction": 17.8, + "ens_median": 18.5, + "ensemble_spread": 2.0999999999999996, + "max_so_far_gap": null, + "peak_flag": 0.0, + "sample_source": "daily_record" + }, + { + "city": "toronto", + "date": "2026-03-18", + "actual_high": -6.0, + "raw_mu": -1.01, + "raw_sigma": 0.8, + "deb_prediction": -0.6, + "ens_median": -1.1, + "ensemble_spread": 0.8, + "max_so_far_gap": null, + "peak_flag": 0.0, + "sample_source": "daily_record" + }, + { + "city": "toronto", + "date": "2026-03-19", + "actual_high": -2.0, + "raw_mu": 5.67, + "raw_sigma": 2.1500000000000004, + "deb_prediction": 6.4, + "ens_median": 6.3, + "ensemble_spread": 2.1500000000000004, + "max_so_far_gap": null, + "peak_flag": 0.0, + "sample_source": "daily_record" + }, { "city": "warsaw", "date": "2026-03-17", @@ -1240,134 +682,30 @@ "sample_source": "daily_record" }, { - "city": "singapore", + "city": "wellington", "date": "2026-03-18", - "actual_high": 32.0, - "raw_mu": 32.0, + "actual_high": 21.0, + "raw_mu": 21.0, "raw_sigma": 0.9500000000000011, - "deb_prediction": 30.2, - "ens_median": 30.1, + "deb_prediction": 19.2, + "ens_median": 19.1, "ensemble_spread": 0.9500000000000011, "max_so_far_gap": null, "peak_flag": 0.0, "sample_source": "daily_record" }, { - "city": "singapore", + "city": "wellington", "date": "2026-03-19", - "actual_high": 32.0, - "raw_mu": 32.3, - "raw_sigma": 1.3499999999999996, - "deb_prediction": 31.5, - "ens_median": 32.1, - "ensemble_spread": 1.3499999999999996, - "max_so_far_gap": null, - "peak_flag": 0.0, - "sample_source": "daily_record" - }, - { - "city": "shanghai", - "date": "2026-03-18", - "actual_high": 13.0, - "raw_mu": 13.0, - "raw_sigma": 1.1500000000000004, - "deb_prediction": 13.2, - "ens_median": 13.0, - "ensemble_spread": 1.1500000000000004, - "max_so_far_gap": null, - "peak_flag": 0.0, - "sample_source": "daily_record" - }, - { - "city": "shanghai", - "date": "2026-03-19", - "actual_high": 12.0, - "raw_mu": 12.3, - "raw_sigma": 0.7999999999999998, - "deb_prediction": 10.7, - "ens_median": 11.2, - "ensemble_spread": 0.7999999999999998, - "max_so_far_gap": null, - "peak_flag": 0.0, - "sample_source": "daily_record" - }, - { - "city": "tokyo", - "date": "2026-03-18", - "actual_high": 17.0, - "raw_mu": 17.0, - "raw_sigma": 1.5499999999999998, - "deb_prediction": 15.4, - "ens_median": 15.8, - "ensemble_spread": 1.5499999999999998, - "max_so_far_gap": null, - "peak_flag": 0.0, - "sample_source": "daily_record" - }, - { - "city": "tokyo", - "date": "2026-03-19", - "actual_high": 16.0, - "raw_mu": 16.5, + "actual_high": 18.0, + "raw_mu": 18.3, "raw_sigma": 2.0999999999999996, - "deb_prediction": 17.8, - "ens_median": 18.5, + "deb_prediction": 17.9, + "ens_median": 17.1, "ensemble_spread": 2.0999999999999996, "max_so_far_gap": null, "peak_flag": 0.0, "sample_source": "daily_record" - }, - { - "city": "tel aviv", - "date": "2026-03-18", - "actual_high": 30.0, - "raw_mu": 30.3, - "raw_sigma": 2.1500000000000004, - "deb_prediction": 29.0, - "ens_median": 28.9, - "ensemble_spread": 2.1500000000000004, - "max_so_far_gap": null, - "peak_flag": 0.0, - "sample_source": "daily_record" - }, - { - "city": "tel aviv", - "date": "2026-03-19", - "actual_high": 21.0, - "raw_mu": 21.3, - "raw_sigma": 1.5, - "deb_prediction": 20.7, - "ens_median": 21.1, - "ensemble_spread": 1.5, - "max_so_far_gap": null, - "peak_flag": 0.0, - "sample_source": "daily_record" - }, - { - "city": "madrid", - "date": "2026-03-18", - "actual_high": 14.0, - "raw_mu": 18.43, - "raw_sigma": 1.8499999999999996, - "deb_prediction": 18.3, - "ens_median": 18.7, - "ensemble_spread": 1.8499999999999996, - "max_so_far_gap": null, - "peak_flag": 0.0, - "sample_source": "daily_record" - }, - { - "city": "madrid", - "date": "2026-03-19", - "actual_high": 8.0, - "raw_mu": 18.23, - "raw_sigma": 1.8999999999999995, - "deb_prediction": 18.4, - "ens_median": 18.8, - "ensemble_spread": 1.8999999999999995, - "max_so_far_gap": null, - "peak_flag": 0.0, - "sample_source": "daily_record" } ] } \ No newline at end of file diff --git a/docs/TECH_DEBT.md b/docs/TECH_DEBT.md index 5a6759e4..e1fd71c1 100644 --- a/docs/TECH_DEBT.md +++ b/docs/TECH_DEBT.md @@ -29,8 +29,7 @@ flowchart TD end subgraph S["状态与概率"] - S1["SQLite 第二阶段收口(离线脚本统一数据源)"] - S2["EMOS shadow -> primary 门禁稳定化"] + S1["EMOS shadow -> primary 门禁稳定化"] end A --> P @@ -48,7 +47,7 @@ flowchart TD - 钱包绑定支持浏览器钱包 + WalletConnect。 - 账户中心与 Pro 权限展示链路打通。 - 钱包异动支持独立频道路由。 -- 运行态状态/缓存已完成 SQLite 主读切换。 +- 运行态状态/缓存与核心离线训练、评估、回填链路已完成 SQLite 主路径收口。 - 轻量可观测性已上线(`/healthz`、`/api/system/status`、`/metrics`)。 - EMOS/CRPS 校准链路已上线 shadow 模式。 @@ -56,7 +55,6 @@ flowchart TD | 项目 | 影响 | 建议动作 | | :-- | :-- | :-- | -| SQLite 第二阶段收口 | 线上主链路已切到 `sqlite`,但离线脚本仍有文件默认输入 | 训练、回填、报表脚本统一改成 SQLite 优先,文件参数仅保留显式回退 | | EMOS 上线门禁 | 当前 `hold`,不能切 primary | 继续积累样本,重点压 `bucket_brier` | | 外部监控与告警 | 只有轻量指标,无外部抓取 | 接 Prometheus/Grafana 或最小巡检 | | 退款与售后链路 | 商业闭环不完整 | 增加退款状态机与工单系统 | @@ -78,7 +76,6 @@ flowchart TD ## 6. 下阶段里程碑 -1. 完成 SQLite 第二阶段收口,统一离线脚本与训练输入到 SQLite 优先。 -2. 稳定 EMOS shadow,达到 rollout `observe/promote` 条件。 -3. 补外部监控抓取与告警阈值。 -4. 评估并推进支付合约 V2 升级。 +1. 稳定 EMOS shadow,达到 rollout `observe/promote` 条件。 +2. 补外部监控抓取与告警阈值。 +3. 评估并推进支付合约 V2 升级。 diff --git a/docs/TECH_DEBT_ZH.md b/docs/TECH_DEBT_ZH.md index 5a6759e4..e1fd71c1 100644 --- a/docs/TECH_DEBT_ZH.md +++ b/docs/TECH_DEBT_ZH.md @@ -29,8 +29,7 @@ flowchart TD end subgraph S["状态与概率"] - S1["SQLite 第二阶段收口(离线脚本统一数据源)"] - S2["EMOS shadow -> primary 门禁稳定化"] + S1["EMOS shadow -> primary 门禁稳定化"] end A --> P @@ -48,7 +47,7 @@ flowchart TD - 钱包绑定支持浏览器钱包 + WalletConnect。 - 账户中心与 Pro 权限展示链路打通。 - 钱包异动支持独立频道路由。 -- 运行态状态/缓存已完成 SQLite 主读切换。 +- 运行态状态/缓存与核心离线训练、评估、回填链路已完成 SQLite 主路径收口。 - 轻量可观测性已上线(`/healthz`、`/api/system/status`、`/metrics`)。 - EMOS/CRPS 校准链路已上线 shadow 模式。 @@ -56,7 +55,6 @@ flowchart TD | 项目 | 影响 | 建议动作 | | :-- | :-- | :-- | -| SQLite 第二阶段收口 | 线上主链路已切到 `sqlite`,但离线脚本仍有文件默认输入 | 训练、回填、报表脚本统一改成 SQLite 优先,文件参数仅保留显式回退 | | EMOS 上线门禁 | 当前 `hold`,不能切 primary | 继续积累样本,重点压 `bucket_brier` | | 外部监控与告警 | 只有轻量指标,无外部抓取 | 接 Prometheus/Grafana 或最小巡检 | | 退款与售后链路 | 商业闭环不完整 | 增加退款状态机与工单系统 | @@ -78,7 +76,6 @@ flowchart TD ## 6. 下阶段里程碑 -1. 完成 SQLite 第二阶段收口,统一离线脚本与训练输入到 SQLite 优先。 -2. 稳定 EMOS shadow,达到 rollout `observe/promote` 条件。 -3. 补外部监控抓取与告警阈值。 -4. 评估并推进支付合约 V2 升级。 +1. 稳定 EMOS shadow,达到 rollout `observe/promote` 条件。 +2. 补外部监控抓取与告警阈值。 +3. 评估并推进支付合约 V2 升级。 diff --git a/docs/deep-research-report.md b/docs/deep-research-report.md index 9271788c..431d93e8 100644 --- a/docs/deep-research-report.md +++ b/docs/deep-research-report.md @@ -3,9 +3,9 @@ ## 执行摘要 PolyWeather(仓库:`yangyuan-zhen/PolyWeather`)定位为**面向温度类结算预测市场(如 Polymarket 的温度结算合约)**的“生产级气象情报系统”,核心在于把多源天气观测/预报转化为**结算导向的概率桶(μ + bucket distribution)**,并进一步映射到市场报价完成**错价扫描**;同时提供 Web 仪表盘与 Telegram Bot 两套交互入口,并包含 Polygon 链上 USDC/USDC.e 支付、自动补单与订阅/积分体系。项目 README 现明确仓库代码采用 `AGPL-3.0-only`,同时将品牌、商标、生产私有数据与运营阈值保留在代码许可证之外。 -从工程实现看,截至 `2026-03-21`,项目已经完成一轮明确的工程化收口:多源天气采集仍保持现有业务能力,同时已完成采集层与 Web API 大文件拆分、CI 质量门禁、配置分级(`.env.example` / `.env.secrets.example` / 中文部署文档)、EMOS/CRPS 校准链路、运行态状态与缓存向 SQLite 的渐进迁移,以及基础可观测性接口(`/healthz`、`/api/system/status`、`/metrics`)。 +从工程实现看,截至 `2026-04-02`,项目已经完成一轮明确的工程化收口:多源天气采集仍保持现有业务能力,同时已完成采集层与 Web API 大文件拆分、CI 质量门禁、配置分级(`.env.example` / `.env.secrets.example` / 中文部署文档)、EMOS/CRPS 校准链路、运行态状态与缓存迁移到 SQLite 主路径,以及基础可观测性接口(`/healthz`、`/api/system/status`、`/metrics`)。 这意味着报告里最初最突出的“工程地基缺失”问题,已经有一部分被关闭:`src/data_collection/weather_sources.py` 与 `web/app.py` 不再是原来的超大单文件;GitHub Actions 已覆盖 Python、前端和 Docker build;配置与密钥治理已成体系;运行态状态不再只能依赖 JSON/JSONL 文件;EMOS 也不再只是概念,而是进入了可训练、可评估、可 shadow、可门禁判断的阶段。 -但项目仍处在“从可用走向稳态”的中段,而不是终局。当前真正的高优先级问题已收敛为三类:第一,**运行态 SQLite 已经完成主读切换,但离线训练/回填脚本仍存在 legacy JSON/JSONL 默认输入**,需要继续把数据科学与运维脚本统一到单一数据源;第二,**可观测性只完成了轻量级指标层**,还没有形成完整的外部监控、阈值告警与趋势面板;第三,**EMOS 仍未达到生产切换标准**,当前门禁结论明确为 `hold`,阻塞原因是 shadow bucket brier 明显退化。支付链路方面,链下审计与容灾已明显增强:事件重放、SQLite 审计事件、RPC 多节点容灾、合约静态检查、`/ops` 支付异常单、按邮箱恢复脚本都已补齐;当前剩余风险主要集中在**链上合约本身仍是最小实现**,尚未升级到 SafeERC20、Pausable、链上套餐绑定等更强防护版本。 +但项目仍处在“从可用走向稳态”的中段,而不是终局。当前真正的高优先级问题已收敛为两类:第一,**可观测性只完成了轻量级指标层**,还没有形成完整的外部监控、阈值告警与趋势面板;第二,**EMOS 仍未达到生产切换标准**,当前门禁结论明确为 `hold`,阻塞原因是 shadow bucket brier 明显退化。SQLite 迁移方面,运行态主读切换和核心离线训练/回填链路已经完成验收:在移除 `data/*.json` / `data/*.jsonl` 后,训练、评估、shadow report 与关键 backfill 脚本仍可仅依赖运行时数据库正常执行;当前保留的 legacy 文件路径主要用于迁移、导出、校验和显式回退输入。支付链路方面,链下审计与容灾已明显增强:事件重放、SQLite 审计事件、RPC 多节点容灾、合约静态检查、`/ops` 支付异常单、按邮箱恢复脚本都已补齐;当前剩余风险主要集中在**链上合约本身仍是最小实现**,尚未升级到 SafeERC20、Pausable、链上套餐绑定等更强防护版本。 因此,当前阶段最正确的策略已经不是继续做“大范围基础重构”,而是围绕**迁移验收、可观测性补全、EMOS 上线门禁稳定化**这三条线持续收口。短中期内更高 ROI 的方向依然不是引入新的大模型,而是把现有“采集→后处理→市场映射→支付/订阅”的链路做成**状态一致、指标可见、发布可控、回退明确**的生产平台。 ## 项目概览 @@ -58,7 +58,7 @@ flowchart TB WX[WeatherDataCollector] CITY[CITY_REGISTRY] HIST[(SQLite runtime state
daily_records / cache / snapshots)] - JSON[Legacy JSON files
dual-mode fallback] +JSON[Legacy JSON files
migration/export/explicit fallback only] end subgraph ExternalAPIs @@ -122,7 +122,7 @@ flowchart TB **推理流水线(在线)**: Web/Telegram 请求 → FastAPI 调用采集器抓取/复用缓存 → 分析引擎输出结构化结果(μ、概率桶、趋势、死盘/窗口判定、DEB 预测、市场扫描)→ 前端渲染或 bot 消息格式化。 **检查点(checkpoints)**:传统 ML checkpoint 不适用;但项目现已形成两类“业务状态 checkpoint”: -(a)SQLite 运行态存储(当前线上主路径);(b)legacy JSON/JSONL 文件(主要保留给迁移回滚与部分离线脚本默认输入)。当前设计仍支持 `POLYWEATHER_STATE_STORAGE_MODE=file|dual|sqlite`,但对线上部署而言,推荐目标状态已经是 `sqlite`。 +(a)SQLite 运行态存储(当前线上与核心离线链路主路径);(b)legacy JSON/JSONL 文件(主要保留给迁移回滚、导出比对与显式回退输入)。当前设计仍支持 `POLYWEATHER_STATE_STORAGE_MODE=file|dual|sqlite`,但对线上部署与离线训练/回填而言,推荐目标状态都已经是 `sqlite`。 ### 测试、CI/CD 与运维验证 **测试**:仓库存在 `tests/test_trend_engine.py`,覆盖 μ 计算、死盘判定、预报崩盘提示、趋势方向等核心逻辑(通过 patch 隔离外部依赖)。 @@ -142,7 +142,7 @@ Web/Telegram 请求 → FastAPI 调用采集器抓取/复用缓存 → 分析引 **核心文件过大问题已明显缓解,但边界仍需继续稳定**:`WeatherDataCollector` 与 `web/app.py` 的超大文件问题已完成第一阶段拆分;当前风险已从“文件过大”转为“跨模块兼容与边界稳定性”,例如旧调用路径、兼容导出、跨层 helper 仍需持续清理。 **可复现性已从“缺模板”进入“模板与生产对齐”的阶段**:`.env.example`、`.env.secrets.example`、中文配置文档、前端部署文档、运行时配置校验器都已存在;当前风险主要在于线上历史 `.env` 与新模板并存、旧变量命名残留、以及密钥轮换与分层是否真正落实。 **CI 已建立,但组织级质量门禁未必完全收口**:CI 现已覆盖 Python、前端与 Docker build。当前问题不再是“缺 CI”,而是是否把这些 status check 绑定到 `main` 保护策略,以及是否逐步引入更严格的 pre-merge 审查。 -**运行态状态/缓存迁移已完成主切换,但离线脚本仍待收口**:`daily_records`、`telegram_alert_state`、`probability_training_snapshots`、`open_meteo` 缓存已经支持并可在生产中主读 SQLite,迁移/校验脚本也已验证可用;当前残留问题不再是线上是否能切,而是部分训练、回填、报表脚本仍默认读取 `data/*.json` / `data/*.jsonl`,容易形成“线上一套数据、离线一套输入”的维护成本。 +**运行态状态/缓存与核心离线链路的 SQLite 收口已完成**:`daily_records`、`telegram_alert_state`、`probability_training_snapshots`、`open_meteo` 缓存已经支持并在生产中主读 SQLite,迁移/校验脚本可用;进一步地,在临时移除 `data/*.json` / `data/*.jsonl` 后,训练集导出、概率拟合、评估报告、shadow report 和关键 backfill 脚本已验证仍可运行。当前 legacy 文件路径主要是显式回退入口,而不再是默认主输入。 **第三方服务合规与稳定性风险**: 项目强依赖外部 API(Open-Meteo、AviationWeather、NWS、HKO、CWA、Polymarket、Supabase)。其中 AviationWeather Data API 有明确速率限制;Polymarket 官方说明 Gamma/Data/CLOB 三套 API 分属不同域,CLOB 交易端点需鉴权且策略可能变化;Supabase 明确强调 `service_role`/secret keys 绝不可暴露。若缺乏集中治理(重试/退避/熔断/降级/配额监控/密钥轮换),稳定性与合规不可控。 **可观测性已起步,但仍不构成完整监控体系**:项目现在已有 `/healthz`、`/api/system/status`、`/metrics`,并为 HTTP 与关键第三方源增加了轻量指标;但仍缺少 Prometheus/Grafana 级别的外部抓取、告警阈值、趋势面板和运行日报。这部分现在属于“已开始,不算完成”。 @@ -172,7 +172,6 @@ Web/Telegram 请求 → FastAPI 调用采集器抓取/复用缓存 → 分析引 下表按截至 `2026-03-21` 的真实状态重排优先级。已完成项不再继续列为“待做”,只保留当前仍需推进的事项。 | 优先级 | 改进项 | 预估工作量 | 主要收益 | 主要风险 | 可执行步骤(建议顺序) | | ------ | --------------------------------------------------------------------------------------------------------------------------------- | -------------------: | ------------------------------------------------------------------- | ------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| 高 | **完成 SQLite 迁移的“第二阶段收口”**:把离线脚本、训练与回填链路统一成 SQLite 优先 | 2–5 天 | 彻底形成单一数据源,避免线上 SQLite 与离线 JSON/JSONL 双轨漂移 | 训练脚本行为变化可能影响既有报表或回填输出 | 1) 盘点所有默认读取 `data/*.json` / `data/*.jsonl` 的脚本 → 2) 改为按 `state_storage_mode` 自动优先读 SQLite → 3) 保留显式 `--history-file/--snapshot-file` 作为回退输入 → 4) 用同一批数据对比训练与报表结果 | | 高 | **把轻量可观测性接入外部监控与告警**:围绕 `/metrics` 建立抓取、阈值与巡检 | 3–7 天 | 不再只靠日志定位问题;可以监控第三方源错误率、缓存命中与 HTTP 延迟 | 指标不分层会导致噪音高、告警无用 | 1) 抓取 `/metrics` → 2) 先围绕 HTTP、Open-Meteo、MGM、METAR 建立最小仪表板 → 3) 为 429/403/error/stale_cache 设阈值 → 4) 增加巡检脚本或告警通道 | | 高 | **稳定 EMOS shadow 并收紧上线门禁** | 1–2 周 | 让概率引擎升级具备明确发布条件,避免拍脑袋切换 | 当前 shadow bucket brier 退化明显,存在误上线风险 | 1) 持续积累 snapshot 样本 → 2) 定期重训与生成 `evaluation_report` / `shadow_report` / `rollout_report` → 3) 重点压 `bucket_brier` 退化 → 4) 只有门禁从 `hold` 进入 `observe/promote` 后才考虑上线 | | 中 | **市场层升级为 async + 类型安全**:引入 `aiopolymarket` 或在现有层加重试/backoff/连接池 | 4–7 天 | 行情层更稳,减少短时网络抖动;更易扩展更多市场/分页 | 依赖升级带来的行为差异 | 1) 把 requests.Session 替换为 aiohttp/httpx → 2) 在 Gamma/CLOB 调用侧实现指数退避 → 3) 引入 typed models,减少解析失败 | diff --git a/scripts/backfill_daily_record_model_gaps.py b/scripts/backfill_daily_record_model_gaps.py index 2f3218a1..4668e5a4 100644 --- a/scripts/backfill_daily_record_model_gaps.py +++ b/scripts/backfill_daily_record_model_gaps.py @@ -16,6 +16,7 @@ from src.analysis.probability_snapshot_archive import ( # noqa: E402 load_snapshot_rows_for_day, ) from src.database.runtime_state import STATE_STORAGE_FILE, get_state_storage_mode # noqa: E402 +from scripts.fit_probability_calibration import _default_history_arg # noqa: E402 def _load_daily_records(path: Path) -> Dict[str, Dict[str, Dict[str, Any]]]: @@ -53,8 +54,8 @@ def main() -> int: ) parser.add_argument( "--history-file", - default=str(Path("data") / "daily_records.json"), - help="Path to daily_records.json", + default=_default_history_arg(), + help="Optional legacy daily_records.json path. In sqlite mode this defaults to the runtime database.", ) parser.add_argument("--city", help="Optional city filter, e.g. ankara") parser.add_argument("--date", help="Optional YYYY-MM-DD filter") @@ -70,8 +71,8 @@ def main() -> int: ) args = parser.parse_args() - history_path = Path(args.history_file) - data = _load_daily_records(history_path) + history_path = Path(args.history_file) if args.history_file else None + data = _load_daily_records(history_path or Path()) model_name = str(args.model or "").strip() city_filter = str(args.city or "").strip().lower() or None date_filter = str(args.date or "").strip() or None @@ -133,8 +134,8 @@ def main() -> int: if changed: previous_mode = get_state_storage_mode() # Reuse existing save path semantics. In sqlite-only mode, save_history would skip file write. - save_history(str(history_path), data) - if previous_mode == STATE_STORAGE_FILE and not history_path.exists(): + save_history(str(history_path or ""), data) + if previous_mode == STATE_STORAGE_FILE and (history_path is None or not history_path.exists()): raise FileNotFoundError(history_path) return 0 diff --git a/scripts/backfill_probability_shadow_history.py b/scripts/backfill_probability_shadow_history.py index e183865c..eac88583 100644 --- a/scripts/backfill_probability_shadow_history.py +++ b/scripts/backfill_probability_shadow_history.py @@ -13,6 +13,7 @@ from src.analysis.probability_calibration import ( # noqa: E402 apply_probability_calibration, build_probability_features, ) +from scripts.fit_probability_calibration import _default_history_arg # noqa: E402 def _sample_to_features(sample): @@ -44,7 +45,7 @@ def main(): parser = argparse.ArgumentParser(description="Backfill shadow probability snapshots into daily records.") parser.add_argument( "--history-file", - default=os.path.join(PROJECT_ROOT, "data", "daily_records.json"), + default=_default_history_arg(), ) parser.add_argument( "--training-samples", diff --git a/scripts/backfill_recent_daily_actuals_from_metar.py b/scripts/backfill_recent_daily_actuals_from_metar.py index 2489de8e..1c095d5f 100644 --- a/scripts/backfill_recent_daily_actuals_from_metar.py +++ b/scripts/backfill_recent_daily_actuals_from_metar.py @@ -9,6 +9,7 @@ if PROJECT_ROOT not in sys.path: from src.analysis.deb_algorithm import load_history, reconcile_recent_actual_highs, save_history # noqa: E402 from src.data_collection.city_registry import CITY_REGISTRY # noqa: E402 +from scripts.fit_probability_calibration import _default_history_arg # noqa: E402 def _target_dates(city_info: dict, lookback_days: int) -> list[str]: @@ -50,7 +51,7 @@ def main() -> None: ) args = parser.parse_args() - history_file = os.path.join(PROJECT_ROOT, "data", "daily_records.json") + history_file = _default_history_arg() or "" data = load_history(history_file) selected = {str(item).strip().lower() for item in args.cities if str(item).strip()} diff --git a/scripts/build_probability_shadow_report.py b/scripts/build_probability_shadow_report.py index 579f9506..07fd7479 100644 --- a/scripts/build_probability_shadow_report.py +++ b/scripts/build_probability_shadow_report.py @@ -11,6 +11,7 @@ if PROJECT_ROOT not in sys.path: from src.analysis.deb_algorithm import load_history # noqa: E402 from src.analysis.settlement_rounding import apply_city_settlement # noqa: E402 +from scripts.fit_probability_calibration import _default_history_arg # noqa: E402 def _sf(value): @@ -112,7 +113,7 @@ def main(): parser = argparse.ArgumentParser(description="Build live shadow probability report from daily records.") parser.add_argument( "--history-file", - default=os.path.join(PROJECT_ROOT, "data", "daily_records.json"), + default=_default_history_arg(), ) parser.add_argument( "--output", diff --git a/scripts/evaluate_probability_calibration.py b/scripts/evaluate_probability_calibration.py index 94fd5066..7807733d 100644 --- a/scripts/evaluate_probability_calibration.py +++ b/scripts/evaluate_probability_calibration.py @@ -16,6 +16,7 @@ from src.analysis.probability_calibration import ( # noqa: E402 ) from src.analysis.settlement_rounding import apply_city_settlement # noqa: E402 from scripts.fit_probability_calibration import ( # noqa: E402 + _default_history_arg, _extract_samples, _load_json_if_exists, ) @@ -61,7 +62,7 @@ def main(): parser = argparse.ArgumentParser(description="Evaluate legacy vs EMOS probability calibration.") parser.add_argument( "--history-file", - default=os.path.join(PROJECT_ROOT, "data", "daily_records.json"), + default=_default_history_arg(), ) parser.add_argument( "--settlement-history", diff --git a/scripts/export_probability_training_dataset.py b/scripts/export_probability_training_dataset.py index 69890a5a..fd78138c 100644 --- a/scripts/export_probability_training_dataset.py +++ b/scripts/export_probability_training_dataset.py @@ -8,6 +8,8 @@ if PROJECT_ROOT not in sys.path: sys.path.insert(0, PROJECT_ROOT) from scripts.fit_probability_calibration import ( # noqa: E402 + _default_history_arg, + _default_snapshot_arg, _extract_samples, _load_history_with_fallback, _load_json_if_exists, @@ -19,7 +21,7 @@ def main(): parser = argparse.ArgumentParser(description="Export normalized probability calibration training samples.") parser.add_argument( "--history-file", - default=os.path.join(PROJECT_ROOT, "data", "daily_records.json"), + default=_default_history_arg(), ) parser.add_argument( "--settlement-history", @@ -41,7 +43,7 @@ def main(): ) parser.add_argument( "--snapshot-file", - default=os.path.join(PROJECT_ROOT, "data", "probability_training_snapshots.jsonl"), + default=_default_snapshot_arg(), ) args = parser.parse_args() diff --git a/scripts/fit_probability_calibration.py b/scripts/fit_probability_calibration.py index 9f258bb5..5d42ddda 100644 --- a/scripts/fit_probability_calibration.py +++ b/scripts/fit_probability_calibration.py @@ -16,6 +16,7 @@ from src.analysis.probability_calibration import ( # noqa: E402 from src.analysis.deb_algorithm import load_history # noqa: E402 from src.database.runtime_state import ( # noqa: E402 ProbabilitySnapshotRepository, + STATE_STORAGE_FILE, STATE_STORAGE_SQLITE, get_state_storage_mode, ) @@ -38,6 +39,22 @@ def _load_json_if_exists(path): return data if isinstance(data, dict) else {} +def _legacy_history_path(): + return os.path.join(PROJECT_ROOT, "data", "daily_records.json") + + +def _legacy_snapshot_path(): + return os.path.join(PROJECT_ROOT, "data", "probability_training_snapshots.jsonl") + + +def _default_history_arg(): + return _legacy_history_path() if get_state_storage_mode() == STATE_STORAGE_FILE else None + + +def _default_snapshot_arg(): + return _legacy_snapshot_path() if get_state_storage_mode() == STATE_STORAGE_FILE else None + + def _load_history_with_fallback(path): data = load_history(path) if data: @@ -253,8 +270,8 @@ def main(): parser = argparse.ArgumentParser(description="Fit PolyWeather probability calibration parameters.") parser.add_argument( "--history-file", - default=os.path.join(PROJECT_ROOT, "data", "daily_records.json"), - help="Path to the historical daily_records.json file.", + default=_default_history_arg(), + help="Optional legacy daily_records.json path. In sqlite mode this defaults to the runtime database.", ) parser.add_argument( "--output", @@ -273,8 +290,8 @@ def main(): ) parser.add_argument( "--snapshot-file", - default=os.path.join(PROJECT_ROOT, "data", "probability_training_snapshots.jsonl"), - help="Optional JSONL file with archived probability snapshots.", + default=_default_snapshot_arg(), + help="Optional legacy JSONL snapshot archive path. In sqlite mode this defaults to the runtime database.", ) parser.add_argument( "--version", diff --git a/src/bot/analysis/deb_analysis_service.py b/src/bot/analysis/deb_analysis_service.py index 44678f5a..2f139d88 100644 --- a/src/bot/analysis/deb_analysis_service.py +++ b/src/bot/analysis/deb_analysis_service.py @@ -4,13 +4,18 @@ import os from datetime import datetime as _dt from datetime import timedelta as _td +from src.database.runtime_state import STATE_STORAGE_FILE, get_state_storage_mode + class DebAnalysisService: """DEB analytics adapter with lazy imports to trim cold startup.""" def __init__(self, project_root: str): self.project_root = project_root - self.history_file = os.path.join(project_root, "data", "daily_records.json") + if get_state_storage_mode() == STATE_STORAGE_FILE: + self.history_file = os.path.join(project_root, "data", "daily_records.json") + else: + self.history_file = "" @staticmethod def _load_aliases() -> dict[str, str]: diff --git a/src/models/lgbm_features.py b/src/models/lgbm_features.py index 806e42b3..4417394e 100644 --- a/src/models/lgbm_features.py +++ b/src/models/lgbm_features.py @@ -8,6 +8,13 @@ from typing import Any, Dict, List, Optional, Tuple from src.analysis.deb_algorithm import load_history from src.data_collection.city_registry import ALIASES +from src.database.runtime_state import ( + DailyRecordRepository, + ProbabilitySnapshotRepository, + STATE_STORAGE_FILE, + STATE_STORAGE_SQLITE, + get_state_storage_mode, +) BASE_MODEL_COLUMNS: List[Tuple[str, str]] = [ @@ -82,12 +89,16 @@ def _parse_timestamp(value: Any) -> Optional[datetime]: def _history_file_path() -> str: root = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) - return os.path.join(root, "data", "daily_records.json") + if get_state_storage_mode() == STATE_STORAGE_FILE: + return os.path.join(root, "data", "daily_records.json") + return "" def _snapshot_archive_path() -> str: root = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) - return os.path.join(root, "data", "probability_training_snapshots.jsonl") + if get_state_storage_mode() == STATE_STORAGE_FILE: + return os.path.join(root, "data", "probability_training_snapshots.jsonl") + return "" def _normalized_city_key(city_name: str) -> str: @@ -125,8 +136,26 @@ def _compute_model_summary(features: Dict[str, Optional[float]]) -> Tuple[Option def load_snapshot_index(archive_path: Optional[str] = None) -> Dict[Tuple[str, str], Dict[str, Any]]: + mode = get_state_storage_mode() + if mode == STATE_STORAGE_SQLITE: + latest_rows: Dict[Tuple[str, str], Dict[str, Any]] = {} + for row in ProbabilitySnapshotRepository().load_all_rows(): + if not isinstance(row, dict): + continue + city = _normalized_city_key(str(row.get("city") or "")) + date_str = str(row.get("date") or "").strip() + if not city or not date_str: + continue + key = (city, date_str) + current_best = latest_rows.get(key) + if current_best is None or str(row.get("timestamp") or "") >= str( + current_best.get("timestamp") or "" + ): + latest_rows[key] = row + return latest_rows + path = archive_path or _snapshot_archive_path() - if not os.path.exists(path): + if not path or not os.path.exists(path): return {} latest_rows: Dict[Tuple[str, str], Dict[str, Any]] = {} @@ -258,7 +287,12 @@ def build_training_samples( history_data: Optional[Dict[str, Any]] = None, snapshot_index: Optional[Dict[Tuple[str, str], Dict[str, Any]]] = None, ) -> List[Dict[str, Any]]: - data = history_data if isinstance(history_data, dict) else load_history(_history_file_path()) + if isinstance(history_data, dict): + data = history_data + elif get_state_storage_mode() == STATE_STORAGE_SQLITE: + data = DailyRecordRepository().load_all() + else: + data = load_history(_history_file_path()) snapshots = snapshot_index if isinstance(snapshot_index, dict) else load_snapshot_index() samples: List[Dict[str, Any]] = []