feat(harness): extract_fixtures --keep-ev — zmrazit EV sessions do fixture

Default zůstává vynulování otevřených EV sessions (historické okno bez
session); --keep-ev je zmrazí pro EV scénáře (deadline, měkký cíl, min.
výkon wallboxu). meta.keep_ev ve fixture dokumentuje způsob pořízení.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Dusan Vojacek
2026-06-12 19:32:06 +02:00
parent 3b5f07b66e
commit 73a665457d
2 changed files with 21 additions and 3 deletions

View File

@@ -45,6 +45,11 @@ python3 scripts/harness/extract_fixtures.py --site-code home-01 --day 2026-06-07
cd backend && GOLDEN_UPDATE=1 python3 -m pytest tests/test_golden_replay.py -q
```
`--keep-ev` zmrazí do fixture i otevřené EV sessions z doby extrakce (default je
vynulovat — historické okno bez session). Hodí se pro EV scénáře (deadline,
měkký cíl / oportunistické nabíjení, min. výkon wallboxu); `meta.keep_ev`
ve fixture říká, jak byla pořízena.
Pokryté scénáře (v4 fixtures): home-01 hluboký neg-sell (sell 1.57, buy 0.89),
home-01 běžný spot den, BA81 běžný den, KV1 fixní nákup. Při změnách heuristik
přidávej scénář, který změnu pokrývá.

View File

@@ -154,9 +154,11 @@ async def extract(args: argparse.Namespace) -> Path:
# Determinismus replay:
# - SoC/TUV fixujeme do contextu (přepis aktuálních hodnot historickými / extrakčními),
# - otevřené EV sessions z doby extrakce nepatří k historickému oknu → vynulovat,
# - otevřené EV sessions z doby extrakce nepatří k historickému oknu → default
# vynulovat; --keep-ev je zmrazí do fixture (EV scénáře: deadline, měkký cíl),
# - operating_mode fixně AUTO (plný solver, srovnatelnost napříč fixtures).
ctx["soc_wh"] = soc_wh
if not args.keep_ev:
ctx["ev_sessions"] = []
ctx["operating_mode"] = "AUTO"
@@ -172,12 +174,18 @@ async def extract(args: argparse.Namespace) -> Path:
"soc_wh": round(soc_wh, 1),
"soc_source": soc_source,
"tag": args.tag,
"keep_ev": bool(args.keep_ev),
"extracted_at": datetime.now(tz=PRAGUE).isoformat(),
"dsn_host": dsn.split("@")[-1].split("/")[0] if "@" in dsn else "?",
"note": (
"Vstupy plánovače zmrazené k okamžiku extrakce (context = aktuální konfigurace, "
"sloty = fn_load_planning_slots_full nad historickými cenami/forecasty). "
"EV sessions vynulovány, operating_mode=AUTO."
+ (
"EV sessions zmrazeny (--keep-ev)"
if args.keep_ev
else "EV sessions vynulovány"
)
+ ", operating_mode=AUTO."
),
},
"context_json": ctx,
@@ -209,6 +217,11 @@ def main() -> None:
p.add_argument("--day", required=True, help="Pražský den YYYY-MM-DD (začátek okna 00:00)")
p.add_argument("--hours", type=int, default=36, help="Délka okna v hodinách (default 36)")
p.add_argument("--tag", required=True, help="Krátký popis scénáře (neg_sell_deep, normal, …)")
p.add_argument(
"--keep-ev",
action="store_true",
help="Zachovat otevřené EV sessions v contextu (default: vynulovat — historické okno)",
)
p.add_argument("--dsn", default=None, help="postgresql:// DSN (jinak EMS_DB_DSN / DB_* env)")
p.add_argument("--out-dir", default=str(DEFAULT_OUT_DIR), help="Cílový adresář fixtures")
args = p.parse_args()