diff --git a/personal/projects/zont-config-compiler.md b/personal/projects/zont-config-compiler.md index e424a28b..dd21188f 100644 --- a/personal/projects/zont-config-compiler.md +++ b/personal/projects/zont-config-compiler.md @@ -3688,7 +3688,7 @@ Alex отверг форму `objcmd: <имя>` («и почему objcmd: set_s **Инструмент:** правки энкодера внесены идемпотентным скриптом `/tmp/fix_encoder_objcmd.py` (6 замен с проверкой `count == 1`, печатает OK/SKIP) — не sed, не инлайн-питон в шелле. -### 26.6. ⏳ СЛЕДУЮЩЕЕ — тип 9 в ту же форму («имя действия — ключ») +### 26.6. ✅ ВЫПОЛНЕНО (круг 46, коммит `75f46f3`) — тип 9 в форме «имя действия — ключ» Запрос Alex в конце круга 45: привести тип 9 (`relay_commands`) к тому же виду, что `set_var`. @@ -3707,8 +3707,43 @@ Alex отверг форму `objcmd: <имя>` («и почему objcmd: set_s Ключ надо выводить **из значения** (`true`/`false` → вкл/выкл, число → сетпойнт). `descr` при этом **обязан остаться внутри** — иначе 45 подписей исчезнут из YAML. -**Ждём от Alex:** имя ключа (`set_relay` / `set_output` / `relay_cmd`) и подтверждение, что `descr` -остаётся полем. Форма типа 9 — последний незакрытый пункт формы. +#### 🔴 Ключевое открытие: `set_contour_target` ≠ `set_contour_temp` + +Alex: *«`8817` и `10379` — разные objcmd форматы (установить целевую температуру x для контура y +против установить целевую температуру для контура отопления x в значение y)»*. + +| id | тип | строка | ключ | значение | смысл | +|---|---|---|---|---|---| +| `8817` | **9** | `#Z8817=9,'descr',10034,'2782'` | `set_contour_target` | `5.2` (число) | уставка ЧИСЛОМ | +| `10379` | **59** | `#Z10379=59,'objcmd 8669 ",,,%0";#h',9146,0,0` | `set_contour_temp` | `{id: 9146, type: var}` | значение ИСТОЧНИКОМ | + +**Раньше оба действия носили одно имя** `set_contour_temp` → непонятно, какое из двух имеется +в виду, и тексты команд схлопывались. Два разных действия = два разных имени, ключи не пересекаются: + +- **тип 9** (команда, поле 4 — уставка/код): `set_relay` · `set_contour_target` · `activate_mode` +- **тип 59** objcmd (поле 3 — объект-источник либо литерал): `set_sensor` · `set_analog_output` · `set_contour_temp` + +#### Формула Кельвина — ТОЛЬКО при цели типа 16 + +Различие целей внутри типа 9: `2782` у контура (16) — уставка `5.2 °C`, а `8574` у режима (20) — +это **id режима отопления**, не температура. Раньше формула применялась ко всем числам >1000, +и `activate_mode` с `8574` превращался в `584.4 °C`. Правка: декодировать только когда +`_tgt_type == 16` **и** значение не является id объекта типа 20. + +**Три места, где это чинилось (питфолл «две точки входа»):** +1. `dump_step` (ветка тип 9 в шаге сценария); +2. секция `relay_commands` (свой обход `Z`, своя копия логики); +3. `_build_type9_line` в энкодере — читает тело **через `_action9_in`**, а не с плоского узла. + +#### Устранение дубля id `8817` + +`8817` — единственный тип 9, который лежит **и** в сценарии (шагом), **и** объектом в секции. +Оба эмитили строку → validation: `Duplicate ID 8817`. Плюс тело `set_contour_target` перехватывалось +веткой objcmd (одно имя!) и собиралось как `#Z8817=59,'objcmd 10034 ",,,%0";#h',...`. + +Лечение: ключи разведены (`set_contour_target` отсутствует в `_OBJCMD_MASKS`) — конфликт снят. +`_register_action9` возвращает управление, если запись с таким id **уже пришла из YAML-секции**: +шаг ссылается на объект, тело живёт в секции (одна строка на один id). ### 26.5. 🔴 ПИТФОЛЛ 92 — форма согласована ≠ в код внесена @@ -3719,3 +3754,64 @@ Alex третий раз видел `args` у `objcmd` при том, что ф --- +## 27. ✅ Круг 46 (2026-09-18) — `set_contour_target`, Кельвин, дубль `8817` + +**HEAD после круга: `75f46f3`.** Круг **9/9 зелёный, 759 → 759**, YAML валиден. + +### 27.1. Что сделано + +1. **`set_contour_target` (тип 9) отделён от `set_contour_temp` (objcmd тип 59)** — два разных + действия, два имени, ключи не пересекаются. +2. **Кельвин только при цели типа 16** и только если значение не id объекта типа 20. +3. **Секция `relay_commands` получила ключ действия** — читается так же, как шаг сценария. +4. **`_build_type9_line` читает тело через `_action9_in`**, а не с плоского узла. +5. **Дубль id `8817` устранён** — `_register_action9` уступает, если id уже пришёл из секции. + +### 27.2. Итоговые формы (проверены в артефакте) + +```yaml +relay_commands: +- id: 8470 + activate_mode: # значение = id режима, НЕ температура + descr: Активировать режим отопления Режим отопления для Контур ГВС + target: 8669 + value: '8574' +- id: 8817 + set_contour_target: # тип 9: уставка ЧИСЛОМ + descr: Установить целевую температуру 5.2 для контура Спальня + target: 10034 + value: 5.2 +``` + +```yaml + - id: 10379 + set_contour_temp: # тип 59 objcmd: значение ИСТОЧНИКОМ + target: 8669 + value: {id: 9146, type: var} + - id: 10381 + set_contour_temp: + target: 9339 + value: {id: 10380, type: objstate, object: 9841} +``` + +### 27.3. 🔴 ПИТФОЛЛ 96 — одно имя на два разных действия = схлопывание текстов команд + +Оба действия звались `set_contour_temp`. Ветка objcmd перехватывала тело типа 9, и `8817` +собирался как `#Z8817=59,'objcmd 10034 ",,,%0";#h',5.2,0,1` вместо `#Z8817=9,'...',10034,'2782'`. +**Признак той же природы, что питфоллы 92–95:** форма живёт в двух словарях — сверять пересечение +имён ключей при каждом переименовании (`_ACTION9_KEYS` ∩ `_OBJCMD_MASKS`). + +### 27.4. 🔴 ПИТФОЛЛ 97 — артефакт-`.yml` в репо ≠ свежий вывод + +`zont_config/*.yml` в репо — это **выход прошлого прогона**, он же вход для круга. Пока не +перегенерён, он показывает старую форму (тут: плоскую секцию `relay_commands` и Кельвин в `8470`). +**Порядок приёмки:** гнать декодер в ЦЕЛЕВОЙ файл (`> zont_config/<имя>.yml`), затем открывать +глазами. `test_roundtrip.py` пишет в temp и целевой артефакт не обновляет. + +### 27.5. Открыто на после круга 46 + +- 5 `objcmd`-орфанов (`8669`, `8382`, `11907` и др.) — форма не согласована; +- поле 4 = `2` у `expr` (`10077`–`10085`) — имени нет; +- авто-id (`_resolve_id` + аллокатор `max+1`, 17 точек) — план есть, код не написан; +- push `75f46f3` в Gitea — по команде. +