fix(meta-compile): регистронезависимый ввод в py-порте — паритет с PS

PowerShell не различает регистр нигде, куда попадает пользовательский ввод:
свойства объекта из ConvertFrom-Json, ключи Hashtable, -eq/-contains, имена
параметров, ValidateSet. Python различает везде, поэтому один и тот же DSL
давал разный результат на разных портах — и чаще всего молча: "CodeLength"
вместо "codeLength" в py просто не находился, навык печатал [OK], а свойство
в выход не попадало.

Пилот на meta-compile. В py-порт добавлены общие обёртки: CIDict (поиск без
учёта регистра, ключи хранятся как есть — часть из них имена объектов и
попадает в XML), ci_json (рекурсивно на разобранный DSL), ci_parse_args (имена
параметров и значения choices). Ими же обёрнуты словари синонимов видов,
алиасов enum и типов.

Попутно исправлен дефект самого канона: PS принимал "type":"catalog", но
дальше использовал значение как есть — в имени тега и в регистрации в
Configuration.xml, то есть отдавал <catalog>, которую платформа не примет.
Теперь вид приводится к канону списка в обоих портах.

check-inline-drift: extractPy научен доставать class (иначе тело CIDict
невидимо), заведены три семьи с ps1: null — в PS1 этих обёрток быть не должно.

Проверка: кейс lenient-key-case зелёный на обоих портах; полный регресс
673/673 (PS) и 670+3 skipped (PY); гарды 4/4; sweep по 400 справочникам трёх
конфигураций (декомпиляция → компиляция обоими портами) — 0 расхождений.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Nick Shirokov
2026-08-09 19:48:24 +03:00
co-authored by Claude Opus 5
parent 4622234b52
commit 8c0fbed7d6
14 changed files with 863 additions and 5 deletions
+25
View File
@@ -202,6 +202,31 @@ PS1 `@{}` (Hashtable) итерирует ключи в порядке хэш-к
PS1: `'^(?i)desc$'` — работает. Python 3.11+: `r'^(?i)desc$'` — ошибка. Inline-флаг `(?i)` должен быть в начале строки паттерна: `r'(?i)^desc$'` или `re.IGNORECASE`.
### Регистр: PS не различает его нигде, Python различает везде
Самая дорогая ловушка портирования, потому что молчаливая. В PowerShell регистр не значим во
всём, куда попадает пользовательский ввод: свойства объекта из `ConvertFrom-Json`, ключи
`Hashtable`, `-eq`/`-contains`, имена параметров, `[ValidateSet]`. В Python совпадение точное,
поэтому `"CodeLength"` вместо `"codeLength"` в py-порте просто не находится: навык печатает
`[OK]`, а свойство в выход не попадает.
В py-портах ввод поэтому проходит через общие обёртки (реестр — в
`tests/skills/check-inline-drift.mjs`, семьи `case-insensitive input: *`):
```python
args = ci_parse_args(parser) # имена параметров и значения choices — как ValidateSet
defn = ci_json(json.loads(json_text)) # словари DSL → CIDict: поиск без учёта регистра
enum_value_aliases = CIDict(enum_value_aliases) # словари, по которым ищут ввод пользователя
```
`CIDict` хранит ключи КАК ЕСТЬ — часть из них это имена объектов, попадающие в XML;
регистронезависим только поиск. В `.ps1` этих обёрток нет и быть не должно.
Обёртка чинит поиск по словарю, но не сравнение строк: `if k in valid_types` в PS
регистронезависим (`-contains`), в Python нет. Такие места правятся точечно приведением к
одному регистру — и обязаны приводить значение к КАНОНУ списка, иначе прощённый регистр утечёт
в имя тега (в `meta-compile` `"type":"catalog"` так и делал `<catalog>`).
### Обращение к отсутствующим свойствам
PS1 молча возвращает `$null` при обращении к несуществующему свойству (`.empty` на массиве). Python падает с `AttributeError`. Добавляйте `isinstance()` проверки при портировании.