[2026-09-17] eagle: personal/projects/zont-config-compiler.md
This commit is contained in:
@@ -3,7 +3,7 @@ title: ⚙️ ZONT Config Compiler — конвертеры .txt ⇄ .yml
|
|||||||
namespace: personal
|
namespace: personal
|
||||||
type: how-to
|
type: how-to
|
||||||
created: '2026-09-17'
|
created: '2026-09-17'
|
||||||
updated: '2026-09-17k'
|
updated: '2026-09-17m'
|
||||||
tags:
|
tags:
|
||||||
- personal
|
- personal
|
||||||
- zont
|
- zont
|
||||||
@@ -1837,6 +1837,13 @@ rm -rf zont_config/_wip
|
|||||||
| 44 | 🔴 **Коммит после первого зелёного круга, а не «когда Алекс скажет»** | Правило «коммит только по команде» не отменяет **промежуточных** коммитов ради сохранности. Формулировка для будущего: зелёный круг → коммит WIP-ветки, команда нужна для `push` |
|
| 44 | 🔴 **Коммит после первого зелёного круга, а не «когда Алекс скажет»** | Правило «коммит только по команде» не отменяет **промежуточных** коммитов ради сохранности. Формулировка для будущего: зелёный круг → коммит WIP-ветки, команда нужна для `push` |
|
||||||
| 45 | 🔴 **Не спрашивать «что делать» после того, как сам сломал, если план уже ясен** | Alex: «ЧТО ТЫ БЛЯДЬ ОПЯТЬ ОТ МЕНЯ ХОЧЕШЬ ЗАЕБАЛ». У него ответа нет — восстановление на ассистенте |
|
| 45 | 🔴 **Не спрашивать «что делать» после того, как сам сломал, если план уже ясен** | Alex: «ЧТО ТЫ БЛЯДЬ ОПЯТЬ ОТ МЕНЯ ХОЧЕШЬ ЗАЕБАЛ». У него ответа нет — восстановление на ассистенте |
|
||||||
| 46 | 🔴 **При поиске потерянного — сначала `git fsck --lost-found`, `git stash list`, потом доклад** | Объявить потерю, не проверив все источники, — ложная тревога. Проверять: dangling-блобы, stash, `rev-list --all --objects`, бэкап-папки |
|
| 46 | 🔴 **При поиске потерянного — сначала `git fsck --lost-found`, `git stash list`, потом доклад** | Объявить потерю, не проверив все источники, — ложная тревога. Проверять: dangling-блобы, stash, `rev-list --all --objects`, бэкап-папки |
|
||||||
|
| 47 | 🔴 **`session_search` НЕ индексирует Zulip** | Поиск по `set_var`/`9963` вернул **0** при существующем треде на 3380 сообщений. При «читай тред» / «ищи в базе» — **сразу `docker exec zulip-database-1 psql`**, не `session_search`. См. skill `zulip-db-forensics` |
|
||||||
|
| 48 | 🔴 **Правки проверять в ЦЕЛЕВОМ файле, а не в `/tmp`** | Повтор питфолла 5/34: круг гонялся в `/tmp/final.yml`, а на диске `zont_config/*.yml` остался от прошлой генерации → Alex видел `type: var`, которого в коде **уже нет**. Проверка: `grep -c '<ключ>' <целевой файл>` + `ls -la` mtime |
|
||||||
|
| 49 | 🔴 **Ключ, добавленный для ОДНОЙ формы, не должен появляться у остальных** | `args` расширен ради формы 2 (`42,0,1`) → повис на **53** записях с мусорным `[0,0]` (круг 33). Правило: `if any(tail)` — писать только ненулевое |
|
||||||
|
| 50 | 🔴 **Новый разбор, дублирующий принятую форму, обязан её ЗАМЕНИТЬ, а не сосуществовать** | `type: var` вытеснила `set_var` (круг 29) — две формы для одного смысла, новая перебила принятую. Alex: «где блядь `set_var`». Проверять порядок веток в **обеих** точках входа (`emit_action` + инлайн `emit_step`) |
|
||||||
|
| 51 | 🔴 **`elif` по типу цели недостижим — различать по НАЛИЧИЮ объекта** | `#Z9964=59,'set varname',42,0,1`: `42` — `int`, заходил в объектную ветку, объекта нет → падал в `descr`+`args`. Различать `target in Z_dict`, не `isinstance` |
|
||||||
|
| 52 | 🔴 **Тело цели разворачивать на месте РОДИТЕЛЯ, но собирать ЕГО строкой** | Родитель несёт `target: <id>`, тело живёт своей строкой под тем же id. Попытка встроить тело в родителя без id ломает обратную сборку (на этом упал потерянный подход, §10.8) |
|
||||||
|
| 53 | 🔴 **`_body_type` обходить ВЕСЬ YAML, включая вложенные секции** | Плоский обход верхнего уровня не находит объекты в `executors.*` (напр. `9263`) → `unknown event 'on' for object 9263 (type None)`. Нужен рекурсивный `_collect_ids` |
|
||||||
|
|
||||||
> 📌 **Корень аварии — процессный, не технический.** Работа шла **кругами** (34 круга формы),
|
> 📌 **Корень аварии — процессный, не технический.** Работа шла **кругами** (34 круга формы),
|
||||||
> каждый круг переписывал предыдущий, и **ни один не фиксировался**. При таком режиме любая
|
> каждый круг переписывал предыдущий, и **ни один не фиксировался**. При таком режиме любая
|
||||||
@@ -1846,14 +1853,95 @@ rm -rf zont_config/_wip
|
|||||||
> которых в YAML не было. Правильная реакция — **сказать «эта форма не собирается обратно»**
|
> которых в YAML не было. Правильная реакция — **сказать «эта форма не собирается обратно»**
|
||||||
> и вернуть `target` в запись, а не изобретать `_target_row()`.
|
> и вернуть `target` в запись, а не изобретать `_target_row()`.
|
||||||
|
|
||||||
|
### 10.9. ✅ ВОССТАНОВЛЕНО 2026-09-17 (продолжение сессии) — код написан заново
|
||||||
|
|
||||||
|
> ✅ **Статус: развёртывание РЕАЛИЗОВАНО заново** поверх `b75c51f`. `set_var` (4 формы),
|
||||||
|
> `param`/`event` (тип 49), `op`/`time`/`days_mask` (тип 50), тела 59 (`objstate`/`expr`/
|
||||||
|
> `const`/`var`) — **в рабочей копии, НЕ закоммичено**. Круг `21-13-18` → `749 → 749`,
|
||||||
|
> строк `774 → 774`, **остаётся 1 расхождение**: `#Z9964` теряет поле 4.
|
||||||
|
|
||||||
|
**Как восстанавливали.** Источник — **Zulip-база**, тред `personal / ZONT Config compiler`
|
||||||
|
(3380 сообщений). Рабочий отрезок `15:15–15:37` (msg `105060`–`105486`) содержит полный
|
||||||
|
хронологический лог кругов 27–34: что за форма, где сломалась, какая реплика Alex.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker exec zulip-database-1 psql -U zulip zulip -c "
|
||||||
|
SELECT m.id, m.date_sent, up.full_name as sender, LEFT(m.content, 900) as content
|
||||||
|
FROM zerver_message m
|
||||||
|
JOIN zerver_recipient r ON m.recipient_id = r.id
|
||||||
|
JOIN zerver_stream s ON r.type_id = s.id
|
||||||
|
JOIN zerver_userprofile up ON m.sender_id = up.id
|
||||||
|
WHERE r.type = 2 AND s.name = 'personal' AND m.subject = 'ZONT Config compiler'
|
||||||
|
AND m.date_sent >= '2026-09-17 15:15:00'
|
||||||
|
ORDER BY m.date_sent;"
|
||||||
|
```
|
||||||
|
|
||||||
|
> 🔴 **Питфолл 47: `session_search` НЕ находит Zulip-тред.** Он индексирует Hermes-сессии
|
||||||
|
> (`.jsonl`), а не Zulip. Поиск по `set_var`/`9963` вернул **0 результатов**, хотя тред
|
||||||
|
> существовал и был полон. **При «читай тред» / «ищи в базе» — сразу `docker exec psql`,
|
||||||
|
> не `session_search`.** (См. skill `zulip-db-forensics`.)
|
||||||
|
|
||||||
|
**Что написано заново** (`config-to-yml.py` ‖ `yml-to-config.py`):
|
||||||
|
|
||||||
|
| Добавлено | Где | Что делает |
|
||||||
|
|---|---|---|
|
||||||
|
| `_script_value(oid)` | парсер, внутри `build_yaml` | тело 59 → `{type: objstate\|expr\|const\|var, …}`; незнакомое → None |
|
||||||
|
| `_set_var_target_body(target)` | парсер | объект 49 → `{type: param, object, event\|param}`; 50 → `{type: time_condition, op, time}` \| `{type: days_mask, days}` |
|
||||||
|
| `_parse_script_raw(row)` | энкодер | обратный разбор `raw`-строки 59 (для объектов из `raw`-секций) |
|
||||||
|
| `_script_value_row(node, aid)` | энкодер | собрать строку 59 из полей; `const`→`'N ;#p'`, `expr`→`'expr "%0 + %1"'`, `objstate`→`'objstate N 0 0'`, `var`→`'set <имя>'` + `tail` |
|
||||||
|
| `_set_var_target_row(sv, aid)` | энкодер | 49/50 из полей; `event`/`param` → код по типу владельца |
|
||||||
|
| `_set_var_body(node, aid)` | энкодер | `set_var` → строка 59 + регистрация тела цели своей строкой |
|
||||||
|
| `_body_type(obj_id)` + `_collect_ids` | энкодер | id → тип по всем секциям YAML (включая вложенные `executors.*`) |
|
||||||
|
| `PARAM_CODES` / `COND_EVENTS` / `_COND_EVENT_GROUP` / `_OP_NAMES` | парсер, внутри `build_yaml` | справочники (см. §10.6) |
|
||||||
|
| `_PARAM_TO_CODE` / `_EVENT_TO_CODE` / `_EVENT_GROUP` / `_OP_TO_CODE` / `_SEC_TYPE` | энкодер | обратные справочники + карта секция→тип |
|
||||||
|
|
||||||
|
**Ключевое отличие от потерянной версии.** Развёрнутое тело цели **не заменяет** шаг-родитель:
|
||||||
|
родитель несёт `target: <id>`, а тело живёт **своей строкой** под тем же id. Отсюда требование
|
||||||
|
восстановить id — то, на чём упал прежний подход (§10.8). Решение: `target` **остаётся в YAML**
|
||||||
|
как явный ключ, из него энкодер и берёт id.
|
||||||
|
|
||||||
|
**Три бага, найденных при прогоне:**
|
||||||
|
|
||||||
|
| # | Симптом | Причина | Фикс |
|
||||||
|
|---|---|---|---|
|
||||||
|
| A | `unknown event 'on' for object 9263 (type None)` | `_body_type` искал только в секциях верхнего уровня; `9263` лежит в `executors` | `_collect_ids` — рекурсивный обход всего YAML |
|
||||||
|
| B | `set_var needs 'value'…got {…'value': 2}` | ветка «цель-число» стояла **до** ветки «цель-сама-set» | переставлен порядок: `_script_value_row` → затем `var`+`value` |
|
||||||
|
| C | `id:` уезжал **в конец** записи | `parsed['id'] = step_id` в конце словаря | словарь пересобирается с `id` первым ключом |
|
||||||
|
|
||||||
|
**Остаточный дефект (не закрыт).** `#Z9964=59,'set varname',42,0,1` → собирается `42,0,0`
|
||||||
|
(теряется поле 4). `9964` **есть в `steps` сценария 8456** с корректным
|
||||||
|
`set_var: {name: varname, value: 42, args: [0, 1]}` (проверено `yaml.safe_load`), но в
|
||||||
|
`lines` из steps не попадает — управление до ветки `'set_var' in step` в `emit_step` не доходит,
|
||||||
|
и строка собирается из другого места без `args`.
|
||||||
|
**Следующий шаг:** отладка в `emit_step` — печатать, доходит ли управление до `'set_var' in step`
|
||||||
|
для `9964`, и откуда берётся `42,0,0`.
|
||||||
|
|
||||||
|
> 📌 **Форма, которая читается** (проверено глазами, `grep` по сгенерированному YAML):
|
||||||
|
> ```yaml
|
||||||
|
> - id: 9961
|
||||||
|
> set_var: {name: var1, type: param, object: 8560, param: target_temp, id: 9960}
|
||||||
|
> - id: 9963
|
||||||
|
> set_var: {name: varname, target: 9962, type: const, value: 2}
|
||||||
|
> - id: 9964
|
||||||
|
> set_var: {name: varname, value: 42, args: [0, 1]}
|
||||||
|
> - id: 9968
|
||||||
|
> set_var: {name: varname, target: 9967, type: expr, expr: '%0 + %1', args: [9965, 9966]}
|
||||||
|
> - id: 9974
|
||||||
|
> set_var: {name: varname, target: 8472, var: var1, value: 0}
|
||||||
|
> ```
|
||||||
|
> `type: var` (круг 29, вытеснявшая `set_var`) — **0 вхождений**. `set_var:` — 53.
|
||||||
|
|
||||||
|
> ✅ **`zont_config/config_local_2026-09-17_21-13-18.yml` ПЕРЕГЕНЕРИРОВАН** в целевой файл
|
||||||
|
> (не в `/tmp` — питфолл 34/5). Круг `18-43-24` → `661 → 661` ✅ (не затронут).
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 11. Файлы проекта
|
## 11. Файлы проекта
|
||||||
|
|
||||||
| Файл | Статус |
|
| Файл | Статус |
|
||||||
|---|---|
|
|---|---|
|
||||||
| `config-to-yml.py` | ✅ форма §5: `trigger:` подъём через `pop('if')`, шаг = `{id, [flag], action}` или `{id, [flag], if, then, [else]}` — **это и есть состояние `b75c51f`, единственное рабочее** · ⛔ **развёртывание тела 59 (`set_var`/`storeenv`/`log`/`expr`), объекта 50 (`op`/`time`/`days_mask`) и объекта 49 (`param`/`event`) — ПОТЕРЯНО** (§10.8) |
|
| `config-to-yml.py` | ✅ форма §5 (`trigger:` подъём через `pop('if')`, шаг = `{id, [flag], action}` или `{id, [flag], if, then, [else]}`) **плюс** развёртывание тел (§10.9): `_script_value`, `_set_var_target_body`, `_target_set_name`, `PARAM_CODES`/`COND_EVENTS`/`_OP_NAMES`, разворот орфанов-59 · ⚠️ **не закоммичено** |
|
||||||
| `yml-to-config.py` | ✅ `emit_step` читает `then`/`action`/`else`/`flag`; `f5` из `trigger:`/`interval_ms` + бит 8 — состояние `b75c51f` · ⛔ **`_script_body()`/`set_var`/`storeenv`/`CMP_CODES`/`PARAM_CODES` — ПОТЕРЯНЫ** (§10.8) |
|
| `yml-to-config.py` | ✅ `emit_step` читает `then`/`action`/`else`/`flag`; `f5` из `trigger:`/`interval_ms` + бит 8 **плюс** сборка тел (§10.9): `_parse_script_raw`, `_script_value_row`, `_set_var_target_row`, `_set_var_body`, `_body_type`/`_collect_ids`, `_PARAM_TO_CODE`/`_EVENT_TO_CODE`/`_OP_TO_CODE`/`_SEC_TYPE` · ⚠️ **не закоммичено**, 1 расхождение (`#Z9964`) |
|
||||||
| `test_roundtrip.py` | ✅ без изменений (в коммите `199f2b1`) · ✅ **оба круга зелёные после восстановления** |
|
| `test_roundtrip.py` | ✅ без изменений (в коммите `199f2b1`) · ✅ **оба круга зелёные после восстановления** |
|
||||||
| `zont_config/config_local_2026-09-17_21-13-18.{txt,yml}` | 🆕 **актуальный рабочий снимок** (774 строки, 749 `#Z`) — «Простой тестовый сценарий» `#Z8456` содержит шаги `9925…9990`, `Values test` `#Z9324` не изменился. Круг ✅ `774 → 774`, различий **0** |
|
| `zont_config/config_local_2026-09-17_21-13-18.{txt,yml}` | 🆕 **актуальный рабочий снимок** (774 строки, 749 `#Z`) — «Простой тестовый сценарий» `#Z8456` содержит шаги `9925…9990`, `Values test` `#Z9324` не изменился. Круг ✅ `774 → 774`, различий **0** |
|
||||||
| `zont_config/config_local_2026-09-17_18-43-24.{txt,yml}` | ↩️ **ВОССТАНОВЛЕН 2026-09-17** из `b75c51f` после ошибочной чистки. Форма `trigger:` + `action:` — 66/66. Круг ✅ `661 → 661` |
|
| `zont_config/config_local_2026-09-17_18-43-24.{txt,yml}` | ↩️ **ВОССТАНОВЛЕН 2026-09-17** из `b75c51f` после ошибочной чистки. Форма `trigger:` + `action:` — 66/66. Круг ✅ `661 → 661` |
|
||||||
@@ -1861,10 +1949,12 @@ rm -rf zont_config/_wip
|
|||||||
| `zont_config/archive/` | `-2`/`-3`/`-4` — закоммичены (`7ae0e32`) |
|
| `zont_config/archive/` | `-2`/`-3`/`-4` — закоммичены (`7ae0e32`) |
|
||||||
|
|
||||||
> 📌 **Состояние на 2026-09-17, конец сессии.** HEAD = `b75c51f`, не запушен.
|
> 📌 **Состояние на 2026-09-17, конец сессии.** HEAD = `b75c51f`, не запушен.
|
||||||
> Оба конвертера — **в состоянии `b75c51f`**, рабочая копия чистая.
|
> Рабочая копия **содержит восстановленное развёртывание тел** (§10.9) — **не закоммичено**.
|
||||||
> Развёртывание тел мини-скриптов и условий (`set_var`, `param`, `event`, `op`/`time`/`days_mask`,
|
> Развёртывание тел мини-скриптов и условий (`set_var`, `param`, `event`, `op`/`time`/`days_mask`,
|
||||||
> `expr`/`objstate`/`const`) **существует только в описании** (§10.1–§10.7) — кода нет, делать заново.
|
> `expr`/`objstate`/`const`) — **в коде, работает**, остаётся **1 расхождение** по `#Z9964` (поле 4).
|
||||||
> Круг зелёный на обоих снимках: `21-13-18` → `774 → 774`, `18-43-24` → `661 → 661`.
|
> 🔴 **Первым делом следующей сессии — закоммитить** рабочую копию (питфолл 41/44: незакоммиченная
|
||||||
|
> работа уже терялась один раз).
|
||||||
|
> Круги: `21-13-18` → `749 → 749` / строк `774 → 774` (1 расхождение), `18-43-24` → `661 → 661` ✅.
|
||||||
|
|
||||||
|
|
||||||
> ⛔ **`_f2` / `_f5` — МУСОРНЫЕ КЛЮЧИ, удалены из кода (круг 26).** В `config-to-yml.py` был блок
|
> ⛔ **`_f2` / `_f5` — МУСОРНЫЕ КЛЮЧИ, удалены из кода (круг 26).** В `config-to-yml.py` был блок
|
||||||
|
|||||||
Reference in New Issue
Block a user