Files
ems/.cursor/skills/ems-planner-bug-triage/SKILL.md
Dusan Vojacek 3161421d5c
Some checks failed
CI and deploy / migration-check (push) Failing after 15s
CI and deploy / deploy (push) Has been skipped
skill pro debug
2026-06-06 22:41:56 +02:00

107 lines
5.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
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 AE (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, 35 klíčových flags, 23 večerní sloty (W, SoC %, buy/sell).
2. **Root cause** — jedna věta: degradovaný retry / konfigurace site / režim / exekuce.
3. **Bug typ** — AE z [reference.md](reference.md).
4. **Doporučená větev opravy** — Branch 15 + 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 v55v57 | `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).