Fáze 3.4: router verzí plánovače — v2 zapojeno do shadow porovnání
_solve_dispatch_for_version: 'v2' → services.planning.solver_v2 (čisté jádro), jinak v1 two-pass; chyby v2 balené do PlannerSolverError (failure pipeline). Zapojeno do _maybe_add_planner_comparison (peer) i aktivních běhů run_daily_plan / run_rolling_replan (gated PLANNING_ENGINE_VERSION). Aktivace shadow: env PLANNING_ENGINE_COMPARE_ENABLED=true (aktivní zůstává v1, v2 se počítá paralelně, srovnání v planning_run.solver_params.comparison). Přepnutí: PLANNING_ENGINE_VERSION=v2. Default beze změny — golden 7/7, plná sada 245 passed (1 předexistující reg340 fail), 4 xfailed. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -24,6 +24,7 @@ from app.config import get_settings
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
from services.planning.solver_v2 import solve_dispatch_v2
|
||||
from services.planning.types import (
|
||||
PlannerSolverError,
|
||||
_timestamptz_from_db,
|
||||
@@ -242,6 +243,63 @@ def _planner_compare_enabled() -> bool:
|
||||
return bool(get_settings().planning_engine_compare_enabled)
|
||||
|
||||
|
||||
def _solve_dispatch_for_version(
|
||||
version: str,
|
||||
slots: list["PlanningSlot"],
|
||||
battery,
|
||||
heat_pump,
|
||||
grid,
|
||||
ev_sessions: list,
|
||||
vehicles: list,
|
||||
current_soc_wh: float,
|
||||
current_tuv_temp_c: float,
|
||||
*,
|
||||
tuv_delta_stats: Optional[dict[tuple[int, int], float]] = None,
|
||||
operating_mode: str = "AUTO",
|
||||
charge_commitment_prev_w: Optional[list[Optional[float]]] = None,
|
||||
evening_push_ts_override: Optional[set[int]] = None,
|
||||
) -> tuple[list["DispatchResult"], int, dict[str, Any]]:
|
||||
"""
|
||||
Router verzí plánovače: "v2" = čisté ekonomické jádro (services.planning.solver_v2,
|
||||
bez heuristických penalt; commitment/evening_push override nemá — koncepty v1),
|
||||
jinak v1 two-pass. Chybu v2 balí do PlannerSolverError kvůli failure pipeline.
|
||||
"""
|
||||
if str(version).strip().lower() == "v2":
|
||||
try:
|
||||
return solve_dispatch_v2(
|
||||
slots,
|
||||
battery,
|
||||
heat_pump,
|
||||
grid,
|
||||
ev_sessions,
|
||||
vehicles,
|
||||
current_soc_wh,
|
||||
current_tuv_temp_c,
|
||||
tuv_delta_stats=tuv_delta_stats,
|
||||
operating_mode=operating_mode,
|
||||
planner_version="v2",
|
||||
)
|
||||
except PlannerSolverError:
|
||||
raise
|
||||
except RuntimeError as exc:
|
||||
raise PlannerSolverError(f"v2: {exc}", relax_chain=["v2"]) from exc
|
||||
return solve_dispatch_two_pass(
|
||||
slots,
|
||||
battery,
|
||||
heat_pump,
|
||||
grid,
|
||||
ev_sessions,
|
||||
vehicles,
|
||||
current_soc_wh,
|
||||
current_tuv_temp_c,
|
||||
tuv_delta_stats=tuv_delta_stats,
|
||||
operating_mode=operating_mode,
|
||||
charge_commitment_prev_w=charge_commitment_prev_w,
|
||||
planner_version=version,
|
||||
evening_push_ts_override=evening_push_ts_override,
|
||||
)
|
||||
|
||||
|
||||
def _planner_peer_version(version: str) -> str:
|
||||
v = str(version).strip().lower()
|
||||
if v == "v1":
|
||||
@@ -344,7 +402,8 @@ def _maybe_add_planner_comparison(
|
||||
if peer_version == active_version:
|
||||
return None
|
||||
try:
|
||||
peer_results, peer_ms, peer_snapshot = solve_dispatch_two_pass(
|
||||
peer_results, peer_ms, peer_snapshot = _solve_dispatch_for_version(
|
||||
peer_version,
|
||||
slots,
|
||||
battery,
|
||||
heat_pump,
|
||||
@@ -356,7 +415,6 @@ def _maybe_add_planner_comparison(
|
||||
tuv_delta_stats=tuv_delta_stats,
|
||||
operating_mode=operating_mode,
|
||||
charge_commitment_prev_w=charge_commitment_prev_w,
|
||||
planner_version=peer_version,
|
||||
evening_push_ts_override=None,
|
||||
)
|
||||
except RuntimeError as exc:
|
||||
@@ -3502,7 +3560,14 @@ async def run_daily_plan(
|
||||
|
||||
om = operating_mode or "AUTO"
|
||||
try:
|
||||
if om == "AUTO":
|
||||
if planner_version_resolved == "v2":
|
||||
results, duration_ms, solver_snapshot = _solve_dispatch_for_version(
|
||||
"v2",
|
||||
slots, battery, hp, grid, ev_sessions, vehicles, soc_wh, tuv_temp,
|
||||
tuv_delta_stats=tuv_stats,
|
||||
operating_mode=om,
|
||||
)
|
||||
elif om == "AUTO":
|
||||
results, duration_ms, solver_snapshot = solve_dispatch_two_pass(
|
||||
slots, battery, hp, grid, ev_sessions, vehicles, soc_wh, tuv_temp,
|
||||
tuv_delta_stats=tuv_stats,
|
||||
@@ -3739,7 +3804,14 @@ async def run_rolling_replan(
|
||||
|
||||
om = operating_mode or "AUTO"
|
||||
try:
|
||||
if om == "AUTO":
|
||||
if planner_version_resolved == "v2":
|
||||
results, duration_ms, solver_snapshot = _solve_dispatch_for_version(
|
||||
"v2",
|
||||
slots, battery, hp, grid, ev_sessions, vehicles, soc_wh, tuv_temp,
|
||||
tuv_delta_stats=tuv_stats,
|
||||
operating_mode=om,
|
||||
)
|
||||
elif om == "AUTO":
|
||||
results, duration_ms, solver_snapshot = solve_dispatch_two_pass(
|
||||
slots, battery, hp, grid, ev_sessions, vehicles, soc_wh, tuv_temp,
|
||||
tuv_delta_stats=tuv_stats,
|
||||
|
||||
Reference in New Issue
Block a user