Как дать LLM контекст формы 1С без выдуманных связей

14.08.26

Интеграция - Нейросети

Модуль формы сам по себе почти ничего не говорит LLM (Large Language Model - большая языковая модель) о поле, его типе и месте в структуре. Я собрал подтверждённые факты из elem.json, модуля и метаданных в компактный неизменяемый FormContext, не подменяя неизвестные связи догадками. Подход подойдёт разработчикам 1С, которым нужен короткий и проверяемый контекст формы для модели, а не сырая выгрузка целиком.

Бесплатные

ВНИМАНИЕ: Файлы из Базы знаний - это исходный код разработки. Это примеры решения задач, шаблоны, заготовки, "строительные материалы" для учетной системы. Файлы ориентированы на специалистов 1С, которые могут разобраться в коде и оптимизировать программу для запуска в базе данных. Гарантии работоспособности нет. Возврата нет. Технической поддержки нет.

Узнавайте о новых бесплатных решениях в нашей телеграм-группе Инфостарт БЕСПЛАТНО

Наименование Скачано Бесплатно
v8unpack_agent_infographic
.pdf 71,62Kb
3 Скачать бесплатно
v8unpack_agent_poster
.pdf 80,58Kb
4 Скачать бесплатно

Вы можете заказать платную доработку или адаптацию этой разработки под вашу конфигурацию на «Бирже заказов».

  • 0% комиссии — оплата напрямую исполнителю;
  • Исполнители любого масштаба — от отдельных специалистов до команд под проект;
  • Прямой обмен контактами между заказчиком и исполнителем;
  • Безопасная сделка — при необходимости;
  • Рейтинги, кейсы и прозрачная система откликов.

Когда я впервые получил распакованную форму, казалось, что задача уже решена. Вот дерево элементов, вот модуль, вот метаданные. Можно отдавать это модели.

На первом же вопросе стало ясно, что нет. Поле с Object.Counterparty не объясняет ни тип реквизита, ни синоним, ни то, действительно ли эта связь относится к конкретному элементу. А отправить в запрос всю распаковку - значит потратить бюджет на технический шум и случайно выдать модели предположение за факт.

Сначала я пытался получить максимум прямо из парсера: за один проход связать элементы формы, реквизиты и типы, в том числе по совпадению имён. На небольшом примере это выглядело убедительно, но на полном корпусе могло породить недоказанные связи. Поэтому я отказался от универсального парсера и разделил задачу на проверку отдельных фактов.

Все количественные результаты ниже получены на демонстрационной базе УТ 10.3. Они показывают эффект на этом проверенном корпусе, но не обещают такое же покрытие на других конфигурациях.

 

Коротко: что делать

  • Считайте elem.json, модуль формы и метаданные разными источниками фактов. Не соединяйте их по похожему имени.

  • Принимайте data_path только после проверки структуры. Неизвестная раскладка должна оставить пробел и добавить предупреждение.

  • Разрешайте ссылочный UUID (Universally Unique Identifier - уникальный идентификатор) через индекс всей выгрузки. Если ответа нет, сохраняйте Ref#<uuid>.

  • Собирайте один неизменяемый FormContext из семи полей, а реестр оставляйте реестром путей и контрольных сумм.

  • Держите в metadata только шесть безопасных полей и делайте пути относительными.

  • Формируйте фрагмент для модели в порядке FORM, SUMMARY, BSL (Built-in Script Language - встроенный язык 1С). По умолчанию возвращайте его полностью, а положительный max_chars задавайте только там, где нужен явный символьный лимит.

  • Очищайте не только поля, но и диагностические сообщения. Абсолютный путь в предупреждении - такая же утечка, как путь в метаданных.

Схема: распакованная форма, проверенные источники, FormContext и фрагмент для LLM с явным лимитом

 

Сначала доказать связь, потом обогащать

У формы есть минимум три разные правды. elem.json описывает дерево и привязки. Модуль хранит код обработчиков. Метаданные помогают понять, где лежат артефакты и можно ли им доверять.

Первой моей ошибкой было желание склеить их по именам. Это хорошо работает на демонстрационном примере и быстро ломается на реальной структуре: похожее имя ещё не делает элемент реквизитом. Поэтому наружу из декодера выходит только имя, тип и подтверждённый data_path.

Путь извлекается из data[*].raw лишь для распознанного формата. Повреждённая, неоднозначная или неизвестная раскладка не получает красивой догадки. Элемент остаётся без пути, а причина уходит в диагностику. Для модели это полезнее ложной уверенности.

 

Сегментный путь: два независимых признака

Самый неприятный случай - путь из нескольких сегментов. В сыром блоке рядом встречаются локальные идентификаторы, идентификаторы таблиц и UUID типов. Если просто найти первый UUID и назначить ему смысл, можно получить технически существующую, но неверную связь.

Я принял сегментный путь только при двух условиях:

  1. UUID таблицы объявлен среди адресов определений этой же формы.

  2. Склеенные имена всех сегментов посимвольно совпадают с именем элемента.

Это дало 377 новых подтверждённых data_path без изменения прежних путей. Именно отсутствие изменений здесь важнее самого прироста: новый разбор расширил покрытие, но не переписал уже доказанные связи.

Практическое правило: для нового формата нужны минимум два независимых подтверждения. Один найденный UUID - это повод исследовать раскладку, а не публиковать связь.

Ссылочный тип: индекс вместо догадки

У реквизита может быть не примитивный тип, а ссылка на другой объект. В таком случае декодер честно возвращает Ref#<uuid>. Это корректно, но человеку и модели от такой строки мало пользы.

Здесь мне помог не новый поиск в каждом объекте, а индекс, который строится при общем обходе выгрузки. scan_forms() уже проходит дерево, поэтому именно там логично сопоставить UUID и читаемое имя. Декодеру передаётся только функция разрешения:

index = scan_forms(export_root)
result = decode_object_attributes(
    object_json,
    type_resolver=index.resolve_reference_type,
)

Важная граница контракта: резолвер необязателен. Если его нет, он вернул None или завершился ошибкой, строка остаётся Ref#<uuid>, а обработка формы продолжается. Примитивные и уже понятные типы в резолвер не уходят.

Я сначала проверил одну удобную гипотезу о расположении UUID. Синтетические тесты были зелёными, а на полном корпусе она разрешила ровно ноль ссылок. Пришлось вернуться к структуре и индексировать все валидные UUID эквивалентных слотов блока, а не выдавать частную выборку за правило формата.

Из 5226 ссылочных реквизитов индекс разрешил 4670 в читаемые имена, а 556 остались неизвестными. Это не дефект, который надо замазывать. Для неразрешённого UUID правильный ответ системы - всё ещё Ref#<uuid>.

Практическое правило: синтетический тест проверяет контракт, но не доказывает устройство каждой реальной раскладки. Неизвестный ссылочный тип лучше сохранить неизвестным.

Где заканчивается реестр и начинается контекст

После разбора связей возник соблазн положить в запись реестра и чтение файлов, и выжимку структуры, и модуль. Я вовремя остановился. FormEntry должен оставаться карточкой указателей: путей, хэшей и служебных признаков. Иначе объект, пригодный для индекса, внезапно начинает зависеть от файловой системы.

FormContext решает другую задачу: материализует форму для одного запроса. Его публичный API (Application Programming Interface - программный интерфейс приложения) небольшой и намеренно скучный:

@dataclass(frozen=True)
class FormContext:
    form_name: str
    container_name: str
    object_type: str
    object_name: str
    bsl_text: str | None
    summary: FormSummary
    metadata: dict


def build_form_context(form_entry, unpacked_root) -> FormContext: ...


def to_llm_prompt_fragment(context, max_chars: int = -1) -> str: ...

FormContext ровно семь полей. Он не запускает второй разбор структуры и не изобретает новый data_path: выжимка строится единственным путём через build_form_summary поверх parse_elem_json.

Внутри metadata ровно шесть полей: form_path, elem_json_path, bsl_sha256, elem_sha256, has_bsl и warnings. Первые два пути относительны. Содержимого модуля, абсолютных каталогов и лишних полей записи реестра там нет.

 

Отсутствие - не пустота

Я отдельно зафиксировал три состояния модуля формы. Это мелочь, пока не начнёшь объяснять форму модели.

 

Состояние

Что попадает в контекст

Файл есть и содержит текст

bsl_text содержит текст, has_bsl равен True

Файла нет

bsl_text is None, has_bsl равен False

Файл существует, но пуст

bsl_text == "", has_bsl равен True

 

Текст читается с явной кодировкой UTF-8 (Unicode Transformation Format, 8-bit - 8-битное представление Unicode). Если структуры нет, контекст получает пустые бакеты выжимки и предупреждения разбора. Если нет каталога формы, парсер не запускается вовсе. Эти детали не делают ответ модели красивее, но не позволяют ей принять отсутствие файла за пустой код.

Практическое правило: реестр хранит адреса, контекст хранит содержимое. И пустой модуль нельзя подменять отсутствующим, как и наоборот.

Полный фрагмент с явным лимитом

Полный FormContext удобен программе, но модели нужен предсказуемый текст. to_llm_prompt_fragment() собирает его всегда в одном порядке:

# FORM <object_type>/<object_name>/<container_name>/<form_name>
## SUMMARY
<детерминированная JSON (JavaScript Object Notation - текстовый формат обмена данными) выжимка>
## BSL
<текст модуля или сообщение об отсутствии>

Сначала идут структура и связи, затем код. По умолчанию max_chars=-1, поэтому функция возвращает полный фрагмент без скрытой обрезки. Положительный лимит применяется последним и по символам: при max_chars > 0 длина результата никогда не превышает заданное значение. max_chars == 0 и значения меньше -1 возвращают пустую строку.

Вот минимальный сценарий с синтетической выгрузкой:

from pathlib import Path

from v8unpack_agent import build_form_context, to_llm_prompt_fragment
from v8unpack_agent.scan_forms import scan_forms

root = Path("sample_export")
index = scan_forms(root)
context = build_form_context(index.forms[0], root)
fragment = to_llm_prompt_fragment(context, max_chars=4000)

assert len(fragment) <= 4000
assert fragment.index("## SUMMARY") < fragment.index("## BSL")

 

Сначала я поставил лимит 8000 значением по умолчанию. Решение выглядело практично, но у него оказался неприятный побочный эффект: вызывающий код мог потерять хвост модуля, хотя явно обрезку не просил. Теперь безопасное умолчание - полный фрагмент, а ограничение включается положительным max_chars в том месте, где уже известен бюджет запроса.

Символьный лимит остаётся сознательным компромиссом. Он прозрачен и не привязан к конкретной модели, но не обещает точный бюджет токенов. При очень малом лимите выжимка может оборваться в середине JSON, поэтому этот текст предназначен для модели, а не для машинного разбора.

Практическое правило: соберите полный фрагмент, проверьте порядок разделов и только затем режьте. Лимит на одном контексте не заменяет распределение бюджета между несколькими формами.

Диагностика не должна выдавать локальное окружение

Одна из самых неприятных поломок пришла не через поле metadata, а через warning парсера. Локально там был абсолютный путь к каталогу формы. Для отладки удобно, для внешнего контекста - нет.

Сначала я очистил путь на границе FormContext. Но те же предупреждения попадают в FormSummary и могут использоваться без FormContext, поэтому одной защиты на выходе оказалось мало. Очистка появилась у источника сообщений и осталась вторым барьером при сборке контекста.

Например, синтетическое предупреждение до очистки могло выглядеть так:

Метаданные владельца не найдены для
C:\Users\demo\dump\Catalog\Объект\CatalogForm\ФормаЭлемента

После очистки смысл сохраняется, а сведения о локальной машине исчезают:

Метаданные владельца не найдены для
.../Catalog/Объект/CatalogForm/ФормаЭлемента

 

Корень выгрузки, имя пользователя, буква диска и сетевой хост удаляются, но полезный хвост пути остаётся.

На контрольном прогоне число warning-текстов с абсолютными путями снизилось с 42 до 0. Проверка покрывает Unix-подобные и Windows-подобные пути, путь с буквой диска и сетевой путь. Не стоит ослаблять такой тест из-за одной необычной строки исключения: OSError вполне способен вернуть имя файла в собственной форме записи.

Эту же границу я проверил в четырёх вариантах CI (Continuous Integration - автоматическая сборка и проверка): Python 3.10 и 3.12 на Ubuntu и Windows. Отдельно тестируется ленивый корневой экспорт: обычный import v8unpack_agent не загружает модуль form_context. Он импортируется только при первом обращении к FormContext, build_form_context() или to_llm_prompt_fragment().

Практическое правило: диагностический текст - часть внешнего контракта. Очищайте его у источника и повторно проверяйте перед передачей за пределы локального окружения.

Границы слоя, которые я не стал прятать

FormContext собирает одну форму, но не ищет формы по большому корпусу и не решает, какой из них отдать модели. Он также не классифицирует форму и не токенизирует общий запрос. Попытка закрыть всё одним объектом быстро превратила бы прозрачный контракт в смесь несвязанных обязанностей.

Ограничения у решения тоже вполне земные:

  • max_chars измеряет символы, а не токены конкретной модели.

  • При жёстком лимите фрагмент может заканчиваться внутри JSON.

  • Без резолвера или при отсутствии записи в индексе ссылочный тип остаётся Ref#<uuid>.

  • Ноль привязок не всегда означает ошибку: сервисная или диалоговая форма может не иметь связанных с данными элементов.

  • Равенство агрегатных счётчиков не доказывает равенство множеств. Сравнивать изменения нужно по формам и обезличенным ключам.

Практическое правило: честная деградация - это не исключение и не догадка. Это частичный контекст с понятным признаком того, чего в нём нет.

Что бы я сделал иначе

  • Раньше проверил бы гипотезу о слоте ссылочного UUID на полном корпусе. Синтетические тесты подтвердили слишком узкую модель, и она дала нулевой полезный результат. Теперь индексируются все валидные эквивалентные слоты.

  • Сразу разделил бы FormEntry и FormContext. Поначалу было удобно дать записи реестра самой читать файлы, но это смешало бы адреса, содержимое и кэширование. Сейчас материализация происходит только в build_form_context().

  • Добавил бы проверку абсолютных путей в warnings вместе с первым текстовым выводом. Защита лишь в контексте закрывает один маршрут, а не проблему целиком. Теперь есть очистка у источника и на внешней границе.

  • Проверял бы ленивость каждого нового корневого экспорта в чистом дочернем процессе. Один «удобный» импорт способен незаметно вернуть тяжёлую цепочку зависимостей.

  • Не ставил бы 8000 лимитом по умолчанию. Такой контракт незаметно обрезал данные без явного решения вызывающего кода. Сейчас -1 возвращает полный фрагмент, а положительный лимит задаётся только там, где уже известен бюджет.

 

Чек-лист для применения

  1. Пропустите elem.json, модуль и метаданные как независимые источники и не связывайте их по имени.

  2. Добавляйте data_path только после структурного подтверждения формата.

  3. Для сегментного пути проверьте адрес таблицы определений формы и точное совпадение собранного имени с именем элемента.

  4. Постройте индекс ссылочных типов во время общего обхода и передайте его резолвер в decode_object_attributes().

  5. Оставляйте неразрешённый ссылочный тип в виде Ref#<uuid> и записывайте причину вместо угадывания имени.

  6. Создавайте контекст через build_form_context(form_entry, unpacked_root) и не добавляйте в него второй парсер структуры.

  7. Ограничьте metadata шестью полями контракта и проверьте относительность обоих путей.

  8. Покройте тестами модуль с текстом, отсутствующий модуль и существующий пустой модуль.

  9. Проверьте, что to_llm_prompt_fragment(context) возвращает полный фрагмент в порядке FORM, SUMMARY, BSL, max_chars > 0 не превышается, а 0 и значения меньше -1 дают пустую строку.

  10. Прогоните очистку warnings на Unix-подобном, Windows-подобном и сетевом синтетических путях.

  11. Запустите чистый импорт в дочернем процессе и убедитесь, что модуль контекста не загружается до обращения к его символу.

  12. Оставьте поиск по нескольким формам и токенизацию общего бюджета отдельному слою.

 

Что дальше

Контекст одной формы теперь можно собрать без подмены неизвестных связей. Следующий шаг - выбрать несколько релевантных форм из большого корпуса и распределить между ними общий бюджет запроса, не теряя признаки неполноты.

 

Ссылки

Вступайте в нашу телеграмм-группу Инфостарт

LLM FormContext elem.json контекст формы метаданные модуль формы data_path v8unpack-agent промпт

См. также

Нейросети Системный администратор Разработчик Аналитик Бухгалтер Пользователь Руководитель проекта 1С 8.3 1С:Документооборот 1С:Бухгалтерия 3.0 1С:Зарплата и Управление Персоналом 3.x Россия Платные (руб)

Задавайте вопросы базе 1С обычными словами: получайте данные, находите ошибки и связанные документы, проверяйте права, работайте с вложениями и контролируемо вносите изменения. Всё это работает в самой программе, а Codex и Claude подключаются по желанию.

16990 руб.

30.07.2026    13374    29    4    

28

Инструментарий разработчика Нейросети Платные (руб)

Первые попытки разработки на 1С с использованием больших языковых моделей (LLM) могут разочаровать. LLMки сильно галлюцинируют, потому что не знают устройства конфигураций 1С, не знают нюансов синтаксиса. Но если дать им подсказки с помощью MCP, то результат получается кардинально лучше. Далее в публикации: MCP для поиска по метаданным 1С, справке синтакс-помощника и проверки синтаксиса.

15250 руб.

25.08.2025    71490    142    41    

150

Распознавание документов и образов Нейросети 1С:Предприятие 8 1С 8.3 1С 8.5 1C:Бухгалтерия 1С:Зарплата и Управление Персоналом 3.x Беларусь Россия Казахстан Армения Платные (руб)

ИИ-сканер документов с REST API для интеграции с 1С и корпоративными системами. Извлекайте данные из счетов, паспортов, дипломов, патентов и трудовых книжек за секунды. Точность человека - скорость машины. Приложение поддерживает восемь типов документов, четырех провайдеров ИИ (имеется возможность использования локальных ИИ), локальный REST API и экспорт в JSON. Важно! модель должна поддерживать функцию Vision (распознавание файлов и картинок). Запускайте используя локальные ИИ, без подписок и ограничений

6100 руб.

24.08.2026    595    3    0    

1

Инструментарий разработчика Нейросети Разработчик 1С:Предприятие 8 Абонемент ($m)

MCP-сервер даёт модели всю цепочку правки кода: найти метод, показать изменения построчно, внести, загрузить в базу с проверкой синтаксиса и проверить результат на живых данных. Плюс перенос данных между базами со сверкой остатков, поиск по коду и по смыслу, проверка выдуманных вызовов и аргументов, обезличивание персональных данных на выходе. И главное: пока не выполнено обновление из хранилища, сервер отказывается править и загружать. Инструмент умеет говорить «нет» — в статье есть кадр с таким отказом.

6 стартмани

24.09.2026    4158    5    Rafael-87    13    

10

Нейросети 1С:Управление торговлей 11 Бесплатно (free)

Я не считаю покупку специализированных платных инструментов обязательной для разработки с ИИ: нужную обвязку тоже можно создать с агентом. Показываю этот подход на расширении УТ 11 с динамическим списком остатков. Одно задание Codex, 37 минут до проверки, работающая форма. Рассказываю, как устроено окружение, почему первую попытку пришлось переснять и что получилось в повторном прогоне.

17.09.2026    6086    105    Ibrogim    62    

20

Нейросети Разработчик Руководитель проекта 1C:ERP Бесплатно (free)

Служба на Rust, через которую Claude Code, Cursor или другой MCP-клиент вызывает узких ИИ-агентов. Агент — папка с prompt.md и config.toml, модель — строка в конфиге: DeepSeek, Claude Code по подписке, Codex или локальная модель. Агент получает MCP-инструменты, работает в фоне, каждый ход записывается. Внутри — цифры за три месяца: 10 351 вызов, 78 агентов.

17.09.2026    1807    0    Sorm    9    

10

Нейросети Бесплатно (free)

Отладка кода 1С традиционно выглядит примерно одинаково: поставить точку останова, запустить клиент, воспроизвести сценарий, дождаться остановки, посмотреть локальные переменные, пройти несколько строк, раскрыть очередную структуру или коллекцию, вычислить выражение — и повторить все это еще несколько раз. А что, если значительную часть этой рутины поручить AI-агенту?

15.09.2026    3765    andrew.ab    5    

15

Нейросети Разработчик Аналитик Руководитель проекта Бесплатно (free)

Я принёс команде приём, с которым нейронка наконец начала понимать нашу конфигурацию: у меня он работал, у коллег — нет. Дело было не в постановке задач и не в настройках: причина в том, что на их машинах индекс конфигурации считался бы несколько дней. Замер на одном и том же своде из 26 035 записей: три часа на процессоре против трёх с половиной минут на видеокарте. Разбираю, что такое индексация конфигурации и почему она дорогая ровно один раз, почему наша основная серверная машина — 64 ядра, 768 гигабайт памяти — на этой задаче проигрывает домашнему компьютеру, и почему приём одного человека упирается в вопрос, который никто не любит задавать.

09.09.2026    4973    solbol    9    

10
Комментарии
Подписаться на ответы Инфостарт бот Сортировка: Древо развёрнутое
Свернуть все
1. nedomolkov.ivan 256 15.08.26 13:28 Сейчас в теме
Про "неизвестная раскладка оставляет пробел" подпишусь, но добавлю неприятное уточнение.

Пробел работает только если он виден модели. Мы выгружали структуру метаданных под LLM и ловили ровно ваш класс ошибок: если реквизит просто отсутствует в куске, модель дырку не замечает, а достраивает сама, уверенно и в терминах вашей же конфигурации. Как только в фрагмент попадает явная отметка вида "путь не доказан", выдумывание прекращается. То есть пропуск надо печатать, а не молчать про него.

Второе, про чистку диагностики. Это самое частое место утечки и самое незаметное: поля обезличивают, а предупреждения и трейсы забывают, потому что их "никто не читает". В выгрузку они уезжают ровно так же. У нас это отдельный пункт в чек-листе после того, как один абсолютный путь уехал в чат.

Из 5226 ссылочных 556 неразрешённых, это чуть больше 10 процентов. Они размазаны по конфигурации или кучкуются в паре подсистем? Если кучкуются, там скорее один невскрытый формат раскладки, а не 556 разных случаев.
2. MRDK80 12 16.08.26 17:19 Сейчас в теме
(1) Перепроверил оба замечания и заодно посмотрел, как распределяются оставшиеся ссылки (УТ 10.3.88.3 платформа 8.3.27.2214).
Насчёт пробела в данных для модели - так и есть. Прогонял именно итоговые LLM-фрагменты, а не внутренний результат парсера. Все 2216 форм построились без ошибок. Поле warnings есть во всех выжимках, в 916 формах оно непустое. При этом ни в одном SUMMARY нет явного отрицательного признака: unresolved, unknown_layout, «путь не доказан», data_path: null и т. п.
Сейчас получается так: неизвестный путь не угадывается, предупреждение сохраняется, но рядом с самим полем модель ничего не видит. Если диагностика выпадет из контекста, останется просто пустое место без объяснения.

Думаю, в таких случаях нужно выводить что-то вроде:
data_path: null
status: unresolved
reason: unknown_layout

То есть это нужно будет явно закрепить в формате сериализации.

Диагностику тоже проверил отдельно - и scan_warnings, и готовые LLM-фрагменты. В этом прогоне абсолютный домашний путь, имя пользователя и корень выгрузки наружу не попали. Но полагаться на это нельзя: сейчас просто не встретился проблемный случай. Поэтому санитизацию лучше делать в одном месте перед выдачей результата и пропускать через неё весь выход: warnings, исключения, traceback, пути и служебные превью.

Теперь про оставшиеся 556 ссылок.
Исходные числа подтвердились: 5226 ссылочных вхождений, 4670 разрешено, 556 остались в виде Ref#uuid - это 10,6%; ошибок декодирования и потерь нет.
Но эти 556 вхождений относятся всего к 49 уникальным UUID.
По объектам они распределены довольно широко: крупнейший объект даёт ~7.6%, первые пять - ~14.4%, первые десять - ~20.1%.
По классам метаданных тоже нет одной явной группы: Report - 28.6%, DataProcessor - 24.8%, InformationRegister - 20.7%...
А вот по UUID картина совсем другая. Один UUID даёт 174 случая, то есть 31.3%. На первые пять приходится 66.4%, на первые десять - 87.8%.
Поэтому 556 независимых исключений здесь, похоже, нет. Скорее, несколько повторяющихся случаев встречаются во многих объектах.
Чтобы проверить гипотезу до конца, разберу десять самых частых UUID и посмотрю, в каких структурных позициях они встречаются и потом уже приму решение, надо ли расширять эвристику.

По итогам добавил себе задачи в следующий спринт, вернусь к ним в скорее всего в сентябре - надо отвлечься на небольшую задачу.
3. nedomolkov.ivan 256 16.08.26 17:35 Сейчас в теме
(2) (2) Спасибо, что пересчитали, обычно на такие вопросы отвечают "потом посмотрю".

Раз один UUID даёт 174 вхождения, а первые десять 87,8 процента, то до разбора структурных
позиций я бы потратил пять минут на другую проверку: находятся ли эти 49 UUID вообще
в выгрузке. Не в форме, а в конфигурации целиком. Часть таких хвостов это не "мы не поняли
раскладку", а ссылка на объект, которого в дампе нет: удалённый реквизит, объект расширения,
остаток от старого обновления. Эвристику под такое расширять бесполезно, она будет ловить
пустоту.

Отсюда и к формату. Я бы разделил status на два. unknown_layout - раскладку не распознали,
парсер можно дообучить. not_found - UUID в выгрузке отсутствует, разбирать нечего. Для модели
это разные вещи: в первом случае "путь есть, мы его не показали", во втором "такого объекта
нет", и второе она имеет право отдать пользователю как ответ.

И наблюдение про сам null. Мы выгружали метаданные под чат-модель и напоролись: data_path:
null модель часто читает как "поля нет" и просто не упоминает его. Строка вместо null,
прямо в значении, работает надёжнее - тогда в ответе появляется "путь для этого поля
неизвестен". Для схемы некрасиво, зато видно.

Про санитизацию одним местом перед выдачей согласен. Добавлю только, что её надо накрывать
отдельным тестом именно на исключении: поля идут через ваш сериализатор, а traceback летит
мимо него, и утечка вылезает там.
4. MRDK80 12 16.08.26 19:16 Сейчас в теме
(3) Надо будет это проверить, а заодно подумать, как лучше обозначить неизвестный путь вместо null, ну и куда же без тестов. Результаты - в следующей статье )
nedomolkov.ivan; +1 – Ответить
5. MRDK80 12 22.09.26 12:16 Сейчас в теме
(3) написал новую статью, там на часть вопросов ответил
https://infostart.ru/1c/articles/2794715/
Для отправки сообщения требуется регистрация/авторизация