From b635070106116348dd33ac9c7d1d2b4ceb1431ff Mon Sep 17 00:00:00 2001 From: "2569718930@qq.com" <2569718930@qq.com> Date: Thu, 16 Apr 2026 13:26:53 +0800 Subject: [PATCH] Fix history fallback handling and auth status probe behavior --- scripts/build_probability_shadow_report.py | 8 +++++--- scripts/fit_probability_calibration.py | 4 ++-- src/models/lgbm_features.py | 5 ++++- tests/test_web_observability.py | 13 +++++++++---- 4 files changed, 20 insertions(+), 10 deletions(-) diff --git a/scripts/build_probability_shadow_report.py b/scripts/build_probability_shadow_report.py index 07fd7479..73b67533 100644 --- a/scripts/build_probability_shadow_report.py +++ b/scripts/build_probability_shadow_report.py @@ -9,9 +9,11 @@ PROJECT_ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) if PROJECT_ROOT not in sys.path: sys.path.insert(0, PROJECT_ROOT) -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 +from scripts.fit_probability_calibration import ( # noqa: E402 + _default_history_arg, + _load_history_with_fallback, +) def _sf(value): @@ -126,7 +128,7 @@ def main(): ) args = parser.parse_args() - history = load_history(args.history_file) + history = _load_history_with_fallback(args.history_file) overall = _blank_metrics() by_city = defaultdict(_blank_metrics) by_date = defaultdict(_blank_metrics) diff --git a/scripts/fit_probability_calibration.py b/scripts/fit_probability_calibration.py index 18e15d13..530fa7df 100644 --- a/scripts/fit_probability_calibration.py +++ b/scripts/fit_probability_calibration.py @@ -72,10 +72,10 @@ def _load_history_with_fallback(path): if get_state_storage_mode() == STATE_STORAGE_SQLITE: return DailyRecordRepository().load_all() return {} - data = load_history(path) + data = _load_json_if_exists(path) if data: return data - return _load_json_if_exists(path) + return load_history(path) def _load_truth_history(): diff --git a/src/models/lgbm_features.py b/src/models/lgbm_features.py index 12a33beb..3d994b43 100644 --- a/src/models/lgbm_features.py +++ b/src/models/lgbm_features.py @@ -296,7 +296,10 @@ def build_training_samples( runtime_history = DailyRecordRepository().load_all() else: runtime_history = load_history(_history_file_path()) - if mode == STATE_STORAGE_SQLITE: + if isinstance(history_data, dict): + truth_history = runtime_history + training_feature_history = {} + elif mode == STATE_STORAGE_SQLITE: truth_history = TruthRecordRepository().load_all() training_feature_history = TrainingFeatureRecordRepository().load_all() else: diff --git a/tests/test_web_observability.py b/tests/test_web_observability.py index 9c761bcb..6f835aaa 100644 --- a/tests/test_web_observability.py +++ b/tests/test_web_observability.py @@ -134,7 +134,7 @@ def test_payment_runtime_endpoint_returns_shape(): assert 'recent_audit_events' in payload -def test_auth_me_auto_reconciles_missing_subscription(monkeypatch): +def test_auth_me_does_not_reconcile_on_status_probe(monkeypatch): monkeypatch.setattr(routes, "_assert_entitlement", lambda request: None) def _bind_identity(request): @@ -147,11 +147,10 @@ def test_auth_me_auto_reconciles_missing_subscription(monkeypatch): monkeypatch.setattr(routes.SUPABASE_ENTITLEMENT, "enabled", True) calls = {"count": 0} + reconcile_calls = {"count": 0} def _latest_subscription(user_id, respect_requirement=False): calls["count"] += 1 - if calls["count"] == 1: - return None return { "plan_code": "pro_monthly", "starts_at": "2026-03-22T00:00:00+00:00", @@ -164,10 +163,15 @@ def test_auth_me_auto_reconciles_missing_subscription(monkeypatch): _latest_subscription, ) monkeypatch.setattr(routes.PAYMENT_CHECKOUT, "enabled", True) + + def _reconcile_latest_intent(user_id): + reconcile_calls["count"] += 1 + return {"ok": True, "action": "reconciled_confirmed_intent"} + monkeypatch.setattr( routes.PAYMENT_CHECKOUT, "reconcile_latest_intent", - lambda user_id: {"ok": True, "action": "reconciled_confirmed_intent"}, + _reconcile_latest_intent, ) response = client.get("/api/auth/me") @@ -176,6 +180,7 @@ def test_auth_me_auto_reconciles_missing_subscription(monkeypatch): payload = response.json() assert payload["subscription_active"] is True assert payload["subscription_plan_code"] == "pro_monthly" + assert reconcile_calls["count"] == 0 def test_ops_memberships_prefers_supabase_auth_email(monkeypatch):