IDE + MCPРасследование сбоя и исправление данных
Найдена и устранена причина сбоя при массовом формировании реализаций по счетам — исправлены 43 счёта без договора
Коротко
При массовом формировании реализаций по счетам около 40 документов выдавали ошибку и не проводились. Агент установил причину — в 43 счетах не был заполнен договор контрагента, из-за чего срабатывал контроль прослеживаемости. Недостающие договоры были созданы, во все 43 счёта подставлен подходящий договор «С покупателем». После исправления все проведённые счета имеют заполненный договор, формирование реализаций проходит без ошибок.
Что требовалось
Бухгалтер запустил массовое формирование реализаций по счетам покупателям. Примерно на 40 документах из 400 операция прерывалась ошибкой, которая выдавалась типовым механизмом прослеживаемости. Причина была неочевидной: текст ошибки указывал на внутренний контроль программы, а не на конкретный документ. Требовалось понять, из-за чего именно валятся документы, и привести данные в порядок, чтобы реализации формировались без сбоев.
Как помог агент
Агент проанализировал ситуацию и нашёл причину: часть счетов проведена без заполненного договора контрагента, и именно на этих документах срабатывал контроль прослеживаемости.
Затем он сверил все проведённые счета и выяснил масштаб: из 418 проведённых счетов договор не заполнен в 43. Агент разобрал, откуда взялись эти счета: 20 — старые карточки, перенесённые при миграции и импорте из других систем, ещё 23 — ручной ввод двух пользователей, которые при заполнении шапки счёта не подставляли договор. Отдельно подтвердил, что данное расширение к появлению этих счетов отношения не имеет.
По каждому контрагенту агент подобрал подходящий действующий договор «С покупателем». Для 21 контрагента такой договор уже был в справочнике. Для 3 контрагентов, у которых договора не было, агент создал недостающие договоры «Без договора» по образцу действующего, чтобы все реквизиты заполнились корректно. После этого он подставил подходящий договор во все 43 счёта и проверил результат.
Дополнительно из расширения был убран ранее добавленный технический блок-«заплатка»: после наведения порядка в данных он стал не нужен, на его месте оставлено короткое понятное сообщение для пользователя на случай, если счёт снова окажется без договора.
Результат
- Проведённых счетов всего — 418, из них без договора было 43, стало 0.
- Создано 3 недостающих договора для контрагентов, у которых их не было.
- Исправлены все 43 счёта: в каждый подставлен подходящий действующий договор.
- Массовое формирование реализаций по счетам теперь проходит без ошибки прослеживаемости.
Вся работа выполнена непосредственно в рабочей базе: дополнительные обработки не загружались, ручная правка данных не потребовалась.
1. Контекст
Расширение счт_ФормированиеСчетов (БП 3.0) делает две вещи:
- по документам
счт_СоставыСчетовНаОплатумассово формируетСчетНаОплатуПокупателю+ проводит АВР (РеализацияТоваровУслугс видом операции «Услуги») на основании каждого счёта; - по уже существующим счетам за период даёт сформировать партию реализаций.
В тот же день перед началом расследования были завершены две доработки в этом же расширении:
- проставление
Счет.ВидОперации = ТоварыИУслугипри создании счёта (без этого счёт не проводится); - добавление документа
счт_СоставыСчетовНаОплатув состав плана обменаМиграцияПриложенийс авторегистрацией «Запретить» — требование сервиса Маркет42 при публикации расширения.
Эти две правки уже были опубликованы в сервисе. Третья — защитный блок «восстанавливать ДоговорКонтрагента из счёта, если БП его обнулил» — оставалась локально, в ожидании проверки на рабочих данных.
2. Обращение заказчика
«Опубликовалось. Запустили формирование реализаций — на 40 документах выдал ошибку:
ОшибкаПриВызовеМетодаКонтекста(Записать), дальше стек вПрослеживаемостьБП.Модуль(2074), строкаЕсли Не Реквизиты[0].РасчетыВУсловныхЕдиницах Тогда, иПреобразование значения к типу Булево не может быть выполнено.»
Типичный сценарий: ошибка возникает в типовом модуле, её причина неочевидна, а сама операция выполняется массово. Конкретные данные потребовалось получить самостоятельно.
3. Исследование
3.1 Декомпозиция стека и формулирование гипотезы
По стеку и тексту ошибки видно: на 2074-й строке ПрослеживаемостьБП (Если Не Реквизиты[0].РасчетыВУсловныхЕдиницах Тогда) поле РасчетыВУсловныхЕдиницах возвращает NULL. Это поле — Булево на справочнике ДоговорыКонтрагентов. NULL оно может вернуть только в одном случае: запрос Реквизиты.ДоговорКонтрагента.РасчетыВУсловныхЕдиницах разыменовывает пустую ссылку ДоговорКонтрагента.
Гипотеза: у части счетов в шапке пустой договор контрагента.
3.2 Замер масштаба — один запрос
ВЫБРАТЬ
ЕСТЬNULL(Счета.ДоговорКонтрагента.ВидДоговора, ЗНАЧЕНИЕ(...ПустаяСсылка)) КАК ВидДоговора,
ВЫБОР КОГДА Счета.ДоговорКонтрагента = ЗНАЧЕНИЕ(...ПустаяСсылка)
ТОГДА ИСТИНА ИНАЧЕ ЛОЖЬ КОНЕЦ КАК ДоговорПуст,
КОЛИЧЕСТВО(*) КАК Кол
ИЗ Документ.СчетНаОплатуПокупателю КАК Счета
ГДЕ Счета.Проведен = ИСТИНА
СГРУППИРОВАТЬ ПО ...
| Вид договора | Договор пустой | Счетов |
|---|---|---|
| С покупателем | нет | 375 |
| — (нет договора) | да | 43 |
Прочих видов договоров (С прочим, С поставщиком и т.п.) нет — только корректный «С покупателем» и пустой. Таким образом, причина — пустой ДоговорКонтрагента, а гипотеза про обнуление договора в ОбработкаЗаполнения БП (если ВидДоговора не подходит для «Услуги») в этой базе не подтверждается, поскольку других видов нет.
3.3 Проверка причастности обработки
Маркер автосоздания — строка [счт_Авто] в комментарии. Выполнена проверка:
ВЫБРАТЬ ... КОЛИЧЕСТВО(*) ...
ГДЕ Комментарий ПОДОБНО "%!_счт_Авто!_%" СПЕЦСИМВОЛ "!"
(и зеркальный запрос для отсутствия маркера)
Технический момент. Первая попытка без
СПЕЦСИМВОЛдала ложные срабатывания: 1С трактует[счт_Авто]вПОДОБНОкак символьный класс (как в MS SQL: «любой символ из набора с, ч, т, _, А, в, т, о»). Любая строка с буквой «о» или «т» попадала в выборку. Скобки были экранированы черезСПЕЦСИМВОЛ "!"— после этого выборка стала корректной. Аналогичная проблема была отмечена и в коде расширения — там используется такой же запрос (_ФормированиеСчетов.bsl:251), вынесена в отдельную задачу.
Результат: все 43 проблемных счёта созданы не данным расширением. Источники — ручной ввод (бухгалтер yrtsevanatasha, ассистент Помощник Делового Бухгалтера) или импорт из других систем (старые карточки <Не указан> без ответственного).
3.4 Подробный разбор источников
ВЫБРАТЬ Дата, Номер, Контрагент.Наименование, СуммаДокумента,
Ответственный.Наименование, Комментарий
ИЗ Документ.СчетНаОплатуПокупателю ... ГДЕ ДоговорКонтрагента = ПустаяСсылка
УПОРЯДОЧИТЬ ПО Дата
Распределение по авторам:
| Ответственный | Счетов | Период |
|---|---|---|
<Не указан> (старые миграции/импорт) |
20 | 2023-11 → 2025-04 |
yrtsevanatasha |
12 | 2025-12 → 2026-03 |
Помощник Делового Бухгалтера |
11 | 2026-03 → 2026-05 |
Таким образом, половина (20 из 43) — это ранее мигрированные карточки без ответственного. Остальные 23 относятся к двум пользователям, которые при ручном вводе шапки счёта не подставляли договор. У большинства таких контрагентов договор «С покупателем» в справочнике уже имеется — он не был подставлен в документ.
3.5 Контрагент → договор: матрица для исправления
Запросом по Справочник.ДоговорыКонтрагентов с фильтром «Владелец = X, Организация = Y, ВидДоговора = СПокупателем, не ПометкаУдаления» составлена карта:
- 21 контрагент — договор «С покупателем» уже есть. Приоритет выбора:
Основной договор>Без договора> первый по коду. - 3 контрагента (Гусева Е.О., Гусев Г.М., Зорин М.Е. ИП) — договоры отсутствуют, требуется создать.
4. Решения
4.1 Создание недостающих договоров через batch_1c и особенность формата
Первая попытка — три договора одним пакетом, СПокупателем, организация подставлена из счёта:
{
"action": "CREATE",
"type": "Справочник.ДоговорыКонтрагентов",
"data": {
"Наименование": "Без договора",
"Владелец": {"metadata_type": "Справочник.Контрагенты", "uuid": "..."},
"Организация":{"metadata_type": "Справочник.Организации", "uuid": "..."},
"ВидДоговора":{"type": "EnumRef.ВидыДоговоровКонтрагентов", "value": "СПокупателем"}
}
}
Сервер вернул status: CREATED × 3. Контрольный запрос показал, что ВидДоговора и ВалютаВзаиморасчетов в созданных договорах остались NULL — MCP принял формат {type, value} без ошибки, но фактически поле не записал. Объект создан с дефектом.
После подстановки этих некорректных договоров в 4 счёта возникли те же ошибки прослеживаемости (NULL передан в Реквизиты.ДоговорКонтрагента.РасчетыВУсловныхЕдиницах).
Правильный путь по MCP guide (1cca-public/docs/mcp-guide.md line 41):
"ВидДоговора": { "metadata_type": "Перечисление.ВидыДоговоровКонтрагентов", "uuid": "СПокупателем" }
uuid — имя предопределённого значения, либо с префиксом ref-no-props:.
Выполнить UPDATE некорректных договоров не удалось — БП заблокировал правку ключевых реквизитов «использованного» договора. Использован способ copyFrom: созданы три новых договора как копии заведомо рабочего эталона (Основной договор Беляев А.И.), с переопределением только Наименование, Владелец, Организация. Все технические поля (ВидДоговора, ВалютаВзаиморасчетов, СуммаВключаетНДС, СпособЗаполненияСтавкиНДС, ...) унаследованы автоматически.
{
"action": "CREATE",
"type": "Справочник.ДоговорыКонтрагентов",
"copyFrom": "ad9a319a-d884-11ef-a728-74d02b8fb989",
"data": {
"Наименование": "Без договора",
"Владелец": { "metadata_type": "Справочник.Контрагенты", "uuid": "..." },
"Организация":{ "metadata_type": "Справочник.Организации", "uuid": "..." }
}
}
Затем выполнен UPDATE 4 счетов с новыми UUID и DELETE_MARK старых некорректных договоров одним пакетом.
Технический момент. Ранее возникла отдельная ошибка: при первой попытке поле
Владелецбыло указано как «Контрагент» (так оно отображается в синониме палитры свойств в БП), тогда как в коде поле называетсяВладелец. MCP вернулЗначение поля "Контрагент" не заполнено или заполнено неверно— сообщение корректно, но называет поле по синониму. Имя поля уточнено черезmetadata_1c(там указано: «Владелец(Стандартный реквизит, Синоним: Контрагент)»).
Правило зафиксировано в персональной памяти агента — feedback_batch_1c_enum_format.md: для enum-полей в batch_1c всегда {metadata_type, uuid} с именем предопределённого значения, либо copyFrom от рабочего эталона, либо проверка через query_1c сразу после CREATE.
4.2 Массовое UPDATE 43 счетов через batch_1c
В Python сформирован массив операций «invoice_uuid → contract_uuid» по карте назначений из 3.5 и собран один пакет с 43 UPDATE:
{
"action": "UPDATE",
"ref": {"metadata_type": "Документ.СчетНаОплатуПокупателю", "uuid": "<инв>"},
"data": {"ДоговорКонтрагента": {"metadata_type": "Справочник.ДоговорыКонтрагентов", "uuid": "<дог>"}}
}
Сервер: mode: parallel, threads_used: 20. Все 43 — status: UPDATED. Записи в регистрах движения от счёта не зависят от ДоговорКонтрагента, поэтому перепроведение не требовалось (post: false по умолчанию).
Контрольный запрос «Счета.Проведен = ИСТИНА И ДоговорКонтрагента = ПустаяСсылка» — 0 строк.
4.3 Упрощение кода BSL
После исправления данных рассматривался вопрос о целесообразности защитного блока «восстановить договор из счёта после Заполнить, если БП его обнулило». Анализ показал, что блок предусматривал случай «договор у контрагента есть, но ВидДоговора <> СПокупателем». В этой базе такой случай отсутствует (см. 3.2). На случай его появления в будущем предусмотрена короткая проверка с информативным исключением.
Было (12 строк защиты):
РеквизитыСчета = ОбщегоНазначения.ЗначенияРеквизитовОбъекта(
СсылкаСчет, "Контрагент, ДоговорКонтрагента");
Если НЕ ЗначениеЗаполнено(Реализация.Контрагент) Тогда
Реализация.Контрагент = РеквизитыСчета.Контрагент;
КонецЕсли;
Если НЕ ЗначениеЗаполнено(Реализация.ДоговорКонтрагента) Тогда
Реализация.ДоговорКонтрагента = РеквизитыСчета.ДоговорКонтрагента;
КонецЕсли;
Если НЕ ЗначениеЗаполнено(Реализация.ДоговорКонтрагента) Тогда
ВызватьИсключение СтрШаблон(
НСтр("ru = 'В счёте %1 не заполнен договор контрагента — нельзя сформировать акт'"),
СсылкаСчет);
КонецЕсли;
Стало (5 строк):
// Без договора в шапке проведение РТУ валится в ПрослеживаемостиБП на NULL-преобразовании.
// Сообщаем пользователю явно, что счёт нужно поправить.
Если НЕ ЗначениеЗаполнено(Реализация.ДоговорКонтрагента) Тогда
ВызватьИсключение СтрШаблон(
НСтр("ru = 'В счёте %1 не заполнен договор контрагента — нельзя сформировать акт'"),
СсылкаСчет);
КонецЕсли;
Изменение применено в обеих процедурах — СформироватьИПровестиАкт и СформироватьИПровестиРеализацию. Расширение пересобрано через v8unpack -B.
4.4 Записанные правила работы
В персональную память агента (host-scope) добавлено правило: запись в 1С через MCP выполняется только через batch_1c, не через invoke_1c. Использование invoke_1c для записи является обходным путём и нарушает аудит и транзакционность. Это правило сформулировано по ходу работы: первоначальный вариант «выполнить всё через invoke_1c execute с собственным BSL» был скорректирован пользователем.
5. Инструменты
5.1 Использовали в этом кейсе
| Инструмент | Что делали |
|---|---|
query_1c |
Замер масштаба, фильтр по виду договора и пустоте, разбор по авторам, карта «контрагент → подходящий договор», контрольные верификации |
metadata_1c |
Уточнение состава реквизитов Документ.СчетНаОплатуПокупателю (поле Ответственный) и Справочник.ДоговорыКонтрагентов (синоним Владелец → «Контрагент») перед batch_1c |
batch_1c |
CREATE 3 договоров «Без договора» (parallel 3 потока) + UPDATE 43 счетов с подстановкой ДоговорКонтрагента (parallel 20 потоков). Один HTTP-вызов на пакет, замена внешней обработке |
session_info_1c |
Проверка контекста и прав сессии перед началом — yrtsevanatasha, полные права |
Локально, совместно с MCP:
- v8unpack — пересборка
.cfeпосле правки BSL; - Python — формирование массива операций для
batch_1cиз карты соответствий «42 счёт → 1 договор».
5.2 Инструменты, не задействованные в данном кейсе
| Инструмент / компонент | Что даёт | Когда пригодился бы в похожей задаче |
|---|---|---|
invoke_1c |
Вызов экспортной функции типовой конфигурации/модуля расширения | Не для записи (для записи — batch_1c). Применяется для вызова готовой серверной функции: пересчёт таблицы, перепроведение регистратора, запуск регламентного задания |
run_task / task_status / task_stop |
Длительные асинхронные задачи с поллингом | Перепроведение тысяч документов после правки шапок; восстановление последовательности; фоновая очистка движений |
get_skill |
Поиск переиспользуемого скилла под задачу (Skill Server + pgvector) | При наличии скилла «массовая подстановка договоров в счета по контрагенту» — применение по шаблону, без проектирования карты с нуля |
skill_report |
Отчёт о применении скилла в библиотеку | Сохранение факта «в этой базе исправлены 43 счёта, с указанием метрик» в общую базу скиллов |
invalidate_knowledge |
Сброс семантического кэша знаний агента | После добавления счт_СоставыСчетовНаОплату в план обмена МиграцияПриложений — для перечитывания агентом актуального состава плана |
get_run_history |
История запусков и операций агента в этой базе | Аудит «кто и когда исправлял эти счета»; SLA-отчёт заказчику |
web_search |
Поиск в интернете через Tavily под токеном клиента | Если стек ошибки не удаётся декодировать напрямую — поиск в ИТС/форумах схожих случаев ПрослеживаемостьБП + NULL |
| Компонент продукта | Что даёт | Когда применим |
|---|---|---|
ai_ПанельАгента (нативная BSL-панель) |
Бухгалтер взаимодействует с агентом непосредственно в 1С | Пользователь самостоятельно запускает диагностику счетов и исправления в привычной программе, без отправки скриншотов разработчику |
| Skill Server | Каталог переиспользуемых скиллов | Накопление сценариев «диагностика пустых договоров», «массовая подстановка по карте», «откат массовой правки» |
| Identity Server | Multi-tenant с per-client scope | Сервисная компания обслуживает 10+ ИП с одного контура, у каждого изолированные права на свою базу |
| Audit-trail runtime | Все вызовы инструментов агентом фиксируются в журнал | На каждый из 43 UPDATE сохраняется запись в аудите с привязкой к токену клиента — доступна для предъявления в спорной ситуации |
6. Результаты
| Метрика | Значение |
|---|---|
| Проведённых счетов всего | 418 |
Из них с пустым ДоговорКонтрагента до |
43 |
Из них с пустым ДоговорКонтрагента после |
0 |
| Создано новых договоров «Без договора» | 3 (через copyFrom — после неудачной первой попытки с {type, value}) |
| Обновлено счетов | 43 + 4 (перепривязка после пересоздания договоров) |
Из них созданных расширением (с маркером [счт_Авто]) |
0 (все 43 — ручной ввод/импорт) |
Пакетов batch_1c (CREATE / UPDATE / DELETE_MARK) |
5 |
| Параллельность сервера 1С на пакет | до 20 потоков |
| EPF загружено в рабочую базу | 0 |
| Визитов в Конфигуратор для правки данных | 0 |
| Удалено строк защитного кода из BSL | 12 → 5 (в каждой из двух процедур) |
| Полезных правил, записанных в персональную память агента | 2 («запись через batch_1c», «формат EnumRef в batch_1c») |
7. Что это даёт пользователю MCP ai-agent-1c
Один сценарий объединил три типа работы в рамках одной сессии:
- Диагностика типовой ошибки. Стек из
ПрослеживаемостьБП.Модуль(2074)декодирован: определена семантика поля (Булевона договоре,NULLтолько при разыменовании пустой ссылки), гипотеза сформулирована и подтверждена одним запросом. Безai-agent-1cпотребовалась бы последовательность «разработчик → удалённый доступ → SQL-консоль на стороне 1С → ручная выгрузка → анализ». - Исправление данных через MCP без внешних обработок. 3 создания и 43 правки в двух
batch_1c-пакетах. Не потребовалось разрабатыватьзм_ОчисткаДоговоров.epf, согласовывать с администратором рабочей базы, инструктировать бухгалтера. Цикл сводится к: запрос → подтверждение списка пользователем →batch_1c→ верификация. - Упрощение кода. После исправления данных установлено, что защитный блок в коде был ответом на гипотезу, не подтвердившуюся в этой базе. Удалены 7 строк, оставлены 5 строк информативного исключения для краевых случаев. После расследования кодовая база стала проще.
Отдельно отметим второй пункт: разовое массовое исправление данных — типовая работа, под которую ранее разрабатывалась и устанавливалась в базу EPF. Связка query_1c → batch_1c закрывает этот класс задач.
Приложения
A. Файлы кейса
| Файл | Назначение |
|---|---|
1cdev/ОбработкаФормированияСчетов/счт_ФормированиеСчетов.cfe |
Расширение после упрощения кода |
1cdev/ОбработкаФормированияСчетов/счт_ОбработкаФормированияСчетов/ФормаОбработки/_ФормированиеСчетов.bsl |
Процедура СформироватьИПровестиАкт — короткая проверка вместо 12-строчного блока |
1cdev/ОбработкаФормированияСчетов/счт_ФормированиеРеализацийПоСчетам/ФормаОбработки/_ФормированиеРеализаций.bsl |
Процедура СформироватьИПровестиРеализацию — то же изменение |
~/.claude/projects/-home-rdp-Projects-1cdev/memory/feedback_mcp_dbuh_write.md |
Правило «запись через batch_1c, не invoke_1c» |
B. Карта проблемы
43 счёта с пустым ДоговорКонтрагента
(наследие ручного ввода / импорта — НЕ наша обработка)
│
▼
Реализация.Заполнить(Счёт) → пустой договор в РТУ
│
▼
ПрослеживаемостьБП(2074):
Если Не Реквизиты[0].РасчетыВУсловныхЕдиницах Тогда
(NULL ─ нельзя в Булево)
│
▼
ошибка проведения на 40 счетах
│
┌──────────────────────┴──────────────────────┐
│ │
Чистка данных за пользователей Уборка кода
(batch_1c CREATE + UPDATE) (минус 12 строк защиты)
│ │
├─ 3 договора «Без договора» ├─ Оставили 5 строк
│ созданы для безконтрактных контрагентов │ осмысленного исключения
├─ 43 счёта обновлены подходящим │ на будущее
│ договором «С покупателем» │
└─ 0 счетов без договора └─ Расширение пересобрано