diff --git a/personal/projects/zont-config-compiler.md b/personal/projects/zont-config-compiler.md index 9ffdcec8..201cfcc7 100644 --- a/personal/projects/zont-config-compiler.md +++ b/personal/projects/zont-config-compiler.md @@ -2976,14 +2976,15 @@ Alex прочитал `git show --stat ba6ef44` (2 файла, 10 строк) и | # | Что | Кто должен решить | |---|---|---| -| 1 | ✅ Смысл `unresolved` назван — **конец сценария** (§20.2.1). Осталось **одно слово**: имя пометки `end` ‖ `terminal` ‖ `finish` ‖ оставить голый id | **Alex** (вопрос задан) | -| 2 | Имя хвоста `args: [0, 1]` у `#Z10069` (§15.2) — открыто с круга 32 | **Alex** | -| 3 | Форма `objcmd` (`9925`/`9929`/`9931`/`9948`, `10033`/`10036`) — держит 5 орфанов | форма не согласована (§13 п.2) | -| 4 | Поле 4 = `2` у `expr` (`10077`–`10085`) — имя не дано | форма не согласована | -| 5 | Push в Gitea — 7 коммитов не запушены | по команде Alex | +| 1 | ✅ **ЗАКРЫТО** — смысл `unresolved` = конец сценария, ключ переименован в **`end`** (§21.1) | — | +| 2 | 🔴 **`steps` триггер-сценария**: убрать `- id: 8550 / action: 8549`, тело действия — прямо в `steps`. **Куда девается id шага `8550`?** Три попытки откачены (§21.3) | **Alex** — назвать форму | +| 3 | ✅ **ЗАКРЫТО формально** — `objcmd` разобран: `descr` + `args` + `target` (`10029`/`10033`/`10036`/`10053`) | — | +| 4 | Имя хвоста `args: [0, 1]` у `#Z10069` (§15.2) — открыто с круга 32 | **Alex** | +| 5 | Поле 4 = `2` у `expr` (`10077`–`10085`) — имя не дано | форма не согласована | +| 6 | Push в Gitea — 11 коммитов не запушены | по команде Alex | -> 🔴 **Приёмка не выполнена:** два пункта (1 и 2) требуют ответа Alex — **код по ним не трогать**, -> пока форма не названа. Всё остальное в этом доке — ✅ закоммичено и проверено на 9 конфигах. +> 🔴 **Приёмка не выполнена по п.2** — код не трогать, пока форма не названа. Всё остальное в этом доке — +> ✅ закоммичено и проверено на 9 конфигах. --- @@ -3047,7 +3048,7 @@ Alex прочитал `git show --stat ba6ef44` (2 файла, 10 строк) и | | | |---|---| -| **HEAD** | **`4c6a6f5`** — «Орфаны: тела 49/50 раскрыты как param, raw убран (10030/10031/10035)» | +| **HEAD** | **`272f4c6`** — «trigger: id шага 46 переехал в trigger.step, steps = тела действий» | | **Содержимое `ba6ef44`** (история) | только снятие флага: `config-to-yml.py` (4 точки) + регенерация артефакта. 2 файла, `+6/-7` | | **Рабочее дерево** | чистое по конвертерам | | **Файл на диске** | `config_local_2026-09-17_22-26-26.yml` — 757 объектов; `4171`/`4178`/`4233` = `end: true` | @@ -3056,17 +3057,71 @@ Alex прочитал `git show --stat ba6ef44` (2 файла, 10 строк) и | **Незакоммичено в `zont_config/`** | 2 удалённых `.yml`-снапшота (`18-43-24`, `19-53-21`), новый `.txt` | | **Открыто** | §20.3 — п.1 ✅ закрыт (`end`), п.3 `objcmd` ✅ форма есть (`descr`+`args`+`target`); остались `args`-хвост `#Z10069`, поле 4 `expr`, push | -| | | +### 21.3 ✅ ЗАКРЫТО — Круг 39 (ФИНАЛ): `action` выброшен, id шага едет в `trigger.step` + +**«какой нахуй action»** · **«steps блядь - log»** · **«засунь в триггер»** — целевую форму Alex +назвал. Итог: ключа `action` нет; шаг 46 не пишется в `steps`; его id поднимается в `trigger:` +ключом **`step`**; `steps` содержит **тела действий**. + +```yaml +- id: 8547 + name: тестовый сценарий по времени + enabled: false + trigger: + step: 8550 # id шага 46 — раньше был шаг в steps с action: 8549 + id: 8548 # условие шага + type: days_mask + days: [mon, wed, thu, sat, sun] + steps: + - id: 8549 # тело действия, развёрнуто на месте + log: test +``` + +| Точка | Что | |---|---| -| **HEAD** | `ba6ef44` — «Убрана отметка unresolved: у неразрешённого шага остаётся только id» | -| **Содержимое `ba6ef44`** | **только** снятие флага: `config-to-yml.py` (4 точки: `562`, `594`, `861`, `1146`) + регенерация артефакта (3 строки `unresolved: true` у `10099`, `10103`, `8601`). Итого 2 файла, `+6/-7`. `yml-to-config.py` **не входил** | -| **Рабочее дерево** | чистое по конвертерам (`git diff` пуст) — правки `action: 10099` **откачены** | -| **Файл на диске** | `zont_config/config_local_2026-09-17_22-26-26.yml` — перегенерирован, 757 объектов; строки `4170` (`- id: 10099`) и `4176` (`- id: 10103`) — голый id | -| **Круг** | ✅ **9/9** — `598→598`, `660→660`, `661→661` ×5, `749→749`, `757→757`, потеряно 0, лишнее 0 | -| **Коммиты сессии** | `ba6ef44` · `0cbbeb8` · `2007771` · `0c4b9a6` · `821659b` · `16ec710` · `375d01a` · `07c076f` — **push не делался** | -| **Незакоммичено в `zont_config/`** | 2 удалённых `.yml`-снапшота (`18-43-24`, `19-53-21`), новый `.txt` — висят с прошлых сессий | -| **Открытые вопросы** | §20.3 — 5 пунктов, два ждут **одного слова** от Alex (пометка терминатора, имя `args`) | -| **Статус решения по откату** | ⏳ Alex сказал «откатывай / делай как просил» → **не откачено**, ждём выбора: `revert ba6ef44` ‖ `reset --hard 0cbbeb8` ‖ оставить + переименовать пометку | +| `config-to-yml.py` (`~1161`) | `scenario['trigger'] = {'step': , **<условие>}`; `steps` = `dump_step` по `then` | +| `config-to-yml.py` `_is_body_inline` (`~1240`) | `v.get('step') == obj_id` считается ссылкой — иначе шаг падал в орфаны (**было 70**) | +| `yml-to-config.py` (`~1071`) | из `trigger` вынимается `step` + `flag`, шаг `46` собирается обратно, `steps` → его `then` | + +Круг ✅ **9/9 чистый**, орфанов **4** (было 6: `8549`/`8554` развернулись). + +**Коммит:** **`272f4c6`** («trigger: id шага 46 переехал в trigger.step, steps = тела действий»). + +#### Откаченные попытки (не возвращаться) + +| # | Что сделал | Результат | Откат | +|---|---|---|---| +| 1 | декодер: `then` → `action: [тело]`; энкодер: `action` через `emit_step` | `action` — выдуманный ключ + обёртка-список на один элемент | ⛔ | +| 2 | декодер: тело **плоско** в `action` | ключ `action` остался | ⛔ | +| 3 | декодер: `steps` = тела, id шага ключом `step:` — **без** правки `_is_body_inline` | **65–70 орфанов**: шаги 46 уехали в `raw` | ⛔ | +| 4 | `then:` на шаге вместо `action` | не то: `then` закреплён за шагом со своим `if` | ⛔ | + +🔴 **ПИТФОЛЛ 83 — четыре круга на одну форму.** Я правил по одному месту и гонял круг. Правильно: +выяснить форму **одним вопросом** («куда девается id шага 8550?» — ответ Alex: «засунь в триггер»), +затем править **все точки сразу** (декодер + `_is_body_inline` + энкодер) и только потом круг. + +🔴 **ПИТФОЛЛ 84 — зелёный круг ≠ правильный вывод.** Круг был зелёным при **70 орфанах**: энкодер +аккуратно собрал `raw` обратно. Приёмка = **круг + артефакт** (число орфанов, отсутствие `raw`) — +иначе байт-в-байт маскирует потерянную читаемость. + +🔴 **ПИТФОЛЛ 85 — `_is_body_inline` держит орфан-свип.** Любой объект 46 засевается в `referenced` +(`config-to-yml.py ~1235`); если его id больше не встречается в теле сценария, он улетает в +`scenario_orphans` с `raw`. Поднимая id шага в `trigger:`, **сразу** добавить ключ в +`_is_body_inline`. + +### 21.4. ✅ Круг 38 (ФИНАЛ) — `action` развёрнут, шаги ушли из `scenario_orphans`** + +**Коммит `6d0b6a5`** («action: тела шагов развёрнуты на месте, шаги ушли из scenario_orphans»): + +| Точка | Что | +|---|---| +| `config-to-yml.py` | в trigger-сценарии тела действий разворачиваются через `dump_step` | +| `yml-to-config.py` | ветка `action` прогоняет элементы через `emit_step` (было `then_ids = list(raw_action)`) | + +Орфаны: **6 → 4** (`8549`, `8554` развернулись на месте). Круг ✅ 9/9. + +⚠️ **Коммит `6d0b6a5` оставлен как есть**, хотя форма `action:` затем отвергнута (§21.3): он **не ломает** +круг и не теряет данные, а откат вернул бы орфаны. Форма будет заменена, когда Alex назовёт целевую. --- diff --git a/personal/tech/roundtrip-key-verification.md b/personal/tech/roundtrip-key-verification.md index 7f724329..f18e390c 100644 --- a/personal/tech/roundtrip-key-verification.md +++ b/personal/tech/roundtrip-key-verification.md @@ -100,3 +100,38 @@ diff <(iconv -f <вх> -t utf-8 <оригинал> | tr -d '\r' | sort) \ 1. Новый ключ, где эмитится, какие точки входа поправлены. 2. Команду подмены и наблюдённый результат («1 строка изменилась, маркер на месте»). 3. Питфолл «две точки входа» — чтобы следующая сессия сразу проверяла обе. + +--- + +## 🔴 Круг зелёный ≠ приёмка (2026-09-17, ZONT круг 39) + +Жёсткий урок той же сессии. Round-trip **байтово чистый** не означает, что правка верна. + +**Случай:** правка декодера + энкодера прошла круг 9/9, но владелец проекта посмотрел на артефакт +и увидел **выдуманный ключ** и **обёртку-список на один элемент**. С точки зрения байтов всё +правильно; с точки зрения человека — сломано. + +``` +круг зелёный + артефакт читается плохо = правка не принята +``` + +**Правило:** перед правкой формы назвать **целевую форму словами владельца** и только потом +трогать код. Если форма не названа — **не угадывать**: спросить одним вопросом. + +**Правило трёх:** третья подряд правка «вслепую» (форма не названа, гипотеза за гипотезой) — +стоп. Не править код. Назвать **допущение, которое может быть неверным**, и задать ОДИН вопрос. + +**Симптом «сломано, хотя круг зелёный»:** объект, у которого есть id **в строке конфига**, при +развороте тела в YAML **теряет этот id** → энкодеру не из чего собрать строку, и объекты уезжают +в `raw`-секции (в ZONT: орфаны с `46` выросли с 4 до 69). Проверять **не только** число объектов +и строк, но и **состав служебных секций** до/после. + +**Проверка, которую стоит добавить в любой конвертер:** + +```bash +# число объектов в raw-фоллбэк-секциях ДО и ПОСЛЕ правки должно совпадать +grep -c '^\- id:' out.yml.before # <секция-фоллбэк> +grep -c '^\- id:' out.yml.after +``` + +Рост этой секции = форма не разобрана, а не «данных нет».