107 lines
5.6 KiB
Markdown
107 lines
5.6 KiB
Markdown
---
|
||
name: ems-planner-bug-triage
|
||
description: >-
|
||
Triages EMS planner bugs from live Postgres (MCP): degraded Infeasible retry chain,
|
||
evening export vs battery hold, neg-buy/neg-sell days, fixed-tariff sites (BA81/KV1),
|
||
failed replan vs stale active plan. Use when the user reports planner errors, wrong
|
||
evening export, battery held while buy ~5 Kč/kWh, relaxed_neg_prep_window,
|
||
evening_push_hard_suppressed, or multi-site planner comparison. Complements
|
||
ems-plan-explain — use this skill for incident/bug classification and fix-branch hints.
|
||
---
|
||
|
||
# EMS — triáž bugů plánovače
|
||
|
||
## Kdy použít (vs. ems-plan-explain)
|
||
|
||
| Situace | Skill |
|
||
|---------|--------|
|
||
| „Proč v tom slotu nabíjí / neexportuje?“ | [ems-plan-explain](../ems-plan-explain/SKILL.md) |
|
||
| „Plánovač blbne / neprodává večer / 422 Infeasible / BA81 vs home-01“ | **tento skill** |
|
||
| Degradovaný plán (relaxed solve) ale run `active` | **tento skill** |
|
||
| Porovnání více lokalit uživatel **explicitně** jmenoval | **tento skill** (jinak jedna site) |
|
||
|
||
Typické spouštěče: *neprodává večer*, *drží baterku @ 5 Kč*, *nepřeplánovalo po OTE*, *Solver: Infeasible*, *evening_push prázdný*, *sell<0 a výroba do site*.
|
||
|
||
## Tvrdá pravidla
|
||
|
||
1. **MCP first** — server `user-postgres-ems`, nástroj `query`, jen `SELECT`. Po chybě: přesný text + VPN/MCP zapnutý.
|
||
2. **Selhání plánu není v `planning_run`** — status je jen `active` / `superseded` / `comparison` / `draft`. API **422** a scheduler exception = logy backendu; aktivní run může být **starý** nebo **degradovaný**.
|
||
3. Rozliš: **plán v DB** vs **exekuce** — `site_operating_mode != AUTO` → rolling replan se **přeskakuje** (ne nutně solver bug).
|
||
4. **Dvě podlahy SoC:** export / strategie → **`reserve_soc_percent`** (~20 %); dům v noci (Deye PASSIVE) → může jít k **`min_soc_percent`** (~10 %). Před návrhem večerního vývoje se u exportu domluv **`reserve`**, ne `min_soc`, pokud uživatel neřekne jinak.
|
||
5. **`neg sell` ≠ `buy < 0`:** vyprázdnit před **`sell < 0`** (headroom FVE) není totéž co strategie před **`buy < 0`** (levný import).
|
||
|
||
## Checklist triáže
|
||
|
||
```
|
||
- [ ] site_id (kód / id / výběr ze seznamu — viz ems-plan-explain reference §0)
|
||
- [ ] site_operating_mode + poslední řádky site_operating_mode_log
|
||
- [ ] active planning_run: id, created_at, run_type, triggered_by, soc_at_replan_wh
|
||
- [ ] solver_params.inputs: relaxed_*, evening_push_hard_suppressed, neg_evening_*,
|
||
pre_neg_pv_export_forecast_ok, charge_acquisition_buy_czk_kwh
|
||
- [ ] Večerní okno: planning_interval (battery/grid setpoint, soc target, ceny)
|
||
- [ ] Zítra: neg sloty ve vw_site_effective_price; snap neg_sell_day_pv_usable_wh
|
||
- [ ] Klasifikace bug typu A–E (reference.md §1)
|
||
- [ ] Návrh fix větve + ověření po fixu
|
||
```
|
||
|
||
## Rozhodovací strom
|
||
|
||
```
|
||
Replan 422 / žádný nový run po OTE?
|
||
├─ mode != AUTO → provozní (MANUAL/SELF_SUSTAIN), plán zastaralý
|
||
├─ poslední run any_relaxed + evening_push_hard_suppressed
|
||
│ └─ BUG typ A/B: degradovaný solve — Branch 1 + 2
|
||
└─ žádný řádek v planning_run → backend log „Infeasible“ (Branch 1)
|
||
|
||
Večer neprodává, drží vysoké SoC?
|
||
├─ evening_push_hard_suppressed = true → tvrdý push vypnutý (Branch 2)
|
||
├─ grid import @ drahý buy + vysoké SoC → terminal SoC + pos_sell_pre_neg_buy (Branch 2/5)
|
||
├─ zítra buy<0 + vysoká FVE, pre_neg ok = false
|
||
│ └─ měl jít večer k reserve, ne držet ~80 % (Branch 2)
|
||
└─ fixed tarif + evening_push_ts = [] → v58 / charge-slot-budget (Branch 3)
|
||
|
||
BA81: sell<0, výroba „do site“ / export?
|
||
└─ deye_gen_microinverter_cutoff + pole B — exekuce GEN (Branch 4)
|
||
```
|
||
|
||
## Retry řetězec (solve_dispatch)
|
||
|
||
Při Infeasible solver postupně zapíná (viz `planning_engine.py` ~4216):
|
||
|
||
1. `relaxed_expensive_import`
|
||
2. `relaxed_neg_buy_charge`
|
||
3. `relaxed_neg_prep_window` → **vypne** neg-evening push, kotvy, prep hold; **`evening_push_hard_suppressed = true`**
|
||
4. `neg_sell_phases_fallback` (prep_soc = 100 %)
|
||
|
||
**Symptom degradace:** run `active`, ale ve špičce **import ze sítě** místo exportu baterie; `neg_evening_push_ts` prázdné; plán drží SoC nad očekávání před neg dnem.
|
||
|
||
## Výstup pro uživatele (šablona)
|
||
|
||
1. **Fakta z DB** — run id, čas, mode, 3–5 klíčových flags, 2–3 večerní sloty (W, SoC %, buy/sell).
|
||
2. **Root cause** — jedna věta: degradovaný retry / konfigurace site / režim / exekuce.
|
||
3. **Bug typ** — A–E z [reference.md](reference.md).
|
||
4. **Doporučená větev opravy** — Branch 1–5 + soubor v repu.
|
||
5. **Ověření** — MCP dotaz nebo `pytest backend/tests/test_planning_dispatch_milp.py -k "…"`.
|
||
|
||
## Kód a dokumentace
|
||
|
||
| Téma | Soubor |
|
||
|------|--------|
|
||
| LP + retry | `backend/services/planning_engine.py` — `solve_dispatch` |
|
||
| `evening_push_hard_suppressed` | ~2810 |
|
||
| `pos_sell_pre_neg_buy` → `ge=0` | ~3929 |
|
||
| SQL masky | `db/routines/R__063_fn_load_planning_slots_full.sql` |
|
||
| Charge-slot budget (plán) | `docs/04-modules/planning-charge-slot-budget.md` |
|
||
| Changelog v55–v57 | `docs/planning-changelog.md` |
|
||
| Bisect fixture | `scripts/diagnose_home01_infeasible.py` |
|
||
|
||
## SQL a archetypy site
|
||
|
||
→ [reference.md](reference.md)
|
||
|
||
## Anti-patterns
|
||
|
||
- Diagnostikovat Infeasible **bez** `solver_params.inputs` z posledního úspěšného runu — může být právě ten degradovaný.
|
||
- Zaměnit „plán neexportuje“ s „exporter neběží“ — v MANUAL/SELF_SUSTAIN se plán nemusí aktualizovat.
|
||
- U fixního tarifu očekávat stejné `evening_push_ts` jako u home-01 — BA81/KV1 mají jinou větev (viz reference §3).
|