Add export plan guard to block Deye export against plan.
Some checks failed
CI and deploy / migration-check (push) Failing after 39s
CI and deploy / deploy (push) Has been skipped

Force PASSIVE/no-export when sell is negative or export_mode is NONE,
and alert NEG_SELL_EXPORT in plan_actual_slot_guard when export still occurs.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Dusan Vojacek
2026-05-29 00:14:52 +02:00
parent 620a557a89
commit a7dff75e58
8 changed files with 230 additions and 4 deletions

View File

@@ -58,6 +58,21 @@ Ověření: logy backendu kolem pokusu **nebo** `select id,status,created_at fro
---
## Exekuční pojistky exportu (AUTO)
Po `_build_setpoints`, před zápisem Modbus (`orchestrator.export_setpoints`):
| Guard | Podmínka | Efekt |
|-------|----------|--------|
| **`_apply_export_plan_guard`** | `effective_sell_price < 0` **nebo** (`export_mode = NONE` a `grid_setpoint_w ≥ 0`) | PASSIVE, `export_ban`, `grid_export_limit = 0`, vybíjení baterie do sítě vynulováno (`battery_w = max(0, …)`), `deye_physical_mode = PASSIVE` |
| **`_apply_price_failsafe_guard`** | `is_predicted_price = true` | PASSIVE, všechny výkonové setpointy 0, žádný export |
Implementace: `backend/services/control/setpoints.py`. Ověření: `pytest backend/tests/test_control_export_plan_guard.py`.
**Poznámka:** PV B (nekontrolovatelné pole) může při záporné vykupní stále fyzicky exportovat — pojistka řídí Deye (baterie + řízené FVE A), ne mikroinvertory na GEN bez cut-off.
---
## Logika exportu
```python

View File

@@ -60,7 +60,7 @@ pro **reg 178** (spolu s peak shaving bity 45).
| Job | Frekvence | Popis |
|-----|-----------|--------|
| `verify_modbus` | každé **2 min** | Pro každou aktivní site vybere `written` příkazy s `written_at` v posledních **20 min** a zavolá `verify_modbus_commands`. |
| `plan_actual_slot_guard` | **:05, :20, :35, :50** (po `audit_filler`) | `ems.fn_plan_actual_slot_guard_all_active` (+ `plan_actual_slot_guard.py` jen Discord): poslední 2 uzavřené 15min sloty — fatální odchylka **plán vs. audit síť****Discord** (`critical`), dedup přes `ems.plan_fatal_deviation_sent`. |
| `plan_actual_slot_guard` | **:05, :20, :35, :50** (po `audit_filler`) | `ems.fn_plan_actual_slot_guard_all_active` (+ `plan_actual_slot_guard.py` jen Discord): poslední 2 uzavřené 15min sloty — fatální odchylka **plán vs. audit síť****Discord** (`critical`), dedup přes `ems.plan_fatal_deviation_sent`. Kódy: `GRID_SIGN_MISMATCH`, `GRID_EXPORT_SPIKE`, **`NEG_SELL_EXPORT`** (`sell < 0` a skutečný vývoz &lt; 4 kW), `GRID_LARGE_DEVIATION`, … Exekuční pojistka proti opakovanému vývozu: [`control.md`](control.md) — `_apply_export_plan_guard`. |
Plná tabulka jobů je v [`lifespan.py`](../../backend/app/lifespan.py).

View File

@@ -5,6 +5,16 @@ Formát: **datum (ISO)** · stručný důvod · soubory · chování / ověřen
---
## 2026-05-29 — Exekuční pojistka exportu (Plan 3)
**Problém:** Plán `export_mode = NONE` nebo záporná vykupní, ale Deye zůstává v **SELL** → skutečný vývoz ~12 kW (zpoždění přepnutí režimu).
**Změna:** `_apply_export_plan_guard` v `setpoints.py` (volá `orchestrator.export_setpoints` před `_apply_price_failsafe_guard`): při `sell < 0` nebo (`export_mode = NONE` a `grid_setpoint_w ≥ 0`) vynutí PASSIVE, `export_ban`, `grid_export_limit = 0`, vynulování vybíjení v plánu (`battery_w ≥ 0`). SQL guard **`NEG_SELL_EXPORT`** v `R__076_fn_plan_actual_slot_guard.sql` (`sell < 0` a vývoz &lt; 4 kW).
**Soubory:** `backend/services/control/setpoints.py`, `orchestrator.py`, `db/routines/R__076_fn_plan_actual_slot_guard.sql`, `backend/tests/test_control_export_plan_guard.py`, `docs/04-modules/control.md`, `docs/04-modules/modbus-command-journal.md`.
**Ověření:** `pytest backend/tests/test_control_export_plan_guard.py`; po incidentu Discord s `reason_code = NEG_SELL_EXPORT`.
## 2026-05-28 — Dokumentace strategie sell&lt;0 + termika + bazén
**Soubor:** [`docs/04-modules/planning-neg-sell-strategy.md`](04-modules/planning-neg-sell-strategy.md) — cíle, slovník, časová osa dne, v32v35, návrh v36+, TČ/TUV podle typu dne, bazén, UI curtail/reg 340, roadmap, SQL ověření.