Files
ems/docs/improvement-backlog-2026-06-14.md
Dusan Vojacek 17147ca412 docs(backlog): export-constrained lokalita — curtailment-min test use-case
Tier 3 test: malý export limit + velký instal → ověřit, že MILP drží baterce
rezervu na polední peak místo naivního plnění ráno. Závislé na PV forecast review.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-16 09:47:20 +02:00

27 KiB
Raw Blame History

EMS — Prioritizovaný implementovatelný backlog

Syntéza nálezů (6 dimenzí) + dvě kritiky (kompletnost, riziko), dedup + sloučení. Ověřeno proti kódu na větvi main/dev (k 2026-06-14). Filozofie v2: ceny, ne heuristiky; žádná sezónní okna.


1. TL;DR

Systém řídí produkci přes v2 solver, ale backlog stojí na jedné tiché iluzi a několika single-point-of-failure dírách.

Iluze: golden gate je v dokumentaci „tvrdá brána", ale neběží v CI (.gitea/workflows/deploy.yml dělá jen migration-immutability + flyway-validate + deploy). Navíc 7. fixture home-01_2026-06-13_ev_neg_day.json nemá snapshot (fixtures/=7, snapshots/=6) → ten test buď failuje, nebo nikdy neběžel na zelenou. A CI golden replay (kdyby běžel) testuje default v1 (planning_engine.py:239 "or v1"), ne produkční v2 — pokud nemá PLANNING_ENGINE_VERSION=v2 v env. Proto je CI golden gate enforcement nový Tier 1 PŘED jakoukoli změnou solveru — bez něj je každá solver-touching položka (TUV fix, terminal clamp, dead-penalty delete, arbitráž, perf) reálně nechráněná a regrese se nasadí tiše.

Díry SPOF (tiché, dokud se nestane neštěstí): chybí DB záloha (jediná Postgres v Docker volume, žádné pg_dump/WAL); Open-Meteo je jediný PV forecast provider bez fallbacku/staleness alertu (výpadek zneplatní celý plán tiše); price importer bez staleness alertu (§16 horizont se tiše zkrátí); FastAPI zápisová vrstva je BEZ JAKÉKOLI autentizace (POST /sites/{id}/mode mění fyzické setpointy střídače, CORS allow_methods=['*'], main.py:46-50) — kdokoli na síti přepne režim; signal abandoned (vč. EXPORT_BAN_ACTIVE na Loxone) padá bez notify; kritické joby v lifespan.py mají jen logger.exception. A Discord dedup/rate-limit primitive NEEXISTUJE — je předpokladem všech alert itemů, ne poznámka.

Konkrétní chyba s číslem: TUV ochlazování je 60× podhodnocené (solver_v2.py:348 delta * INTERVAL_H, kde delta je °C/min × 0.25 h). Fix * 15 je matematicky správný, ale tuv_heat_t/tuv_emergency jsou HARD constraints (solver_v2.py:354,356) → 60× silnější signál může vynutit ohřev v drahých slotech nebo udělat deep-neg-sell den Infeasible (§6 zákaz exportu + plná baterie + vynucený ohřev). To není low-risk a vyžaduje napřed TČ/TUV golden fixture (žádná ze 7 současných ho nemá).

Druhá zbývající díra v řízení: write_heat_pump_setpoint() (outputs.py:255-278) je čistý logger — solver_v2 počítá TUV look-ahead, ale nikdy nezapíše reg 73/74; HP navíc vůbec není ve verify.py/modbus_journal.py (jiné zařízení MIM-B19N) → je to nová verify větev + failsafe rozhodnutí, ne příloha k write stubu.

Co NEDĚLAT: nepřidávat penalty/binárky bez (CI) golden gate a time-budget revize (v2 už na 10s limitu u 2 fixtures); neobcházet §6 (zákaz exportu při sell<0); neměnit historická data (tuv_usage_stats = °C/min, audit_interval do 2026-06-12 = CT reg 619 legacy, forecast_pv_*, ev_arrival_stats) — opravovat dopředně/filtrovaně; nemazat penalty z constants.py hromadně (sdílené s živým v1 shadow peer); max_connections na slabém nočním serveru nešvihat tvrdě na 250.

Korekce předchozího draftu: git log main..dev je prázdný → export-guard carve-out (521a365) i reg15 re-assert (54288ee) jsou na main, ne „čekají v dev". Ty fixy jsou shipped.


2. Tier 1 — Quick wins + tiché SPOF díry (S/M, hodnota nebo pojistka teď)

Položka Co Hodnota První krok Co ohlídat
CI golden gate enforcement ⚠️ PŘEDŘAZENÉ test_golden_replay.py neběží v CI (deploy.yml = jen migrace+validate+deploy). Solver-touching změny jdou do prod nechráněné. Reálná regresní brána místo iluzorní lokální. Předpoklad VŠECH solver položek níže. Přidat CI step pytest backend/tests/golden s PLANNING_ENGINE_VERSION=v2 (jinak testuje default v1). Vyřešit 7. chybějící snapshot napřed (viz níže). Snapshoty neukládají verzi enginu → CI env MUSÍ explicitně v2. Slabý server: golden běh nesmí kolidovat s 15:00 daily / OTE okny.
7. fixture chybí snapshot fixtures/=7, snapshots/=6; home-01_2026-06-13_ev_neg_day.json bez baseline → test failuje (test_golden_replay.py:177-180). „EV+neg pokrytý/zelený" je nepravda. Skutečná regresní ochrana EV+neg scénáře. Vygenerovat baseline snapshot vědomě (přečíst plán, ne slepě accept), pak ekonomický assert battery_arbitrage_czk > 0. Snapshot generovat pod v2; ověřit že plán dává smysl, ne jen „zelená".
TČ/TUV golden fixture ⚠️ PŘED TUV fixem Žádná ze 7 fixtures nemá aktivní TČ/TUV (nenulový tuv_delta_stats + current_tuv_temp_c) → tuv_heat_t se nikde netestuje. Ekonomická brána pro TUV 60× fix i budoucí TČ write. Bez ní jsou oba fixy slepé. Extrahovat home-01 zimní/přechodový den s aktivním TČ; přidat do golden setu (→ 8 fixtures). Slot s neg-sell + plná baterie + nucený ohřev = Infeasible kandidát; fixture to musí umět zachytit.
TUV delta 60× fix solver_v2.py:348 tuv_pred += delta * INTERVAL_H sčítá °C/min × 0.25 h. Opravit na delta * 15 (°C/15min) na straně solveru. Solver „vidí" chladnutí → předehřev TUV před buy<0. GAP +1-3 %, hlavně zima. Až po TČ/TUV fixture. Edit jen solver_v2.py (čtecí vrstva), pak solver_v2_eval + golden gate. Riziko medium, ne low: tuv_heat/tuv_emergency HARD (řádky 354,356) → 60× signál může vynutit ohřev v drahých slotech NEBO Infeasible v deep-neg-sell. Historické tuv_usage_stats NEMĚNIT (°C/min). Δcashflow vysvětlit.
API-key gate na FastAPI ZÁPISOVÉ endpointy 0 auth (žádný Depends/Security/JWT, grep prázdný), CORS allow_methods=['*'] (main.py:46-50). POST /sites/{id}/mode, PATCH /configuration, EV patche mění fyzické řízení. Okamžitá redukce attack surface; kdokoli na síti dnes přepne režim střídače. Shared-secret header dependency na write routes. Server-internal cesty (scheduler, lifespan, mismatch→SELF_SUSTAIN přes fn_set_mode/fn_expire_modes) NESMÍ projít přes gate ani Loxone callback (§4.4). HTTP gate v Pythonu je OK; autorizační LOGIKA/RLS zůstává mimo Python (§2.2).
Discord dedup/rate-limit primitive discord_bot.py nemá cooldown/throttle (grep: jen EV handlery). Předpoklad VŠECH alert itemů. Bez něj job-fail loop (rolling každých 15 min) spamuje kanál → alerty se ignorují. Sdílená cooldown registry (max 1×/N min per alert-key). MUSÍ být ve stejném PR jako první alert. Vlastní mini-task, ne poznámka v „Co ohlídat".
Discord alert na kritické joby Joby v lifespan.py mají jen logger.exception; rolling_replan Infeasible/timeout se zjistí druhý den. Selhání plánu/exportu v minutách, ne dnech. Decorator @async_discord_alert(job, level). Severity: plán/export/verify=CRITICAL, audit/forecast/stats=WARNING. DISCORD_WEBHOOK_URL existuje. Realisticky M, ne S (dedup primitive napřed). Rozšířit na VŠECHNY joby (lifespan.py:86-237), ne jen 3: audit_filler, signal_send/verify, verify_modbus, forecast, price_importer, baseline/price/tuv stats.
Discord alert na signal abandoned signal_service.py přepíná do abandoned na 5+ místech (330,359,372,523,658,683) bez notify. EXPORT_BAN_ACTIVE na Loxone (§6-relevant, loxone-integration.md:30,48-49) tiše umře → EMS neví o desync. EMS ví, že Loxone nedostal export-ban stav. Notify v okamžiku přechodu do abandoned, dedup per signal_code. Signal infra a per-endpoint backoff jsou bezpečnostní featury — zachovat.
Forecast staleness watchdog Open-Meteo je jediný PV provider (forecast.md:62,234 — Solcast jen „budoucí"); forecast_service.py try/except (63,108,111,118,132) bez fallbacku/alertu → plán běží na zastaralém PV tiše. Detekce výpadku feedu, který zneplatní CELÝ plán (větší dopad než EUR/CZK). Job: stáří nejnovějšího forecast_pv_run.created_at per site > X h (např. 8 h) → Discord WARNING. Read-only. Cenový fallback do LP je ZAKÁZÁN (§16) — fallback PV forecastu OK (vstup), ale žádná predikovaná CENA do solveru.
Price/OTE staleness watchdog price_importer.py jen retryuje (65-98); při trvalém failu §16 horizont (fn_planning_horizon_end) tiše zkrátí. Detekce výpadku cen místo tichého zkrácení horizontu. Job: poslední market_interval_price.interval_start per zdroj starší než očekávaný horizont → Discord. Fallback na market_price_stats jen jako diagnostika/UI, nikdy do LP (§16).
DB pg_dump cron + retence Žádná záloha/WAL/PITR; Docker volume = SPOF (deployment-self-hosted.md §10 je jen reset). Pojistka proti ztrátě 6 měsíců telemetrie/auditu (faktura, NZÚ evidence). Cron pg_dump | gzip/opt/ems-deploy/backups/dump-DATE.sql.gz, keep 30 d, rsync na NAS. Read-only; bez dopadu na běh. Test restore 1×/měsíc.
Terminal SoC shadow price ≥ 0 clamp (Python) R__063 SQL clampuje charge_acquisition na greatest(acq,0), ale Python NE: planning_engine.py:1163 terminal_soc_kcz_per_wh = avg_buy_terminal * terminal_factor / 1000 bez max(0,), objektiv :1928 - … * soc[T-1]. Při avg buy<0 v 24h → záporná terminal value → solver vybíjí na konci horizontu. Invariant „energie má kladnou hodnotu" i v sustained neg-buy (§16). Přidat clamp na avg_buy_terminal/terminal_soc_kcz_per_wh. Interakce s terminal_neg_buy_weight (cap 0.95, constants:82, heuristics.py:890): max(0, avg_buy*factor)max(0, avg_buy)*factor — pevný clamp na 0 může zrušit záměrné škálování faktoru v neg-buy. Effort spíš S→M (návrh interakce dvou §16 mechanismů). Clamp musí být ATOMICKY na všech místech (989-997, 1163, 710 _recompute) jinak solve≠audit (§8). Relevantní jen když 24h-průměr buy<0 (vzácné) — ověřit na fixture extreme_neg_buy (2026-05-01) + normální den.
Telemetry backoff per-gateway dedup alert Jeden WB (172.16.1.16) v backoffu blokuje čtení druhého na stejné bráně; tichý drift. EV nepojede na 15-20 min staré telemetrii bez upozornění. Dedup alert (1×/10 min/endpoint) + endpoint-level health do fn_health_detailed_db. Per-endpoint backoff i watchdog reg 19/20 ZACHOVAT (bezpečnostní).
CI: Flyway validate retry + timeout flyway validate proti sdílené prod DB padá na transient connection (2590eeb) → falešné negativy. Méně flaky CI. Timeout 10→30 s, retry 2× na connect-timeout v ci_flyway_validate_remote.sh. Retry jen na connect chyby — nezaměnit transient za skutečný migration bug.
CI duplicate-SHA guard Stejný SHA dev→main / prázdný commit → skip s combined status success, deploy se tiše neaplikuje (deployment.md §11). Konec „myslím že nasazeno, ale neběží". Step git rev-parse HEAD vs origin/main, error při shodě bez deploye. Re-trigger přes workflow_dispatch; doc v CLAUDE.md §Kadence.

3. Tier 2 — Střední (M)

Položka Co Hodnota První krok Co ohlídat
Samsung TČ Modbus zápis (reg 73/74) + verify větev write_heat_pump_setpoint (outputs.py:255-278) je stub (logger). HP NENÍ ve verify.py ani modbus_journal.py (grep prázdný) → celá nová verify větev, ne příloha. Design: tuv-control-design.md. Letní využití přebytků na ohřev + zimní dohřev v levných slotech; NZÚ RD compliance. Implementovat zápis → modbus_command journal; postavit vlastní HP verify cestu. Effort horní M / spodní L. Samsung = jiné zařízení (MIM-B19N): §18 FC 0x10 platí jen pro Deye 60-499 — ověřit vlastní FC Samsungu. NECPAT do DEYE_CRITICAL_REGS_SELF_SUSTAIN. Rozhodnout failsafe semantiku: mismatch TČ → SELF_SUSTAIN nedává smysl (spíš Discord + ponechat Samsung autonomní, analogicky výjimce hodin 62-64 §17). Špatný zápis = mráz/legionella, ne jen ekonomika.
Arbitráž: acquisition z okna, ne min(buy) charge_acquisition = vážený průměr N nejlevnějších slotů (home-01 nabíjí 2-4 h), ne jeden min(buy). Two-pass už existuje (planning_engine.py:705-720, _recompute :710). Korektní ekonomika baterie (+6-10 % GAP). Ověřit/dokončit vážení v _recompute_charge_acquisition_from_results; eval. §8: neúčtovat buy/sell téže kWh v jednom slotu; min(buy)≠cena nabití; SQL clamp greatest(acq,0) R__063:1177. Two-pass má ACQUISITION_TWO_PASS_EPS_KWH — agresivnější vážení může rozbít konvergenci → oscilace acq → nedeterministický plán. Ladit solver I audit současně. Golden gate.
Solver v2 výkon — méně binárek 2 ze 7 fixtures naráží na 10 s limit (SOLVER_TIME_LIMIT=10, constants:18); y_imp/z_exp/z_gen na všech slotech (solver_v2.py:155-158). Rolling replan <2 s spolehlivě, žádný fallback na v1 při daily 15:00. Profilovat. Redukovat binárky strukturálně (např. fyzikální nemožnost), NE podle ceny/forecastu. Redukce „jen sloty kde import/export reálně možný podle ceny" ZAVÁDÍ cenovou heuristiku do struktury LP = porušení v2 filozofie (§4) a může vynechat slot kde je export optimální. z_exp[t] drží §19 export reserve (soc≥arb_floor, :250), y_imp exkluzivitu. Při time-limit HiGHS vrátí suboptimum bez varování. Golden gate.
EUR/CZK kurz — ČNB denní fetch eur_czk_rate fixní 25.0 (config.py:31); v 36h horizontu EUR oscilace 1-2 %. Přesnější efektivní ceny OTE (drobný vstup — nižší dopad než forecast staleness). Denní fetch z ČNB API + cache + fallback na fixní. Jen vstupní parametr; fallback při výpadku API; golden gate.
Loxone heartbeat readback + alert EMS NEVÍ, že Loxone přepnul na SELF_SUSTAIN po výpadku → posílá AUTO setpointy, které Loxone ignoruje. EMS ví o desync; export se neztratí tiše. Job čte site_heartbeat.last_control_heartbeat_ts, po 5 min bez ACK → Discord INFO. §4 — NEMĚNIT watchdog logiku Loxone; jen čtecí/alert job.
Lehká observabilita (/metrics nebo rozšířený health) Žádný Prometheus//metrics/OTel (grep prázdný); jen /health + /health/detailed (main.py:113-131). Reaktivní alerty neukáží trend. Proaktivní signál: solve-time trend (v2 u 2 fixtures na 10s limitu), hloubka fronty modbus_command/signal_outbound_journal (pending), stáří telemetrie/forecastu. Rozšířit fn_health_detailed_db o pending counts + stáří forecastu/cen + poslední rolling_replan trvání/stav; volitelně /metrics. Read-only čtení; SQL-first (rozšíření fn, ne ad-hoc dotazy v Pythonu).
fn_plan_current_bundle výkon (3.8 s) 90 % času v fn_forecast_pv_slots_range_canonical_ab (audit 2026-06-11). #1 endpoint plánu. Rychlejší UI. LATERAL fix view (vzor FE perf memo); virtualizace tabulky. Stejné řádky/planning_interval; jen SQL refaktor.

4. Tier 3 — Velké sázky (L / vyžaduje rozhodnutí uživatele)

Položka Co Hodnota První krok Co ohlídat / co rozhodne uživatel
Bazén jako flexible_load v LP Shelly asset live (V087/V088), telemetrie + on/off signál; LP integrace návrh (pool-shelly.md §5+). ~1-4 kW. Filtrace v přebytkových/levných slotech místo noci za 4 Kč; ~100-200 Kč/měsíc. Asset jako flexible_load, constraint min X h/den, preference E_surplus. NEpřebít GFCI port sdílený s EV; Loxone fallback. Rozhodnout: min h/den, UI paradigma (open-q §32, blocker UI workshop).
Spirála TUV v LP (z_spiral[t]) Dnes jen Loxone signál (dump bez ceny). Kaskáda neg-sell (baterie→EV→TČ→spirála) je emergentní, ne řízená. +1-2 % v neg-sell dnech; cílený dohřev místo 1 kW dumpu. Binárka z_spiral podmíněná bilancí (neg-sell okno, SoC≥reserve), bez min-run. Loxone watchdog nesmí zůstat na spirále při výpadku. Rozhodnout: priorita vs TČ reg 74; NZÚ skepse k dohřevu bez COP.
Onboarding harness pro novou lokalitu Dnes ruční copy-paste SQL (new-site-setup-template.md §8) do Flyway migrace, bez validace (chybějící endpoint, špatný azimut, zapomenutý block_export). Bezchybný multi-site rollout (Fáze 2, open-q §69). Skript: z parametrů → migrace ze šablony + post-deploy ověření (endpoint reachable, telemetrie teče, forecast běží, první plán feasible). SQL-first; ověření nesmí psát do prod naslepo. Rozhodnout: kdy přijde 2. lokalita.
FastAPI write auth → plný RBAC + PostgREST RLS/JWT API-key gate (Tier 1) je dočasná záplata. ems_anon read-only na views bez RLS → vidí všechny sites. Bezpečnost před multi-user produkcí. RLS policy per site + JWT; GET /me/sites filtr. §2.2 — autorizační logika/RLS NESMÍ do Pythonu. Rozhodnout: kdy 2. tenant / externí přístup (jinak parkovat, ale Tier 1 API-key gate udělat hned).
pgbouncer connection pooling max_connections (deploy/docker-compose.yml:17 ${POSTGRES_MAX_CONNECTIONS:-100}) na slabém nočním serveru: skok na 250 = +~1.5 GB RAM (250×~10 MB) → OOM/swap riziko místo občasného timeoutu. Řeší „remaining connection slots" bez RAM nárůstu. Zavést pgbouncer; max_connections může zůstat nízko. Nešvihat tvrdě na 250 na slabém serveru. Pooling je správné řešení; mezitím ops-checklist: zvednout na 150-180 + sledovat pg_stat_activity a RAM.
Termo-flex blok (TČ + spirála + bazén) TČ reg 74 + spirála + bazén = jeden produktový balík „flexibilní zátěže". Konzistentní řízení flex zátěží. Pořadí: TČ zápis (Tier 2) → spirála → bazén. Žádná sezónní okna (v2 filozofie); každá zátěž opt-in per site config.
Export-constrained lokalita — curtailment-min use-case (TEST) Hypotetická lokalita: malý export limit (~4.5 kW), velký instal (~10 kW), konečná baterka. Otestovat, že MILP drží baterce rezervu na polední peak (ráno export na limitu + nabíjení zbytkem, baterka se plní pomalu) místo naivního „plná baterka ráno → v poledne se peak curtailuje". Přes kladné ceny: export limit + zbytek do baterky; přes záporné/peak: export off, vše do baterky + curtail zbytku. Ověření, že na export-omezených sitech minimalizujeme curtailment vs naivní Deye (méně „škoda na střeše"); připravenost na 2. typ lokality. Syntetický golden fixture (bell-curve PV >> export limit, konečná kapacita+rychlost baterky) + assert: Σ curtailment < naivní baseline a SoC nenajede na plno před peakem. Stojí a padá na kvalitě forecastu peaku (podstřel → málo rezervy → zbytečný curtail; viz PV forecast review — canonical rolling_factor/delta) → až po něm. Curtail nad (export+load+battery_charge_RATE) je fyzicky nevyhnutelný, ne bug. Reaktivní řez nechat na Deye (CT smyčka), EMS jen strategie (viz ems-not-realtime-inverter-battery-buffer). v2 filozofie (žádná sezónní okna).

5. Rozdělané k dotažení (půl hotové — chybí poslední krok)

Co Stav Chybí poslední krok
CI golden gate Test existuje (test_golden_replay.py), lokálně běží. Zařadit do .gitea/workflows/deploy.yml s PLANNING_ENGINE_VERSION=v2 (viz Tier 1).
7. EV+neg fixture home-01_2026-06-13_ev_neg_day.json existuje. Chybí baseline snapshot (snapshots/=6 vs fixtures/=7) → vygenerovat + ekonomický assert.
TČ Modbus zápis Telemetrie MIM-B19N live (V096/V101), design hotový, solver TUV look-ahead počítá. write_heat_pump_setpoint (outputs.py:274 stub) → reg 73/74 + celá nová verify větev (HP ve verify.py/modbus_journal.py chybí).
EV oportunismus z cen Flag target_soc_forecast_enabled zaveden; session bez deadline viditelná (BUG2 fix, R__038). Heuristika P50 nejlevnějších oken z market_price_stats místo konstanty 1 Kč/kWh. Za flagem → v1 netknut.
Bazén Asset, endpoint, telemetrie, čidlo, on/off signál live (V087-V092). LP model (výběr ON slotů).
Spirála TUV signal_def/signal_route infra (V085), Loxone dump funguje. LP binárka.
Reg 340 (max solar) DB sloty deye_reg340_max_solar_w + logika setpoints.py:143-167; není v critical regs (správně). Ověřit firmware limit na SUN-20K (V082, todo.md ř.67) — jinak možná mrtvý registr.
Externí CT reg 619 Doinstalován 2026-06-12 (V100), nová pole inverter_grid_port_w/ups_load_w. Baseline rebuild po týdnu dat (fn_rebuild); audit do 2026-06-12 nechat legacy.
WB2 + Chint elektroměr WB2 deaktivován (V105, reaktivace v SQL komentáři); Chint plánován unit 3. Fyzická instalace na majiteli (HW, mimo kód).
Evening-push override (v54-v55) Oprava Infeasible na relaxed retry v produkci. Robustnější test + finální doc (brittle stale_evening_push_override).

6. Rizika / „NErozbít"

  • CI golden gate (NEběží!). Nejzávažnější: golden gate je dnes lokální-only → ochrana solveru je v nasazení iluzorní. Dokud neběží v CI (s env v2), KAŽDÁ solver-touching změna může regrese nasadit tiše. Snapshoty neukládají verzi enginu; default je v1 (planning_engine.py:239).
  • v1 je STÁLE živý shadow peer (PLANNING_ENGINE_COMPARE_ENABLED) a sdílí constants.py s v2 (solver_v2.py:62). Nemazat penalty hromadněpenalty_audit Δ=0 je měřeno jen na v2 a jen na 7 fixtures (ne v1, ne edge dny mimo fixtures). Per-penalta grep v1 cesty + vědomá regenerace snapshotů. Hodnota „rychlejší v2" je navíc malá (mrtvé penalty obvykle nemají binárky → nezrychlí MILP). → spíš parkovat než Tier 2.
  • §6 — zákaz exportu při sell<0. Export-guard carve-out (521a365, setpoints.py:313) řeší false positive u nabíjení — carve-out jen pro pm=='CHARGE' nebo grid_sp>0 & bat_sp>0 (import). Žádná další úprava nesmí povolit reálný export při sell<0. Ověřit i na BA81/KV1 (block_export_on_negative_sell=true, V074).
  • §7 — buy<0 import cap. Záporná nákupní cena nesmí dělat „nekonečný" import (solve_dispatch).
  • §8 — arbitráž. Neúčtovat buy/sell téže kWh v jednom slotu; min(buy)≠cena nabití. Acquisition ≥ 0 (SQL greatest R__063:1177 + Python clamp na všech 3 místech atomicky). Two-pass konvergence (ACQUISITION_TWO_PASS_EPS_KWH) — agresivnější vážení může oscilovat. Solver i audit musí ladit.
  • §16/§19 — terminal SoC & export reserve. Shadow price ekonomická kotva ≥ 0; clamp musí být sladěn s terminal_neg_buy_weight (jinak se dva mechanismy perou). z_export drží soc ≥ arb_base_wh při exportu. Žádná predikovaná CENA do LP — forecast/price fallbacky jsou jen diagnostika/vstup, ne cena ve solveru.
  • §17/§18 — Modbus journal & FC 0x10. Nové TČ registry (73/74) přes journal + vlastní verify větev (HP ≠ Deye); FC 0x10 pravidlo §18 platí jen pro Deye 60-499 — Samsung ověřit zvlášť. Reg 15 už re-assert každý tick (54288ee) — nevracet na write-on-change. TČ mismatch → SELF_SUSTAIN NEDÁVÁ smysl.
  • FastAPI auth gate nesmí blokovat server-internal cesty (scheduler, lifespan, mismatch→SELF_SUSTAIN, fn_expire_modes) ani Loxone callback (§4.4). HTTP gate v Pythonu OK; autorizační logika/RLS mimo Python (§2.2).
  • Discord alerty bez dedup = spam. Dedup primitive NEEXISTUJE (discord_bot.py) — musí být ve stejném PR jako první alert, jinak rolling-fail loop (15 min) zaplaví kanál a alerty se začnou ignorovat.
  • TUV 60× fix mění chování VŠECH slotů s TČ, ne jen zimních. HARD constraints (solver_v2.py:354,356) → riziko nuceného ohřevu v drahých slotech i Infeasible v deep-neg-sell. tuv_delta_stats filtr abs<5/min = až 75°C/15min (R__018:100). Bez TČ/TUV fixture neimplementovat.
  • max_connections na slabém nočním serveru. 250×~10 MB = +1.5 GB → OOM/swap riziko. ${POSTGRES_MAX_CONNECTIONS:-100} je jen .env změna (ops-checklist, ne feature). Cíl 150-180 + pgbouncer, ne tvrdých 250.
  • Historická data NEPŘEPISOVAT. tuv_usage_stats (°C/min normalizace), audit_interval do 2026-06-12 (CT reg 619 legacy), forecast_pv_run/interval (§12), ev_arrival_stats (§14) — fix dopředně/filtrovaně.
  • Loxone watchdog = bezpečnostní feature. Žádný readback/alert job nesmí měnit autonomní fallback do SELF_SUSTAIN.
  • v2 filozofie. Ceny, ne heuristiky; žádná sezónní okna. Redukce binárek podle ceny = zakázaná heuristika ve struktuře LP. Nové penalty podezřelé (16/26 mrtvých).

7. Co dozraje časem (data/zima — jen sledovat)

  • Zimní termální cykly. Žádná vlastní zimní data (telemetrie od 3/2026); 2 zimy jen raw OTE. TUV delta fix (Tier 1) a TČ zápis (Tier 2) jsou klíčové AŽ s reálnými zimními daty — malé spready / žádné neg dny → TČ track rozhoduje. Neladit sezónně teď.
  • Současně buy<0 AND sell<0 v jednom horizontu. Home-01 viděl 1-2×; gray zone (§57+§59 interakce). Přidat invariant test až bude reálný fixture — neimplementovat naslepo.
  • Sustained neg-buy blok (24h-průměr buy<0). Vzácný; jediný kandidát extreme_neg_buy (2026-05-01). Bez fixtury s tímto profilem nelze terminal SoC clamp (Tier 1) bezpečně ověřit.
  • Tesla deadline drift +36h. Root cause neuzavřen (open-q), symptom ošetřen (03b7396: charge_limit = strop, ne cíl). Sledovat návrat.
  • Idle-skip 840 s heartbeat. Práh nevalidovaný proti reálnému poll intervalu; ovlivňuje TUV delta agregaci. Sledovat, neměnit dokud nevadí.
  • Clock drift reg 62-64. Discord-only bez auto SELF_SUSTAIN (§17 výjimka, záměr). Sledovat lidskou reakci.
  • PV pole B v auditu. Politika „neřízená výroba vs ignorovat" (open-q §59) — jen mix A+B; nízká frekvence. Rozhodnout až bude potřeba pro green-bonus výkaz.
  • OCPP vs Tesla REST. Tesla Fleet API běží živě; rozhodnutí protokolu lze odložit (obě cesty za flagem koexistují).
  • HP verify failsafe semantika. Až se reg 73/74 zapisuje: mismatch → co? (SELF_SUSTAIN nedává smysl; spíš Discord + Samsung autonomní, analogicky výjimce hodin 62-64 §17).

Poznámka k ověření: git log main..dev prázdný — export-guard carve-out (521a365) i reg15 re-assert (54288ee) jsou na main, ne „čekají v dev". Golden gate má fixtures/=7 ale snapshots/=6 (7. fixture bez baseline) a neběží v CI → „7 fixtures = tvrdá brána" je v nasazení iluzorní. CI golden enforcement (s env v2) je nový Tier 1 PŘED jakoukoli změnou solveru.