form-add отказывал видом объекта 'Table', хотя платформа такие формы делает, а в DSL
таблицы есть слоты defaultObjectForm/defaultRecordForm/defaultListForm/defaultChoiceForm.
Инструкция при этом обещала обратное — строка исправлена.
Таблица — единственный вид, чьи ссылки трёхчастные: слот
ExternalDataSource.<И>.Table.<Т>.Form.<Ф>, главный реквизит ExternalDataSourceTableObject.<И>.<Т>,
MainTable динамического списка ExternalDataSource.<И>.Table.<Т>. Имя источника в файле таблицы
не хранится — берётся из пути ExternalDataSources/<И>/Tables/<Т>.xml, единственное место,
где навык смотрит на путь.
Набор назначений зависит от вида данных таблицы — замерено загрузками на 8.3.24.1691:
ObjectData даёт Object/List/Choice, NonobjectData — Record/List/Choice. Неверная пара
схемой формы не отвергается: она валит загрузку ВСЕЙ конфигурации «Исключением XDTO при
чтении файла» без указания причины, поэтому form-add проверяет её сам и объясняет, а без
-Purpose у таблицы с составным ключом основной становится форма записи.
form-validate: типы ExternalDataSourceTable* добавлены в список известных cfg-префиксов —
иначе корректная форма получала предупреждение «unrecognized cfg prefix».
Проверено: form-add и form-validate зелёные в обоих рантаймах, гарды прошли (в том числе
check-form-purposes: спека и оба порта сходятся), снэпшот eds-table-forms принят платформой,
формы всех четырёх назначений загружены в базу и выгружены обратно со ссылками без потерь.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NBsZA5cr2WFThtgp7i5WVi
Мелкие находки ревью, по одному кейсу на каждую:
- meta-compile: BinaryData(N[,fixed|variable]) — фиксированная длина больше не теряется;
голая форма по-прежнему 4294967292/Fixed, как её пишет платформа при импорте из СУБД.
Посторонний текст в скобках (BinaryData(abc)) отвергается, а не даёт тихий безлимит —
PS принимал его и молча подставлял дефолт, py такой тип не понимал вовсе.
- meta-decompile: сворачивает в голый BinaryData только точное совпадение с этим дефолтом.
- meta-info: xs:base64Binary без квалификаторов — вторая форма ХранилищаЗначения, а не
двоичные данные; раньше два навыка читали один и тот же узел по-разному.
- meta-remove (py): в ветке «файлов нет» корень реестра был жёстко Configuration, поэтому
осиротевшая таблица внешнего источника не находилась и навык падал, тогда как PS её
разрегистрировал. Сообщение в обоих портах теперь называет реальный реестр.
Проверено: наборы meta-compile/decompile/info/remove/edit/validate зелёные в обоих
рантаймах, гарды прошли, снэпшот eds-binary-data принят платформой 8.3.24.1691.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NBsZA5cr2WFThtgp7i5WVi
Декомпилятор собирает DSL источника целиком: читает файл источника, подтягивает файлы таблиц
из <Источник>/Tables/ и складывает поля, ключи, ссылки и функции обратно в тот же синтаксис,
который принимает meta-compile. Ссылки на поля возвращаются короткими именами, таблица без
собственных свойств — коротким массивом полей, функция с типом по умолчанию — одной строкой.
Это замыкает дешёвый контур проверки: XML → декомпиляция → компиляция → сравнение с исходником,
без 1С и без Docker. На нём и проверено: наша выгрузка, выгрузка платформы и четыре таблицы
внешних источников из чужого рабочего проекта возвращаются байт в байт. У выгрузки платформы
остаются два известных расхождения: значение незаполненного родителя (платформа сама сбрасывает
его при любой загрузке) и формы (декомпилятор их не захватывает — так задумано).
Побочно закрыт дефект, к внешним источникам не относящийся: xs:base64Binary разбирался как
ХранилищеЗначения, хотя это ДвоичныеДанные. Различать их можно по квалификаторам —
у ХранилищеЗначения платформа пишет v8:ValueStorage, а у двоичных данных есть
BinaryDataQualifiers. Компилятор научен типу BinaryData (и BinaryData(N)) — до этого он
принимал такое имя, но эмитил его как есть, то есть невалидный XML.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NBsZA5cr2WFThtgp7i5WVi
Дыра в сценарии: добавить таблицу или функцию к уже существующему источнику было нечем.
Совет «пересоберите источник целиком через meta-compile» оказался вредным — повторная
компиляция заменяет файл источника, выдаёт объекту НОВЫЙ uuid и оставляет файлы не
упомянутых таблиц сиротами: в ChildObjects их уже нет, а на диске они остались.
meta-edit на файле источника принимает add.tables и add.functions. Таблица — единственная
операция навыка, создающая файл: <Источник>/Tables/<Имя>.xml плюс имя в ChildObjects.
Синтаксис тот же, что у meta-compile.
Формат файла таблицы обязан быть один и тот же, кем бы файл ни был создан, поэтому эмиттеры
скопированы из meta-compile механически и зарегистрированы в check-inline-drift.mjs — гард
теперь сверяет семь функций между двумя навыками. Чтобы копии не тянули за собой пол-navыка,
две из них развязаны от эмиттеров-специфик: Build-EdsTableXml принимает готовый XML полей,
Emit-EdsFunction — готовый XML типа. Каждый навык рендерит их своим эмиттером, вывод не изменился.
meta-compile теперь предупреждает о перезаписи существующего объекта — для всех видов, не только
внешних источников: молчаливая замена uuid ломает ссылки, а узнать об этом было неоткуда.
Раундтрип на платформе 8.3.24.1691: таблица, добавленная через meta-edit, возвращается из
выгрузки байт в байт.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NBsZA5cr2WFThtgp7i5WVi
Свойство теряется не «в DSL», а при любой загрузке XML — платформа сбрасывает его даже при
загрузке собственной выгрузки. Проверено изолированно: dump-1 без правок загружен и выгружен
обратно, узел UnfilledParentValue — единственное расхождение во всём файле.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NBsZA5cr2WFThtgp7i5WVi
Перечитал reference глазами модели, которая будет им пользоваться, и убрал то, что отвечает
на вопрос «как сделано», а не «как применять»: развёртывание коротких имён полей в полный путь,
«компилятор отказывает сразу», обоснование через поведение Конфигуратора, отдельный раздел про
пустой ключ (ужат до строки в таблице свойств).
Исправлено по существу:
- `unfilledParentValue` был описан как рабочий ключ, хотя платформа сбрасывает его при загрузке
XML — теперь сказано прямо, что через DSL его не задать;
- добавлена строка `readOnly` у таблицы с подсказкой ставить его представлениям и таблицам вида
Expression (загрузка этого не требует — проверено, — но писать в них нельзя);
- `inputByString` документирует вывод из поля представления;
- убран дубль строки `readOnly` в таблице свойств.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NBsZA5cr2WFThtgp7i5WVi
Вид ExternalDataSource навыки meta-* не поддерживали вовсе: в корпусе выгрузок его нет
ни одного, формат был неизвестен. Разведан на стенде (PostgreSQL в Docker + база 8.3.24)
и по реальной выгрузке рабочего проекта.
meta-compile собирает источник целиком одним JSON: сам источник, его таблицы с полями
и функции. Единственный вид, у которого объект складывается более чем из одного XML —
файл источника плюс по файлу на таблицу в <Источник>/Tables/.
DSL без новых конвенций: tables — dict имя → массив полей ЛИБО объект (как tabularSections),
поле — обычный реквизит плюс три своих ключа (nameInDataSource/readOnly/allowNull),
ссылки на поля короткими именами (как inputByString у справочника), functions — dict
имя → строка ИЛИ объект (как urlTemplates). Параметры функций не объекты метаданных:
они живут в самом выражении как &1, &2.
Инструкция под каскадом: в SKILL.md строка индекса, вся специфика — в
reference/external-data-source.md.
meta-validate принимает ExternalDataSource и Table, знает их наборы GeneratedType,
состав ChildObjects и шестичастную ссылку на форму таблицы. Проверено на выгрузке
платформы и на чужой рабочей выгрузке из другого проекта — обе проходят чисто.
Раундтрип на платформе 8.3.24.1691: наш эмит → загрузка → выгрузка даёт файлы,
идентичные поданным (с точностью до uuid). Два поведения платформы пришлось воспроизвести
явно, оба измерены: ввод по строке выводится из поля представления, а заданное значение
незаполненного родителя платформа при загрузке XML сбрасывает в пустую строку — задать
его можно только интерактивно.
Спека: раздел «Внешние источники данных» в 1c-config-objects-spec.md, формат ссылок,
наборы GeneratedType, строка в индексе спек.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NBsZA5cr2WFThtgp7i5WVi
meta-decompile не знал тип WebService — 18 сервисов УТ не проходили раундтрип.
Добавлен разбор (оба порта): namespace, состав XDTO-пакетов, дескриптор,
операции с параметрами.
Компилятор поддерживал тип поверхностно; раундтрип на реальных сервисах
показал, чего не хватало:
- XDTOPackages эмитился скаляром, а это СПИСОК элементов: ссылка на пакет
конфигурации (xr:MDObjectRef) либо URI внешнего пространства имён
(xs:string). Presentation пуст, CheckState 0 — 19/19 по корпусу;
- DescriptorFileName не эмитился вовсе, хотя есть у всех 18 сервисов и НЕ
выводится из имени (DMILService -> dmil.1cws) — нужен явный ключ;
- DataLockControlMode не эмитился (Managed у всех 192 операций);
- Comment не эмитился ни у сервиса, ни у операций и параметров;
- типы из собственного пространства имён (81 случай) писались без локального
xmlns. В DSL задаются нотацией Кларка "{uri}ИмяТипа", компилятор объявляет
xmlns сам — как это делает платформа.
Nillable захватывается явно у операций и параметров: по корпусу значения
смешанные (операции 103/89, параметры 128/395), дефолт угадать нельзя.
Порядок операций и параметров приведён к порядку DSL в обоих портах — PS шёл
в порядке хеш-таблицы, py сортировал.
Проверка: 25 сервисов УТ (18 WebService + 7 HTTPService) 25/25 без
расхождений; JSON декомпилятора побайтово совпадает у PS и py на всех 25;
сюита 76/76 на обоих портах; 1С-сертификация обоих кейсов пройдена.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Дельта формата 2.17→2.20 содержит три безусловных свойства, которых компилятор
не эмитил. Все три пишутся ТОЛЬКО при формате >= 2.20 (Detect-FormatVersion),
поэтому 2.17-проекты не меняются: полная сюита зелёная, ни один существующий
снэпшот не сдвинулся.
- xr:TypeReductionMode — каждому стандартному реквизиту, после CreateOnInput.
TransformValues, кроме Owner → Deny (правило проверено против выгрузки acc:
9 из 9 реквизитов совпали, включая Owner).
- TypeReductionMode — измерениям регистра СВЕДЕНИЙ (у прочих семейств и у
реквизитов/ресурсов платформа его не пишет).
- LineNumberLength — табличным частям, последним в Properties.
LineNumberLength — прикладная возможность 8.3.27 (5..9 → до 999 999 999 строк
вместо 99 999), поэтому получил полноценный DSL-ключ и описание в spec §5.2.
Его дефолт зависит НЕ от версии формата, а от режима совместимости на момент
создания ТЧ (<=8_3_26 → 5, >=8_3_27 → 9) — платформа фиксирует значение и позже
не пересчитывает, поэтому в одной конфигурации соседствуют ТЧ с 5 и 9. Отсюда
новая Detect-CompatibilityMode: читает CompatibilityMode из Configuration.xml
(префикс 64 КБ — тег лежит на ~11-12 КБ, существующим 2000 байт не хватает).
Декомпилятор: TypeReductionMode захватывается только при отклонении от правила
(компилятор выводит его сам), LineNumberLength — всегда при наличии тега:
выводить его дефолт значило бы дублировать логику компилятора с риском разойтись.
Компараторы версий числовые по компонентам — строковое сравнение неверно
("2.9" > "2.17" лексикографически).
Тест-инфра: setup-фикстуры empty-config-220 и empty-config-220-compat24
(строятся тем же cf-init), два кейса — по одному на каждую ось.
Проверка: роундтрип реального 2.20-документа БП (АвансовыйОтчет, 7 ТЧ) —
по новым тегам 0 расхождений, значения и позиции совпали; остаточный хвост
52/39 идентичен такому же на 2.17, то есть пред-существующий. Сюита 570/570
ps1, 567+3 skipped py, ps1==py. 1С-сертификация обоих кейсов на 8.3.27 ✓.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
MDObjectRef ссылается на ОБЪЕКТ метаданных (Catalog.Валюты), а не на тип ссылки.
Эмиттеры пропускали значение как есть, если в нём была точка, поэтому
"CatalogRef.Валюты" доходил до XML без изменений → при загрузке конфигурации
платформа отвечала «Неизвестный объект метаданных».
Инструкция вела в баг сама: reference/catalog.md документировал
owners: ["CatalogRef.Контрагенты"]. Тестами не ловилось — все кейсы
использовали каноническую форму.
- Normalize-MDObjectRef расширена ссылочными формами (англ. *Ref + рус. *Ссылка);
вида метаданных, оканчивающегося на Ref, не существует → схлопывание однозначно.
В ТИПАХ реквизитов запись CatalogRef.X верна — там мапа не применяется.
- Добавлен параметр defaultRoot (голое имя без точки), инлайн-подстановка
"Catalog.$ownerRef" в owners убрана — логика теперь в одном месте.
- Нормализация применена в 4 местах, где её не было: owners, basedOn,
registerRecords, baseCalculationTypes.
- Кейс catalog-inputbystring-datalock переведён на неканонический вход:
снэпшот не изменился ни на байт — прямое доказательство нормализации.
Регресс 73/73 ps1+py, полная сюита 566/566. Живая проверка на 8.3.27:
подчинённый справочник с owners CatalogRef./СправочникСсылка. грузится чисто.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
CommandGroup.category — допустимые значения (из upload/meta/CommandGroups):
NavigationPanel/ActionsPanel (командный интерфейс раздела) или FormCommandBar/
FormNavigationPanel (командный интерфейс формы). + связь с command.group=CommandGroup.<Имя>.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
«Секционные» — выдуманный термин, в 1С его нет. Группы противопоставляются как
командный интерфейс РАЗДЕЛА (панель навигации/действий) и ФОРМЫ. Поправлены
reference/blocks.md, тексты ошибок и комментарии (ps1+py). Поведение не изменилось
(имена переменных внутренние; expectError-подстроки на месте).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Emit-Command: резолв группы (Resolve-CommandGroup) — русские подписи групп
(«Панель навигации.Важное» → NavigationPanelImportant и т.д.), `ГруппаКоманд.X`
→ `CommandGroup.X`. Закрыты два пробела валидации (найдены при 1С-cert):
- пустая/опущенная group → ошибка с подсказкой (список валидных групп), а не
молчаливый незагружаемый <Group/>;
- секционная группа (NavigationPanel*/ActionsPanel*) + commandParameterType →
ошибка (тип параметра доступен только для групп формы/CommandGroup — подтверждено
выгрузкой ЕРП: команды с параметром только в Form*/CommandGroup).
Списки групп из реального erp_8.3.24. Зеркало ps1+py (идентично).
reference/blocks.md: каноничный список групп + правило параметра (без прощающего
ввода — usage-голос). Тесты: catalog-command-groups (рус-синонимы/секц/форма/кастом
через preRun CommandGroup, 1С-cert ✓) + 2 expectError (пустая group; секц+параметр).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
В charts.md createOnInput был документирован у ChartOfCharacteristicTypes,
но не у ChartOfAccounts/ChartOfCalculationTypes (в одном файле — несогласованно,
читатель мог решить, что у них его нет). Добавлен с фактическим значением
DontUse (как эмитит компилятор).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Порезал документацию по слою абстракции и форме DSL вместо внутренней
таксономии 1С: тонкий SKILL.md с двухосевым индексом + 13 reference-файлов
(по типу/семейству + кросс-типовые attributes.md/blocks.md) взамен 4 types-*.md.
Вынес в поставку объектную форму реквизита/ТЧ и блоки объекта (fillValue,
choiceParameters, представления, команды, predefined и т.д.) — раньше жили
только в dev-спеке, модель их не видела. Usage-голос: каноничная форма,
дефолты, значения перечислений; без внутряка (синонимы/резолв/декомпилятор,
колонка XML). Починены противоречия дефолтов и убраны фантомные свойства
(по аудиту компилятора).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Normalize-EnumValue now uses 4-step logic: alias→case-insensitive→
error (if propName known)→pass-through (if unknown). Previously step 3
silently passed invalid values through to XML, causing cryptic 1C
LoadConfigFromFiles errors.
Also fixed RequireCalculationTypes→OnActionPeriod (the former never
existed in 1C; verified against ERP/ACC dumps). Added NotUsed→DontUse
alias, synced meta-edit.ps1 aliases with meta-compile.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace monolithic docs/meta-dsl-spec.md link with 4 domain-specific
reference files inside the skill directory. Agent reads only the
relevant file when compiling a specific type, reducing context usage.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>