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]] = []