Files
obsidian-vault/family/tech/zont-scenario-logic-11109.md
T

227 lines
14 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.
# 8.17. ✅ МОДЕЛЬ ЗАКРЫТА (2026-09-17, финал) — поле 5, форма сценария, type 47/49
> **Статус:** все открытые вопросы §8.16 закрыты. Ниже — подтверждённые факты.
> Таблица `TRIGGER_KINDS` **удалена из кода**; доказательство получено **тостингом 5 сценариев
> в UI**: Alex выключил и снова включил каждый тестовый сценарий, поле 5 снято до и после.
## (а) 🔴 Поле 5 типа 11 = тип запуска + флаг «выключен». ПОДТВЕРЖДЕНО тостингом
```text
kind = field5 & 7 # 0 = ручной/расписание, 1 = триггер, 2 = интервал
enabled = not (field5 & 8) # бит 8 = сценарий ВЫКЛЮЧЕН
```
| Сценарий | Выкл | Вкл | `kind` | Прочие поля |
|---|---|---|---|---|
| `8456` «Простой тестовый» | `8` | `0` | 0 | — |
| `8597` «по расписанию» | `8` | `0` | 0 | поля 3/4 = `61`, `3354` |
| `8547` «по времени» | `9` | `1` | 1 | — |
| `8551` «по триггеру» | `9` | `1` | 1 | — |
| `9628` «Автомат.: Рад. ванная 2эт ВКЛ» | `9` | `1` | 1 | — |
| `8599` «по интервалу» | `10` | `2` | 2 | поле 6 = `43200000` мс |
**Почему старая модель `{0:manual,1:manual,8:schedule,9:trigger,10:interval}` была неверна:**
она читала число как «класс запуска» целиком. На самом деле число **двухбитовое по смыслу**:
младшие 3 бита = тип, бит `8` = выключено. Отсюда все противоречия §8.16:
`9628` с `1` — триггерный (бит 8 не стоит, kind = 1), `8456` с `8` — ручной, но выключенный.
> ⚠️ **Ручной (0) и расписание (0) — один и тот же `kind`.** Различаются **наличием полей 3/4**
> (`days_mask` + `time`): у расписания они заполнены, у ручного — нули.
> Кодировку расписания см. §8.1 (`61` = ПН,СР,ЧТ,ПТ,СБ; `3354` = `(13<<8)|26` = 13:26).
**Что в коде:** `TRIGGER_KINDS`, `_raw_trigger_kind`, `_raw_trigger_params`, `time_raw` **удалены**.
Заголовок сценария в YAML теперь: `enabled`, `_f5` (поле 5 целиком), `_kind` (только если
`f5 & 7 ≠ 0`), `days_mask`, `time`, `interval_ms`.
> ⚠️ **Обновлено после правок формы:** `kind`/`kind_raw` из видимой части **убраны** — это тоже
> была выдумка (слова `kind` в конфиге нет). Всё, что нужно энкодеру, лежит в служебных
> `_f5`/`_kind` с подчёркиванием.
## (б) Форма YAML сценария — ПЕРЕСМОТРЕНА Alex'ом (финал сессии)
Alex отверг `if`/`then`/`else` в YAML как **выдумку**:
> «у тебя в `9819` сейчас в yml написан `if`! а это не `if` а **триггер**»
Проверка конфига подтвердила: слов `if`, `then`, `else`, `condition`, `object`, `operator`, `group`,
`op` **в конфиге нет**. Это была интерпретация парсера поверх данных.
**Корневое требование:** `trigger` — это **триггер**, а не `if`; `steps` — это **шаги**, а не ветвление.
### Согласованная форма (принята Alex)
```yaml
- id: 9691
name: 'Автомат.: Прихожая (н/п) (14/14) ВКЛ'
enabled: true
trigger:
- id: 9729
object: '9495'
value: 1
steps:
- id: 9819
action: 9563
```
### Соответствие строкам конфига — `#Z9691` «Прихожая (н/п) 14/14 ВКЛ»
```text
#Z9691=11,'Автомат.: Прихожая (н/п) (14/14) ВКЛ',[9819],0,0,1,0,0
#Z9819=46,0,9729,[9563],[] ← шаг: условие 9729, действие 9563
#Z9729=49,9495,1,1 ← триггер: объект 9495, значение 1
#Z9495=14,'Датч 14/14: Прихожая (н/п)',151408,0
#Z9563=5,'Включить выход 14/14: Прихожая (н/п)',146064,1,0,0,[],0,0,0,512
```
| YAML | Строка конфига | Поля |
|---|---|---|
| `id: 9691`, `name` | `#Z9691=11,…` | 1, 2 |
| `enabled: true` | `#Z9691` поле 5 = `1` | `not (1 & 8)` |
| `trigger[].id: 9729` | `#Z9729=49,…` | 1 (id самого условия) |
| `trigger[].object: '9495'` | `#Z9729` | 2 (id объекта, на который смотрит триггер) |
| `trigger[].value: 1` | `#Z9729` | 4 (значение; поле 3 = оператор) |
| `steps[].id: 9819` | `#Z9819=46,…` | 1 (id шага) |
| `steps[].action: 9563` | `#Z9819` | 4 (первый id из `[9563]`) |
| тело действия | `#Z9563=5,'…',146064,1,…` | живёт своей строкой |
### Терминология Alex — точная
| Id | Что это по Alex | Где в YAML |
|---|---|---|
| `9691` | **сценарий** | `id` верхнего уровня |
| `9729` | **триггер** (не `if`!) | `trigger[].id` |
| `9495` | объект, за которым следит триггер | `trigger[].object` |
| `9819` | **шаг** (`if of the step` по формулировке Alex) | `steps[].id` |
| `9563` | **действие** — «выполнить пользовательское действие» | `steps[].action` |
> Alex: «`#Z9563=5,…` — это шаг «выполнить пользовательское действие» (action) `9563`».
### Единая модель вложенных id
Разница между `trigger` и `steps` — только в том, какое поле `#Z9819` (тип 46) на них указывает:
```text
#Z9819 = 46, 0, 9729, [9563], []
│ │
│ └── steps[].action ← поле 4 (список действий)
└───────── trigger[].id ← поле 3 (условие)
```
`object` выбран словом для ссылки на объект, потому что **в остальном коде уже так**
(`dump_condition` для type 49: `'object': node[1]`), рядом с `target` (реле/контур) и `descr`.
### Следствия для кода — ✅ ПУНКТЫ 1–3, 5 СДЕЛАНЫ (2026-09-17)
| # | Что | Статус |
|---|---|---|
| 1 | `dump_condition` type 49 → `{id, object, value}` вместо `{id, condition: {object, operator, value}}` | ✅ сделано |
| 2 | `dump_step` type 46 → `{id, trigger: <условие>, action: <первый then id>}`, без `if`/`then`/`else` | ✅ сделано |
| 3 | Заголовок сценария — `kind`/`kind_raw` убраны в служебные `_kind`/`_f5` | ✅ сделано |
| 4 | Непустые `then`/`else` / второй+ id → что писать в форме | 🔴 **открытый вопрос, ждёт Alex** |
| 5 | `dump_action` — делегирование в `dump_step` (чтобы type 5/9 в телах не падали в `raw`) | ✅ сделано (было раньше) |
| 6 | Энкодер под новую форму | ⏸ не начат — ждёт подтверждения формы |
### ✅ Фактический вывод парсера после правок (проверено 2026-09-17)
Перегенерация `zont_config/config_local_2026-09-17_17-45-00.yml` (exit 0, 4405 строк — было 5376):
```yaml
- id: 9691
name: 'Автомат.: Прихожая (н/п) (14/14) ВКЛ'
enabled: true
_kind: 1
_f5: 1
steps:
- id: 9819
trigger:
id: 9729
object: 9495
value: 1
action: 9563
```
`if`/`then`/`else`/`condition`/`operator` из YAML ушли полностью. Три служебных ключа
(`_kind`, `_f5`, `_op`) содержат то, что энкодеру нужно для байт-в-байт сборки:
`_op` пишется **только когда оператор ≠ 1**; `_kind` — только когда `field5 & 7 ≠ 0`; `_f5` — всегда.
**Многошаговый `11109` — форма подтвердила проблему:**
```yaml
- id: 11109
name: Передернуть Автомат Котельной
enabled: true
_f5: 0
steps:
- id: 11827
trigger:
id: 11823
object: 11190
value: 0
action: 11191
_then:
- 11191
- 11030
- 11824
- 11029
- 11825
- 11192
- 11826
- id: 11828
wait: 0
```
🔴 **Это и есть открытый вопрос №4.** У `11109` в `then` семь id — цепочка, а не одно действие.
`action: 11191` показывает только первое, остальные шесть ушли в служебный `_then`. Для 11109
`_then`**не служебный ключ, а реальное содержимое**. Форма «один триггер → одно действие»
описывает 64 из 65 сценариев; 11109 из неё выпадает. Ждём решения Alex: `action` остаётся
одиночным, а цепочка — отдельная тема, или появляется `actions:`. **Правка кода остановлена
на этом вопросе, энкодер не тронут.**
## (в) Методология: почему форма переделывалась дважды
1. **`blocks`/`extra_links`** — отвергнуто: порядок терялся, сценарий превращался в список цифр.
2. **`when`/`then` + `if`/`group`/`op`** — отвергнуто как **выдумка**: слов нет в конфиге.
3. **`trigger`/`steps` + `action`** — принято (эта форма).
> 🔴 **Правило, выведенное из трёх итераций:** в YAML попадают **только слова, которые есть
> в конфиге или в UI**. `object` — есть (здесь так называется ссылка), `descr`/`target`/`value` —
> есть (поля строки). `if`/`then`/`condition`/`operator`/`group`/`op`/`kind` — **нельзя**:
> их в данных нет, это интерпретация.
> 🔴 **Второе правило:** `descr` ставить только там, где текст **реально есть в строке**.
> Для `#Z9819` (шаг) текста нет — значит и `descr` у него быть не должно (Alex: «нахуй там тогда
> descr?! если его нет в оригинале?»).
> ⚠️ **Не забегать вперёд с вопросами о том, чего в кейсе нет.** Вопрос «что писать, когда
> в `trigger` окажется type 47» Alex воспринял как шум («что за type 47? нихуя не понятно») —
> в разбираемом сценарии его нет. Сначала форма на текущем кейсе, потом обобщение.
## (г) Состояние на конец сессии (обновлено 2026-09-17, после правок кода)
| Что | Статус |
|---|---|
| Форма YAML сценария | ✅ согласована (см. (б)) |
| Правка `config-to-yml.py` под форму | ✅ **сделана** — 3 патча (`dump_condition` type 49, `dump_step` type 46, заголовок) |
| YAML перегенерирован | ✅ `config_local_2026-09-17_17-45-00.yml`**4405 строк** (было 5376), `if`/`then` ушли |
| Проверка формы глазами | ✅ блок `9691` и `11109` прочитаны |
| Round-trip | ⏸ **не прогнан** после правок формы (энкодер ещё не подогнан — прогон осмыслен только после пункта 6) |
| Многошаговые сценарии (`11109`) в форме | 🔴 **открытый вопрос №4** — ждёт Alex |
| Энкодер под новую форму | ⏸ не начат |
| `git commit` | ⏸ не закоммичено, ждёт команды |
**Артефакты:**
- `zont_config/config_local_2026-09-17_17-45-00.yml` — актуальный, **перегенерирован** под новую форму (4405 строк)
- `/tmp/backup-174500.yml` — бэкап предыдущей генерации (5376 строк, форма со старым `if`/`then`)
> ⚠️ **Питфолл, найденный в этой сессии:** `config-to-yml.py` пишет YAML **в stdout**, а не в файл.
> `main()` не принимает пути вывода (`sys.argv` = только входной `.txt`). Первый прогон
> `python3 config-to-yml.py f.txt -o /tmp/x.yml` **молча проигнорировал `-o`** — скрипт напечатал
> «Использование: zont_to_yaml.py <config.txt>» и `exit 1`, а YAML остался **старым**. Из-за этого
> первый просмотр блока 9691 показал неисправленную форму и выглядел как «патч не сработал».
> **Правильный вызов:** редирект в файл — `python3 config-to-yml.py in.txt > out.yml`, и всегда
> проверять `exit=` и размер целевого файла.
> ⚠️ **Питфолл (продолжение):** `grep -n "id: 9691"` по YAML находит **несколько** совпадений
> (объект живёт и в своей секции, и внутри сценария). Номер строки в старом файле (4877) и в новом
> (3932) различается — индексировать по первому совпадению нельзя, надо смотреть окрестности.