1c-meta MCP Server
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@1c-meta MCP Servercreate a catalog named Products with a string attribute Comment"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
1c-meta — создание и правка метаданных 1С в выгрузке конфигуратора и проекте EDT
Инструмент пишет файлы выгрузки так же, как их пишет конфигуратор, и не даёт нарушить правила, которые иначе всплывают только при загрузке в базу. Исходники в формате проекта 1C:EDT он читает и пишет так же, как их пишет EDT; формат определяется по каталогу сам (раздел «Проект EDT»). Внешние обработки и отчёты он создаёт и правит в их собственной выгрузке (раздел «Внешняя обработка и отчёт»).
Проверено двумя способами: сборкой обратно (побайтно) всех существующих объектов выгрузки крупной типовой конфигурации и кругом «записали → загрузили конфигуратором → выгрузили обратно», в котором платформа не меняет ни символа.
Лицензия — MIT (LICENSE); сторонние компоненты — THIRD_PARTY_NOTICES.md.
Установка
Нужны Python 3.10 или новее (проверено на 3.13) и git в PATH. Пакеты:
py -3 -m pip install "lxml>=5.0" # всегда: разбор и сборка файлов выгрузки
py -3 -m pip install "mcp>=1.29" # только для MCP-сервера (pydantic придёт с ним)
py -3 -m pip install pytest ruff # только для проверокНа Linux и macOS вместо py -3 — python3. Инструмент запускается из каталога
репозитория как есть; пакетом для pip install он не оформлен.
Для проекта 1C:EDT нужна ещё таблица метамодели EDT — порядок и умолчания свойств объектов и форм. В репозитории её нет: она снимается с моделей установленного 1C:EDT, на той машине, где инструмент работает:
py -3 tools/edt_model_from_xcore.py # без аргумента — пул p2: %USERPROFILE%\.p2\pool\pluginsПолучится meta/acl/edt_metamodel.py (в .gitignore). Без неё выгрузка
конфигуратора работает полностью, у проекта EDT работают проверки и
нормализация, а запись и показ отклоняются с этой же подсказкой.
Выгрузка — каталог, который пишет конфигуратор командой «Конфигурация → Выгрузить конфигурацию в файлы». Результат загружается обратно командой «Загрузить конфигурацию из файлов» — целиком, а не частично (раздел «Ограничения»).
Related MCP server: xbsl-mcp
Быстрый старт
Задание — файл JSON: куда писать (repo — каталог выгрузки, где лежит
Configuration.xml) и что сделать. Для пробы годится пустая выгрузка: скопируйте
meta/tests/эталоны/формы/Configuration.xml в пустой каталог и укажите его
в repo. Примеры дальше ссылаются и на типовые объекты (Справочник.Организации
и другие) — в пустой выгрузке их нет, и такие ссылки получат ТИП-НЕТ, пока
объекты не заведены. Справочник с одним реквизитом:
{"repo": "C:/путь/к/выгрузке/cf",
"objects": [
{"вид": "Справочник",
"поля": {"имя": "мой_Пример", "синоним": "Пример",
"реквизиты": [
{"имя": "Комментарий", "синоним": "Комментарий",
"тип": {"вид": "Строка", "длина": 100}}]}}]}Сохраните его в UTF-8 как задание.json и посмотрите, что будет сделано, —
на диск при этом не пишется ничего:
py -3 meta/add.py задание.jsonВыгрузка: C:/путь/к/выгрузке/cf
Справочник мой_Пример
замечаний нет
синоним: Пример
реквизиты: Комментарий «Комментарий» (Строка(100))
(ещё 50 полей не названы в задании — значения по умолчанию; …)
План:
создать C:\путь\к\выгрузке\cf\Catalogs\мой_Пример.xml (6150 Б)
изменить C:\путь\к\выгрузке\cf\Configuration.xml (станет … Б, было … Б)
Просмотр: ничего не записано. Для записи повторите с --apply.План тот — записываем:
py -3 meta/add.py задание.json --applyТо же задание принимает MCP-сервер: metadata_check — просмотр,
metadata_apply — запись (раздел «MCP-сервер для агентов»).
Ограничения
Формат выгрузки — 2.21, то есть платформа 8.5. Выгрузку другого формата инструмент читает, но метаданные и формы в неё не пишет (раздел «Запуск»).
Загрузка обратно — только полная. Служебный
ConfigDumpInfo.xmlинструмент не правит: его пересобирает платформа при загрузке.Заведено 15 видов объектов конфигурации из 43 (и внешние обработка с отчётом) и 15 видов элементов форм из 31; чего нет, перечислено в разделе «Чего нет».
Проект EDT поддерживается наравне с выгрузкой; оговорки — в разделе «Проект EDT».
Внешние обработка и отчёт — в своей выгрузке, без удаления и переименования; оговорки — в разделе «Внешняя обработка и отчёт».
Проект EDT
Инструмент работает с двумя форматами исходников. Какой перед ним, он
определяет по корню: Configuration.xml — выгрузка конфигуратора,
Configuration/Configuration.mdo — проект EDT. Корень проекта EDT — каталог
src (в командном репозитории это может быть подкаталог, например BF\src):
его и указывают в repo, в --проверить и в остальных командах. Ключей и
полей заданий для EDT нет — задание одно и то же.
Чем проект EDT отличается от выгрузки и что из этого следует:
Выгрузка | Проект EDT | |
Карточка объекта |
|
|
Модуль |
|
|
Модуль формы |
|
|
Права роли |
|
|
Реестр объектов |
| списки в |
Форма, макет | отдельные карточки | строка в карточке хозяина + |
Служебный файл |
| нет |
Формат файла | UTF-8 с BOM, CRLF | UTF-8 без BOM, LF |
Адрес модуля в заданиях на код один и тот же в обоих форматах
(Справочник.Банки.МодульОбъекта) — путь к файлу инструмент строит сам.
Что работает в проекте EDT:
проверка правок задачи (
--проверить,verify): пути — от корня исходников, ревизии git читаются из подкаталога репозитория, права ищутся вRights.rights. BOM и переводы строк сверяются с тем, как файлы лежат в репозитории, а не с форматом выгрузки: лишний BOM — находкаФАЙЛ-ЛИШНИЙ-BOM. Правило служебного файла выгрузки к проекту EDT не применимо и попадает в пояснения, а не в пропущенное — прогон остаётся полным;нормализация формата (
normalize_check) — без BOM, перевод строк файла;сверка плана изменений (
plan_check,plan_emit) — состав объектов читается из.mdo;создание объектов всех 15 видов, реквизиты и вложенные сущности, правка и удаление свойств, удаление и переименование объектов, атомарные роли (
metadata_apply);правка кода вставками (
code_apply) в модули безExt;формы (
forms_apply): новая форма объекта и общая форма, правка существующей формы — элементы, реквизиты, колонки, команды, события, те же виды и свойства, что у выгрузки. Новая форма объекта — записьformsв карточке хозяина,Forms/<Форма>/Form.formиModule.bsl; у динамического списка — ещёAttributes/<реквизит>/ExtInfo/ListSettings.dcss;показ объекта и формы (
--показать,show), код доработки типовой формы («код»: true) — он читаетForm.form, чтобы знать соседей и места вставки.
Чего нет в проекте EDT:
у формы — того же, чего нет у формы выгрузки (раздел «Чего нет»), и встроенных картинок (
xr:Abs): EDT хранит их отдельным файлом формы. Новую такую картинку запись отклоняет; у существующих элементов картинки, цвета, шрифты, параметры выбора и всё, чего редактор не касается, едут нетронутыми. Настройки динамического списка (ListSettings.dcss) пишутся только новому реквизиту: файл существующего не перезаписывается;свойства выгрузки, которые инструмент сам не пишет (стандартные реквизиты, параметры выбора, связи по типу, картинки, цвет и шрифт элемента стиля и т. п.), в формат EDT не перекладываются. В существующих объектах они не трогаются: карточка
.mdoчитается и пишется обратно как есть, меняется только то, что задано заданием. Если такое свойство пришлось бы переложить, запись получает отказ с перечнем, а не теряет его молча.
Как устроено. Карточка .mdo — объект EMF, и порядок, умолчания и вид
каждого свойства задаёт метамодель EDT. Её таблица
(meta/acl/edt_metamodel.py) снимается с моделей *.xcore из пакетов
установленного EDT скриптом tools/edt_model_from_xcore.py при установке
(раздел «Установка») — в репозитории её нет, это производное от моделей 1С. Чтение
переводит .mdo в дерево карточки выгрузки (meta/acl/edt_card.py,
Reverse), и дальше работают те же правила, что для выгрузки; запись
переводит обратно (Translation). Чего перевод не понимает, проходит сквозь
него нетронутым. Текст файла — meta/infra/edt_xml.py, площадка —
meta/infra/edt_dump.py, раскладка каталогов — meta/infra/layout.py,
форма — meta/infra/forms/edt.py.
Форма EDT — тоже объект EMF, но устроена иначе, чем Form.xml: элемент —
обобщённый items с классом и видом в поле type, свойства своего вида — в
extInfo, умолчания платформы (visible, enabled, userVisible,
placementArea у кнопки…) записаны явно. Перекладка формы —
meta/acl/edt_form.py: прямая (FormTranslation, Form.xml → Form.form)
и обратная (ReverseForm). Правка существующей формы идёт по кругу:
Form.form → Form.xml → тот же редактор, что у выгрузки → Form.form.
Таблица умолчаний платформы (meta/acl/edt_form_defaults.py) снята с
корпуса и с оракула скриптом tools/edt_form_check.py --умолчания. Элемент,
круг которого по богатой перекладке не сходится, обратная перекладка отдаёт
«скелетом»: имя, id, вид, путь к данным, дети и спутники — по-настоящему,
остальное — переходником; правке редактором это не мешает.
Чем проверено:
таблица метамодели — на всех 23 375 карточках и 11 058 формах проекта крупной типовой конфигурации: ни одного свойства не по порядку (
tools/edt_order_check.py; в тестах — при заданномMETA_EDT_CORPUS);текст — разбор и запись тех же 34 433 файлов побайтно (
tools/edt_text_roundtrip.py);перевод —
.mdo→ дерево выгрузки →.mdoна всех 23 375 карточках побайтно (tools/edt_adapter_roundtrip.py);запись — против самого EDT.
tools/edt_oracle.pyприменяет заданияmeta/tests/эталоны/edt/задания/писателем выгрузки, импортирует выгрузку командной строкой EDT (1cedtcli import) и кладёт полученный проект вэталоны/edt/ожидание. Тест применяет те же задания к проекту EDT и сверяет каждый файл побайтно (test_edt_write.py), в том числе задания на формы: новая форма, наполнение, правка существующей, список, дерево, виды элементов —эталоны/edt/ожидание-формы. Формы оракула, прочитанные изForm.form, сверяются с теми же формами изForm.xml;круг формы —
Form.form→ деревоForm.xml→Form.formна всех 11 058 формах проекта побайтно (tools/edt_form_check.py --круг). Командная строка EDT на Windows пишет CRLF, а в репозитории файлы лежат с LF — оракул приводит эталон к LF, как это делает git.
Эталоны пересобираются так (нужны установленный 1C:EDT и JDK 17 из его комплекта):
py -3 tools/edt_oracle.py C:/временный/каталогВнешняя обработка и отчёт
Внешняя обработка конфигуратором выгружается не в каталог конфигурации, а сама по себе: карточка — корень выгрузки, рядом каталог с тем же именем.
<каталог>/мой_Обработка.xml карточка (ExternalDataProcessor)
<каталог>/мой_Обработка/Ext/ObjectModule.bsl модуль объекта
<каталог>/мой_Обработка/Forms/Форма.xml формы — как у обработки
<каталог>/мой_Обработка/Forms/Форма/Ext/Form.xml
<каталог>/мой_Отчет/Templates/ОсновнаяСхема.xml макеты — так жеВыгрузка внешней обработки — это каталог без Configuration.xml: в
repo указывают его (пустой — под новую обработку). В одном каталоге может
лежать несколько обработок и отчётов. Формат текста тот же, что у выгрузки
конфигурации: UTF-8 с BOM, CRLF, версия 2.21.
Что работает:
Операция | Как |
создать обработку |
|
создать отчёт | вид |
реквизит, табличная часть в существующую |
|
форма |
|
модуль |
|
{"repo": "C:/work/ЗАДАЧА-1/Реализация",
"objects": [{"вид": "ВнешняяОбработка", "поля": {
"имя": "мой_Загрузка", "синоним": "Загрузка",
"реквизиты": [{"имя": "Файл", "синоним": "Файл", "тип": "Строка(0)"}],
"модульОбъекта": "#Область ПрограммныйИнтерфейс
#КонецОбласти
"}}]}Чем внешний объект отличается от обычного, и откуда это известно — круг через конфигуратор 8.5.1 на пустой базе, а не корпус (внешних обработок в корпусе нет):
в служебном блоке первым стоит
xr:ContainedObject— класс вида (постоянный) и свой идентификатор объекта;порождаемый тип один — объект; менеджера у внешнего объекта нет;
свойств у обработки пять (имя, синоним, комментарий, две формы), у отчёта — свойства отчёта конфигурации без команд, справки и представлений;
табличная часть называется
DataProcessorTabularSection…/ReportTabularSection…(неExternal…— так её выгружает конфигуратор, что бы ни было загружено) и всегда несёт блок стандартного реквизита «НомерСтроки»;карточка формы несёт ещё
ExtendedPresentation;основная форма в свойствах —
ExternalDataProcessor.Имя.Form.Форма.
Чего нет:
удаления и переименования — отказ: удаляют каталог обработки вместе с карточкой, переименовывают в конфигураторе;
общих форм и объектов конфигурации в такой выгрузке не бывает — отказ;
проверки прав (
verify): внешний объект в роли не входит, проверять нечего;сверки плана (
plan_check) — как и раньше;«модуль создан задачей» инструмент определяет по git: модуль, которого нет в базовой ревизии, — свой, меток в нём нет. Выгрузка внешней обработки обычно не под git, и тогда каждый существующий модуль — чужой: правка вставкой получает метку. Для обработки, созданной задачей с нуля, текст модуля задают сразу полем
модульОбъекта— он пишется без меток.
Эталоны — от конфигуратора: tools/epf_oracle.py применяет задания
meta/tests/эталоны/внешние/задания/ в пустой каталог, загружает каждую
карточку в файл на пустой базе (/LoadExternalDataProcessorOrReportFromFiles),
выгружает обратно (/DumpExternalDataProcessorOrReportToFiles) — выгрузка и
есть эталон эталоны/внешние/ожидание. Тест test_external_write.py сверяет
запись инструмента с ним побайтно. Оракул сам печатает расхождения записи с
выгрузкой: всё, что конфигуратор дописал или переставил, — недоработка
инструмента. Пересборка (нужна установленная платформа; база создаётся в
рабочем каталоге, открытый конфигуратор не мешает):
py -3 tools/epf_oracle.py C:/временный/каталогЧто умеет
Операция | Виды |
Создать объект | 15 видов: справочник, документ, перечисление, константа, определяемый тип, регистр сведений, регистр накопления, отчёт, обработка, роль, подсистема, общий модуль, общая команда, подписка на событие, регламентное задание; в своей выгрузке — внешние обработка и отчёт |
Создать объект сразу с содержимым | реквизиты; табличные части с их реквизитами; значения перечисления; измерения и ресурсы регистра; права роли; макет со схемой компоновки у отчёта — одной операцией, одним планом |
Добавить вложенную сущность по адресу хозяина | 12 видов: реквизит, измерение, ресурс, табличная часть, значение перечисления; в схеме компоновки — набор данных, параметр, вариант настроек, выбираемое поле, отбор, поле порядка, группировка структуры |
Изменить значение свойства | у объекта и у любой вложенной сущности, включая пункты настроек компоновки, по адресу |
Удалить | объект целиком (карточка, спутники, запись в реестре) или вложенную сущность — в том числе внутри схемы компоновки |
Переименовать объект | вместе со всеми ссылками на него |
Завести атомарные роли | пара «Просмотр»/«Изменение» по схеме имён команды из профиля — к новому объекту тем же заданием или к существующему |
Завести или дополнить управляемую форму | новая форма любого назначения мастера (документа, элемента, списка, записи, обработки…) или существующая: реквизиты формы (в том числе колонки таблиц значений), команды, элементы пятнадцати видов с родителем и местом, свойства по русским именам платформы, обработчики, события формы, удаление; модуль — заготовки обработчиков |
Доработать типовую форму | то же описание -> фрагмент кода доработки формы для вызова из |
Править код BSL вставками | тип метки выводится из правки, метки с датой, задачей и автором, комментирование заменяемого кода, отступы — инструментом; откат вставок задачи, переименование метода в модуле, перенос метода между модулями; модуль — адресом (таблица адресов — в разделе «Правка кода вставками») |
Проверить правки задачи | файлы, которые задача добавила и изменила против базы — под git или парой каталогов «эталон — копия»: метки вставок тем же разбором, что у записи, приставка новых объектов, BOM и переводы строк, правки только пробелами, права на новые объекты; находки с кодом, файлом и строкой, текстом и JSON |
Вернуть файлам задачи формат выгрузки | BOM, переводы строк как в репозитории (у пары — как у эталона), хвостовые пробелы неизменённых строк из базы, отступ пустых строк в методах, завершающий перевод строки как в базе; просмотр и запись, идемпотентно |
Сверить план изменений с фактом | план JSON-ом — объекты задачи, их новые члены с типами, методы модулей — против правок задачи: заявлено, но не сделано; сделано, но не заявлено; типы не совпали; и план по факту в том же формате |
Удаление отказывает, если на объект ссылаются, и называет место каждой ссылки — адрес до реквизита и свойство. Ссылки ищутся по всей выгрузке одним обозначением: типы реквизитов, источники подписок и обработчики, движения документов, состав подсистем (включая подчинённые), права ролей, ссылки реестра конфигурации вне раздела детей и типы в схемах компоновки данных.
Формы, код BSL и остальные макеты не проверяются: на выгрузке крупной
типовой конфигурации 23 443 файла форм читаются две минуты, макетов там 14 447
на 3,4 ГБ (из них схем компоновки 926 на 86 МБ, и они как раз проверяются), а
модули при поиске ссылок не просматриваются. Об этом инструмент говорит при
каждом удалении, а не молчит. ConfigDumpInfo.xml не смотрится намеренно:
там названы все объекты подряд, платформа пересобирает его при загрузке.
Переименование — отдельная операция, а не правка поля «имя»: имя живёт в четырёх местах сразу — в собственной карточке (включая имена порождаемых типов и ввод по строке), в имени файла и каталога-спутника, в записи реестра и в каждой чужой карточке со ссылкой. Меняются все четыре разом; формы, код BSL и прочие макеты не переписываются, и об этом сказано.
Пачка переименований — одно согласованное изменение: имя, занятое другим переименованием той же пачки, отвергается (на диске его ещё нет, и молча вышел бы один файл вместо двух), а ссылка на объект, который переименуют позже, доезжает до нового имени.
Операции не смешиваются в одном задании: создание, добавление и изменение задаются разными ключами и выполняются по одному.
Прикладные объекты создаются вместе с порождаемыми типами: у справочника их пять (объект, ссылка, выборка, список, менеджер), у регистра семь, у перечисления три, у табличной части два (сама и строка), и на каждый по два идентификатора. Платформа принимает идентификаторы, порождённые инструментом, — это проверено загрузкой в базу, а не предположено.
Состав свойств зависит от того, где сущность живёт, и это тоже замерено, а не угадано: у реквизита табличной части 26 свойств против 29 у реквизита справочника — нет «использования» и обоих свойств заполнения; ресурс регистра отличается от измерения ровно четырьмя свойствами. Про незамеренное сочетание инструмент говорит вслух, а не пишет наугад.
Запуск
py -3 meta/add.py <задание.json> [--apply] [--профиль <профиль.json>]
py -3 meta/add.py --поля [Вид]Без --apply — просмотр: печатаются находки инвариантов, разобранные типы
и план изменений, на диск не пишется ничего.
repo — куда пишем. Проверьте путь перед запуском: задания копируют
из примеров, а пишется туда, что написано в задании.
Правка сохраняет переводы строк файла: конфигуратор пишет CRLF, а карточки выгрузки могут лежать с LF, и навязывать свои значило бы переписывать файл целиком — diff во весь файл вместо одной строки. Новый файл пишется переводами площадки.
Формат выгрузки — 2.21 (так выгружает конфигуратор 8.5). Версию инструмент
читает из корня Configuration.xml. Выгрузку другого формата (у платформы
8.3.27 это 2.20) он читает, а писать в неё отказывается: платформа такие
карточки не загрузит («Неизвестная версия формата 2.21 загружаемого файла»).
Метаданные и формы получают отказ до записи, на диске не меняется ни байта.
Правка кода вставками от формата не зависит и идёт в любую выгрузку.
Профиль соглашений команды
Правила живут в инструменте и названы кодами находок (МД-ПРЕФИКС,
ФОРМА-ТИПОВАЯ-ТОЛЬКО-КОДОМ, ПОДПИСКА-НА-СВОЙ-ОБЪЕКТ…). А то, что у команд
разное, — приставка доработок, метка команды в метках вставок, имена
атомарных ролей, язык кода доработки формы и насколько строго держится каждое
правило, — задаёт один файл, профиль соглашений:
{
"приставка": "мой_",
"метки": {"тег": "#TEAM"},
"атомарныеРоли": {"имя": "мой_атом_{вид}_{объект}_{право}",
"синоним": "(Мой) Атом. {вид} - {синоним} - {право}"},
"кодФормы": {"язык": "платформа"},
"правила": {"МОДУЛЬ-КОНТЕКСТ-НЕ-ПО-СТАНДАРТУ": "ошибка", "МД-БЕЗ-СИНОНИМА": "выкл"}
}приставка — с чего начинаются имена всего, что команда добавляет сама: по ней
новое отличается от вендорского, а своя форма — от типовой. Списком — основная
первой (её ставят новым именам и называют в находках), остальные тоже свои:
старые приставки команды, тестовые модули (["мой_", "ОМ_мой_"]). метки.тег — метка
команды, которую открывающая метка вставки ставит перед автором:
// {[+](фрагмент ДОБАВЛЕН), 06.10.2026, #TEAM Автор #Задача; без неё метка
пишется …, 06.10.2026, Автор #Задача. Разбор меток от профиля не зависит:
метку любой команды он узнаёт, а ИД задачи берёт из последнего «#».
метки.ставить — false, если команда меток вставок не ставит вовсе: правка
кода пишется на место старого кода (замена — без закомментированной копии,
удаление — удаляет, новый метод — как есть; история — в git), а проверка
правок не держит правила меток (ВСТАВКА-*, ПРАВКА-ВНЕ-ВСТАВКИ,
ПРАВКА-В-ЧУЖОЙ-ВСТАВКЕ). Метки прошлых задач в модулях не трогаются. По
умолчанию — true.
атомарныеРоли — как команда называет атомарные роли (раздел «Атомарные роли»);
без схемы инструмент таких ролей не заводит. кодФормы — на каком языке
пишется код доработки типовой формы (раздел «Формы»): «платформа» — встроена и
по умолчанию; свой язык команды — файлом-диалектом с его настройками (там же).
правила —
код находки и уровень: «ошибка» (писать нельзя), «предупреждение» (можно, но
посмотреть) или «выкл». Неизвестный ключ профиля, код не по форме кода находки
и неверный уровень — отказ. Существование кода не проверяется: правило с
кодом, которого у инструмента нет, ничего не меняет, поэтому код берут из
ответа инструмента или из этого README.
Профиль подключается переменной окружения META_PROFILE (путь к JSON) — у
сервера MCP и у терминала; терминалу можно и ключом --профиль, он важнее.
Сервер называет соглашения в своей инструкции, и агент знает приставку и метку
команды до первого задания. Без профиля соглашения нейтральные: приставки и
метки команды нет, и правила, которым нужна приставка, не применяются —
инструмент остаётся писателем выгрузки, не навязывая соглашений одной команды
другой.
Имена операций — английские (objects, attributes, additions, changes,
deletions, renames, atomic_roles), как и repo; поля предметной области —
русские (имя, поля, путь, принято).
MCP-сервер для агентов
Второй канал — тот же инструмент для агентов, у которых нет оболочки. Сервер
подключается в настройках MCP-клиента; у Claude Code — файл .mcp.json проекта,
ключ mcpServers:
"1c-meta": {"type": "stdio", "command": "py",
"args": ["-3", "C:\\путь\\к\\1c-meta\\meta\\mcp_server.py"],
"env": {"META_ROOTS": "C:\\путь\\к\\проекту1\\cf;C:\\путь\\к\\проекту2\\cf",
"META_PROFILE": "C:\\путь\\к\\профиль.json"}}py -3 — запуск Python на Windows; на Linux и macOS — "command": "python3"
и путь к mcp_server.py без -3. Разделитель путей в META_ROOTS — «;».
Инструмент | Что делает |
| что лежит в выгрузке: карточка объекта (у роли — с правами, у объекта — перечень форм с пометкой основных) или форма деревом элементов (у групп — группировка; |
| поля вида; без вида — операции и виды с примером пункта (формы — не операция |
| просмотр задания на формы: находки и план, без записи; |
| то же с записью |
| просмотр задания на объекты и их части — одна операция; |
| то же с записью |
| просмотр правки кода вставками: решение по каждой правке — с местом (метод или область) — и текст, который встанет на её место, с номерами строк нового модуля и строкой-соседом сверху и снизу; без записи |
| то же с записью; модули пишутся все разом или ни один; |
| проверка правок задачи против базы — только чтение; раздел «Проверка правок задачи» |
| что нормализация вернёт файлам задачи — без записи |
| то же с записью: все файлы разом или ни один |
| сверка плана изменений с фактом задачи — только чтение; раздел «Сверка плана изменений» |
| план по факту задачи — JSON того же формата |
Описание инструмента не длиннее 2000 знаков: клиент обрезает его на 2048,
и хвост длинного описания агент просто не видит. Описание — суть; полные
правила правки кода — справкой fields(kind="Код") (у терминала
--поля Код). Тест следит за длиной всех описаний и инструкции сервера. У
verbose и accepted в схеме — свои описания: смысл подробного показа у
каждого инструмента свой, а формат кода в accepted иначе пришлось бы
угадывать.
Задание, которое не выполнится, начинается строкой «ОТКАЗ: …» — и отказ языка заданий, и ошибки в находках («ОТКАЗ: ошибок 1, предупреждений 3 — задание не пройдёт; находки ниже»). Признак стоит первой строкой, поэтому любой отказ находится поиском по «ОТКАЗ:», а не дочитыванием ответа до конца.
Задания описаны типами (meta/api/models.py): схема инструмента строится из
них, и формат задания агент получает от самого сервера. У задания на объекты
типами описаны операции и их пункты, а поля самого объекта — словарь: их
сотни, и состав по виду отдаёт fields(kind), включая атомарныеРоли. Схема
объявляет лишние ключи недопустимыми, как и язык заданий. Лишний ключ пункта —
отказ языка заданий; лишний параметр инструмента (FastMCP сам по себе
отбрасывает его молча — например, «принято» вместо accepted) и неверная
форма запроса (объект вместо списка) — отказ «ОТКАЗ: …» по-русски с перечнем
допустимого, а не тишина и не текст валидатора по-английски.
Ключи задания на код в схеме MCP — латиницей: модуль называется module, как
соседи path, edits, line; русское «модуль» понимается тоже, оба сразу —
отказ. Язык заданий терминала зовёт его «модуль», переводит контроллер.
Тип значения пишется краткой записью — так его печатает show, и её
принимают оба задания: Строка(50), Строка(9, фиксированная), Число(15,2),
Число(10,0, неотрицательное), Дата (только дата), ДатаВремя, Время,
Булево, Справочник.Контрагенты (ссылка), Документ.Заявка (Объект),
Справочник.*, ОпределяемыйТип.Имя, Характеристика.ИмяПВХ, ЛюбаяСсылка;
составной — через «|». Объектная запись ({"вид": "Строка", "длина": 50})
принимается тоже. Показ и задание говорят одной записью, поэтому тип,
скопированный из show, задание принимает как есть; набор типов (TypeSet)
показывается своим именем — ОпределяемыйТип.Имя, а не «Произвольным» (на
выгрузке крупной типовой конфигурации таких реквизитов в справочниках и
документах 1597). Тест по замеренной выгрузке разбирает обратно каждый из
48 526 реквизитов справочников и документов.
Адрес формы пишется любым из двух способов — Документ.X.ФормаДокумента или
адресом её модуля Документ.X.Форма.ФормаДокумента (таблица адресов — в
разделе «Правка кода вставками»), общая — Общая.Имя или ОбщаяФорма.Имя, —
и принимается всеми инструментами.
Ответы — простым текстом, без обёртки {"result": …}: в ней переводы строк и
табуляции показа доходят до агента экранированными.
Git сервер запускает с закрытым stdin и таймаутом: унаследовав канал сообщений, git на Windows ждёт следующего сообщения, и сервер встаёт целиком. Тест на это идёт через настоящий stdio.
Чего у терминала нет: белый список — сервер работает только с выгрузками
из META_ROOTS (через «;»), и на чтение, и на запись; без настройки отказ
получает любой инструмент с repo, работает только справка fields. Отказ возвращается
текстом «ОТКАЗ: …», а не ошибкой вызова: агент читает его и исправляет задание
сам. Ответы — тот же текст, что в терминале, но подсказки в них — словами
канала: терминал говорит «повторите с --apply», сервер — «вызовите
forms_apply с тем же заданием».
Какие бывают поля
Наизусть их не помнят, и в документации им не место — разъедутся. Справку печатает сам инструмент по своим же описаниям:
py -3 ...\add.py --поля # виды и что у них бывает внутри
py -3 ...\add.py --поля ТабличнаяЧасть # поля, допустимые значения, умолчания
py -3 ...\add.py --поля ПолеФлажка # свойства элемента формыТабличнаяЧасть: полей 8, обязательные — имя
имя
синоним по умолчанию: ''
комментарий по умолчанию: ''
подсказка по умолчанию: ''
проверкаЗаполнения допустимо: НеПроверять, ВыдаватьОшибку; по умолчанию: 'НеПроверять'
использование допустимо: ДляЭлемента, ДляГруппы, ДляГруппыИЭлемента; по умолчанию: 'ДляЭлемента'
длинаНомераСтроки по умолчанию: '5'
реквизиты список: Реквизит — полями напрямую, без "вид"/"поля"Объект сразу с содержимым
Дети пишутся списком своих полей — без обёртки "вид"/"поля", которая есть
у объекта, — на любой глубине: у справочника есть табличные части, у них —
свои реквизиты.
{
"repo": "C:/путь/к/выгрузке/cf",
"objects": [
{"вид": "Справочник",
"поля": {"имя": "мой_ЛимитыПодразделений",
"синоним": "Лимиты подразделений",
"реквизиты": [
{"имя": "Подразделение", "синоним": "Подразделение",
"тип": {"вид": "Справочник", "имя": "Организации"}}],
"табличныеЧасти": [
{"имя": "Лимиты", "синоним": "Лимиты",
"реквизиты": [
{"имя": "Сумма", "синоним": "Сумма",
"тип": {"вид": "Число", "разрядность": 15, "дробнаяЧасть": 2}}]}]}}
]
}Типы: примитив — {"вид": "Строка", "длина": 20}, {"вид": "Число", "разрядность": 15, "дробнаяЧасть": 2}, {"вид": "Дата", "состав": "Дата"};
ссылка — {"вид": "Справочник", "имя": "Организации"}, грань «Ссылка»
подразумевается. Неизвестный ключ внутри тип — отказ: молчаливое умолчание
здесь незаметно и в задании, и в результате.
Регистр сведений описывается так же — измерения, ресурсы и реквизиты сразу:
{
"repo": "C:/путь/к/выгрузке/cf",
"objects": [
{"вид": "РегистрСведений",
"поля": {"имя": "мой_ЛимитыПоПодразделениям",
"синоним": "Лимиты по подразделениям",
"измерения": [
{"имя": "Подразделение", "синоним": "Подразделение",
"тип": {"вид": "Справочник", "имя": "Организации"}}],
"ресурсы": [
{"имя": "Лимит", "синоним": "Лимит",
"тип": {"вид": "Число", "разрядность": 15, "дробнаяЧасть": 2}}],
"реквизиты": [
{"имя": "Комментарий", "синоним": "Комментарий",
"тип": {"вид": "Строка", "длина": 200}}]}}
]
}Порядок ключей в задании ни на что не влияет: внутри карточки дети лягут в том порядке, которого требует платформа (у регистра сведений это ресурсы, затем реквизиты, затем измерения — вопреки тому, как показывает дерево конфигуратор).
Документ с движениями — поле движения, список регистров строкой «Вид.Имя»
или объектом, как тип:
{"вид": "Документ",
"поля": {"имя": "мой_ЗаявкаНаОплату", "синоним": "Заявка на оплату",
"движения": ["РегистрНакопления.мой_ЛимитыОплат",
{"вид": "РегистрСведений", "имя": "мой_ИсторияЗаявок"}]}}Что проверяется — по замеру всех 634 документов крупной типовой конфигурации (4191 движение): в движениях бывают только регистры (не-регистров — ни одного), только существующие, а регистр сведений — только подчинённый регистратору (986 из 986; независимый конфигуратор и не предложит). Движения при запрещённом проведении — предупреждение, не отказ: так у 7 документов из 383, все они «операции». Регистр заводится предыдущим заданием: объекты одного задания видят друг друга только по факту существования, а режим записи регистра из той же пачки прочитать неоткуда.
Круг через платформу проходит на проверочной пустой конфигурации: регистр накопления, документ с движениями по нему и пара атомарных ролей загружаются и выгружаются обратно — все шесть файлов возвращаются байт в байт, в реестре — ровно записи инструмента.
Формы
Форма для задания — не картинка, а перечень операций над ней, теми же словами, что у кода доработки формы: реквизит, элемент с родителем и местом, путь к данным, свойство, обработчик, команда.
{"repo": "C:/путь/к/выгрузке/cf",
"forms": [{
"форма": "Документ.мой_Заявка.ФормаДокумента",
"создать": {"основная": true, "синоним": "Заявка"},
"реквизиты": [
{"имя": "мой_Флаг", "тип": "Булево"},
{"имя": "мой_Строки", "тип": "ТаблицаЗначений",
"колонки": [{"имя": "Статья", "тип": "Строка(100)"}, {"имя": "Сумма", "тип": "Число(15,2)"}]},
{"имя": "Примечание", "тип": "Строка(50)", "таблица": "мой_Строки"}],
"команды": [{"имя": "мой_Заполнить", "заголовок": "Заполнить"}],
"элементы": [
{"вид": "ГруппаФормы", "имя": "мой_ГруппаШапка",
"свойства": {"Группировка": "Горизонтальная", "ОтображатьЗаголовок": false},
"элементы": [{"вид": "ПолеВвода", "имя": "Номер", "путь": "Номер"},
{"вид": "ПолеВвода", "имя": "Дата", "путь": "Дата"}]},
{"вид": "ПолеВвода", "имя": "Комментарий", "путь": "Комментарий",
"после": "мой_ГруппаШапка", "обработчики": {"ПриИзменении": true}},
{"вид": "ПолеФлажка", "имя": "мой_Флаг", "путь": "мой_Флаг"},
{"вид": "Страницы", "имя": "мой_Страницы", "элементы": [
{"вид": "Страница", "имя": "мой_СтраницаСтроки", "свойства": {"Заголовок": "Строки"},
"элементы": [{"вид": "ТаблицаФормы", "имя": "мой_Строки", "путь": "мой_Строки",
"колонки": [{"имя": "Статья"}, {"имя": "Сумма"}]}]}]},
{"вид": "Кнопка", "имя": "ФормаЗаполнить", "команда": "мой_Заполнить",
"родитель": "ФормаКоманднаяПанель"}],
"события": {"ПриСозданииНаСервере": true}
}]}Правила:
форма—Вид.Имя.ИмяФормыилиОбщая.ИмяФормы. Безсоздатьформа должна существовать; ссоздать— не должна. Назначение выводится из имени формы, как это делает мастер (ФормаДокумента— форма документа,ФормаСписка— списка), или задаётся:"назначение": "Документа".основнаяпишет ссылку в карточку хозяина.видэлемента —ПолеВвода,ПолеФлажка,ПолеНадписи,ПолеКартинки,ПолеПереключателя,Надпись,Картинка,ГруппаФормы,Страницы,Страница,ГруппаКолонок,КоманднаяПанель,ГруппаКнопок,Кнопка,ТаблицаФормы. Дети — вложеннымэлементыили полемродитель;родительне указан — корень формы.перед/после— имя соседа; ни то ни другое — в конец. В автоматическую панель формы кнопка кладётся родителемФормаКоманднаяПанель, в панель таблицы —<Таблица>КоманднаяПанель— и тем же заданием, которым форма или таблица заводится: обе панели рождаются вместе с хозяином, и родителем они годятся сразу, как в примере выше. Родитель, которого нет в форме, — отказФОРМА-РОДИТЕЛЬ-НЕТ.путь— путь к данным: реквизит формы голым именем, реквизит хозяина —Объект.Имяили простоИмя; стандартный реквизит переводится так, как пишет конфигуратор (Номер→Объект.Number: так во всех 594 формах документов корпуса). Колонки таблицы получают путь от таблицы.колонкитаблицы —имяколонки это поле строки (Статья), имя элемента инструмент собирает сам: таблица плюс поле (мой_СтрокиСтатья). Полное имя элемента вместо поля — предупреждениеФОРМА-КОЛОНКА-ИМЯ: иначе вышло бы двойное имя (мой_Строкимой_СтрокиСтатья).свойства— русские имена платформы, как в синтакс-помощнике (Ширина,ТолькоПросмотр,ПоложениеЗаголовка,Группировка); значения перечислений — русские слова. Словарь на 997 свойств 33 видов —meta/domain/form_properties.py, снят со справочника проекта «Накидка» (crimsongoldteam/md_design, MIT). Свойства со своей структурой, выражаются двумя: картинка — «БиблиотекаКартинок.Имя» или «СтандартнаяКартинка.Имя», список выбора — массив{"значение": …, "представление": …}(число, строка, булево или «Перечисление.Вид.Значение»). Остальные (шрифт, цвет, рамка, сочетание клавиш) — отказ, а не текст наугад. Свойство, которого корпус у этого вида не показывал, тоже отказ: поставить его некуда, а молча терять сказанное инструмент не должен.Свойства, которые пишутся сами (что у элемента «рождается»), взяты с эталона конфигуратора: форма
мой_Эталонв проверочной пустой конфигурации — мастер плюс по элементу каждого вида, добавленному руками без настройки. Корпус для этого негоден: формы там прожили годы правок, и «что настроили» от «что родилось» по ним не отличить. По корпусу вышло бы, что у флажка рождается положение заголовка, у группы — поведение, отображение и показ заголовка, у страниц — представление, у таблицы — режим выделения; по эталону ничего этого нет. Зато эталон показывает то, чего корпус не показывает: признак расширенного редактирования у поля,ShowCommandBarу таблицы, подсказку тем же текстом, что и заголовок, у групп и панелей, а у новой формы — пустой корень безWindowOpeningModeиGroup.обработчики:{"ПриИзменении": true}— имя по правилу конфигуратора «ЭлементСобытие» (так названы 15 770 из 18 519 обработчиковПриИзменениикорпуса), строка — своё имя. Команда безобработчикзовёт процедуру своим именем (48 259 команд корпуса из 54 139).Модуль. У новой формы и у формы без модуля он создаётся с заготовками по областям стандарта и сигнатурами, замеренными по 10 239 модулям корпуса. В существующий модуль форма их не пишет: процедуры туда кладёт задание на код (
code_apply) с метками, а инструмент печатает, что положить.Тип реквизита —
Строка(20),Число(15,2),Дата/ДатаВремя/Время,Булево,Справочник.Имя,ТаблицаЗначений; объектная запись тоже принимается.удалить— имена элементов формы, которые убрать:"удалить": ["мой_СтараяГруппа"]; реквизиты и команды —удалитьРеквизитыиудалитьКоманды. Того, чего в форме нет, — отказФОРМА-УДАЛИТЬ-НЕТ.
Проверки до записи: форма и хозяин существуют; родитель и сосед существуют и лежат там, куда ставят; путь ведёт к реквизиту формы или хозяина; имена элементов, реквизитов, команд не заняты; свойство бывает у вида и значение ему подходит; событие известно. Это то, что код формы в сеансе ловит падением, а здесь ловится до записи.
Что доказано кругом через платформу на проверочной пустой конфигурации
(платформа не меняет ни одной строки): рождение формы документа
с регистрацией у хозяина; её наполнение — реквизиты формы, колонки таблицы
значений, команда, группа, поля, флажок, страницы, таблица с колонками,
кнопки обычная и в автопанели, событие формы, модуль; новая форма с таблицей
табличной части одним заданием; правка наполненной формы — вставка перед и
после, колонка в существующий реквизит-таблицу, командная панель с кнопками
своей и стандартной команды, поле-надпись, удаление элемента. Круги
закреплены тестами test_forms.py побайтно.
Устройство: домен (domain/forms.py) не знает ни тегов, ни версии;
сценарий (application/edit_form) просит порт read_form/prepare_form_edits;
реализация формата — infra/forms/designer221 за договором
infra/forms/format.py, выбирается реестром infra/forms/registry.py по
version="2.21" самого файла. Другая версия формата — новый пакет рядом и
строка в реестре; тест стережёт, что реализацию импортирует только реестр.
Типовая форма в XML не правится. Типовые формы меняются только
программно: XML типовой формы — вендорский, и правка в нём сталкивается с
каждым обновлением формы вендором, а код доработки рядом с ней живёт отдельно.
Правило держит сам инструмент, а не внимательность человека: форма, у которой
ни объект, ни она сама не названы с приставкой доработок, даёт отказ
ФОРМА-ТИПОВАЯ-ТОЛЬКО-КОДОМ с подсказкой. Своя форма в вендорском объекте
(форма с приставкой доработок у объекта без неё) — своя, её XML править
можно: это законный и нередкий приём. Без приставки в профиле своё от
типового не отличить, и правило не применяется.
Для типовой формы то же описание даёт код доработки формы — ключ
"код": true у формы. На каком языке он пишется — соглашение команды (профиль,
ключ кодФормы). По умолчанию — методы платформы, которые есть в любой
конфигурации (сверено с синтакс-помощником 8.5.1):
ДобавляемыеРеквизиты = Новый Массив;
ДобавляемыеРеквизиты.Добавить(Новый РеквизитФормы("мой_Состояние", Новый ОписаниеТипов("Строка", , Новый КвалификаторыСтроки(20))));
ДобавляемыеРеквизиты.Добавить(Новый РеквизитФормы("мой_Строки", Новый ОписаниеТипов("ТаблицаЗначений")));
ДобавляемыеРеквизиты.Добавить(Новый РеквизитФормы("Номенклатура", Новый ОписаниеТипов("СправочникСсылка.Номенклатура"), "мой_Строки"));
Форма.ИзменитьРеквизиты(ДобавляемыеРеквизиты);
Элемент = Форма.Элементы.Вставить("мой_Состояние", Тип("ПолеФормы"), Форма.Элементы.ГруппаШапка, Форма.Элементы.Комментарий);
Элемент.Вид = ВидПоляФормы.ПолеВвода;
Элемент.ПутьКДанным = "мой_Состояние";
Элемент.ТолькоПросмотр = Истина;
Элемент.УстановитьДействие("ПриИзменении", "Подключаемый_мой_СостояниеПриИзменении");Реквизиты и колонки таблиц заводятся одним ИзменитьРеквизиты (операция
ресурсоёмкая, платформа просит делать её пакетом), команда —
Команды.Добавить с заголовком и действием, элемент — Вставить перед соседом
или Добавить в конец родителя; вид поля, группы, декорации и кнопки
ставится явно. Составной тип реквизита и заголовок реквизита платформа
выражает: Новый ОписаниеТипов("Строка,Булево", , Новый КвалификаторыСтроки(20)),
заголовок — четвёртым параметром РеквизитФормы.
Свой язык кода — например, построитель форм команды — подключается файлом-диалектом из профиля:
"кодФормы": {"язык": "сборщик", "диалект": "сборщик.py", "модуль": "мой_Формы"}диалект — путь к файлу Python от файла профиля, прочие ключи — настройки
языка, их проверяет сам диалект. Файл объявляет ДИАЛЕКТ — наследника
meta.domain.form_dialect.ДиалектКодаФорм с тем же имя, что язык
в профиле, — и переопределяет то, что у его языка иначе: текст фрагмента
(код); как узнать в модуле процедуру доработки и что в неё дописать
(процедура, дополнение); как назвать место вставки и «перед соседом»
в пояснениях; какими вызовами язык заводит элементы, реквизиты и команды —
по ним узнаётся повтор; находки о том, чего язык не выражает; слова для ответа
и инструкции сервера. Образец с выдуманным языком —
meta/tests/диалекты/сборщик.py. Диалект — код команды, и исполняется он как
код инструмента; нет файла, он не загрузился или его язык не тот, что назван
в профиле, — отказ с причиной, а не тихий переход на язык платформы.
Фрагмент печатается в просмотре готовой процедурой для своего общего модуля
(с описанием, табуляциями и вызовом для ПриСозданииНаСервере формы), а с
--apply ещё и ложится файлом рядом с заданием (или туда, где сказано ключом
файлКода); вносится он заданием на код этого же инструмента — с метками.
Запись (forms_apply) в режиме кода ничего не пишет и так и говорит.
Обработчики элементов и действия команд получают приставку Подключаемый_
(#std492 — номер стандарта из
системы стандартов разработки 1С: и то и
другое код назначает программно), и подсказка перечисляет их процедуры с
сигнатурами для модуля формы. Тем же именем обработчик назван и в показе
задания. В готовых правках вызов
дан без отступа — уровень места ставит инструмент, это сказано в заголовке
блока. Многострочная строка — с «|». Кодом нельзя того, что не выражается
программно, и инструмент говорит об этом отказом: создать форму, назначить
событие самой формы, удалить элемент типовой формы (его прячут свойством
«Видимость»), назначить кнопке стандартную команду. «После» соседа переводится
в «перед» следующим, родитель — тот, где стоит сосед, и ответ это объясняет
словами: сосед взят по форме в выгрузке, и элементы, которые добавляет код
других доработок, в расчёт не входят.
Куда ляжет процедура — "код" объектом:
{"модуль": "ОбщийМодуль.мой_ЗаявкиСервер", "процедура": "…"}. Инструмент
проверяет, что модуль есть (ФОРМА-КОД-МОДУЛЬ), серверный
(ФОРМА-КОД-МОДУЛЬ-НЕ-СЕРВЕР — процедуру зовут из ПриСозданииНаСервере), не
клиентский (ФОРМА-КОД-МОДУЛЬ-КЛИЕНТ — элементы и реквизиты формы
добавляются только на сервере) и не вызова сервера (ФОРМА-КОД-МОДУЛЬ-ВЫЗОВ-СЕРВЕРА
— его экспорт виден клиенту, а форму на сервер не передать; поэтому одного
признака «Сервер» мало), и свой (ФОРМА-КОД-МОДУЛЬ-ТИПОВОЙ —
предупреждение: реализация доработки живёт в своём модуле, в типовом остаётся
вызов), а имя в нём свободно или занято процедурой, которую можно дополнить
(ФОРМА-КОД-ИМЯ-ЗАНЯТО; по умолчанию <Форма>_ПриСозданииНаСервере), и выдаёт
готовый вызов вместо заглушки <Модуль>. Без модуля — предупреждение
ФОРМА-КОД-БЕЗ-МОДУЛЯ, с подсказкой, если у объекта есть свой модуль
«приставка + имя объекта»: искать модуль, его контекст и свободное имя руками
не приходится. Для процедур-обработчиков ответ называет область модуля формы
со строками — или, если её нет, между какими областями её завести по шаблону
стандарта #std455. В описании процедуры нет длинного тире:
BSL Language Server
считает его ошибкой; и нет кавычек-ёлочек — в коде кавычки прямые, и
фрагмент, внесённый дословно, иначе не прошёл бы проверку кода. Ёлочки из
заголовка задания — предупреждение ФОРМА-КОД-ЁЛОЧКИ уже в просмотре формы.
С названным модулем ответ даёт и места номерами строк: процедура — перед
#КонецОбласти области «ПрограммныйИнтерфейс» модуля, вызов — перед
КонецПроцедуры у ПриСозданииНаСервере модуля формы. Когда известны оба
места, ответ даёт и готовые правки задания на код — блок modules с
процедурой, вызовом, номерами строк и текстами якорей; остаются задача, дата и
автор: двадцать строк процедуры, перенесённые руками, легко исказить. Ключ
модуля — слово канала (module у MCP, модуль у терминала). Элемент,
реквизит или команда, которые уже заводит кодом целевой модуль или сам
модуль формы, — ошибка ФОРМА-КОД-УЖЕ-В-МОДУЛЕ: повтор доработки под
другим именем процедуры завёл бы второй элемент с тем же именем, а модуль
типовой формы порой сам заводит элемент с таким именем — так модуль формы
авансового отчёта заводит свою надпись итога. «Заводит» — вызов, который
создаёт в своём пространстве имён: элемент — Элементы.Добавить/Вставить,
реквизит — Новый РеквизитФормы, команда — Команды.Добавить, и заводящие
вызовы языка команды, которые называет его диалект; просто имя в кавычках
заведённым не считается — ОписаниеОповещения("мой_…") называет процедуру, а
не элемент. Описание процедуры — «Дорабатывает форму "…".» (диалект может
дописать, чем), без перечня элементов: дополнение процедуры описание не
трогает, и перечень устарел бы со второй доработкой. «После» соседа в коде
— место перед следующим, и ответ говорит, чем это грозит: уберёт вендор того
соседа — код бросит исключение при открытии формы. "код": true без модуля
берёт свой модуль объекта («приставка + имя объекта»), если он есть и годится
— серверный, не клиентский и не вызова сервера, — и сразу выдаёт готовые
правки; иначе — заглушка с предупреждением ФОРМА-КОД-БЕЗ-МОДУЛЯ. Поле
флажка на реквизите не Булево и не Число — ошибка ФОРМА-ФЛАЖОК-ТИП
(синтакс-помощник: флажок редактирует Булево, Число — при «ТриСостояния»).
Реквизит типа ТабличныйДокумент и прочих документов, чьё поле инструмент
не заводит, — предупреждение ФОРМА-РЕКВИЗИТ-БЕЗ-ПОЛЯ (с тем, как поле
добавить). forms_check с verbose показывает XML формы;
оговорка про uuid — только когда новые uuid в показе есть. Элемент без
приставки доработок в типовой форме — ошибка ФОРМА-БЕЗ-ПРИСТАВКИ, как
МД-ПРЕФИКС у метаданных: ошибку, в отличие от предупреждения, через
accepted не принять.
Вторая доработка той же формы дописывается в её процедуру, а не заводит
вторую процедуру и второй вызов. Процедура с названным именем уже есть и
узнаётся — ответ даёт код и место для него: у кода платформы — перед её
КонецПроцедуры (процедура доработки узнаётся по единственному параметру —
форме), у языка команды — там и так, как скажет его диалект, с пустой строкой
после; вызов в модуле формы уже есть — второй не выдаётся. Процедуру не
узнать — ФОРМА-КОД-ИМЯ-ЗАНЯТО. Модуль формы уже вызывает процедуру с этим
именем, а модуль не назван или назван другой, — ошибка ФОРМА-КОД-ВЫЗОВ-ЕСТЬ с
модулем, который назвать. Имя процедуры задано явно, а модуль формы уже
вызывает процедуру доработки этой формы по умолчанию, — предупреждение
ФОРМА-КОД-ВТОРАЯ-ДОРАБОТКА: другая доработка — законно, та же — задвоение.
show типовой формы напоминает, что элементов, которые добавляет код, в
дереве нет: оно из XML.
События элементов — по виду (meta/domain/form_events.py, по
синтакс-помощнику 8.5.1: события объекта и его расширения для вида; сверено с
11 042 формами крупной типовой конфигурации — ни одного события вне перечней).
Событие чужого вида — ошибка ФОРМА-СОБЫТИЕ-НЕ-ДЛЯ-ВИДА с перечнем событий
вида, неизвестное имя — ФОРМА-СОБЫТИЕ-НЕИЗВЕСТНО, всё в одном ответе и до
записи: у флажка, например, нет ни «НачалоВыбора», ни «ПриСменеСтраницы».
События вида печатает fields(kind="ПолеФлажка") и т. п. Процедура с именем
обработчика в модуле формы уже есть — подсказка говорит «уже есть, заводить не
нужно», а если она обработчиком этого события быть не может (директива, число
параметров по сигнатурам корпуса), — ошибка ФОРМА-ОБРАБОТЧИК-НЕ-ТОТ:
серверная «УправлениеФормой()» без параметров клиентским обработчиком не
станет.
Форма списка заводится вместе с таблицей динамического списка: назначение
«Списка» даёт главный реквизит Список, таблица привязывается к нему
("путь": "Список"), колонки — именами полей. Колонка списка по умолчанию
поле-надписи: список показывают, а не правят (19 465 колонок корпуса против
1262 полей ввода); названный вид уважается. Стандартное поле пишется
английским именем и здесь — «Дата» становится Список.Date: так его пишет
платформа. Поле, которого нет ни у хозяина, ни среди
стандартных, — предупреждение, а не отказ: поля списка приходят из его
запроса.
Дерево значений — та же таблица: реквизит формы типа ДеревоЗначений с
колонками, элемент ТаблицаФормы по нему, поля внутри. Колонка в дерево
добавляется как колонка в таблицу — именем реквизита в таблица:
{"реквизиты": [{"имя": "Норматив", "тип": "Число(15,3)", "таблица": "мой_Дерево"}],
"элементы": [{"вид": "ПолеВвода", "имя": "мой_ДеревоНорматив",
"путь": "мой_Дерево.Норматив", "родитель": "мой_Дерево",
"после": "мой_ДеревоФлаг"}]}Идентификатор колонки живёт внутри своего реквизита, а не в общем счёте формы:
инструмент берёт max+1 по его Columns — у деревьев корпуса нумерация
встречается и с 1000000. У таблицы дерева инструмент не пишет RowFilter
(отбор строк бывает у плоского набора, и круг через платформу его снимает), а
Representation оставляет List: иерархию даёт источник данных, а не
свойство таблицы.
Условное оформление формы лежит в выгрузке внутри раздела реквизитов, и у всех 563 форм корпуса, где оно есть, стоит последним. Поэтому новый реквизит инструмент ставит за последним реквизитом, а не в конец раздела, а показ оформление реквизитом не считает. Круг через платформу это подтверждает: платформа возвращает и оформление, и реквизит перед ним без правок.
Посмотреть, что в форме уже есть, — --показать:
py -3 meta/add.py --показать <выгрузка> Документ.мой_Заявка.ФормаДокументаПечатается то, чем оперирует задание: назначение, реквизиты формы с типами
и главным, команды с обработчиками, события формы и дерево элементов —
имя, вид, привязка, команда кнопки, обработчики. Вид называется по-русски и
у того, чего инструмент не пишет (поля табличного, текстового и
HTML-документа, диаграммы, календаря и другие): английский тег посреди
русских слов читается как ошибка вывода. Слова взяты из справочника свойств,
а не придуманы; на заведение такого вида — отказ с перечнем умеющих.
Спутники (контекстные меню, подсказки, дополнения таблиц) прячутся и
считаются: их на корпусе вдвое больше самих элементов. Показать их —
--подробно. Автоматическая командная панель не прячется, если в ней лежат
настоящие кнопки. У типовой формы в шапке стоит пометка, что править её можно
только кодом.
Это ответ на вопрос «куда вставлять» без чтения Form.xml, а он бывает в
сотню килобайт — у самой большой формы корпуса 182 199 байт и 158 элементов.
У типовой формы дерево целиком — сотни строк, а место вставки ищут в одной
группе. Третий аргумент (у MCP — параметр element) сужает показ до ветки:
путь к элементу от корня, он сам и всё, что внутри; на опечатку — похожие
имена. Правая колонка шапки авансового отчёта — 11 строк вместо 330:
py -3 meta/add.py --показать <выгрузка> Документ.АвансовыйОтчет.ФормаДокумента ГруппаШапкаПраваяКартинка, поле картинки, поле переключателя и группа колонок задаются так (круг через платформу чист — она не меняет ни байта):
{"элементы": [
{"вид": "Картинка", "имя": "мой_Значок",
"свойства": {"Картинка": "СтандартнаяКартинка.Setting"}},
{"вид": "ПолеКартинки", "имя": "мой_ПолеФлажка", "путь": "мой_Флажок",
"свойства": {"КартинкаЗначений": "БиблиотекаКартинок.ЗначокОшибки"}},
{"вид": "ПолеПереключателя", "имя": "мой_ПолеВарианта", "путь": "мой_Вариант",
"свойства": {"КоличествоКолонок": 2,
"СписокВыбора": [{"значение": 1, "представление": "Первый"},
{"значение": 2, "представление": "Второй"}]}},
{"вид": "ТаблицаФормы", "имя": "мой_Таблица", "путь": "мой_Таблица",
"элементы": [{"вид": "ГруппаКолонок", "имя": "мой_ГруппаЧисел",
"свойства": {"Группировка": "ВЯчейке"},
"элементы": [{"вид": "ПолеВвода", "имя": "мой_ТаблицаСумма",
"путь": "мой_Таблица.Сумма"}]}]}]}Поле внутри группы колонок внутри таблицы остаётся полем в таблице — рождённое берётся по таблице, сколько бы групп ни лежало между ними. Группа колонок отличается от групп формы: спутник у неё один (расширенная подсказка, у всех 5490 корпуса; контекстного меню нет ни у одной), заголовок пишется от имени, а подсказка — нет.
Чего у форм нет: полей табличного, текстового, HTML- и форматированного
документа, диаграмм, индикатора, календаря, планировщика, подменю — по числу
элементов это 1 % корпуса (347 258 из 350 799 инструмент пишет). Рождённое
у картинки, поля картинки, поля переключателя и группы колонок снято с
корпуса правилом «есть у 95 % и больше» — эталона конфигуратора на них нет, и
это единственное место, где они стоят слабее остальных. Эталоном проверены
виды элементов формы документа — формы справочника, регистра и обработки
рождаются по замеру корпуса
(UseForFoldersAndItems у форм элемента и группы эталоном не подтверждён).
Атомарные роли
Во многих конфигурациях права собраны из атомарных ролей: на объект — роль «Просмотр» и роль «Изменение», а пользователю права собирают из таких пар. Заводить их руками при каждом новом объекте — та работа, из-за которой создание объекта инструментом всё равно заканчивалось бы в конфигураторе.
Как роли называются, — соглашение команды, его задаёт профиль:
"атомарныеРоли": {"имя": "мой_атом_{вид}_{объект}_{право}",
"синоним": "(Мой) Атом. {вид} - {синоним} - {право}"}В шаблоне имени поля {вид}, {объект} и {право} — каждое ровно один раз,
вне полей — только буквы, цифры и «_»; в шаблоне синонима — {право} и
{синоним} (синоним объекта) или {объект}; {вид} в синониме пишется
словами («Регистр сведений»). Схема, которая дала бы разным ролям одно имя или
один синоним, — отказ при чтении профиля; без схемы атомарных ролей
инструмент не заводит: роль с чужим именем хуже, чем никакой.
Пара заводится к новому объекту тем же заданием:
{"вид": "Документ",
"поля": {"имя": "мой_ЗаявкаНаОплату", "синоним": "Заявка на оплату",
"движения": ["РегистрНакопления.мой_ЛимитыОплат"],
"атомарныеРоли": true}}true — обе роли, список (["Просмотр"]) — только названные. Объект и его
роли пишутся одним планом: объекты одной пачки видят друг друга по факту
существования — и только по нему. К уже существующему объекту — ключом
atomic_roles:
{
"repo": "C:/путь/к/выгрузке/cf",
"atomic_roles": ["Документ.мой_Заявка",
{"объект": "РегистрСведений.мой_Лимиты", "права": ["Просмотр"]}]
}У обработки и отчёта роль одна и без суффикса — права «Использование» и
«Просмотр»: имя и синоним строятся той же схемой без {право} и разделителя
перед ним (мой_атом_Обработка_мой_Загрузка, «(Мой) Атом. Обработка -
Загрузка»), «права» у них не задаются. Так заведено у соседей там, где схема
принята: у обработок 32 роли без суффикса против 11 с ним, у отчётов 25
против 5.
Комментарий ролей — ключ комментарий в пункте atomic_roles и в
объекте атомарныеРоли ({"права": […], "комментарий": "08.10.2026, #TEAM Автор #ЗАДАЧА-1"}): у соседей он есть почти у всех, и без него роль задачи
выделялась бы.
«права» в пункте — это какие из двух атомарных ролей завести («Просмотр»,
«Изменение»), а не права платформы. Состав прав каждой роли — типовой для вида:
самое частое сочетание на выгрузке крупной типовой конфигурации; у документа и
регистров его держат почти все роли, у справочника «Изменение» — меньше
половины (права на предопределённые данные и история данных расходятся).
Насколько ему следуют соседи в вашей выгрузке, инструмент считает сам — по
ролям той же схемы, где права выданы на один объект вида: число, снятое с
одной конфигурации, в другой было бы неправдой. Если типовой состав у соседей
не правило (меньше 85 %), у роли предупреждение РОЛЬ-ШАБЛОН-НЕ-ПРАВИЛО с
долей, другими составами, их числом и примером роли каждого («без ВводПоСтроке —
32, например «Роль.…»»), советом сверить с соседями (права роли показывает
show по адресу «Роль.<имя>») и тем, как получить другой состав: пунктом
objects вида «Роль» с полем «права», а не атомарной парой — права
существующей роли заданием changes не меняются. Совет стоит у самой роли, а
не в плане: шагом плана он не является. Соседей нет — совета нет. Виды вне
четырёх с типовым составом (документ, справочник, регистры сведений и
накопления) — отказ.
Соседи читаются из файлов прав только по выданным правам: у иной роли в файле
названы тысячи объектов со всеми правами false, и на выгрузке крупной
типовой конфигурации (тысячи ролей, сотни мегабайт прав) чтение занимает
секунды на вид.
show роли печатает права только на те объекты, где выдано хоть одно; объекты,
названные в файле прав явным «false», — одной строкой счётом: у иной роли их
сто тысяч, и полный показ вышел бы в девять миллионов знаков.
Если у объекта роли уже есть — отказ с их именами: роли ищутся по выданным
правам среди ролей схемы, потому что имя по имени объекта не угадать —
длинные имена сокращают, и поиск по имени пропустил бы готовую пару. Имя роли
длиннее 80 символов — ошибка (#std474 п. 2.3); для длинного объекта задаётся
«сокращение» — короткое имя объекта для имён ролей: в пункте atomic_roles
или в «атомарныеРоли» объектом {"права": […], "сокращение": "…"}. Синоним
роли инструмент пишет без «ё».
#std474 для всех объектов метаданных: имя длиннее 80 символов —
МД-ИМЯ-ДЛИННОЕ, буква «ё» в имени, синониме, комментарии из задания —
МД-БУКВА-Ё с исправленным текстом (части схемы компоновки — не метаданные,
к ним это не относится).
Каждая роль несёт и шесть прав на конфигурацию (режимы основного окна, клиент системы аналитики) — их ставит конфигуратор новой роли; в корпусе они у большинства атомарных ролей.
Подписка на событие
{
"repo": "C:/путь/к/выгрузке/cf",
"objects": [
{"вид": "ПодпискаНаСобытие",
"поля": {"имя": "мой_ЗаявкаПередЗаписью",
"синоним": "Заявка перед записью",
"комментарий": "#ЗАДАЧА-123",
"источник": [{"вид": "Документ", "имя": "мой_Заявка"}],
"событие": "ПередЗаписью",
"обработчик": "мой_ЗаявкиСервер.ПередЗаписью"}}
]
}Объекты одного задания друг друга не видят: всё задание проверяется по выгрузке на диске и только потом пишется. Поэтому модуль-обработчик заводится предыдущим заданием — и сразу с текстом, иначе экспортного метода в нём не будет и подписка не пройдёт проверку:
{"вид": "ОбщийМодуль",
"поля": {"имя": "мой_ЗаявкиСервер", "синоним": "Заявки, сервер",
"текст": "Процедура ПередЗаписью(Источник, Отказ, РежимЗаписи, РежимПроведения) Экспорт\nКонецПроцедуры"}}Контекст модуля задаёт постфикс его имени — так устроен стандарт #std469 и так же устроена замеренная конфигурация (замер по 4103 модулям):
Постфикс | Что включено | В замеренной конфигурации |
нет или | сервер, внешнее соединение, клиент (обычное приложение) | 1504 из 1705 |
| сервер, вызов сервера | 439 из 455 |
| оба клиента | 631 из 636 |
| все четыре контекста | 466 из 475 |
| глобальный + оба клиента | 56 из 58 |
| плюс повторное использование «на время сеанса» | 205 из 222 |
| плюс привилегированный |
Флаги контекста по умолчанию берутся из постфикса; называют их только чтобы
отступить от него, и названное не переписывается. Имя и флаги обязаны
сходиться там, где стандарт говорит «обязательно»: «вызов сервера» без
постфикса ВызовСервера — отказ (в замеренной конфигурации таких модулей 111 —
ошибка, которую инструмент не даст повторить), «глобальный» без Глобальный —
отказ, Клиент без клиентского контекста или с сервером — отказ. Отклонение
состава контекстов от стандарта — предупреждение, не запрет: такие модули в
замеренной конфигурации есть.
Число параметров задаёт событие вместе с видом и гранью источника: у документа
ПередЗаписью их четыре, у справочника — два, у набора записей регистра — три.
Инструмент сверяет это по таблице, снятой с 639 подписок замеренной
конфигурации, и о расхождении предупреждает — но предупреждает, а не
запрещает: единичные исключения там есть.
ПОДПИСКА-СИГНАТУРА: у «мой_ЗаявкиСервер.ПередЗаписью» параметров 2,
а событие «ПередЗаписью» у источника «Документ» принимает 4 —
так в замеренной крупной типовой конфигурации у 73 подписок из 77Источник, событие и обработчик проверяются вместе и при правке существующей
подписки (changes): правка одного из трёх сверяется с двумя другими, как
они записаны в выгрузке. Источник, переставленный с документа на справочник
при обработчике с четырьмя параметрами, получает предупреждение о сигнатуре, а
не «замечаний нет». Источник принимается списком и одним обозначением — в том
числе так, как его печатает показ: "Справочник.Контрагенты (Объект)".
Принятое предупреждение
Предупреждение, с которым согласились осознанно, отмечается в самом задании — тогда оно печатается принятым, а не повторяется вперемешку с новыми:
{"repo": "C:/путь/к/выгрузке/cf",
"принято": ["ПОДПИСКА-НА-СВОЙ-ОБЪЕКТ"],
"objects": [
{"вид": "ПодпискаНаСобытие",
"поля": {"имя": "мой_ЗаявкаПередЗаписью", "синоним": "Заявка перед записью",
"источник": [{"вид": "Документ", "имя": "мой_Заявка"}],
"событие": "ПередЗаписью", "обработчик": "мой_ЗаявкиСервер.ПередЗаписью"}}]}Ошибку принять нельзя: она говорит о том, чего не возьмёт платформа, и договориться тут не с кем. Код, которого среди предупреждений не оказалось, инструмент называет вслух — иначе список принятых тихо устаревает.
Ключ --подробно печатает в просмотре и то, что решено за вас: у регистра
сведений это периодичность и режим записи, у реквизита — полнотекстовый поиск
и история данных. Без него такие свойства сворачиваются в строку «ещё N полей».
Что лежит в выгрузке
Просмотр отвечает на вопрос «то ли я заказал» — и отвечает про намерение.
На вопрос «то ли записалось» отвечает --показать: он читает карточку с диска
и печатает её тем же языком, что и просмотр.
py -3 meta/add.py --показать C:/путь/к/выгрузке/cf Справочник.мой_ЭталонАдрес тот же, что у правки, и уходит вглубь так же:
Справочник.мой_Эталон.Реквизит.Комментарий. Печатается заполненное; пустые свойства
сворачиваются в строку «ещё N полей пусты».
Чтение ходит по той же схеме видов, что и запись, — не по второму описанию формата. Поэтому круг «записали → прочитали → сверили» проверяет обе стороны разом и работает без платформы; в наборе тестов он и стоит.
Изменение свойства
Адрес читается парами «Вид.Имя» и уходит вглубь так же, как устроена карточка. Правка меняет в файле ровно те строки, которые названы: это закреплено тестом, а не обещанием.
{
"repo": "C:/путь/к/выгрузке/cf",
"changes": [
{"путь": "Справочник.мой_Эталон.Реквизит.КодПодразделения",
"поля": {"индексирование": "Индексировать"}},
{"путь": "Документ.мой_Заявка.ТабличнаяЧасть.Строки.Реквизит.Сумма",
"поля": {"проверкаЗаполнения": "ВыдаватьОшибку"}}
]
}Просмотр показывает «было → стало» по значениям:
Справочник.мой_Эталон.Реквизит.КодПодразделения: индексирование было DontIndex стало Индексировать (Index)Переименование правкой поля не делается и отвергается: имя объекта живёт ещё в реестре конфигурации, в порождаемых типах и в чужих карточках, которые на него ссылаются.
Поля-перечни — состав подсистемы, движения и основание документа —
в правке задаются явно, режимом:
{"путь": "Подсистема.мой_Раздел",
"поля": {"состав": {"добавить": ["Справочник.мой_Новый"], "убрать": ["Отчет.мой_Старый"]}}}добавить— в конец перечня; что уже есть, второй раз не добавляется (предупреждение). Добавляемое проверяется, как при создании: объект должен существовать, движения — только по регистрам;убрать— только названное; убирать то, чего нет, — ошибка;заменить— перечень целиком, один, без двух других; ответ называет, что уходит.
Голый список в правке — отказ: он заменил бы перечень целиком, и подсистема с десятками объектов потеряла бы их молча. При создании объекта перечень, как и раньше, — обычный список.
Вложенная подсистема — своя карточка в каталоге родителя
(Subsystems/Родитель/Subsystems/Дочерняя.xml, в проекте EDT —
…/Subsystems/Дочерняя/Дочерняя.mdo), а не узел его карточки. Адрес —
цепочкой: Подсистема.Родитель.Подсистема.Дочерняя (так её называет и
обратный поиск ссылок); показ и правка — как у корневой. В составе
обозначаются объекты любого вида верхнего уровня: Роль.Имя,
ОбщийМодуль.Имя, РегламентноеЗадание.Имя и т. д.
Удаление
{
"repo": "C:/путь/к/выгрузке/cf",
"deletions": [
"Справочник.мой_Ненужный",
{"путь": "Документ.мой_Заявка.ТабличнаяЧасть.Строки.Реквизит.Старый"},
{"путь": "Отчет.мой_Отчет.Макет.ОсновнаяСхема.НаборДанных.Лишний"}
]
}Объект целиком пишется строкой, часть — объектом с полем путь; и то и другое
принимается в обоих видах. Удаление отказывает, если на объект ссылаются, и
называет место каждой ссылки: держателя, путь до сущности, в которой стоит
ссылка, и свойство — у кого это тип реквизита, у кого — запись прав, и правки
это разные:
ОТКАЗ: ошибок 1 — задание не пройдёт; находки ниже
Справочник мой_Склад
ошибка [УДАЛЕНИЕ-ЕСТЬ-ССЫЛКИ] на «Справочник.мой_Склад» ссылаются (4): Документ.мой_Приход.Реквизит.Склад (тип), Документ.мой_Приход.ТабличнаяЧасть.Товары.Реквизит.Склад (тип), Отчет.мой_Остатки.Макет.Схема.Параметр.Склад (типЗначения), Роль.мой_Кладовщик (права)Свойство названо полем задания (тип, состав, источник), а если такого
поля инструмент не пишет — тегом выгрузки: у графы журнала документов это
References, и по тегу место находится поиском в файле. Права роли — запись
файла прав, а не свойство сущности, поэтому роль названа целиком; так же
назван держатель, карточку которого не удалось разобрать.
Переименование объекта
{
"repo": "C:/путь/к/выгрузке/cf",
"renames": [{"путь": "Справочник.мой_Старое", "имя": "мой_Новое"}]
}Приставки к корню вида в обозначениях собираются из таблиц, а не заменяются
свободным хвостом: корень одного вида бывает приставкой другого (Document
и DocumentJournal), и «любые буквы» переименовали бы журнал документов
вместе с документом.
Реквизит в существующий объект
Это тот же «ребёнок по адресу хозяина», только адрес из одной пары. Ключ
attributes — короткая запись для самого частого случая, а операция за ним
та же, что у additions.
Префикс у вложенного судится по хозяину, а не по самому имени: реквизит
в вендорский объект несёт мой_, реквизит в собственный мой_* — нет.
Поэтому ниже мой_КодПодразделения в БанковскиеСчета, а в примерах правки
свойств — КодПодразделения в мой_Эталон; это не разные соглашения,
а одно правило в двух положениях.
{
"repo": "C:/путь/к/выгрузке/cf",
"attributes": [
{"объект": "Справочник.БанковскиеСчета",
"поля": {"имя": "мой_КодПодразделения",
"синоним": "Код подразделения",
"тип": {"вид": "Строка", "длина": 20},
"индексирование": "Индексировать"}}
]
}Создание объектов и добавление вложенных сущностей в одном задании не смешиваются.
Вложенная сущность по адресу хозяина
attributes умеет одно — реквизит в объект. additions берёт адрес хозяина
и вид ребёнка отдельно, и потому кладёт что угодно куда угодно: измерение
в регистр, табличную часть в справочник, реквизит в существующую табличную
часть, параметр или отбор — в схему компоновки отчёта.
{
"repo": "C:/путь/к/выгрузке/cf",
"additions": [
{"путь": "РегистрСведений.мой_Лимиты", "вид": "Измерение",
"поля": {"имя": "Организация", "синоним": "Организация",
"тип": {"вид": "Справочник", "имя": "Организации"}}},
{"путь": "Справочник.мой_Эталон.ТабличнаяЧасть.Строки", "вид": "Реквизит",
"поля": {"имя": "Сумма", "синоним": "Сумма",
"тип": {"вид": "Число", "разрядность": 15, "дробнаяЧасть": 2}}},
{"путь": "Отчет.мой_Отчет.Макет.ОсновнаяСхема.ВариантНастроек.Основной",
"вид": "Отбор",
"поля": {"использование": true, "левое": "Организация",
"видСравнения": "Равно", "правое": "Основная"}}
]
}Адрес указывает хозяина, а не то, что добавляем: «куда», а не «что». Вид хозяина решает состав свойств ребёнка, имя объекта — нужен ли префикс, а весь адрес целиком — занято ли уже такое имя внутри. Это три разных вопроса, и они задаются трём разным местам.
Чтобы изменить или удалить уже добавленный пункт, адрес продолжается парой
«вид, имя» — но имени у пунктов настроек нет, и вместо него стоит то, чем пункт
опознаётся: у выбираемого поля и поля порядка это поле, у отбора — левое,
у группировки — имя. Например …ВариантНастроек.Основной.Отбор.Организация.
Контейнеры (settings, filter) в адресе не называются никогда — их
разворачивает сама адресация.
Вид сравнения, направление сортировки и прочие перечисления пишутся по-русски
("Равно", "НеЗаполнено", "Убывание") — как и всё в задании; английское
написание из выгрузки отвергается с перечнем допустимого.
Правка кода вставками
Задание на код — модули, правки в каждом, подпись (задача, дата, автор):
{"repo": "C:/work/cf", "task": "ЗАДАЧА-123", "date": "27.08.2026",
"author": "Автор",
"modules": [
{"модуль": "ОбщийМодуль.мой_X", "edits": [
{"line": 1353, "lines": 0, "code": "\tИначеЕсли …"}]},
{"path": "CommonModules/мой_Y/Ext/Module.bsl", "revert": true},
{"модуль": "ОбщийМодуль.мой_Z", "rename": {"from": "Старое", "to": "Новое"}}],
"move_method": {"from": "ОбщийМодуль.мой_A", "method": "Имя",
"to": "ОбщийМодуль.мой_B", "to_line": 42}}Модуль, созданный задачей, меток не получает. Созданный — тот, которого
нет в базе сверки: шапка "base" — ревизия до задачи (коммит или ветка, от
которой она начата), как у проверки правок; без неё — HEAD. Модуль задачи,
уже добавленный в индекс или закоммиченный в её ветке, так остаётся её
модулем — и повторная правка после ревью идёт без меток, а не обёрткой
ИЗМЕНЕН вокруг всего собственного кода. Неизвестная ревизия — отказ;
репозиторий без коммитов и каталог вне git — по-старому: новый тот, которого
нет в индексе (вне git — никакой). Откат сверяет стыки с той же базой.
lines = 0 — чистая вставка перед якорем, code пустой — удаление. При
lines > 0 обе границы (first_line, last_line) обязательны: они
играют роль version из LSP и отказывают всей пачкой, если номер строки
устарел. Номер строки берётся из текущего текста файла.
Модуль называется адресом или путём файла от корня выгрузки (ровно одно
из двух). Адрес — вид объекта по-русски и его имя, за ними — вид модуля
(МодульОбъекта, МодульМенеджера…), у формы и команды — Форма.<имя> и
Команда.<имя>; у объектов с одним модулем вид модуля не пишется:
Адрес | Файл |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| модуль у них один |
|
|
Замер на выгрузке крупной типовой конфигурации: все 22 742 модуля ложатся в
эти пять шаблонов, исключений ноль. Адрес Справочник.X без вида модуля —
отказ: модулей у объекта несколько, и «первый попавшийся» годится для
чтения, но не для записи. Модуля нет — отказ называет, какие у объекта есть.
Что решают правила меток и что инструмент делает сам — тип вставки, метки, их
место (своя вставка, чужая: вложенная метка на каждый фрагмент, обёртка
снаружи — при правке её метки или переписывании больше половины, с отказом при
длине больше 300 строк или вложенных метках), текст запроса,
целый метод с меткой хвостом, по вставке на каждый новый метод, отступ
пустых строк, пустые строки снаружи, — описано в meta/domain/edits.py вместе
с причиной каждого правила.
Правка внутри чужой вставки:
по умолчанию — на месте: каждый изменённый фрагмент своей вложенной меткой нужного типа (ИЗМЕНЕН — закомментированный оригинал и новый код, УДАЛЕН, ДОБАВЛЕН), сколько бы фрагментов ни было в одной чужой вставке и сколько бы строк ни занимал каждый; остальной код чужой вставки живой и нетронутый, её метки на месте. Чистая вставка вкладывается всегда. Метка над методом (отдельной строкой над объявлением, закрывающая — хвостом на
КонецФункции) правке объявления не мешает: наша метка встаёт между чужой открывающей и объявлением, и разбор находит чужую вставку с прежними границами;снаружи — только в двух случаях: правка задевает строку с меткой чужой вставки (открывающую, в том числе хвостом на объявлении метода, или закрывающую — под нашу метку её не вложить) или правки заменяют больше половины её строк кода (непустых и не комментариев между метками; заменяемые считаются так же — пустые строки и комментарии не в счёт: вставка фактически переписывается; ровно половина — ещё на месте). Обёртка одна на все правки вставки: вставка деактивирована целиком, и её исполняемый код повторён следом с правками: метки и деактивированный старый код — её и вложенных в неё чужих вставок — не повторяются, история остаётся в закомментированной копии. Остальные строки — дословно, с хвостовыми пробелами: срезанные, они дали бы в diff косметические правки чужого кода, а их проверка правок считает ошибкой (
ПРАВКА-ТОЛЬКО-ПРОБЕЛЫ). Повторять следом одну правку нельзя: остальные строки вставки ушли бы в комментарий молча, а модуль бы при этом компилировался;правка, пересекающая границу вставки (начало снаружи, конец внутри), — отказ: сузьте её внутрь вставки или расширьте на всю вставку с метками;
вставка, вложенные метки которой спарены внутри и которая сама — ровно целый метод (так бывает у вендорских меток хвостом на объявлении и на
КонецФункции), оборачивается снаружи, а не отклоняется.
Открывающей меткой считаются четыре формы: // {[+]…, // {#TEAM [+]… (2662
на выгрузке крупной типовой конфигурации), // #TEAM{[+]… (484 в 83 модулях:
без этой формы закрывающие таких вставок цеплялись бы к чужим висящим меткам)
и // { [+]…; на месте #TEAM — метка любой команды (всего на той же
выгрузке 36 776 открывающих); строка //}}MRG[ <-> ] — след инструмента
сравнения-объединения (185 строк в 12 модулях), а не закрывающая. Закрывающая
без открывающей и открывающая без закрывающей называются примечанием «в
разборе не учтена» — в файле они остаются как есть; ближние к правкам (60
строк) и по ту сторону, где могут влиять, — поимённо: закрывающая — если
правки выше неё, открывающая — если ниже; остальные — одной строкой с
номерами, «на решения не влияют». Метки внутри закрытого блока «[-]» не
называются: деактивированный код несёт свои старые метки, а их закрывающая
стоит хвостом на закомментированной строке и меткой не считается.
Метка метода без закрывающей: метка хвостом на объявлении или отдельной
строкой над методом (через описание и директиву, без пустых строк; «[-]» сюда
не относится — удалённое это комментарии) без своей пары — вставкой
считается весь метод, до его
КонецПроцедуры/КонецФункции, и правка внутри разбирается как в любой чужой
вставке. Так на выгрузке крупной типовой конфигурации устроены 394 метода
«[+] ДОБАВЛЕН» из 403 незакрытых с меткой хвостом и ещё 107 с меткой над
методом — закрывающую там просто не ставили. Метка закрывается при проходе, а
не после: иначе незакрытая метка, лежащая в стеке, забиралась бы чужой
закрывающей через сотни строк (из 108 пар «метка метода — закрывающая дальше
его конца» на той же выгрузке 94 ложные: 27-515 вместо 27-72).
«Своя пара» сохраняется: та, с которой метка спарилась бы без неявного
закрытия, если у закрывающей та же дата (вставка из нескольких методов, и с
метками у методов внутри) или она стоит сразу за концом метода (закрыли
другим днём). С этим разбором и четвёртой формой метки на той же выгрузке
остаётся 747 закрывающих без пары и 377 незакрытых открывающих (без них было
бы 1077 и 462). Примечание называет допущение, когда правка внутри такого
метода. Деактивированный код вставки «[-]» в новой версии не повторяется, а
живой — повторяется всегда: живой код не теряется ни при каком разборе.
Устаревший якорь — отказ, который называет, где ожидаемая строка сейчас
(«такая строка сейчас на 166 — номер устарел?»). Расхождение одним отступом
называется словами («текст совпал, отступ — нет: ожидалось без отступа, в
файле 2 табуляции»), строка из одних пробельных — «пустая строка (1
табуляция)», а не пустыми кавычками. Отступ при этом сверяется: им
различаются одинаковые КонецЕсли; разной вложенности. Якорь
у замены — первая заменяемая строка; новый метод в конец области якорится её
#КонецОбласти, новая область передаётся в code целиком. Вставка между
директивой компиляции и объявлением метода — отказ с якорем шапки метода.
Отказы по правкам одного модуля приходят все разом («правок с отказом: 2: 1) …;
2) …»), а не по одному за вызов.
Место правки решение называет словами: «перед строкой 55 (в конце области «ОбработчикиКомандФормы»)», «строка 13 (в методе «Служебная»)». Текст якоря «#КонецОбласти» в модуле не один, и по номеру строки не видно, в конец какой области ляжет вставка. Решения идут по порядку строк, как у отката.
Формат файла ответ называет у каждого модуля: «(правок: 2; файл CRLF, BOM —
так и останется)». Переводы строк инструмент сохраняет, LF остаётся LF (это
закреплено тестом). Формат назван словами, потому что grep из Git Bash
отбрасывает CR, и по его выводу сохранённый CRLF легко принять за
переписанный LF.
Переименование правит объявление и обращения внутри модуля, где метод
объявлен (не объявлен — отказ). Обращение через точку переименовывается,
только если перед точкой сам этот модуль: имя общего модуля, имя объекта у
модуля менеджера, ЭтотОбъект/ЭтаФорма; вызовы одноимённых методов других
модулей остаются и перечисляются в примечании. Вызовы из других модулей
инструмент не ищет — их находит поиск по выгрузке, вносятся они обычными
правками; у экспортного метода примечание об этом напоминает. Метка на
объявлении (вставка — весь метод) делает из переименования обёртку всего
метода: закомментированная копия и новый метод целиком. Повтор уже
внесённого переименования — отказ «переименование уже внесено?», а не «не
объявлен».
Символы, которые BSL Language Server считает ошибкой (InvalidCharacterInFile:
мягкий перенос, четыре тире, знак минус, неразрывный пробел — перечень снят с
самой диагностики), и кавычки-ёлочки (в коде кавычки прямые) в новом
коде — отказ с номером строки. Перенесённый текст
(переименование, перенос метода) не проверяется: чужой символ в старой строке
не повод отказать. Код формы с таким символом из заголовка задания —
предупреждение ФОРМА-КОД-СИМВОЛ (ФОРМА-КОД-ЁЛОЧКИ) уже в просмотре формы.
Дата меток, отличная от сегодняшней, — примечание, а не отказ: в метку ставится дата правки, но задание, начатое вчера, законно доносят сегодня. Часы — у корня сборки, домен даты не знает.
Отступ блока набирать не обязательно: код встаёт на уровень места правки —
у замены это уровень первой заменяемой строки, у вставки — якоря, а перед
словом, закрывающим конструкцию (КонецПроцедуры, КонецЕсли, Иначе…), — на
шаг глубже; пришедший мельче сдвигается вправо целиком, и решение это
называет. Метки и пустые строки снаружи — на том же уровне. Отступы внутри
блока — как переданы: «отступ можно не набирать» касается уровня блока
целиком, а не строк внутри него. Метод, тело которого вровень с объявлением, —
отказ (нулевая колонка законна у #-инструкций, комментариев и продолжения
литерала «|»).
Новые методы и области: каждый метод — своя вставка, описание и директива
компиляции (&НаСервере) над ним — его часть (описание передаётся в code
вместе с методом, метка встаёт над описанием), закрывающая метка — хвостом на
КонецПроцедуры; #Область/#КонецОбласти вставками не оборачиваются.
Область, которая на том же уровне модуля уже есть, — отказ с её строками,
как и повтор метода (у BSL Language Server это диагностика
DuplicateRegion). Одноимённая область внутри другой — не повтор.
Откат сверяет пустые строки на стыках снятых вставок с версией модуля в HEAD и возвращает модуль побайтно. Окно стыка ищется в HEAD по окружающим строкам, так что чужие правки в других местах модуля не мешают; где сверить не с чем (модуля в HEAD нет, задача уже закоммичена), решение так и говорит — тогда смотрите diff. Сверено или нет — у каждой вставки своё: одно несверенное окно не делает несверенными остальные стыки модуля. Снятые разделители называются у своей вставки с номерами строк: «снимаются строки 3-9 (7) и пустые строки-разделители 2, 10» — так счёт сходится по каждой вставке; возвращаемые строки — с номерами нового текста. Область, которую завела задача, снимается вместе со своими вставками: директивы областей меток не несут, и иначе откат оставил бы её пустой. Чья область, говорит HEAD — в нём её нет; без HEAD область остаётся, и примечание о ней говорит. Показ отката — со строками-соседями «·», у пустого места — строками стыка.
Подпись проверяется: автор обязателен — своего автора у инструмента нет,
его подставляет тот, кто зовёт инструмент. Автор — только имя (метка команды
в начале срезается — её ставит инструмент по профилю; другой # — отказ),
дата — дд.мм.гггг; недостающие поля подписи называются все разом. Заглушка
вида <Модуль> в коде — отказ. Отказы задания из нескольких модулей приходят
все сразу, и каждый называет свой модуль. Рядом с меткой, стоящей отдельной
строкой, пустая строка-разделитель не ставится.
Повтор задания после записи — отказ, а не задвоение: новый метод с уже объявленным именем, чистая вставка, у якоря которой уже стоит вставка этой задачи с тем же кодом, переименование в занятое имя.
Просмотр показывает под каждым решением текст, который будет записан, с
номерами строк нового модуля («будет записано — строки 653-656») и строкой-
соседом сверху и снизу (знак «·» вместо «│»: видно, встал ли разделитель
рядом с чужой меткой), запись — где искать записанное. Табуляция в пустой
строке видна знаком «→» — проверять её по байтам не нужно. Номера в решениях
и в «разметке модуля» — по тексту до правки, в показе — нового; про «разметку
модуля» шапка говорит, только когда она в ответе есть. Чужие метки без
пары называются поимённо только рядом с правками (60 строк), остальные — одной
строкой с номерами. Откат показывает, что вернётся на место снятой вставки;
длинный блок — краями, verbose / --подробно — целиком. Заданию из одного
отката дата и автор не нужны.
Запись идёт общим планом, как у метаданных: модули пишутся все разом или ни один — сбой на втором модуле откатывает первый.
Правила правки закреплены тестами в meta/tests/test_code.py, включая
побайтную сверку с реальной вставкой.
Проверка правок задачи
Инструмент пишет выгрузку и ставит метки вставок; verify проверяет то же
самое постфактум — по правкам задачи: файлам, которые она добавила, изменила
или удалила относительно базы. Разбор меток у записи и проверки один
(domain/edits.py), и что записал code_apply, проверка принимает без
находок по меткам — это закреплено тестом.
py -3 meta/add.py --проверить C:/work/cf [--база <ревизия>] [--ревизия <ревизия>]
[--задача <ИД>] [--только <код,код>] [--json <файл>]
py -3 meta/add.py --проверить --эталон <каталог> --копия <каталог> [--json <файл>]Источник правок один из двух. Git: рабочая копия против базы (по
умолчанию HEAD) вместе с новыми файлами, которых git ещё не знает, или
ревизия (--ревизия) против базы; переименования — парой «удалён — новый».
Пара каталогов: обработка или отчёт вне репозитория — эталон из
вложения против правленой копии; состав — сравнением по содержимому.
Код | Уровень | Что требует правило |
| ошибка | новый объект метаданных назван с приставкой команды (код тот же, что у записи) |
| ошибка | тип вставки — ИЗМЕНЕН, ДОБАВЛЕН, УДАЛЕН без «Ё»: по этим словам вставки ищут |
| ошибка | в открывающей метке назван тип вставки |
| ошибка | в открывающей метке дата дд.мм.гггг |
| ошибка | в открывающей метке ИД задачи — последним «#» |
| ошибка | правка существующего кода — внутри вставки, удалённое сохранено комментарием |
| предупреждение | правка внутри вставки другой задачи — своей вставкой поверх (нужен ИД задачи) |
| ошибка | открывающая метка, поставленная задачей, закрыта |
| ошибка | вставка вокруг метода закрывается на строке КонецПроцедуры/КонецФункции |
| ошибка |
|
| ошибка | текстовый файл выгрузки — UTF-8 с BOM |
| предупреждение | переводы строк внутри файла одни |
| ошибка | переводы строк — те, что приняты в репозитории |
| предупреждение | хвостовые пробелы строк эталона не срезаны (пара каталогов) |
| ошибка | строка не заменена на себя же с другими пробелами (git) |
| ошибка | права на новый объект выданы в своей роли, а не только в чужой |
| ошибка | новый объект входит в роль с включённым правом |
| предупреждение | у похожих составных членов задачи один состав ссылочных типов: член, чей состав — собственное подмножество состава другого и отличается на один-два типа, почти всегда хранит значения того же происхождения, и запись недостающего типа упадёт |
Уровень каждого правила меняется профилем (правила), правило можно
выключить; приставка и «своя роль» — тоже из профиля. Без приставки
МД-ПРЕФИКС не проверяется, а права считаются выданными в любой роли.
Приставка задаётся и списком: основная первой, остальные тоже свои —
старые приставки команды, тестовые модули YAxUnit ("приставка": ["мой_", "ОМ_мой_"]).
Правки внутри модуля, созданного задачей, меток не требуют; пустые строки и директивы областей — тоже. Строка с тем же текстом на том же месте — не правка: так git показывает строку, у которой изменился только перевод строки в конце файла. Удалённая строка не нарушение, если она сохранена в модуле комментарием.
Пропущенное называется: правило, которое не проверялось (нет приставки,
не задан ИД задачи), идёт в «Пропущено» с причиной, и итог тогда — «НЕПОЛНЫЙ
ПРОГОН», а не «ЧИСТО». Пояснения, которые вердикта не меняют, — отдельно:
переводы строк не сверяются, если git нормализует их сам (core.autocrlf);
права не проверяются у пары каталогов без конфигурации.
Ответ для хука — --json <файл>:
{"источник": "рабочая копия против abc1234 (с новыми файлами)",
"находки": [{"код": "ВСТАВКА-НЕ-ЗАКРЫТА", "уровень": "ошибка",
"файл": "CommonModules/мой_X/Ext/Module.bsl", "строка": 11461,
"текст": "открывающая метка вставки без закрывающей: вставка не закрыта"}],
"пропущено": [{"что": "ПРАВКА-В-ЧУЖОЙ-ВСТАВКЕ", "почему": "не задан ИД задачи"}],
"пояснения": ["переводы строк не сверяются: git нормализует их сам (core.autocrlf)"]}файл — от корня выгрузки, строка — в новой версии; у находки по объекту
метаданных (права) файла нет — объект назван в тексте. У правил о файле
целиком (ПРАВКА-ВНЕ-ВСТАВКИ, ПРАВКА-В-ЧУЖОЙ-ВСТАВКЕ, формат) строки нет,
номера строк — в тексте. Код возврата: 0 — нарушений нет (предупреждения
допустимы), 1 — есть нарушения, 2 — ошибка входа (нет выгрузки, нет
ревизии): это не «чисто», хук обязан считать его провалом.
СОСТАВ-ТИПОВ-УЖЕ смотрит только члены, которых до задачи не было; больше
300 карточек в правках — похоже на перезалив выгрузки, и правило идёт в
«Пропущено», а не читает тысячи карточек. Карточка, которая не читается,
называется в пояснениях.
Что зависит от формата выгрузки. Метки вставок, приставка, права и
составы типов — от модели и годятся любому формату; ВЫГРУЗКА-СЛУЖЕБНЫЙ-ФАЙЛ
— только выгрузке конфигуратора; правила ФАЙЛ-* — общие для выгрузки и
проекта EDT. Раскладка (что модуль, что карточка, где права роли) — в
infra/layout.py, чтение состава карточки — в перекладке
(acl/mapping.py): проекту EDT — своя раскладка и своё чтение рядом.
Нормализация формата
Инструменты записи агентов не пишут BOM, срезают хвостовые пробелы у любой записываемой строки и не доносят до файла строку из одних пробельных символов; разовая правка не держится — следующая перезапись теряет её снова. Поэтому нормализация — операция, а не событие: идемпотентна и запускается перед каждой проверкой правок и перед коммитом.
py -3 meta/add.py --нормализовать C:/work/cf [--база <ревизия>] [--apply]
py -3 meta/add.py --нормализовать --эталон <каталог> --копия <каталог> [--apply]По каждому текстовому файлу задачи (кроме служебных):
BOM — файл выгрузки в UTF-8 с BOM;
переводы строк — принятые в репозитории (по образцам его модулей и карточек); где git нормализует их сам (
core.autocrlf), — свои переводы файла: переписывать файлы там незачем; у пары каталогов — как у эталона, а эталон с разными переводами не навязывает ни одних;хвостовые пробелы — строкам, которые совпадают с базой без хвостов, окончание из базы (класс «строка заменена на себя же без хвоста»); строки внутри настоящих правок не трогаются;
отступ пустых строк в методах — по следующей непустой строке, на шаг глубже перед словом, закрывающим конструкцию; только строки нулевой длины и только добавленные задачей: пустых строк без отступа в чужих модулях сотни, и «починка» их была бы правкой сверх объёма задачи;
завершающий перевод строки — как в базе.
Строка, где пробельный символ уже есть, не переоформляется: это была бы
косметическая правка чужого кода, а её проверка правок запрещает
(ПРАВКА-ТОЛЬКО-ПРОБЕЛЫ). Без --apply — просмотр (код 1 — есть что
исправить), с --apply — запись всех файлов разом; ревизию не переписывают.
Сверка плана изменений
План — намерение: какие объекты задача создаёт, меняет или удаляет, какие члены у них появляются — реквизиты, измерения, ресурсы, табличные части, значения перечисления, с типами — и какие методы в модулях. Сверка с фактом задачи идёт в обе стороны: заявлено, но не сделано; сделано, но не заявлено; типы не совпали. Глазами структурную сверку «замысел — код» делают по многу раз и с пропусками; здесь она — правило.
py -3 meta/add.py --сверить-план C:/work/cf --план план.json [--база <ревизия>]
[--ревизия <ревизия>] [--json <файл>]
py -3 meta/add.py --план-по-факту C:/work/cf [--база <ревизия>] [--ревизия <ревизия>]Источник правок тот же, что у проверки (--эталон/--копия тоже
принимаются). План — JSON:
{"объекты": [
{"вид": "РегистрСведений", "имя": "мой_Остатки", "действие": "создать",
"измерения": {"Договор": ["Справочник.ДоговорыКонтрагентов"], "Период": ["Дата"]},
"ресурсы": {"Сумма": ["Число(15,2)"]},
"модули": {"МодульМенеджера": ["ЗарегистрироватьИзменение"]}},
{"вид": "Перечисление", "имя": "мой_Виды", "действие": "создать", "значения": ["Первый", "Второй"]},
{"вид": "ОбщийМодуль", "имя": "мой_Сервер", "действие": "изменить", "методы": ["Пересчитать"]},
{"вид": "Роль", "имя": "мой_атом_Остатки_Просмотр", "действие": "изменить"}
]}действие—создать,изменить,удалить; у изменяемого объекта перечисляется только то, что задача добавляет.Состав — по группам
реквизиты,измерения,ресурсы,табличныеЧасти,значения: имя -> список типов (null— тип не сверяется) или просто список имён. Тип пишется записью показа (Строка(50),Справочник.Имя) или записью синтакс-помощника (СправочникСсылка.Имя) — это один тип; сверяется род типа: длина, точность и состав даты — нет. Тип-набор (ОпределяемыйТип.Имя) — тоже тип.Методы —
методыу вида с одним модулем (общий модуль, общая команда, сервисы),модулиу прочих:МодульОбъекта,МодульМенеджера,МодульНабораЗаписей,МодульМенеджераЗначения. Служебные методы перечислять не нужно: заявляются те, что составляют замысел задачи.Неизвестный ключ, неизвестное действие, вид, которого выгрузка не знает, объект дважды — отказ (код 2) со всеми бедами разом: опечатка («реквизит» вместо «реквизиты») молча выключила бы сверку того, что за ней стоит.
Код | Уровень | Что требует правило |
| ошибка | объект, заявленный к созданию или изменению, есть в выгрузке |
| ошибка | объект, заявленный к созданию, до задачи не существовал |
| ошибка | объект, заявленный к удалению, удалён |
| предупреждение | в объекте, заявленном к изменению, есть правки |
| ошибка | объект, который задача создала, изменила или удалила, заявлен |
| предупреждение | роль или подсистема, тронутая задачей, заявлена: их правят попутно — право на новый объект, место в интерфейсе |
| ошибка | карточка заявленного объекта читается |
| ошибка | заявленный член объекта есть в выгрузке |
| ошибка | член, который появился в задаче, заявлен |
| ошибка | род типов члена — заявленный |
| ошибка | модуль, где заявлены методы, есть |
| ошибка | заявленный метод объявлен в модуле |
| предупреждение | экспортный метод, появившийся в задаче, заявлен |
Уровни меняются профилем, как у проверки. Объект «тронут», если задача добавила, изменила или удалила любой его файл — карточку, модуль, форму, права роли. Методы читаются тем же разбором объявления, что у правки вставками. Расхождение не обязательно дефект кода: план мог устареть, — но объяснить его обязан тот, кто сдаёт работу.
Ответ — текстом (итог «СОВПАДАЕТ» или «РАСХОЖДЕНИЙ: N») и --json тем же
видом, что у проверки, с полем объект («Вид.Имя»); файл — карточка или
модуль, строка — у метода. Коды возврата — как у проверки: 0, 1, 2.
План по факту (--план-по-факту, plan_emit) — тот же формат по
сделанному: объекты, файлы которых задача тронула; их новые члены с типами
записью показа, с уточнениями (Число(15,2)); новые методы модулей — все, а
не только экспортные. Сверка принимает его без расхождений. Он нужен, чтобы
увидеть сделанное целиком или начать план доработки существующей задачи;
план новой задачи пишется до кода — это намерение, а не отчёт.
Язык
Идентификаторы английские — как в остальном Python проекта. Русский остаётся
там, где он данные, а не код: ключи полей домена ("имя", "источник"),
имена видов ("ПодпискаНаСобытие"), значения перечислений ("НеИспользовать"),
тексты находок, комментарии и docstring'и. В этом и смысл слоя перекладки:
русский — язык предметной области, а не язык программы.
Устройство
meta/domain/ понятия и инварианты. Не знает ни тегов, ни файлов
meta/acl/ перекладка домен ↔ формат. Ядро — три модуля по скорости
изменения: `vocabulary.py` — таблицы соответствий (растут
с каждым видом), `schema.py` — состав и порядок свойств,
`mapping.py` — сама сборка (почти не меняется). Рядом —
адреса модулей (`modules.py`), код доработки формы
(`form_code.py`, `platform_code.py`) и показ формы в HTML
(`form.py`: страница по дереву формы, без канала — из кода)
meta/application/ сценарии — у каждого свой модуль (`add_object/use_case.py`,
`show_form/use_case.py`, `atomic_roles_use_case.py`…),
договоры площадки и справки (`ports.py`), факт задачи
для плана (`plan_facts.py`), общий итог (`dto.py`) и
порождение uuid (`ids.py`)
meta/infra/ файлы: сериализация, запись планом с откатом, чтение конфигурации;
модули кода — формат файла, история в git (`modules.py`)
meta/jobs/ язык заданий: JSON -> модель приложения, семьи операций, справка языка;
задание на код (`code.py`) — всё задание одна работа
meta/report/ язык ответов: результат -> строки текста
meta/cli/ канал терминала: ключи, файл задания, печать
meta/api/ канал MCP: модели запроса, контроллер, инструменты
meta/composition/ корень сборки: подключает инфраструктуру к сценариям, сценарии к каналам
meta/add.py точка входа терминала — запускает корень
meta/mcp_server.py точка входа MCP — запускает кореньСценарий — класс XxxUseCase с площадкой в поле и одним методом execute,
по модулю на сценарий. Сценарий получает модель приложения — доменные
объекты — и не знает ни файлов, ни того, по какому каналу пришёл запрос.
Два канала, терминал и MCP, друг друга не видят. Каждый переводит свою модель в модель приложения своим контроллером и зовёт сценарий. Общее у них только то, что внутри: язык заданий (разбор одного и того же формата), язык ответов (один текст для человека и агента — сообщения не живут двумя жизнями) и корень сборки. Контроллеры не знают ни инфраструктуры, ни конкретных сценариев: корень передаёт им фабрики «сценарий для этой выгрузки», потому что выгрузка приходит в каждом запросе. В ту же фабрику встроена политика доступа канала — белый список у MCP.
Зависимость направлена внутрь: приложение знает только интерфейсы из
ports.py. Другой формат исходников — это новая реализация интерфейса,
домен не меняется: так добавлен проект EDT (EdtDump — наследник площадки
выгрузки, выбирается корнем сборки по каталогу). Проверяется тестом, который
выполняет сценарий на площадке «в памяти», не касаясь ни XML, ни диска.
Проверки
Одной командой — линтер и все тесты:
py -3 check.py # всё
py -3 check.py --fast # без сверки с корпусомПо отдельности — py -3 -m ruff check . и py -3 -m pytest -q.
Границы слоёв
meta/tests/test_architecture.py — гард направления зависимостей: разбирает
исходники через ast, ничего не импортируя, и падает, если появилось ребро
наружу. Правила:
domain — ни от чего
acl → domain
application → domain
infra → domain, acl, application (только ports)
jobs → domain
report → domain, jobs, application (dto, ports)
cli, api → domain, jobs, report, application (dto, ports); друг друга не видят
composition → все
точки входа → только compositionСторонние библиотеки заперты в своём слое: lxml — только infra, mcp и
pydantic — только api. Отдельно проверяет, что domain и acl не знают про файловую систему
(это утверждение встречается в описаниях — здесь оно перестаёт быть обещанием),
и что все слои на диске описаны в таблице гарда. Ребро application -> acl
или import os в домене его роняют.
Сверка с корпусом
Идёт по настоящей выгрузке; путь к ней задаётся переменной
окружения META_CORPUS — каталог выгрузки с Configuration.xml. Без выгрузки
такие тесты помечаются пропущенными, остальные работают.
Что доказано на корпусе — выгрузке крупной типовой конфигурации:
639 подписок и 4100 общих модулей собираются побайтно;
29 374 реквизита из 34 542 по 13 видам — побайтно; остальные 5168 несут то, чего домен не выражает, и это число печатает сам тест;
вложенные сущности: 6673 ресурса, 10 814 значений перечислений и 2139 табличных частей вместе с их реквизитами — побайтно (непокрытое тест тоже печатает: 543, 815 и 752).
Что доказано кругом через платформу:
карточки, выгруженные платформой после загрузки написанного инструментом, совпадают побайтно, включая переводы строк (
meta/tests/эталоны/);схема компоновки проходит тот же круг целиком: отчёт с макетом, набор данных, параметры, четыре вида пунктов настроек и переименование справочника со всеми ссылками — платформа не меняет ни строки,
CheckConfigс проверкой целостности и ссылок чист.xsi:nilу пустого значения параметра иuseRestrictionу параметров инструмент пишет так, как их пишет платформа.
Регрессии языка заданий
Регрессии языка заданий закреплены фикстурами в meta/tests/test_regressions.py.
Они проходят задание целиком — через язык заданий и инварианты, а не через
перекладку напрямую: так ловится то, чего не видно ни в тесте перекладки, ни
в плане записи, — например, значение заполнения, не согласованное с хозяином
реквизита, или опечатка в ключе типа (длина/точность вместо
разрядность/дробнаяЧасть), которую молчаливое умолчание превратило бы в
Число(10,0) вместо Число(15,2) при плане записи того же размера. Отдельный
гард следит, чтобы коды находок и представления типов оставались русскими
строками: механическое переименование идентификаторов не должно задевать
строки-данные.
Чего нет
у форм пишутся элементы пятнадцати видов из 31 (99,0 % корпуса по числу — 347 258 элементов из 350 799); не пишутся поля документов (табличного, текстового, HTML, форматированного), диаграммы, индикатор, календарь, планировщик и подменю; из макетов — только макет со схемой компоновки, табличный документ и текст не пишутся;
заведено 15 видов объектов из 43, встречающихся в замеренной конфигурации, — по числу объектов это 17 033 из 22 284. Не заведены, по убыванию распространённости: общие картинки (2327), функциональные опции (647), элементы стиля (590), общие формы (500 — как объект
metadata_applyне заводятся, но создаются заданием на формы:forms_apply, «Общая.Имя» с «создать»), пакеты XDTO (442), общие макеты (303), параметры сеанса (154), журналы документов (46), группы команд (44), планы обмена (39), планы видов характеристик (32) и ещё семнадцать видов по десятку и меньше;вложенные подсистемы не заводятся: они живут отдельными файлами в каталоге родителя;
из наборов данных схемы компоновки описан только набор-запрос (893 в замеренной конфигурации); набор-объект (273) и объединение (109) описываются другими полями и не заведены;
заданием на метаданные текст общего модуля задаётся только при создании; дописать метод в существующий модуль — заданием на код (
code_apply, раздел «Правка кода вставками»);объекты одного задания друг друга не видят: зависимые заводятся по очереди, отдельными заданиями;
табличная часть замерена у справочника, документа, обработки и отчёта; у планов и прочих видов состав не замерен — инструмент об этом говорит и не пишет;
порядок детей внутри табличной части не замерен: сейчас там бывает один вид, и появление второго — отказ, а не тихая ошибка;
ссылочный тип у параметра схемы компоновки не пишется: приставку для типов конфигурации карточка объявляет в корне (
cfg), а схема — на самом элементе и с порождённым именем (d4p1), правило порождения не замерено. Примитив пишется;связи внутри схемы идут по именам полей — выбираемое поле называет поле набора, запрос называет параметр. Удаление внутри схемы об этом предупреждает и не сверяет;
три свойства реквизита со вложенной структурой: связи параметров выбора, параметры выбора, связь по типу — отвергаются, а не записываются неверно;
значение заполнения умеет «не задано» и пустую строку, настоящее значение — отказ;
ConfigDumpInfo.xmlне трогается намеренно: егоconfigVersionсчитает платформа, снаружи он не вычисляется. Загрузка должна быть полной.формат выгрузки один — 2.21; совместимость с 2.20 и другими не замерена, и писать в такую выгрузку инструмент отказывается.
сверка плана видит состав объекта верхнего уровня и собственные модули: реквизиты табличных частей, формы и их модули, команды объекта в план не входят; длина и точность типов не сверяются — только род типа. Источник — выгрузка конфигурации (под git или парой каталогов той же раскладки): выгрузка внешней обработки, где карточка лежит в корне, сверке плана не подлежит.
Что проверяется на отношения, а не только по отдельности
Мало проверить, что объект существует и что имя права существует, — нужно ещё, чтобы они имели друг к другу отношение. Таких проверок три. Строгость у них разная, и зависит она от того, чем доказано утверждение: «в выгрузке не встречается» — наблюдение, «платформа не примет» — факт, и по выгрузке он не доказывается, только опытом.
имя против стандартных реквизитов вида — ошибка. Измерение «Период» в регистре имя занимает: платформа заводит стандартные реквизиты сама и в выгрузку их не выписывает, так что состав детей о них молчит. Это не наблюдение по корпусу, а опыт: платформа отвергает загрузку словами «Недопустимое имя измерения - Период», и отвергает одинаково у периодического регистра и у непериодического;
право против вида объекта — предупреждение. Проведение справочнику, ввод по строке регистру. Таблица снята по 3,07 млн пар «объект — право» в 2709 ролях замеренной конфигурации;
сигнатура обработчика против события — предупреждение. Число параметров задаёт сочетание события, вида источника и грани: у документа
ПередЗаписьюих четыре, у справочника два, у набора записей регистра три. Таблица снята по 639 подпискам замеренной конфигурации.
Порядок групп в карточке
Куда ставить группу детей — например Attribute, если реквизитов в карточке
ещё нет, — по большинству не угадывается. На взгляд порядок групп внутри
объекта неканонический: 23 варианта на 1783 карточки, и Attribute идёт
первой лишь в 96 % из них. Но опыт показывает обратное: карточка, записанная
с переставленными группами (TabularSection перед Attribute), после
загрузки в базу и выгрузки обратно получает группы на их обычных местах:
порядок канонический, его держит платформа.
Свод по 7179 карточкам замеренной конфигурации даёт этот порядок для 23 видов
без единого противоречия: «разные варианты» — подмножества одного общего
порядка, а не разброс. Таблица — acl/vocabulary.py, CARD_ORDER; она
пересобирается по корпусу в тесте, а не хранится как мнение.
Порядок разный у разных видов, и это не описка: у документа формы идут между
реквизитами и табличными частями, у справочника — после них; у регистра
бухгалтерии измерения впереди ресурсов, у регистра сведений — наоборот.
Правило «по большинству» — Attribute всегда первой — ошибалось бы ровно на
этих случаях.
Словарь
Термин | Что значит |
выгрузка | каталог, который пишет конфигуратор командой «Выгрузить конфигурацию в файлы»: в корне |
карточка | XML-файл объекта в выгрузке ( |
спутники | файлы рядом с карточкой, в каталоге объекта: модули, формы, макеты, права роли; у элемента формы — служебные элементы, которые рождаются вместе с ним (контекстное меню, расширенная подсказка, дополнения таблицы) |
порождаемые типы | типы, которые платформа заводит вместе с прикладным объектом: у справочника — объект, ссылка, выборка, список, менеджер |
грань | какой стороной тип объекта участвует в типе значения: ссылка, объект, менеджер, набор записей…; пишется в скобках — |
вставка, метки вставки | правка существующего кода, обёрнутая парой комментариев: открывающей |
приставка доработок | начало имён всего, что команда добавляет сама ( |
корпус, замеренная выгрузка | выгрузка крупной типовой конфигурации, по которой сняты числа этого README и правила «как пишет платформа»; тесты сверки идут по ней ( |
проверочная конфигурация | пустая конфигурация, на которой проверяется запись: на ней проходят круги через платформу и снят эталон форм |
круг через платформу | записали инструментом → загрузили конфигуратором → выгрузили обратно → сверили побайтно |
This server cannot be deployed
Maintenance
Related MCP Connectors
Checks AI-written code against your rules as it is written, and keeps a record of what it found.
Turn an idea or meeting transcript into a working single-file AI agent, check it, use it right away.
Turn an idea or meeting transcript into a working single-file AI agent, check it, use it right away.
Lints + auto-fixes how AI coding agents discover any new product. 24 rules, 6 tools, score 0-100.
Related MCP Servers
- FlicenseNot gradedqualityDmaintenanceEnables AI agents to interact with 1C:Enterprise databases through natural language, providing metadata retrieval, configuration analysis, and code generation.9-
- AlicenseNot gradedqualityAmaintenanceEnables AI agents to lint, search documentation, and perform metadata scaffolding for 1C:Element projects.11,356 PyPI3MIT
- AlicenseNot gradedqualityAmaintenanceEnables AI agents to interact with 1C: Enterprise development environment, including running tests, managing launch profiles, building configurations, and performing database operations through the 1C: Platform Tools extension.39MIT
- FlicenseNot gradedqualityAmaintenanceEnables 1C:Enterprise development with 74 tools for static analysis, code audit, query validation, EPF verification, and configuration management using local XML exports without a running database.-