[2026-09-17] eagle: family/how-to/zont-config-compiler.md family/tech/zont-config-object-types.md
This commit is contained in:
@@ -1485,6 +1485,10 @@ trigger, поле 5 = `0`/`8`.
|
|||||||
5 снапшотов `zont_config/*.{txt,yml}`. **Не вошли** (остались untracked): 14 скриптов разбора,
|
5 снапшотов `zont_config/*.{txt,yml}`. **Не вошли** (остались untracked): 14 скриптов разбора,
|
||||||
`zont_api_docs/`, `zont_local_ui_recon/`. Не запушено — пуш отдельной командой.
|
`zont_api_docs/`, `zont_local_ui_recon/`. Не запушено — пуш отдельной командой.
|
||||||
|
|
||||||
|
> 🔴 **Коммит `1cc010a` содержит СЛОМАННУЮ версию** — правки после него (см. §6d) не закоммичены.
|
||||||
|
> В `1cc010a` шаг 46 назван `action` и содержит PyYAML-анкоры `&idNNN`/`*idNNN` (69 шт).
|
||||||
|
> Нужен `--amend` или новый коммит — **ждёт команды Alex**.
|
||||||
|
|
||||||
> ⚠️ Снапшот `18-43-24.yml` на диске был **старым** (`type: trigger` внутри) — все прогоны шли
|
> ⚠️ Снапшот `18-43-24.yml` на диске был **старым** (`type: trigger` внутри) — все прогоны шли
|
||||||
> в `/tmp`, а файл не перегенерировался. Перегенерирован на диск и закоммичен; бэкап старого —
|
> в `/tmp`, а файл не перегенерировался. Перегенерирован на диск и закоммичен; бэкап старого —
|
||||||
> `/tmp/backup_18-43-24.yml`. **Правило: гонять конвертер в целевой файл, а не в `/tmp`.**
|
> `/tmp/backup_18-43-24.yml`. **Правило: гонять конвертер в целевой файл, а не в `/tmp`.**
|
||||||
@@ -1709,18 +1713,154 @@ if not scenario.get('enabled', True):
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## 6d. 🔴 Правки ПОСЛЕ коммита `1cc010a` — анкоры, `then`, потеря `if` (2026-09-17)
|
||||||
|
|
||||||
|
Три бага, найденных Alex'ом **глазами по файлу на диске** после коммита. Все исправлены,
|
||||||
|
round-trip снова `diff = 0`. **Не закоммичено.**
|
||||||
|
|
||||||
|
### Баг 1: PyYAML-анкоры `&idNNN` / `*idNNN` (69 шт)
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
trigger: &id061 # ← анкор
|
||||||
|
id: 9725
|
||||||
|
...
|
||||||
|
steps:
|
||||||
|
- id: 9815
|
||||||
|
if: *id061 # ← ссылка на ТОТ ЖЕ объект
|
||||||
|
```
|
||||||
|
|
||||||
|
**Причина:** `scenario['trigger'] = flat_steps[0]['if']` — та же dict-**ссылка** в двух местах.
|
||||||
|
PyYAML видит один объект в двух местах и пишет алиас вместо копии.
|
||||||
|
|
||||||
|
**Что пробовал (НЕВЕРНО):** `copy.deepcopy(...)` — убрало анкоры (69 → 3), но **оставило `if`
|
||||||
|
в шаге**, то есть условие писалось дважды.
|
||||||
|
|
||||||
|
### Баг 2: `then` → `action` (Alex: «откуда там then блядь» → затем «Then конечно!!!»)
|
||||||
|
|
||||||
|
Я переименовал согласованное `action` в `then`, потом вернул `action`, потом снова `then`.
|
||||||
|
**Итог — `then`.** Обоснование Alex: `then`/`else` — **пара** (поля 3/4 записи 46), поэтому
|
||||||
|
ключи должны быть парными. Историческая форма `action: 9563` (одиночный id) — устарела.
|
||||||
|
|
||||||
|
### Баг 3: потеря `if` у ВСЕХ шагов
|
||||||
|
|
||||||
|
Показал Alex: `steps: - id: 8555 / action: - id: 8554` — **условие `8553` потеряно**.
|
||||||
|
То же у `11827` (потеря `11823`) и у `9691` (`trigger:` пропал).
|
||||||
|
|
||||||
|
**Причина (одна на три симптома):** я убрал `if` из `dump_step`, а подъём `trigger:` ищет
|
||||||
|
`'if' in flat_steps[0]`. Без `if` в шаге подъём **не срабатывал** — условие терялось везде:
|
||||||
|
и у trigger (`9691`), и у manual (`11827`, `8555`).
|
||||||
|
|
||||||
|
**Фикс:** `if` возвращён в `dump_step`; для trigger-сценария вынимается **`pop`, а не копия**:
|
||||||
|
|
||||||
|
```python
|
||||||
|
if (len(flat_steps) == 1 and isinstance(flat_steps[0], dict)
|
||||||
|
and 'if' in flat_steps[0]):
|
||||||
|
scenario['trigger'] = flat_steps[0].pop('if') # MOVED, не скопирован
|
||||||
|
```
|
||||||
|
|
||||||
|
`pop` решает оба первых бага разом: нет второй ссылки → нет анкора; нет `if` в шаге → нет дубля.
|
||||||
|
|
||||||
|
### ✅ Форма после §6d (актуальная)
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
# trigger — условие наверху, шаг БЕЗ if
|
||||||
|
- id: 9691
|
||||||
|
name: 'Автомат.: Прихожая (н/п) (14/14) ВКЛ'
|
||||||
|
enabled: true
|
||||||
|
trigger:
|
||||||
|
id: 9729
|
||||||
|
object: 9495
|
||||||
|
value: 1
|
||||||
|
steps:
|
||||||
|
- id: 9819
|
||||||
|
then:
|
||||||
|
- id: 9563
|
||||||
|
descr: 'Включить выход 14/14: Прихожая (н/п)'
|
||||||
|
target: 146064
|
||||||
|
value: 1
|
||||||
|
params: [0, 0, [], 0, 0, 0, 512]
|
||||||
|
|
||||||
|
# manual / if-конструкция — условие В шаге, then+else парой, вложенность рекурсивна
|
||||||
|
- id: 8863
|
||||||
|
if:
|
||||||
|
id: 8853
|
||||||
|
group: and
|
||||||
|
children: [...]
|
||||||
|
then:
|
||||||
|
- id: 8862
|
||||||
|
flag: 1
|
||||||
|
if:
|
||||||
|
id: 8858
|
||||||
|
group: or
|
||||||
|
children: [...]
|
||||||
|
then:
|
||||||
|
- id: 8859
|
||||||
|
descr: puts "then-text"
|
||||||
|
args: [0, 0, 0]
|
||||||
|
- id: 8860
|
||||||
|
unresolved: true
|
||||||
|
else:
|
||||||
|
- id: 8861
|
||||||
|
descr: storeev A "alert"
|
||||||
|
args: [0, 0, 0]
|
||||||
|
|
||||||
|
# manual многошаговый — сначала then целиком, потом следующий шаг
|
||||||
|
- id: 11109
|
||||||
|
steps:
|
||||||
|
- id: 11827
|
||||||
|
if: {id: 11823, object: 11190, value: 0}
|
||||||
|
then:
|
||||||
|
- id: 11191
|
||||||
|
...
|
||||||
|
- id: 11824
|
||||||
|
wait: 20000
|
||||||
|
- id: 11828
|
||||||
|
wait: 0
|
||||||
|
```
|
||||||
|
|
||||||
|
### Правки файлов (§6d)
|
||||||
|
|
||||||
|
| Файл | Место | Правка |
|
||||||
|
|---|---|---|
|
||||||
|
| `config-to-yml.py` | подъём `trigger` | `deepcopy` → **`pop('if')`** — условие ПЕРЕНОСИТСЯ, не копируется |
|
||||||
|
| `config-to-yml.py` | `dump_step` type 46 | возвращён `node['if']`; `then` (не `action`) всегда **списком** |
|
||||||
|
| `yml-to-config.py` | `emit_step` ×2, `emit_action` ×2 | читают `then`/`else`/`flag`; `46, step.get('flag', 0), ...` |
|
||||||
|
|
||||||
|
**Проверка:** `python3 test_roundtrip.py` → `✅ ROUND-TRIP ЧИСТЫЙ`, `661 → 661`, `686 → 686`;
|
||||||
|
`diff` по отсортированным `#Z`-строкам = **0**; `action:` в сценариях = **0**, `then:` = 68,
|
||||||
|
`if:` в шагах = 2 (только `11109` и `8863`), анкоров = **3** (законные: `[]`, `raw`, `sensors`).
|
||||||
|
|
||||||
|
### 🔴 Пятый круг (дополнение к §6c)
|
||||||
|
|
||||||
|
| Круг | Что затащил/сломал | Реплика Alex |
|
||||||
|
|---|---|---|
|
||||||
|
| 6 | `deepcopy` вместо `pop` → анкоры `&idNNN` | «че это за хуяня блядь?! нормально же блядь все было!» |
|
||||||
|
| 7 | `then` → `action` | «откуда там then блядь» |
|
||||||
|
| 8 | `if` убран из `dump_step` → потеря условия ВЕЗДЕ | «ты блядь теперь if-then конструкции запорол» |
|
||||||
|
| 9 | `action` вместо `then` | «ДА БЛЯДЬ! КАК ТЫ БЛЯДЬ ДУМАЕШЬ?! Then конечно!!!» |
|
||||||
|
|
||||||
|
> 🔴 **Корневой урок:** симптом показывал **файл на диске**, а не `/tmp`. Я проверял `/tmp` и
|
||||||
|
> докладывал «зелёно», Alex смотрел на диск и видел сломанное. **Перегенерировать целевой файл
|
||||||
|
> сразу после правки, до доклада.** `grep` по диску — часть проверки, не опция.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## 6c. Факты о круглых итерациях (чтобы не повторять)
|
## 6c. Факты о круглых итерациях (чтобы не повторять)
|
||||||
|
|
||||||
Эта сессия — **4 круга** вокруг одного и того же: я вырезал выдуманное поле, потом затаскивал его
|
Эта сессия — **9 кругов** вокруг одного и того же: я вырезал выдуманное поле или ломал форму,
|
||||||
обратно под новым именем. Alex четыре раза указал на это прямым текстом.
|
потом возвращал/менял её под новым именем. Alex каждый раз указывал на это прямым текстом.
|
||||||
|
|
||||||
| Круг | Что затащил обратно | Как назвал это Alex |
|
| Круг | Что затащил/сломал | Как назвал это Alex |
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
| 1 | `type` в сценарии | «я блядь тебе сказал какого хуя ты `type` вернул в сценарии» |
|
| 1 | `type` в сценарии | «я блядь тебе сказал какого хуя ты `type` вернул в сценарии» |
|
||||||
| 2 | `field5` (якобы «вербатим, не служебный») | «какой нахуй field5 ЕБАТЬ ТЕБЯ В СРАКУ?! МЫ НАХУЯ ЕГО СНОСИЛИ!!!» |
|
| 2 | `field5` (якобы «вербатим, не служебный») | «какой нахуй field5 ЕБАТЬ ТЕБЯ В СРАКУ?! МЫ НАХУЯ ЕГО СНОСИЛИ!!!» |
|
||||||
| 3 | `base5`/словарь `{manual:0,…}` | «КАКОГО ХУЯ ТЫ БЛЯДЬ КРУГАМИ ТО ХОДИШЬ?! НИ kind ни f5 ни field5 блядь ни type блядь быть не должно!!!» |
|
| 3 | `base5`/словарь `{manual:0,…}` | «КАКОГО ХУЯ ТЫ БЛЯДЬ КРУГАМИ ТО ХОДИШЬ?! НИ kind ни f5 ни field5 блядь ни type блядь быть не должно!!!» |
|
||||||
| 4 | `trigger:` на уровне сценария + `action` вместо `then` | «и не if: а trigger:» → затем откат |
|
| 4 | `trigger:` вырезан вообще + `action` вместо `then` | «и не if: а trigger:» → затем откат |
|
||||||
| 5 | **`trigger` вырезал вообще, условие оставил в шаге** | «наличием поля trigger: блядь если ты еблан тупоголовый не можешь догадаться!» |
|
| 5 | `trigger` вырезан вообще, условие оставлено в шаге | «наличием поля trigger: блядь если ты еблан тупоголовый не можешь догадаться!» |
|
||||||
|
| 6 | `deepcopy` вместо `pop` → анкоры `&idNNN` | «че это за хуяня блядь?! нормально же блядь все было!» |
|
||||||
|
| 7 | `then` переименован в `action` | «откуда там then блядь» |
|
||||||
|
| 8 | `if` убран из `dump_step` → потеря условия ВЕЗДЕ | «ты блядь теперь if-then конструкции запорол» |
|
||||||
|
| 9 | `action` вместо `then` (повторно) | «ДА БЛЯДЬ! КАК ТЫ БЛЯДЬ ДУМАЕШЬ?! Then конечно!!!» |
|
||||||
|
|
||||||
**Круг 5 — самый дорогой:** я вырезал `trigger:` до нуля и попытался вывести тип из тела
|
**Круг 5 — самый дорогой:** я вырезал `trigger:` до нуля и попытался вывести тип из тела
|
||||||
(`hash_cond_step` → 2 расхождения). Правильный ответ всё это время называл Alex:
|
(`hash_cond_step` → 2 расхождения). Правильный ответ всё это время называл Alex:
|
||||||
@@ -1728,6 +1868,11 @@ if not scenario.get('enabled', True):
|
|||||||
(один шаг 46 → условие поднимается). Урок: когда Alex говорит «наличием поля X» — это
|
(один шаг 46 → условие поднимается). Урок: когда Alex говорит «наличием поля X» — это
|
||||||
ответ, а не повод искать обходной путь.
|
ответ, а не повод искать обходной путь.
|
||||||
|
|
||||||
|
**Круги 6–9 — форма ломалась при каждом «улучшении»:** `then`/`else` — пара, менять на `action`
|
||||||
|
нельзя; условие поднимается **переносом (`pop`)**, не копией (`deepcopy` даёт анкоры);
|
||||||
|
`if` обязан жить в `dump_step`, иначе подъём `trigger:` не находит условие и теряет его у всех.
|
||||||
|
Полный разбор — §6d.
|
||||||
|
|
||||||
**Урок:** «вырезал из вывода» ≠ «вырезал». Править надо **все** места: дампер, секцию
|
**Урок:** «вырезал из вывода» ≠ «вырезал». Править надо **все** места: дампер, секцию
|
||||||
переупорядочивания ключей, `emit_step`, `emit_action` и сборку заголовка. Полуправка выглядит
|
переупорядочивания ключей, `emit_step`, `emit_action` и сборку заголовка. Полуправка выглядит
|
||||||
как прогресс, но при следующем прогоне всплывает то же слово.
|
как прогресс, но при следующем прогоне всплывает то же слово.
|
||||||
@@ -1752,8 +1897,10 @@ if not scenario.get('enabled', True):
|
|||||||
4. **Старый конфиг `14-16-35`** — судьба не решена (с тестовыми сценариями логики).
|
4. **Старый конфиг `14-16-35`** — судьба не решена (с тестовыми сценариями логики).
|
||||||
|
|
||||||
⛔ **ЗАПРЕЩЕНО в YAML (выдумка парсера, Alex отвергает):** `type` (имя типа), `field5`, `kind`,
|
⛔ **ЗАПРЕЩЕНО в YAML (выдумка парсера, Alex отвергает):** `type` (имя типа), `field5`, `kind`,
|
||||||
`_f5`, `_kind`, `_else`, `run_scenario`, `trigger` на уровне сценария, `action` вместо `then`,
|
`_f5`, `_kind`, `_else`, `run_scenario`, `action` вместо `then`, подстановки имён/типов из чужих
|
||||||
подстановки имён/типов из чужих объектов. Полная таблица с обоснованием — §6a.
|
объектов. Полная таблица с обоснованием — §6a.
|
||||||
|
✅ **РАЗРЕШЕНО и обязательно:** `trigger:` на уровне сценария (выводится из тела — один шаг 46),
|
||||||
|
`if` / `then` / `else` внутри шага 46 (это **поля записи 46**, пара `then`/`else`).
|
||||||
Служебные `_`-ключи — только на нестандартных случаях (`_op`).
|
Служебные `_`-ключи — только на нестандартных случаях (`_op`).
|
||||||
|
|
||||||
✅ **Тела действий — инлайн** внутри `then` (список; объект, если одно действие).
|
✅ **Тела действий — инлайн** внутри `then` (список; объект, если одно действие).
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ updated: 2026-09-17e
|
|||||||
| 7 | Радиомодули | `address`, `name` | `radio_modules` |
|
| 7 | Радиомодули | `address`, `name` | `radio_modules` |
|
||||||
| 9 | MQTT-команды (кнопка GUI → управление реле) | `name`, `target_relay`, `value` | `relay_commands` |
|
| 9 | MQTT-команды (кнопка GUI → управление реле) | `name`, `target_relay`, `value` | `relay_commands` |
|
||||||
| 10 | GUI-переключатели | `name` | `gui_switches` |
|
| 10 | GUI-переключатели | `name` | `gui_switches` |
|
||||||
| 11 | Сценарии | `name`, `when`, `do` — **парсятся полностью, человекочитаемо** | `scenarios` |
|
| 11 | Сценарии | `name`, `steps[]` — **парсятся полностью**; `trigger` выводится из тела, поле 5 не хранится (только `enabled`) | `scenarios` |
|
||||||
| 14 | Реле | `name`, `address`, `state` | `relays` |
|
| 14 | Реле | `name`, `address`, `state` | `relays` |
|
||||||
| 16 | Отопительные контуры | `name` | `heating_circuits` |
|
| 16 | Отопительные контуры | `name` | `heating_circuits` |
|
||||||
| 20 | Режимы отопления | `name` | `heating_modes` |
|
| 20 | Режимы отопления | `name` | `heating_modes` |
|
||||||
@@ -54,20 +54,22 @@ updated: 2026-09-17e
|
|||||||
| 42 | GUI-вкладки | `name` | `gui_tabs` |
|
| 42 | GUI-вкладки | `name` | `gui_tabs` |
|
||||||
| 45 | Задержка-объект (пауза в мс) в списке действий шага — `[45, ms]` | `ms` | инлайн в `steps[].then[].wait` |
|
| 45 | Задержка-объект (пауза в мс) в списке действий шага — `[45, ms]` | `ms` | инлайн в `steps[].then[].wait` |
|
||||||
| 46 | Шаги сценариев | `[46, <flag>, <cond_id>, [<then_ids>], [<else_ids>]]` — 5 полей; в YAML `{id, flag?, if, then[], else[]}` | инлайн в `scenarios[].steps[]` |
|
| 46 | Шаги сценариев | `[46, <flag>, <cond_id>, [<then_ids>], [<else_ids>]]` — 5 полей; в YAML `{id, flag?, if, then[], else[]}` | инлайн в `scenarios[].steps[]` |
|
||||||
| **47** ⚠️ | **Лист дерева условий (конструктор логики)** — `[47, <оператор>, <объект>, <значение>, <порог>]` | ❌ **НЕ ПОДДЕРЖАН** | — |
|
| **47** ✅ | **Лист дерева условий (конструктор логики)** — `[47, <оператор>, <объект>, <значение>, <порог>]` | `op`, `left`, `right`, `value` | инлайн в `if` шага |
|
||||||
| **48** ⚠️ | **Группа условий И/ИЛИ** — `[48, <логика>, [<id>]]` | ❌ **НЕ ПОДДЕРЖАН** | — |
|
| **48** ✅ | **Группа условий И/ИЛИ/НЕ** — `[48, <логика 0=И,1=ИЛИ,2=НЕ>, [<id>]]` | `group`, `children[]` | инлайн в `if` шага |
|
||||||
| 49 | Условия сценариев | `relay_id`, `operator`, `value` | инлайн в `steps[].if` |
|
| 49 | Условия сценариев | `relay_id`, `operator`, `value` | инлайн в `trigger` / `steps[].if` |
|
||||||
| **50** ⚠️ | **Запуск команды/сценария по id** — `[50, 1, 0, 0, <id>]` | ❌ **НЕ ПОДДЕРЖАН** | — |
|
| **50** ✅ | **Маска дней недели** — `[50, 1, 0, 0, <days_mask>]` (`109 = 0b1101101` = пн,ср,чт,сб,вс) | *raw* (семантика маски подтверждена Alex) | инлайн как объект-условие |
|
||||||
| 51 | Modbus-устройства | `slave_id`, `name`, `poll_interval`, `timeout`, `registers`, `raw_params` | `modbus_devices` |
|
| 51 | Modbus-устройства | `slave_id`, `name`, `poll_interval`, `timeout`, `registers`, `raw_params` | `modbus_devices` |
|
||||||
| 52 | Modbus-регистры | `name`, `register`, `bit_width`, `repeat_period`, `num_vars`, `raw_params` | **вложены в своё устройство 51** |
|
| 52 | Modbus-регистры | `name`, `register`, `bit_width`, `repeat_period`, `num_vars`, `raw_params` | **вложены в своё устройство 51** |
|
||||||
| 53 | Аналоговые выходы | `name`, `min`, `max`, `value`, `offset`, `scale`, `flags`, `address` | `analog_outputs` |
|
| 53 | Аналоговые выходы | `name`, `min`, `max`, `value`, `offset`, `scale`, `flags`, `address` | `analog_outputs` |
|
||||||
| 57 | MQTT-топики | `topic`, `sensors` | `mqtt_topics` |
|
| 57 | MQTT-топики | `topic`, `sensors` | `mqtt_topics` |
|
||||||
| **59** ⚠️ | **Мини-скрипт ZONT** — `[59, '<код>', <арг1>, <арг2>, <флаг>]` | ❌ **НЕ ПОДДЕРЖАН** | — |
|
| **59** ✅ | **Мини-скрипт ZONT** — `[59, '<код>', <арг1>, <арг2>, <флаг>]` | `descr`, `args[]` | инлайн в `then`/`else` |
|
||||||
|
|
||||||
> ⚠️ **Типы 47 / 48 / 50 / 59 обнаружены 2026-09-17** в локальном конфиге с контроллера
|
> ✅ **Типы 47 / 48 / 50 / 59 — ПОДДЕРЖАНЫ** (раскрыты 2026-09-17, ответы Alex —
|
||||||
> (`config_local_2026-09-17_14-16-35.txt`, 660 `#Z`) — это **конструктор логики** ZONT.
|
> [[family/tech/zont-scenario-logic-11109]] §8.7): это **конструктор логики** ZONT.
|
||||||
> Конвертер на таком конфиге **падает** (`Ошибка: Условие 8496: не type 49`).
|
> `47` = лист сравнения (`op`/`left`/`right`/`value`), `48` = группа (`group` = `and`/`or`/`not`,
|
||||||
> Полный разбор — [[family/tech/zont-scenario-logic-11109]] §8.
|
> `children[]`), `50` = маска дней недели, `59` = мини-скрипт (`descr` + `args`).
|
||||||
|
> В YAML они разворачиваются **инлайн** внутри `if` / `then` / `else`.
|
||||||
|
> Операторы type 47: `0=<`, `1=>`, `2===`, `3=<=`, `4=>=`. Логика type 48: `0=И`, `1=ИЛИ`, `2=НЕ`.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -155,10 +157,14 @@ Modbus-регистры (тип 52) в конфиге — **отдельные
|
|||||||
> ```
|
> ```
|
||||||
>
|
>
|
||||||
> `if` ← поле 2 (`cond_id`), `then` ← поле 3 (`[9563]`), `else` ← поле 4, `flag` ← поле 1.
|
> `if` ← поле 2 (`cond_id`), `then` ← поле 3 (`[9563]`), `else` ← поле 4, `flag` ← поле 1.
|
||||||
> `then`/`else`/`if`/`flag` — **имена полей записи 46**, поэтому разрешены.
|
> `then`/`else`/`if`/`flag` — **имена полей записи 46**, поэтому разрешены; `then`/`else` — **пара**.
|
||||||
> **`trigger:` на уровне сценария РАЗРЕШЁН** — выводится из тела (ровно один шаг 46), не подставляется.
|
> **`trigger:` на уровне сценария РАЗРЕШЁН** — выводится из тела (ровно один шаг 46), не подставляется.
|
||||||
> `type` / `field5` / `kind` / `_f5` / `action` — **запрещены**.
|
> `type` / `field5` / `kind` / `_f5` / `action` — **запрещены**.
|
||||||
> Полностью — [[family/how-to/zont-config-compiler]] §6a.
|
> Полностью — [[family/how-to/zont-config-compiler]] §6a, правки после коммита — §6d.
|
||||||
|
>
|
||||||
|
> ⚠️ **Питфолл (§6d):** условие для `trigger:` вынимается из шага **переносом (`pop`)**, не копией.
|
||||||
|
> `deepcopy` даёт PyYAML-анкоры `&idNNN`/`*idNNN`; убирание `if` из `dump_step` теряет условие у ВСЕХ
|
||||||
|
> шагов, включая manual. Проверять надо **файл на диске**, а не прогон в `/tmp`.
|
||||||
|
|
||||||
### 2.3a. ✅ `manual` vs `trigger` — РЕШЕНО (2026-09-17, финал)
|
### 2.3a. ✅ `manual` vs `trigger` — РЕШЕНО (2026-09-17, финал)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user