Дорожка CLI из кампании паритета: PowerShell не различает регистр ни в именах
параметров, ни в значениях [ValidateSet], argparse различает и в том и в
другом. Проверено на читающем навыке: cf-info -Mode BRIEF на PS отрабатывает,
на py падал.
ci_parse_args (эталон — meta-compile) вставлен в 68 py-портов, вызовы
parser.parse_args заменены. Навыков с DSL меньше трети, поэтому именно эта
правка делает паритет общим: *-info, *-validate, db-*, cfe-*, web-* тоже
принимают ввод так же, как их .ps1.
Реестр check-inline-drift дополнен списком потребителей — и сразу окупился:
поймал, что массовая замена переписала последнюю строку внутри самого
хелпера и копии стали рекурсивными.
Версии бампнуты синхронно в обоих портах всех 68 навыков.
Проверка: 673/673 (PS), 670+3 skipped (PY), гарды 4/4; паритет версий портов
проверен по заголовкам.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
У 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>
Оба пробела нашёл цикл через базу 8.5 (собрать навыками → загрузить → выгрузить):
- cf-init не писал возможность мобильного приложения TextToSpeech, добавленную
форматом 2.21 последней в списке UsedMobileApplicationFunctionalities;
- form-add не писал <UseInInterfaceCompatibilityMode>Any</…> в метаданных формы.
meta-compile эмитил это свойство только для общей формы, а платформа 8.5 пишет
его у форм любых объектов — сразу после UsePurposes, до ExtendedPresentation.
После правки выгрузка платформы совпала с исходниками везде, кроме
ConfigurationExtensionCompatibilityMode (платформа поднимает значение до своего
максимума — так и задумано), скелета Ext/Form.xml и тела MXL: оба расхождения
предсуществующие, к формату 2.21 не относятся.
663/663 ps1, 660/663 py.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Детекторы версии искали только Configuration.xml, поэтому внутри автономной
внешней обработки или отчёта всегда получалось 2.17 — независимо от version в
корне самого объекта. Теперь версия наследуется от корня EPF/ERF: подъём по
дереву проверяет и <каталог>.xml с корнем ExternalDataProcessor/ExternalReport,
а form-add и template-add читают её прямо из файла объекта, с которым работают.
Только после этого у epf-init/erf-init появился параметр -FormatVersion
(2.17…2.21, дефолт 2.17 — прежнее поведение). Без наследования он дал бы
обработку 2.21, внутри которой формы и макеты остаются 2.17.
Проверено сквозным прогоном: epf-init -FormatVersion 2.21 → form-add →
template-add → mxl-compile, все файлы 2.21 с xmlns:pal, порты идентичны.
Снэпшоты role-info/role-validate/cf-edit обновлены — их фикстуры строит
role-compile, дрейф только от смены его формата на платформенный.
648/648 ps1, 645/648 py.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Платформа 8.5 объявляет пространство палитры в шапках MetaDataObject и Form.
Радиус снят по выгрузке УНФ 8.5, а не угадан: pal есть у MetaDataObject, Form,
document (тело MXL), Style, AppearanceTemplate, GraphicalSchema; у Rights, Help,
CommandInterface, DataCompositionSchema и корней extrnprops его нет. Поэтому
role-compile правит шапку Role.xml и не трогает Rights.xml.
Вставка идёт на место — после lf, перед style: объявления платформа держит по
алфавиту, дописать в конец нельзя.
Попутно в cfe-borrow тег <Form> больше не копируется из исходной формы целиком:
из него берутся только объявления пространств, а version подставляется своя.
Раньше версия источника молча побеждала — вопреки комментарию рядом.
Тесты: снята нормализация xmlns в снэпшотах py-прогона (она прятала ровно этот
класс расхождений и к моменту снятия была мёртвой — ни один кейс на неё не
опирался); добавлены expect.fileContains/fileNotContains по сырым байтам и гейт
на неизвестные ключи expect.* — он вскрыл два кейса-пустышки (skd-compile,
skd-edit), они починены.
648/648 ps1, 645/648 py.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Объявления пространств имён вынесены в переменную рядом с определением версии
формата; места эмиссии её только интерполируют. Раньше шапка была вклеена в
литерал в каждой точке записи, и любая правка шапки ложилась в каждый навык
по-своему.
Попутно в form-compile убрана мёртвая эмиссия Title и шапки перед пересозданием
буфера (её результат затирался).
Вывод байт-в-байт: 648/648 ps1, 645/648 py.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Три остатка волны #57, все в одной точке — блоке записи XML.
1. Порты расходились по EOL. PS гонял документ через XmlWriter с дефолтным
NewLineHandling.Replace и принудительно переводил весь файл в CRLF, а py
сохранял стиль исходника: role-compile на LF-ном Configuration.xml давал
10311 байт против 10062. Ещё в пяти навыках None стоял, но финальной
нормализации не было, и на LF-исходнике выходил смешанный EOL (meta-edit:
40 CRLF + 136 одиночных LF) — та же форма, что у исходного дефекта #57.
Приведено к форме cf-edit.ps1: None + канонизация к LF + целевой перевод
строки (стиль файла-назначения, для создаваемого файла — канон CRLF).
Replace не годится как замена: он превращает переводы строк внутри значений
атрибутов в .
2. Гард `if (-notmatch CDATA)` не обрабатывал CDATA, а отказывался от канона
во всём файле — то есть деградировал до «не сделал ничего». Заменён
альтернацией: участки CDATA и комментариев возвращаются как есть, замена
идёт только вне них. На реальных данных поведение не меняется — в корпусе
из 476 942 XML нет ни одного CDATA и ни одного комментария.
3. py: три реализации одного правила детекта EOL сведены к одной. Мажоритарное
правило в role-compile/subsystem-compile давало ДРУГОЙ ответ на смешанном
входе. Дефолты _finalize_xml_bytes для нового файла приведены к канону
(UTF-8, CRLF, без хвостового перевода); meta-edit срезает хвост в обеих
ветках, а не только при создании файла.
Попутно, найдено байтовой сверкой портов:
- py вставлял <Role>/<Form>/<Subsystem> с пятью табами вместо трёх —
подстановка по голому </ChildObjects> удваивала отступ строки; снэпшоты
этого не видели, так как схлопывают пробелы между тегами;
- py-порты xdto-* писали XML-декларацию одинарными кавычками (так отдаёт
lxml), платформа и PS пишут двойные.
Регресс: runner 647/647 ps1, 644/647 py (3 skipped), дрейфа снэпшотов нет.
Корпусный раундтрип метаданных: 4897 объектов, match 100%, совпадает с
эталонами захода #57.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Код нормализации пустого тега повторён в 24 местах, а комментарий к нему за время
работы над #57 расплодился в шесть вариантов формулировки. Это то же расхождение
копий, что и в коде, только в тексте: читающий не понимает, значима разница или нет.
Сведено к одной паре формулировок — про сам тег с гардом и про запись через
MemoryStream. Комментарий теперь начинается с ПРАВИЛА, а не с причины: раньше
верхняя строка рассказывала, что here-string наследует LF от .ps1, и читалось это
как «переводы строк берём из скрипта навыка» — тогда как правило обратное:
создаём файл — пишем канон, правим существующий — наследуем его стиль.
Два пояснения в cfe-borrow унификация чуть не стёрла, они возвращены: источником
там служит OuterXml, а не XmlWriter, и нормализация стоит после вставки реквизитов,
чтобы накрыть и их. Это причина местного отличия, а не дубль.
Ссылки на ишью прорежены: #44/#46/#47 осталась по одной на файл — там, где правило
формулируется, — и убрана оттуда, где была эхом. #57 в скриптах не было вовсе.
Заодно выровнены две мелочи, найденные той же сверкой копий: interface-edit в
py-порте не обрезал хвостовой перевод там, где PS обрезает (поведение совпадало,
код — нет), а cf-edit нормализовал EOL инлайном вместо общей двухшаговой формы.
Версии подняты в ОБОИХ портах всех затронутых навыков, включая те, где текстуально
менялся только .ps1: номер версии в этом проекте читается как «одно и то же
поведение», и разводить его из-за комментария нельзя. Паритет проверен — 69 пар,
ноль расхождений.
Windows 641/641 обоими портами.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Навыки автономны, общей библиотеки нет — значит копии функции записи должны быть
буквально одинаковыми, иначе теряется смысл копипасты. PS-порт дисциплину держал
(7 копий байт-в-байт), а py разъехались: три варианта имени параметра, два стиля
кавычек, у cfe-borrow ещё и другое имя функции (save_xml_file).
Сведено к одной форме: имя write_xml_file, параметр content, одинаковое тело.
Различаются ровно две вещи, и обе осмысленные: вызов локального базового writer'а
(имена исторические — write_utf8_bom / write_text_with_bom / save_text_bom) и одна
строка примечания там, где у навыка есть исключение (модуль .bsl, HTML).
Текст комментария в PS выровнен с docstring'ом py: раньше он описывал ПРИЧИНУ
(here-string наследует LF), а не правило, и после правки py ports разъехались по
смыслу. Синтаксис остаётся разным по природе языков: в py docstring (в портах их
421 против 73 функций с #-комментарием — это местная норма), в PS — #.
Windows 641/641 обоими портами.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Скелетные генераторы писали Module.bsl с LF, а платформа пишет модули с CRLF:
в выгрузке БП 2643 CRLF и чисто-LF 0 из 3001 модуля (358 «смешанных» — LF внутри
строковых литералов кода), BOM 2001/2001. По тому же доводу сходимости, что и для
XML: платформа перепишет модуль в CRLF при первой выгрузке, значит наш LF — дифф,
созданный нами.
В репозитории уже была встречная конвенция: meta-compile (модуль команды) и
cfe-patch-method (base/local/remote.bsl) пишут .bsl явным CRLF в обоих портах.
Выбивались только эти три скелета.
Хвостовой перевод строки НЕ трогаем: у платформы он неканоничен — 1235 модулей
с ним, 766 без; это след автора кода, а не правило. Меняем только разделители.
Правка в точке записи, а не в шаблоне: так одна строка на скрипт и не трогаются
\u-экранированные кириллические литералы в py (Edit по ним переэкранирует).
Снэпшоты нормализуют EOL и увидеть это не могут — добавлен preserves на модуль
в epf-init/basic, erf-init/basic, form-add/basic.
Windows 641/641 обоими портами, мак 590/0/51, дрейфа снэпшотов нет.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Головной дефект тикета: cfe-init выдавал Configuration.xml с 10 CR на 70 строк, а
роль и язык — вовсе без CR. Теперь 70/70, последний байт `>`.
Правило: меняем только РАЗДЕЛИТЕЛИ строк, содержимое текстовых узлов не трогаем.
Платформа его не трогает тоже — в запросах СКД из чистой выгрузки встречаются и
CRLF, и одиночный LF. Поэтому сплошная нормализация файла применяется только там,
где многострочных текстовых узлов нет по построению (скелеты), а в объектном XML
и формах разделители правятся в точке сборки.
Источников оказалось четыре, а не один:
1. Скелеты (cf-init, cfe-init, epf-init, erf-init, form-add, help-add,
template-add) собираются here-string'ами, а .ps1/.py в репозитории хранятся с
LF — отсюда LF и смешанный EOL.
2. py-порты склеивали документ через '\n'.join(lines); PS в тех же местах давал
CRLF через AppendLine — порты расходились побайтово.
3. Билдеры Predefined в meta-compile собирались с явным LF и даже сворачивали
CRLF→LF из общего эмиттера типов.
4. Чтение существующего файла в python БЕЗ newline='' молча схлопывает CRLF в LF
(универсальные переводы строк), и запись потом кладёт LF. Так role-compile и
subsystem-compile переписывали в LF весь Configuration.xml. meta-compile это
уже делал правильно — там newline='' стоял с фикса #44/#46/#47.
Отдельно: XML-парсер по спецификации схлопывает CRLF при разборе, поэтому
lxml-порты (xdto-compile, xdto-edit) отдавали LF-документ там, где .NET возвращал
CRLF через NewLineHandling. Восстанавливаем EOL исходного файла.
Разделение канона и сохранения стиля:
- файл СОЗДАЁМ — канон (CRLF, без хвоста);
- существующий ПРАВИМ — наследуем его EOL, включая перевод строки вставки
(контракт #44/#46/#47). Иначе LF-проект получал бы смешанные файлы — ровно то,
на что заведён #57. Кейсы roundtrip-crlf-preserve остаются зелёными.
Хелпер записи скопирован в каждый навык (навыки автономны). У meta-compile он
называется Write-XmlFileKeepEol / write_xml_file_keep_eol: там нормализовать EOL
НЕЛЬЗЯ (многострочные запрос, синоним, значение заполнения), и одинаковое имя при
разном поведении было бы ловушкой.
Заодно: имя временного файла батча в meta-compile.ps1 получило GUID. Фиксированное
"meta-compile-batch-$idx.json" в общем %TEMP% сталкивало два параллельных запуска
(«file is being used by another process») — из-за этого полный набор приходилось
гонять с урезанной параллельностью. py-порт уже брал mkstemp.
Аудит: было ~250 файлов с дефектом EOL, стало 0 в обоих портах. Осталось четыре
законных случая — фикстуры roundtrip-crlf-preserve (сохранение стиля) и запрос
динсписка с многострочным текстом. Дрейф снэпшотов — 1 файл. Тесты 641/641.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Конфигуратор не пишет перевод строки в конце файла — последний байт `>`. Это видно
на чистой выгрузке пустой ИБ (Windows и macOS) и на всех 8 выгрузках в cfsrc.
Наши эмиттеры добавляли лишний, причём оба порта и по разным причинам:
- PS: StringBuilder.AppendLine дописывает Environment.NewLine после последней строки;
- PY: '\n'.join(lines) + '\n' — хвост добавлен явно.
В meta-compile заведена единая точка записи Write-XmlFile: там документ собирают
и AppendLine, и явные `n в билдерах Predefined/Content/Flowchart, а выходов семь.
В остальных обрезка стоит в самом вызове записи.
Модули .bsl, JSON-выход form-compile, HTML-справка help-add и XSD из xdto-decompile
сюда НЕ входят: канон Конфигуратора описывает XML метаданных, а у этих артефактов
свои правила. Результаты XmlDocument.Save тоже не трогаются — у них хвоста нет.
Навыки редактирования продолжают сохранять стиль ВХОДНОГО файла: кейс
subsystem-edit/roundtrip-crlf-preserve, где фикстура намеренно с хвостом, остаётся
зелёным. Это контракт #44/#46/#47, и он не отменяется.
Дрейф снэпшотов: 547 файлов, у каждого только последняя строка, содержательных
изменений ноль. Тесты 641/641.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
.NET XmlWriter пишет `<a />`, а Конфигуратор — `<a/>`. Поскольку Save переписывает
файл целиком, meta-edit при добавлении одного реквизита переводил в пробельную форму
все пустые теги документа. Дефект только у PS-порта: lxml (45 из 49 py-портов) уже
пишет плотно, то есть порты расходились побайтово.
Канон измерен, а не предположен: чистая выгрузка пустой ИБ на Windows и macOS плюс
сплошной скан 8 выгрузок в cfsrc — 476 943 XML, 21 294 119 самозакрывающихся тегов,
пробельных 0. Форма не зависит от ОС, версии платформы (8.3.20-8.5) и наличия
атрибутов. Правило уже было реализовано в skd-edit — оттуда и взято.
Замена безопасна доказуемо: .NET экранирует `>` как `>` и в тексте, и в атрибутах,
поэтому ` />` после Save — только конец тега. Лазейки (CDATA, комментарии) в
1С-метаданных не встречаются — 0 из 476 943 файлов; гард на них всё равно стоит.
Одиннадцать скриптов писали прямо в FileStream без пост-обработки — переведены на
MemoryStream, что заодно чинит `encoding="utf-8"` строчными (335 файлов в снэпшотах).
В cfe-borrow правится и сборка Form.xml: куски берутся из OuterXml, а он спацовывает
так же, как XmlWriter.
Дрейф снэпшотов: 12 838 строк тегов + 335 деклараций, содержательных изменений ноль.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Detect-FormatVersion читает префикс Configuration.xml как
ReadAllText(...).Substring(0, Min(2000, (Get-Item).Length)). Размер файла — в
БАЙТАХ, Substring считает СИМВОЛЫ: на кириллице байт больше, и если файл
короче 2000 символов, длина среза выходит за строку и навык падает
исключением. Проявлялось на маленьких конфигурациях — например на фикстуре
EPF внутри конфигурации на поддержке.
Функция расходится копиями по навыкам, поэтому правка одинаковая в восьми:
длина берётся по самой строке. В help-add так было изначально; в
meta-compile рядом (Detect-CompatibilityMode) уже стоял верный вариант.
py-порты иммунны: там f.read(2000) в текстовом режиме — читает символы и не
бросает исключение. Зеркалить нечего, версии выровнены по обоим портам.
Заодно tests/skills/verify-snapshots.mjs: outputPath кейса читался только из
params, тогда как runner.mjs берёт его с верхнего уровня — из-за расхождения
харнесс искал результат не там, где навык его написал, и это маскировало
падение как «выход не создан».
Проверка: 1С-сертификация mxl-compile 13/13 (кейс guard-allow-external падал
с начала кампании), полная сюита 630/630 на PowerShell и 627+3 skipped на python.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
form-add и template-add вставляли запись в ChildObjects безусловно.
Если форма/макет уже зарегистрированы (например, form-compile
регистрирует <Form>, не создавая файл метаданных, а затем вызывается
form-add) — возникал дубль <Form>/<Template>, ломавший валидацию.
Приведено к идемпотентной модели, уже применённой в form-compile и
meta-compile: перед вставкой ищем существующую запись по имени; при
наличии — пропускаем и печатаем "Already registered ... (skipped
duplicate)". Зеркально в ps1 и py, регрессионный тест-кейс.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
При поиске корня конфигурации guard поднимался по дереву вверх и «проскакивал»
собственный корень автономной внешней обработки/отчёта (ExternalDataProcessor /
ExternalReport), лежащей внутри дерева выгрузки конфигурации. Если у охватывающей
конфигурации выключена возможность изменения (G=1), внешний объект ложно
блокировался как «объект типовой конфигурации на поддержке», а info-навыки
выводили нерелевантную строку «Поддержка: конфигурация read-only».
Теперь climb останавливается на границе автономного объекта: если целевой файл или
встреченный по пути <каталог>.xml имеет корень ExternalDataProcessor/ExternalReport,
подъём прекращается и объект не привязывается к конфигурации. Корень внешнего объекта
всегда глубже Configuration.xml, поэтому встречается первым — регрессии для обычных
объектов конфигурации нет.
Синхронно во всех копиях guard-а (навыки автономны): хук support-state.mjs
(decideSupport + findConfigRoot), 16 мутаторов (Assert-EditAllowed), 5 info-навыков
и meta-info (Get-SupportStatusForPath / Get-ObjectSupportStatus) — ps1 и py. Для
info-навыков строка «Поддержка:» для внешнего объекта опускается.
Тесты: hooks/test/run.mjs — секция внешней границы (G=1 + встроенная EPF);
tests/skills — кейсы mxl-compile (guard пропускает) и mxl-info (строка опущена).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
DocumentJournal добавлен в список поддерживаемых типов form-add — журналы
теперь принимают форму (списочную, через общий DynamicList-путь). Нужно для
1С-сертификации журналов, ссылающихся на собственную defaultForm. Зеркало ps1+py.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Синхронизация §1B с улучшенным текстом хука (ветка feat/support-guard-hooks):
вместо общего списка всех вариантов — текст под конкретную причину
(capability-off / locked / not-removed) с подставленным реальным путём и
точными командами support-edit. Понятно модели вне контекста.
- Все 16 навыков-мутаторов (оба рантайма): Assert-EditAllowed /
assert_edit_allowed строят сообщение по $code/code причины отказа.
- Терминология «редактирование» (как у платформы 1С).
- Версии заголовков подняты в обоих рантаймах.
- EOL/BOM каждого файла сохранены; deny-тесты 16/16 на PS и PY.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Замыкает петлю issue #23: после отказа support-guard модель может
легитимно включить редактирование. support-edit правит правила поддержки
в Ext/ParentConfigurations.bin выгрузки (только XML; в ИБ — полной загрузкой):
-Path <путь> -Set editable|off-support|locked (пообъектно или корень)
-Path <путь> -Capability on|off (возможность изменения)
Path-based, симметрично гарду — модель берёт путь прямо из отказа.
Реализация: regex-замена in-place по разобранному формату bin (round-trip
байт-в-байт; парсер подтверждён consumed=100% на корпусе acc/erp/K=7).
При выключенной возможности (G=1) пообъектный -Set отказывает с подсказкой
«сначала -Capability on» (явные шаги). Включение возможности ставит всё на
замок (вендорские флаги «не редактировать» в выгрузке недоступны — массовой
разблокировки нет; non-goal). Оба порта дают байт-в-байт идентичный bin.
Диагностика support-guard (32 файла, 16 мутаторов × 2 порта) теперь печатает
готовую команду support-edit под конкретный отказ.
Тесты: фикстуры g0/g1 + кейсы set-editable/off-support/предусловие/capability
со снапшотами bin; зелёные на PowerShell и Python. Все 16 мутаторов +
support-edit зелёные на обоих рантаймах.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Контракт Assert-EditAllowed (дословная копия из meta-edit, оба порта)
добавлен в 13 навыков-мутаторов. Всем единый вызов require=editable —
«кого проверять» решает не навык, а walk-up по файловой системе от пути
цели:
- целевой файл имеет root-uuid → его f1 (правка существующего элемента);
- иначе ближайший вверх <dir>.xml с uuid → f1 владельца (добавление
дочернего: форма/реквизит/макет к объекту);
- иначе корень Configuration.xml → f1 корня (новый объект верхнего уровня).
Это воспроизводит семантику поддержки 1С автоматически, поэтому один и
тот же навык проверяет разное по состоянию дампа: skd-compile/mxl-compile/
form-compile в существующий макет/форму → f1 этого элемента (modify), в
несуществующий → f1 владельца. Проверено обоими сценариями.
Навыки: form-edit, form-add, form-compile, skd-edit, skd-compile, cf-edit,
subsystem-edit, subsystem-compile, interface-edit, template-add, help-add,
mxl-compile, role-compile. Диагностика через [Console]::Error.WriteLine +
exit 1 (как в эталоне). Версии подняты в обоих портах.
Проверено: deny на обоих портах (крафт-фикстуры на копиях, корпус не
тронут); все 16 навыков-мутаторов зелёные на PowerShell и Python
(264 кейса). BOM сохранён везде.
Follow-up (в upload-плане): пред-существующий баг help-add
Detect-FormatVersion (Substring на кириллице, до гарда, не связан);
авторезолв пути в meta-edit; per-skill committed deny-тесты.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Codex runner on Windows launches PowerShell as login-shell and decodes
stdout/stderr without UTF-8, garbling Cyrillic output. The other 51 ps1
scripts already set `[Console]::OutputEncoding = UTF8`; bring these 7
in line and add `InputEncoding = UTF8` for symmetry.
Touched: epf-init, erf-init, form-add, form-remove, help-add,
template-add, template-remove. Versions bumped in both ps1 and py
headers to keep the pair in sync.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
form-add теперь покрывает и объекты конфигурации, и standalone EPF/ERF
source tree (тип определяется из корневого XML, маппинг типов уже был).
Изменения form-add scaffold:
- Module.bsl: пустые регионы вместо скелета процедуры ПриСозданииНаСервере
- Form.xml: убран <Events> (раньше привязывал OnCreateAtServer к процедуре)
- Form.xml: <SavedData>true</SavedData> теперь условный — ставится для
Catalog/Document/etc (стандарт ERP, 99% форм), не ставится для
DataProcessor/Report/External* (где у объекта нет состояния)
Это согласуется с workflow: form-compile перегенерирует Form.xml целиком,
поэтому привязки в scaffold могут стать orphan; пустые регионы +
без Events — корректная стартовая точка, которую form-edit/form-compile
наполняют атомарно.
Удалён навык epf-add-form (директория + тесты), вызовы заменены на
form-add в integration-тестах, в кейсах epf-validate/help-add, в
description epf-init/epf-bsp-init, в docs и README.
Перегенерированы snapshot'ы 5 навыков (form-add, form-compile,
form-edit, form-info, form-validate). Платформенная верификация в 1С 8.3.24
прошла для всех 9 кейсов form-add.
Bump form-add v1.3 → v1.4.
Add InformationRegister (Record/List), AccumulationRegister (List),
ChartOfCharacteristicTypes (Item/Folder/List/Choice via Catalog delegation),
ExchangePlan (Item/List/Choice via Catalog delegation),
ChartOfAccounts (Item/Folder/List/Choice with AccountingFlags + ExtDimensionTypes).
Generalize extractAttrs → extractFields with tag parameter.
Add preset defaults and erp-standard.json keys for all new types.
Bump version to v1.6 in both PS1 and PY.
Also: form-add now supports AccumulationRegister (PS1+PY).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
When working with existing configs dumped from newer platforms (8.3.27+),
XML files use version="2.20" instead of "2.17". Skills now detect the
version from the nearest Configuration.xml walking up the directory tree,
falling back to "2.17" if not found. This prevents format version mismatch
errors during LoadConfigFromFiles.
Updated skills (11): meta-compile, form-compile, form-add, template-add,
cfe-borrow, epf-add-form, help-add, role-compile, subsystem-compile,
interface-edit. Also fixed form-validate to accept version 2.20.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- form-add v1.2: ExtendedPresentation only for DataProcessor/Report/External* forms
(Catalogs, Documents, Registers etc. don't have this property — platform rejects it)
- cf-init v1.1: InterfaceCompatibilityMode Taxi → TaxiEnableVersion8_2
(matches all real configs: acc 8.3.20/24/27, erp 8.3.24)
- cfe-init v1.1: read InterfaceCompatibilityMode from -ConfigPath base config
(analogous to existing CompatibilityMode auto-detection)
- Remove workaround in platform-cfe integration test (cf-edit modify-property)
- Update 162 snapshot Configuration.xml + 7 form metadata snapshots
Tests: 301/301 passed
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Skill fixes (all ps1+py, version bumped to v1.1):
- role-compile: accept "rights" as synonym for "objects"
- subsystem-compile: accept "objects" as synonym for "content"
- form-add: resolve directory path to .xml (like meta-validate)
- form-info: resolve directory path to Ext/Form.xml (like form-validate)
- mxl-compile: support absolute OutputPath (IsPathRooted check)
- meta-remove: exit 1 when object not found; v1.1
- cfe-patch-method: accept plural type names (Catalogs → Catalog)
Test fixes:
- basic-role.json: use canonical "objects" key
- basic.json (subsystem): use canonical "content" key
- catalog-form.json: fix outdated DSL format
- New synonym test cases for role-compile and subsystem-compile
- error-not-found.json: expect error (exit 1)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Without reconfiguring stderr, Cyrillic error messages appear garbled
on Windows (cp1251 default). Mirrors the existing stdout fix.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
When ObjectPath is a directory (e.g. Catalogs/Номенклатура),
auto-resolve to the sibling XML file (Catalogs/Номенклатура.xml)
before parsing. Matches behavior of other edit scripts.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Python on Windows defaults to cp1251 for piped stdout, which cannot
handle Unicode box-drawing characters used in info/analysis output.
Added sys.stdout.reconfigure(encoding="utf-8") to all 59 Python scripts.
Tested on real config data: epf-init, epf-validate, cf-info, cf-validate,
meta-info, form-info, role-info, skd-info, subsystem-info — all passing.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add cross-platform Python alternatives alongside existing PowerShell
scripts. PS1 remains the default runtime; Python is opt-in via switch
scripts. All parameters are identical between runtimes.
New files:
- 58 Python scripts in .claude/skills/*/scripts/*.py
- scripts/switch-to-python.py and switch-to-powershell.py
- docs/python-porting-guide.md
- __pycache__/ added to .gitignore
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1. meta-compile + cfe-borrow: add Manager GeneratedType for Report/DataProcessor
2. cfe-borrow: rewrite Form.xml generation — extract only visual elements
(AutoCommandBar + ChildItems), replace CommandName→0, strip Attributes/Events/Parameters
3. cfe-init: add -ConfigPath to auto-resolve Language UUID and CompatibilityMode
4. form-add: guard against overwriting existing Form.xml and Module.bsl
5. docs: update GeneratedType table for Report/DataProcessor
6. docs: rewrite section 5.4.2 with accurate borrowed form structure
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Create forms (metadata XML + Form.xml + Module.bsl) for Document,
Catalog, InformationRegister and other configuration object types.
Supports Object/List/Choice/Record purposes with automatic
ChildObjects registration and DefaultForm setup.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The skill modifies existing forms (adds elements/attributes/commands),
not creates new ones. "form-edit" better reflects its purpose.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- stdCommand dot syntax: "Товары.Add" → Form.Item.Товары.StandardCommand.Add
- Event name validation: warn on unknown events per element type (13 types, ~60 events)
- Form-level event validation (19 known events)
- Document events reference and popup element in SKILL.md
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
form-add: warn about unrecognized DSL keys in element definitions,
matching the same validation added to form-compile earlier.
form-guide.md: update form-info output examples to reflect new
Title-in-header format and DSL-friendly command display
(-> Name [cmd], -> Close [std]).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
form-compile: warn about unknown DSL keys in element definitions,
document stdCommand/command button keys and EPF-specific notes.
form-validate: check that form-level Title uses multilingual XML,
not plain text (which causes XDTO errors at build time).
form-add: warn about duplicate element names, clarify after-not-found
message when using into+after together.
form-info: show Title in header instead of Properties line, display
commands as DSL-friendly format (-> Name [cmd], -> Close [std])
instead of raw Form.Command/Form.StandardCommand paths.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Rename DSL keys to match 1C property names (Visible, Enabled):
- form-compile/form-add: accept "visible": false and "enabled": false
as primary keys, keep hidden/disabled as synonyms
- form-info: output [visible:false] and [enabled:false] flags
- Update SKILL.md docs and form-guide.md
Improves round-trip consistency: form-info output now directly maps
to form-compile/form-add input keys.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
form-add: Scan column IDs (same pool as attribute IDs) to prevent
duplicate ID collisions. Use XPath .//*[@id] instead of ChildItems
recursion to capture companion element IDs (ExtendedTooltip, ContextMenu).
form-compile: Extract title from properties and route through Emit-MLText
instead of generic Emit-Properties, which produced plain text <Title>
rejected by 1C XDTO schema.
Found during E2E testing of full pipeline (epf-init → form-compile →
form-add → epf-build).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Adds elements, attributes, and commands to existing managed forms
via JSON input. Supports positional insertion (into/after), auto ID
allocation from correct pools, companion generation, and event handlers.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>