# EMS plan explain — reference SQL (MCP) Všechno jen **read-only** `SELECT`. Server MCP: **`user-postgres-ems`**, nástroj **`query`**, argument `{"sql": "…"}`. ## 0) Lokalita neuvedená v dotazu — seznam pro výběr Spusť jeden dotaz; výsledek **vyrenderuj uživateli jako číslovaný seznam** (`id`, `code`, `name`, příznaky). ```sql select s.id, s.code, s.name, coalesce(s.active, true) as site_active, pr.id as active_planning_run_id, pr.created_at as active_plan_created_at from ems.site s left join lateral ( select id, site_id, created_at from ems.planning_run where site_id = s.id and status = 'active' order by created_at desc limit 1 ) pr on true order by (pr.id is not null) desc, coalesce(s.active, true) desc, s.id; ``` **Po seznamu vždy zeptej se uživatele** na jednu lokalitu (číslo řádku, `code`, nebo `id`). **Nespouštěj** `fn_plan_explain_bundle` pro více lokalit najednou ani „tiše“ pro první řádek — viz skill `ems-plan-explain` Krok 1. Volitelně můžeš v jedné větě upozornit, kdo má `active_planning_run_id`, ale **výběr nech na uživateli** (u jediného záznamu v tabulce stačí krátké potvrzení typu „ano“). Až uživatel lokalitu vybere nebo potvrdí, pokračuj `fn_plan_explain_bundle(s.id, hours)`. ## 1) `site_id` z kódu lokality Nahraď literál v uvozovkách (příklad `BA81`): ```sql select id, code, name, timezone from ems.site where code ilike 'BA81' or name ilike '%BA81%'; ``` Pokud více řádků → **zeptat se uživatele**, kterou lokalitu myslí. ## 2) Primární balík (doporučeno pro vysvětlení) Druhý argument = **počet hodin** od začátku aktuálního 15min slotu (UTC), stejně jako plánovač. ```sql select ems.fn_plan_explain_bundle(3, 6) as bundle; ``` Typicky druhý argument **6**. Větší okno jen když uživatel chce delší výhled (více tokenů). ## 3) Konkrétní sloty v čase (Europe/Prague) Intervaly v DB jsou **`timestamptz` (UTC)**. Pro „zítra 11:15“ převeď na UTC v dotazu nebo použij okno: ```sql select pi.interval_start, pi.battery_setpoint_w, pi.grid_setpoint_w, pi.load_baseline_w, pi.pv_a_forecast_solver_w, pi.pv_b_forecast_solver_w, pi.pv_a_curtailed_w, pi.effective_buy_price, pi.effective_sell_price, pi.deye_physical_mode, pi.deye_gen_cutoff_enabled from ems.planning_interval pi where pi.run_id = ( select id from ems.planning_run where site_id = 3 and status = 'active' order by created_at desc limit 1 ) and pi.interval_start >= '2026-04-27T08:00:00+00:00' and pi.interval_start < '2026-04-27T14:00:00+00:00' order by pi.interval_start; ``` Hodnoty `site_id` a časové meziráky nahraď podle kontextu. ## 4) Žádný aktivní plán Když `fn_plan_explain_bundle` vrátí chybu / `no_active_plan`, ověř: ```sql select id, status, run_type, created_at, horizon_start, horizon_end from ems.planning_run where site_id = 3 order by created_at desc limit 5; ``` ## 5) Dokumentace v repu - `docs/07-mcp-postgres-ems.md` — MCP bezpečnost a příklady - `.cursor/rules/plan-explain-bundle.mdc` — co číst z JSONu - `backend/services/planning_engine.py` — `solve_dispatch` (omezení `sell < 0`, `buy < 0`, curtailment) - `docs/04-modules/planning.md` — bilance, účelovka, edge cases