Commit Graph
8 Commits
Author SHA1 Message Date
Nick ShirokovandClaude Opus 5 ff01102b9b docs(tests): зафиксировать природу расхождения оставшихся семей
Храповик без пояснения читается как «когда-нибудь свести». Разбор показал, что
из четырёх оставшихся семей одна вообще не является общей: import_fragment имеет
разные сигнатуры и разные наборы xmlns по навыкам — одно имя на разные задачи,
сводить его нельзя. Остальные три сводятся, но каждое сведение меняет вывод и
требует решения, а не аккуратности.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-09 12:30:54 +03:00
Nick ShirokovandClaude Opus 5 01749ad6ee refactor(skills): свести write_xml_file и write_utf8_bom к общему эталону
У write_xml_file в docstring прямо написано «Держать копии одинаковыми —
сознательно: разошедшиеся копии сводят на нет весь смысл», и при этом копий было
три варианта. Различие оказалось не в логике нормализации, а в имени
вспомогательной функции записи байт: write_utf8_bom (11 навыков),
write_text_with_bom (form-add, help-add, template-add), save_text_bom
(cfe-borrow) — тела всех трёх побайтово эквивалентны.

Имя сведено к write_utf8_bom, тело помощника — к общему эталону (различались
только имена переменных). PS1-порт Write-XmlFile расхождений не имел.

Обе семьи переведены из храповика в реестр с эталоном: 24 семьи, 309 копий,
разъехавшихся осталось 4.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-09 12:29:43 +03:00
Nick ShirokovandClaude Opus 5 f2216745e6 refactor(validate): свести Report-* к общему эталону вывода
interface-validate, subsystem-validate и xdto-validate отличались от остальных
шести валидаторов только стилем: инлайн-сигнатура вместо param-блока и
однострочный if. Приведены к эталону cf-validate.

form-validate и mxl-validate оставлены отдельным вариантом с обоснованием:
они пишут через Write-Host, а не через буферизованный Out-Line. Буферизация
нужна для -OutFile (тот же отчёт в файл), которого у этих двух навыков нет;
для модели-потребителя stdout одинаков — на успешном прогоне обе ветки дают
одну строку.

Семьи Report-OK/Error/Warn переведены из храповика в реестр с эталоном.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-08 21:23:58 +03:00
Nick ShirokovandClaude Opus 5 fadda6a287 refactor(meta-validate,web-publish): свести format_rank и db-обвязку к эталонам
format_rank в meta-validate отличался только именем параметра, _version_key в
web-publish инлайнил каталог версии вместо общего _version_dir (и знал только
Windows-раскладку .../bin/exe). Обе копии приведены к эталону db-create/
meta-compile; для Windows-навыка web-publish поведение не меняется.

В реестр добавлены семьи _version_dir и _find_project_v8path.

Экстрактор PS1 в гарде и сканере научен видеть вложенные определения: db-load-git
объявляет Find-ProjectV8Path внутри if, и поиск по `function` с нулевой позиции
считал функцию отсутствующей. Конец тела теперь ищется по закрывающей скобке на
отступе самого слова function.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-08 21:13:50 +03:00
Nick ShirokovandClaude Opus 5 974ca3aac9 fix(form,skd,init,meta-edit): развести экранирование атрибута и текста
esc_xml был один на две задачи, и в атрибутном контексте применялся текстовый
вариант без &quot;. form-compile с choiceParameters, имя которого содержит
кавычку, выдавал <app:item name="Отбор.Наименование "кавычка"">: lxml падает с
attributes construct error, то есть файл невалиден как XML. Затронуто 9 мест в
form-compile и 3 в skd-compile, одинаково в обоих портах.

Раундтрип через базу показал границу: в ТЕКСТЕ элемента платформа экранирует
только & < > (кавычка и апостроф возвращаются сырыми байт-в-байт), а в ЗНАЧЕНИИ
АТРИБУТА пишет &quot; — внутри "..." литеральная кавычка невалидна. Поэтому две
функции с говорящими именами, а не одна с флагом:
  esc_xml      — значение атрибута: & < > "
  esc_xml_text — текст элемента:    & < >

Заодно закрыто расхождение портов в init-навыках: PY экранировал текст с &quot;,
PS1 — через SecurityElement::Escape (ещё и &apos;), а epf-init/erf-init в PS1 не
экранировали вовсе, из-за чего амперсанд в синониме давал невалидный XML.

Кейсы: form-compile/attr-value-escaping, skd-compile/additional-properties-escaping,
cf-init/synonym-escaping — все три проверены негативным прогоном на обоих портах
и верификацией снэпшотов на платформе.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-08 20:53:12 +03:00
Nick ShirokovandClaude Opus 5 826ba3de71 fix(form,meta,skd): resolve_type_str — одно тело + срезание префикса типа
Шесть копий resolve_type_str разошлись на 6 вариантов в PY и 4 в PS1, а вместе
с формой разошлось и поведение: префикс ссылочного типа срезал только
form-compile.

Проверка на платформе (стенд 8.3.24.1691, cf-init → meta-compile → db-load-xml)
показала, что это не косметика. Префикс ломает поиск в словаре синонимов, из-за
чего русское имя типа остаётся непереведённым:
  СправочникСсылка.Склады      → cfg:CatalogRef.Склады        (верно)
  cfg:СправочникСсылка.Склады  → cfg:СправочникСсылка.Склады  (неверно)
Платформа отвечает «Неизвестное имя типа - СправочникСсылка.Склады» и
отклоняет загрузку. Именно с префиксом тип и написан в выгрузке, откуда
пользователь его копирует.

cfg: снимается всегда, d5p1: — только у ссылочных типов (с точкой): сам по себе
префикс неоднозначен, в формах d5p1:Chart, d5p1:TextDocument и ещё три типа
адресуют свои пространства имён, и там он часть канонического значения. Первая
версия правки срезала его безусловно и уронила 4 кейса form-compile.

Тело общее для всех шести навыков; словари синонимов остаются локальными, навык
объявляет на свой словарь алиас TYPE_SYNONYMS / $script:typeSynonyms.

Регресс-кейс meta-compile/type-prefix-lenient проверяет все три формы ввода.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-08 19:44:39 +03:00
Nick ShirokovandClaude Opus 5 d99d63288e refactor(skills): detect_format_version — один вариант на всех потребителей
Семья была разбита на «знает про автономную EPF/ERF» (form-*, mxl-compile,
template-add, help-add) и «не знает» (cfe-borrow, interface-edit, meta-compile,
role-compile, subsystem-compile, xdto-compile), плюс редакторски разошедшаяся
PS1-копия help-add.

Расширенный вариант корректен и для конфигурационных навыков: ветка срабатывает
только если <каталог>.xml — корень ExternalDataProcessor/ExternalReport, чего в
дереве конфигурации не бывает. Переключатель не нужен — раскопирован как есть.

Семья в реестре схлопнута до одного варианта: 11 копий, оба порта.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-08 18:18:52 +03:00
Nick ShirokovandClaude Opus 5 c8144a01e5 test(skills): реестр и гард общих inline-реализаций
Навыки автономны, общие утилиты копируются в каждый .ps1/.py, но нигде не было
зафиксировано, какая копия эталонная и какие расхождения законны. Ревизия по #60
показала два класса семей: одни держатся побайтово (support-guard — 16 копий,
db-обвязка — 12), другие разъехались без эталона (resolve_type_str — 6 копий и
6 вариантов, get_ml_text — 7 и 7).

check-inline-drift.mjs держит реестр семей внутри себя: вариант → эталон → копии.
Копия обязана совпадать с эталоном своего варианта; отклоняющийся вариант обязан
иметь обоснование, иначе печатается как долг. Часть расхождений законна (esc_xml
без &quot; в form-* ради раундтрипа), поэтому модель хранит варианты, а не одно
эталонное тело. Разъехавшиеся целиком семьи стоят на храповике maxVariants.

Извлечение тел: PS1 — до строки ровно `}` (балансировка скобок даёт ложные
18 вариантов из 18 копий Assert-EditAllowed); PY — с обязательным снятием
docstring-ов (иначе одинаковый код с разным описанием читается как расхождение).

check-all.mjs — единая точка входа: check-enum-drift и check-uuid-invariant были
рабочими, но не упоминались в README и никем не запускались.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-08 17:22:33 +03:00