Dokumentace refaktoru a delta-triage skill
- docs/refactor-clean-planner.md: plán Fází 0-4, stav, závazná pravidla (golden gate), návod nasazení v2 (shadow → vyhodnocení → přepnutí) - docs/planning-changelog.md: záznam 2026-06-11 (Fáze 0-3 kompletní) - docs/04-modules/planning.md: sekce Verze enginu v1/v2 + env flagy - docs/audits/*: stav implementace FE fixů - .claude/skills/ems-delta-triage: postup triáže neekonomického chování (realita vs plán vs shadow peer vs oracle, verdikt s Kč) - CLAUDE.md: ukazatele na refaktor, solver_v2 a delta-triage v 'Kde hledat co' Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -799,3 +799,19 @@ Planner v2 má dělat přesně toto:
|
||||
- PV A škrtit jen když je to nutné
|
||||
- PV B nikdy neškrtit
|
||||
- BA81 řešit přes GEN cutoff
|
||||
|
||||
---
|
||||
|
||||
## Verze enginu: v1 (heuristický) vs v2 (čisté jádro) — od 2026-06-11
|
||||
|
||||
Plánovač má dvě implementace, přepínané env proměnnými (`backend/app/config.py`):
|
||||
|
||||
| Env | Default | Význam |
|
||||
|-----|---------|--------|
|
||||
| `PLANNING_ENGINE_VERSION` | `v1` | Aktivní engine pro daily i rolling plán |
|
||||
| `PLANNING_ENGINE_COMPARE_ENABLED` | `false` | Shadow režim: druhá verze se počítá paralelně, diff se ukládá do `planning_run.solver_params.comparison` (status `comparison`) |
|
||||
|
||||
- **v1** = `solve_dispatch_two_pass` (heuristické fáze/okna/kotvy + penalty; popsáno výše v tomto dokumentu).
|
||||
- **v2** = `services/planning/solver_v2.py`: objective = jen reálné peníze (cash + degradace − terminal SoC value z `asset_battery.planner_terminal_soc_value_factor`); tvrdá pravidla (CLAUDE.md 5/6/7/19), EV deadline (placený slack), TUV look-ahead, provozní režimy. SQL masky `allow_charge`/`allow_discharge_export` **ignoruje**.
|
||||
- Router: `_solve_dispatch_for_version` v `planning_engine.py`; chyby v2 jdou do standardní failure pipeline (`fn_planning_run_fail`).
|
||||
- Regresní brána a měření: `scripts/harness/README.md` (golden replay, economics report, penalty audit, `solver_v2_eval.py`); plán refaktoru: `docs/refactor-clean-planner.md`.
|
||||
|
||||
@@ -24,3 +24,10 @@ Měřeno na živé DB (site_id=2) + statická analýza kódu a bundle. Plný kon
|
||||
1. **Backend SQL**: fn_plan_current_bundle + fn_site_full_status (největší dopad, řeší se samostatně).
|
||||
2. **FE quick wins**: polling 60/15 s, telemetry limit 420, lazy routes + manualChunks.
|
||||
3. **FE větší**: 2-vlnové načítání, virtualizace Planning tabulky, memoizace.
|
||||
|
||||
## Stav implementace (2026-06-11)
|
||||
|
||||
- ✅ Quick wins (polling 60/15/120 s, payload okna grafu, manualChunks + lazy routes, 2 vlny načítání) — merge `60f5f77`, build ověřen.
|
||||
- ✅ `vw_latest_inverter` / `vw_latest_ev_charger` → LATERAL (508→56 ms, 460→75 ms živě) — commit `1d5b97c`, projeví se deployem.
|
||||
- ⬜ `fn_plan_current_bundle` (90 % času ve `fn_forecast_pv_slots_range_canonical_ab`) — vyžaduje hlubší zásah.
|
||||
- ⬜ Virtualizace Planning tabulky, Recharts Cell mapování.
|
||||
|
||||
@@ -22,3 +22,8 @@ Hlášené problémy: grafy na mobilu špatně zobrazené; tooltip při dotyku k
|
||||
3. **Střední**: grid breakpointy všude, ControlPanel, font scaling, touch targets.
|
||||
|
||||
Odhad: ~220–250 řádků změn napříč ~13 soubory.
|
||||
|
||||
## Stav implementace (2026-06-11)
|
||||
|
||||
- ✅ Kritické + vysoké: responsive výšky grafů (tailwind chart-*), StatePanel mobile, PlanSlotDetail sticky řádek, tap-to-pin tooltip (Chart.js panel / Recharts trigger click, hook `useIsCoarsePointer`), viewport-fit, touch targets, grid breakpointy — merge `60f5f77` + fix `b5dbc8c`, build ověřen.
|
||||
- ⬜ Otestovat na reálném mobilu (tap-to-pin chování, scroll Planning tabulky).
|
||||
|
||||
@@ -5,6 +5,28 @@ Formát: **datum (ISO)** · stručný důvod · soubory · chování / ověřen
|
||||
|
||||
---
|
||||
|
||||
## 2026-06-11 — Refaktor „Čistý plánovač“: harness, dekompozice, solver_v2 (Fáze 0–3)
|
||||
|
||||
**Kontext:** Ekonomický audit potvrdil systémový problém heuristické vrstvy: na neg-sell dnech Σ heuristických penalt v objective 13× převažuje reálný cashflow; GAP actual vs perfect-hindsight oracle za 29 dní home-01 = **2 185 Kč ≈ 27 %**. Plný plán a stav: `docs/refactor-clean-planner.md`.
|
||||
|
||||
**Fáze 0 — harness (`scripts/harness/`, `backend/tests/golden/`):**
|
||||
- `extract_fixtures.py` (vstupy solveru z DB → JSON), **golden replay gate** `test_golden_replay.py` (bit-perfektní diff, `GOLDEN_UPDATE=1` jen vědomě), `economics_report.py` (actual vs oracle, SoC-adjusted), `penalty_audit.py`.
|
||||
- 6 fixtures vč. **`home-01_2026-05-01_extreme_neg_buy`** (buy −13,26): v1 **Infeasible po všech 8 relax krocích** — zmrazeno jako golden failure snapshot.
|
||||
|
||||
**Fáze 1 — dekompozice:** `planning_engine.py` 6 345 → 3 960 ř.; nový balíček `services/planning/` (`constants` — všech 59 konstant vč. penalt, `types`, `forecast`, `db_io`, `heuristics` — 88 pre-solver funkcí). Engine = fasáda, importy beze změny, golden gate zelená po každém kroku.
|
||||
|
||||
**Fáze 2 — audit:** 16 z 26 ekonomických penalt **mrtvých** na všech fixtures (vč. `EVENING_PUSH_Z_EXPORT_BONUS` na evening-push dni); aktivní penalty silně interagují. 4 trvale failující testy = **stale** (chování před retry-chain v5) → `@unittest.expectedFailure` se zdůvodněním; suite poprvé zelená (120 passed, 4 xfailed).
|
||||
|
||||
**Fáze 3 — `services/planning/solver_v2.py` (čisté jádro):**
|
||||
- Objective = cash + degradace − terminal SoC value (DB faktor); tvrdá pravidla (bilance, breaker, curtail jen A, GEN cutoff binárka, neg-buy/neg-sell bloky, export z baterie ⇒ arb floor, zákaz souč. imp+exp), EV deadline s placeným slackem (50 Kč/kWh), TUV look-ahead, režimy. **SQL masky `allow_*` ignoruje** (heuristika, ne fyzika).
|
||||
- **Výsledky (`solver_v2_eval.py`):** lepší než v1 na všech 5 řešitelných fixtures (**+231,5 Kč ≈ +22 %**, SoC-fér); extreme_neg_buy den v1=INFEASIBLE → v2 OK. Časy 0,4–10 s (2 extrémy na time limitu — TODO méně binárek).
|
||||
- **Router verzí:** `_solve_dispatch_for_version` v engine; env `PLANNING_ENGINE_COMPARE_ENABLED=true` = shadow (v1 aktivní, v2 peer, diff v `planning_run.solver_params.comparison`); `PLANNING_ENGINE_VERSION=v2` = přepnutí. Default v1 — beze změny chování.
|
||||
|
||||
**Soubory:** `services/planning/*`, `planning_engine.py`, `tests/test_solver_v2.py` (11), `tests/test_golden_replay.py`, `scripts/harness/*`.
|
||||
**Ověření:** plná sada 245 passed / 4 xfailed (1 předexistující reg340 fail); golden 7/7; `solver_v2_eval.py`.
|
||||
|
||||
---
|
||||
|
||||
## 2026-06-06 — Pozdní replan večer: Infeasible při vysokém SoC (home-01)
|
||||
|
||||
**Problém:** Po přepnutí na AUTO a ručním replanem (~21:00, SoC **~74 %**, zítra `buy<0` + `sell<0`): všechny retry včetně `neg_sell_phases_fallback` → **`Solver: Infeasible`**. Aktivní zůstal starý plán z 17:00 (import místo večerního vývozu k **reserve ~20 %**).
|
||||
|
||||
62
docs/refactor-clean-planner.md
Normal file
62
docs/refactor-clean-planner.md
Normal file
@@ -0,0 +1,62 @@
|
||||
# Refaktor „Čistý plánovač“ — plán a stav
|
||||
|
||||
Cíl: odstranit příčinu neekonomického provozu — heuristickou vrstvu okolo MILP
|
||||
solveru (pre-solver fáze/okna/kotvy + ~26 ručně laděných penalt v objective),
|
||||
která se vzájemně pere a převažuje reálné peníze. Strategie: **ne big-bang
|
||||
přepis projektu** (predikce, Modbus, telemetrie, audit, DB jsou odladěné),
|
||||
ale řízená náhrada jádra plánovače za regresním harnessem.
|
||||
|
||||
## Diagnóza (měřeno 2026-06-11)
|
||||
|
||||
- `planning_engine.py` (před refaktorem 6 345 ř., 112 funkcí): ~35 % ekonomické
|
||||
logiky v heuristikách PŘED solverem, ~60 % jako měkké penalty v objective
|
||||
s ~20 konstantami natvrdo. Solver = „vykonavatel heuristického plánu“.
|
||||
- Na neg-sell dni Σ penalt 2 119 Kč při cashflow −163 Kč (13×).
|
||||
- GAP actual vs perfect-hindsight oracle, home-01 29 dní: **2 185 Kč ≈ 27 %**
|
||||
(stabilní dny 1–5 %, volatilní/neg-sell 50–160 %).
|
||||
- Den 2026-05-01 (buy −13,26): v1 Infeasible po všech 8 relax krocích.
|
||||
- Penalty audit: **16/26 penalt mrtvých** na 6 reprezentativních fixtures.
|
||||
|
||||
## Fáze a stav
|
||||
|
||||
| Fáze | Obsah | Stav |
|
||||
|------|-------|------|
|
||||
| 0 | Ekonomický harness: golden replay gate, fixtures z reálné DB, economics report (actual vs oracle), penalty audit | ✅ hotovo |
|
||||
| 1 | Dekompozice `planning_engine.py` → `services/planning/` (constants/types/forecast/db_io/heuristics), fasáda, identita chování | ✅ hotovo |
|
||||
| 2 | Penalty audit, stale testy → xfail, rozšíření fixtures (extrémní dny) | ✅ hotovo |
|
||||
| 3 | `solver_v2` (čisté jádro) + router verzí + shadow porovnání | ✅ hotovo (kód); **čeká na shadow data z produkce** |
|
||||
| 4 | Slupka: FE výkon + responsivita | ✅ první vlna (viz `docs/audits/`) |
|
||||
|
||||
## Jak se pracuje (závazná pravidla)
|
||||
|
||||
1. **Golden gate** (`backend/tests/test_golden_replay.py`) musí projít po každé
|
||||
změně plánovače. Snapshoty se regenerují (`GOLDEN_UPDATE=1`) jen při vědomé
|
||||
změně chování, s odůvodněním v commitu a s nezhoršeným GAPem
|
||||
(`scripts/harness/economics_report.py`).
|
||||
2. Ekonomické parametry patří do DB (CLAUDE.md pravidlo 16), ne do Pythonu.
|
||||
3. v2 nikdy neměnit bez `solver_v2_eval.py` (v2 vs v1 na fixtures).
|
||||
|
||||
## Nasazení v2 (návod)
|
||||
|
||||
1. **Shadow**: do prod env `PLANNING_ENGINE_COMPARE_ENABLED=true` → v1 řídí,
|
||||
v2 se počítá paralelně, diff v `planning_run.solver_params.comparison`.
|
||||
2. Po ~týdnu vyhodnotit: `select solver_params->'comparison' from ems.planning_run …`
|
||||
+ `economics_report.py` (trend GAPu).
|
||||
3. **Přepnutí**: `PLANNING_ENGINE_VERSION=v2`; golden snapshoty vědomě
|
||||
zregenerovat; heuristics.py + mrtvé penalty postupně mazat.
|
||||
|
||||
## Klíčové výsledky v2 (fixtures, SoC-fér)
|
||||
|
||||
v2 lepší na všech 5 řešitelných fixtures, **+231,5 Kč ≈ +22 %**; den
|
||||
2026-05-01 v1=INFEASIBLE → v2 řeší (−674,5 Kč). Detail:
|
||||
`scripts/harness/solver_v2_eval.py`, changelog 2026-06-11.
|
||||
|
||||
## Otevřené body
|
||||
|
||||
- v2 výkon na extrémních dnech (10 s time limit) — omezit binárky
|
||||
`y_imp`/`z_exp` jen na sloty, kde dávají smysl.
|
||||
- `fn_plan_current_bundle` 3,8 s (90 % v `fn_forecast_pv_slots_range_canonical_ab`)
|
||||
— viz `docs/audits/frontend-performance-2026-06-11.md`.
|
||||
- Virtualizace Planning tabulky; Recharts Cell mapování.
|
||||
- Po přepnutí na v2: smazat mrtvé heuristiky/penalty, přepsat 4 xfail testy
|
||||
na ekonomické asserty.
|
||||
Reference in New Issue
Block a user