Разделы документации
Мапперы: входящие и исходящие
Содержание
Почему это важно. Классификатор решает, какого рода инцидент это событие; маппер решает, как он выглядит. Входящий маппер превращает сырой вендорский JSON, который попадает в SOARForge, в поля кейса, которые читают ваши аналитики — заголовок, severity, статус, адрес отправителя, целевой хост — сохраняя при этом нетронутый оригинал для аудита. Сделайте маппинг правильно — и аналитики видят чистый, единообразный кейс независимо от того, из какого из дюжины источников он пришёл; сделайте неправильно — и они таращатся на кейс с пустым заголовком и стеной неподписанных атрибутов.
Эта глава покрывает два направления маппера, когда и как именно входящий маппер отрабатывает во время ingest, полный редактор маппинга, грамматику путей и операторов, которую понимает маппер, как протестировать маппер сквозь и где на самом деле используются исходящие мапперы.
4.1. Концепция: два направления, одна модель полей
#Маппер — это именованный, переиспользуемый объект, привязанный к бренду интеграции (source key коннектора) и направлению:
- Входящий маппер — отрабатывает в момент ingest. Вход — сырой JSON события; выход — набор значений полей кейса. Это мост между схемой вендора и моделью кейса SOARForge.
- Исходящий маппер — отрабатывает, когда изменение кейса зеркалится обратно в систему-источник. Вход — поля кейса; выход — payload, сформированный под вендора. Исходящие мапперы выполняются только для инстансов коннекторов с включённым зеркалированием (см. §4.12).
Куда пишет входящий маппер. Понимание модели хранения — ключ к грамотному использованию мапперов. У созданного кейса четыре дома данных, и входящий маппер решает, что куда идёт:
| Хранилище кейса | Что сюда попадает | Задаётся |
|---|---|---|
| Встроенные колонки кейса (title, description, severity, status, tags, occurred, …) | Встроенные цели маппера | Правилами, целящими в name, details, severity, status, tags, occurred, category, owner, phase, … |
custom_fields |
Каждая кастомная (не встроенная) цель, которую сопоставил маппер | Правилами, целящими в machine-имя кастомного поля, напр. emailfrom |
raw_json |
Неизменяемый исходный payload события | Никогда не маппится — хранится дословно, всегда |
labels |
Каждый сырой атрибут события, который маппер не сопоставил | Автоматически — см. ниже |
Неизменяемый оригинал хранится всегда.
raw_json— это нетронутое событие, каким оно прибыло; маппер никогда его не переписывает. Всё, что маппер явно не сопоставляет, тоже не теряется — писатель ingest материализует каждый несопоставленный сырой атрибут в метку ({ type: "<path>", value }), так что ни одно поле молча не исчезает. Несопоставленные данные идут в labels, никогда вcustom_fields— это пространство имён зарезервировано для полей, которые маппер сопоставил намеренно.
4.2. Когда запускается входящий маппер
#Входящий маппер — это один этап конвейера ingest. Алерты входят через POST /ingest, ставятся в очередь на RabbitMQ, и воркер ingest обрабатывает каждый
внутри одной транзакции базы данных. Порядок фиксирован:
- Построить конверт — воркер нормализует payload в канонический конверт:
source,sourceInstance,sourceRef,payload(сырое событие) и производные скаляры (name,details,occurred). - Правила pre-processing — опциональные правила, которые могут отбросить или подправить событие.
- Классифицировать — классификатор, привязанный к инстансу коннектора, отрабатывает первым и выбирает тип инцидента (или fallback incident type инстанса).
- Смаппить — затем отрабатывает входящий маппер, привязанный к тому же инстансу, ограниченный тем типом инцидента, который только что выбрал классификатор.
- Спроецировать и записать — вывод маппера проецируется в запись кейса и
записывается: встроенные — в колонки кейса, кастомные цели — в
custom_fields, оригинал — вraw_json, несопоставленные атрибуты — вlabels.
Сначала классификатор, затем маппер для выбранного типа. Решение классификатора выбирает, какие правила маппера применяются. Вот почему у маппера есть и common-правила (гоняются для каждого типа инцидента), и specific-правила (гоняются, только когда кейс одного типа инцидента) — см. §4.4.
Как выбирается маппер — приоритет. Глобального маппера по умолчанию нет. Выбор целиком привязан к инстансу:
- Каждый инстанс коннектора (конфигурация, которую вы задаёте в Settings →
Integrations → Connectors → Advanced Settings → Incoming Mapper) держит
incomingMapperId. Это маппер, который воркер ingest гоняет для событий с этого инстанса. - Если у разрешённого инстанса есть привязанный маппер с хотя бы одним правилом, воркер гоняет его. Иначе он откатывается к проекции только по конверту — задаются лишь встроенные из конверта (title, description, occurred), а каждый листовой атрибут становится меткой. Ни одно правило никогда не «отрабатывает наполовину».
Привязывайте маппер на инстансе. Маппер, существующий в реестре, сам по себе ничего не делает. Он участвует в ingest, только когда инстанс коннектора направляет свою настройку Incoming Mapper на него. Редактор маппинга может создать и сохранить эту привязку за вас, когда вы открываете его из инстанса коннектора (§4.4).
4.3. Где мапперы в интерфейсе
#Маршрут: /admin/incident-types (Objects Setup → Incident Types & Pipelines,
группа Classification) · Права: incident_types.view,
incident_types.manage
К мапперам добираются с двух взаимодополняющих поверхностей:
- Реестр объектов маппинга — единая таблица, перечисляющая классификаторы и оба направления мапперов. Используйте её, чтобы просматривать, клонировать, удалять и открывать любой маппер, а также создавать новые. Разобрано в §4.9.
- Incoming Mapping Editor — живой, управляемый инстансом визуальный редактор, где вы фактически собираете входящий маппер по реальным данным событий. Разобран далее.
Открытие входящего маппера из реестра ведёт в визуальный редактор. Открытие исходящего маппера открывает более простой диалог таблицы правил (тот же диалог, что вы используете для его создания) — у исходящих мапперов нет живого JSON-дерева, потому что они гоняются по полям кейса, а не по входящим событиям.
4.4. Редактор входящего маппинга
#Маршрут: /admin/incident-types?tab=classification&classificationTab=incident-mapper
· Права: incident_types.view, incident_types.manage
Почему это важно. Именно здесь фактически происходит маппинг. Он кладёт реальный JSON события с одной стороны и поля кейса с другой и позволяет соединять их кликом или перетаскиванием — затем показывает точное значение, которое получило бы каждое поле, вычисленное тем же движком, что гоняется в момент ingest. Что вы видите в превью — то и получаете.
Редактор — это двухпанельное рабочее пространство под управляющим заголовком.
Элементы заголовка
#| Элемент | Назначение |
|---|---|
| Mapper name | Имя, под которым сохраняется объект-маппер. |
| Save mapper | Сохранить маппер. Если вы открыли редактор из инстанса коннектора, сохранение также привязывает маппер к этому инстансу. |
| Branch (тип инцидента) | Какому типу инцидента принадлежат specific-правила на экране. |
| Scope (Common / Specific) | Редактируете ли вы правила, гоняющиеся для каждого типа (Common), или только для выбранного типа инцидента (Specific). |
| Connector / Instance | Инстанс коннектора, из которого тянуть образцы событий и (опционально) к которому привязать маппер. |
| Data (Pull / Schema / Upload) | Откуда берутся события превью: Pull живых событий из инстанса, генерировать Schema/образец события или Upload (вставить) свой JSON. |
| Pull (+ limit / sort) | Забрать события превью; для живых pull выберите сколько и newest/oldest first. |
Под элементами управления кнопки веток показывают число common-правил и число правил каждого релевантного типа инцидента; ветка, которую классификатор может произвести, но у которой пока нет правил, подсвечена, чтобы вы замечали пробелы покрытия. Сворачиваемая панель details резюмирует активную ветку, привязанный классификатор, источник превью, поля конверта интеграции и живое превью того, какие сырые атрибуты пока несопоставлены (и какие станут метками).
Левая панель — список целевых полей
#Левая панель перечисляет каждое поле, в которое можно маппить, взятое из двух источников:
- Встроенные цели — канонические поля кейса, которые распознаёт маппер:
name(title),details(description),severity,status,tags,occurred,owner,phase,category,dueDate,closeNotes,closeReason,playbookId. - Поля инцидента — кастомные и системные поля инцидента, обнаруженные для бренда коннектора.
Список можно фильтровать (поле поиска), показывать только mapped или
unmapped поля и добавлять ad-hoc кастомную цель, набрав её machine-имя. Два
имени отклоняются намеренно: всё, что начинается с case. (устаревшая форма), и
имена, принадлежащие конверту, — source / sourceInstance / sourceRef (ими
владеет интеграция, а не маппер).
Кнопка Auto-map просит бэкенд оценить текущее событие против целевых полей и заполняет высоко-уверенные предложения путей, не перезаписывая маппинги, которые вы задали вручную.
Правая панель — JSON события
#Правая панель показывает текущее выбранное событие превью как цветокодированное дерево (значения окрашены по типу), сырое JSON-представление и вкладку guide с разобранными примерами путей. Поле поиска подсвечивает совпадающие ключи. Массивы показывают короткий образец своего содержимого, чтобы вы видели, что собираетесь маппить.
Маппинг поля: построчная строка и мастер
#Каждое целевое поле — это строка. Чтобы его смаппить:
- Кликните Choose data path на строке (или кнопку
{}), затем кликните нужное значение в JSON-дереве — или перетащите лист из дерева на строку. Выбранный путь заполняет поле источника строки. - Строка Result: под строкой показывает значение, которое производит этот путь, после фильтров и трансформеров, вычисленное живой симуляцией превью.
Кнопка … (Filters & transformers) на сопоставленной строке открывает
встроенный мастер, меню из трёх строк:
| Строка мастера | Что настраивает |
|---|---|
| Get | Путь источника (пере-открывает выбор пути). |
| Where | Цепочку фильтров, применяемую к забранному значению (см. §4.6). |
| Transformers | Цепочку трансформеров, применяемую после фильтров. |
Иконка корзины на строке Get очищает всё правило (путь, фильтры, трансформеры и любые расширенные настройки). Добавление фильтра или трансформера открывает редактор цепочки: каждый шаг — пронумерованная карточка с выпадающим списком выбора оператора, описанием, динамически отрисованными вводами аргументов (текст, число, чекбокс или JSON-текстовая область в зависимости от оператора) и кнопкой удаления. Add filter / Add transformer дописывает шаг в конец цепочки; порядок карточек — порядок выполнения.
Переупорядочивание цепочки. Шаги выполняются сверху вниз в показанном порядке. Встроенный редактор позволяет добавить шаг (в конец), сменить оператор шага на месте и удалить шаг. Чтобы переупорядочить, удалите и пере-добавьте в нужном порядке.
Если тип сопоставленного значения источника не совпадает с типом целевого поля, строка показывает предупреждение с конкретным предложением исправления (например, добавить трансформер Join with comma или First item, чтобы подать текстовому полю значение из массива).
4.5. Синтаксис путей
#Маппер резолвит путь источника относительно контекста события небольшой, предсказуемой грамматикой — это не общий язык запросов.
- Точечная нотация.
payload.sender.emailAddress.addressидёт по вложенным объектам ключ за ключом. - Префикс
payload.. Поля события живут подpayload.*. Редактор добавляет префикс автоматически, когда вы выбираете путь из дерева. Горстка скаляров конверта адресуется в корне вместо этого:source,sourceInstance,sourceRef,name,details,occurred. - Числовой индекс массива. Числовой ключ индексирует массив:
payload.toRecipients.0.emailAddress.addressберёт первого получателя. - Проекция массива. Нечисловой ключ, применённый к массиву, проецируется по
каждому элементу и собирает результаты:
payload.toRecipients.emailAddress.addressвозвращает адрес каждого получателя как массив (undefined-элементы отбрасываются).
Это вся грамматика. Нет wildcard (*), нет [*]-слайса и нет
выражения/интерполяции внутри пути источника. Логика формования значений —
включая выражения в стиле DT — живёт в цепочке трансформеров, а не в пути
(трансформер DT резолвит выражение относительно уже забранного значения; он не
часть резолвинга путей).
4.6. Фильтры (Where) и трансформеры
#Каждое правило маппинга прогоняет забранное значение через фиксированный конвейер:
путь источника → Where (фильтры) → значение по умолчанию (если пусто) → Трансформеры → запись в цель
- Where / фильтры отрабатывают первыми. Они урезают значение — отбрасывают пустые элементы, оставляют уникальные или первые элементы или оставляют только те элементы массива, что совпадают с условием. Если после фильтрации значение пусто, подставляется значение по умолчанию правила (если задано).
- Трансформеры отрабатывают последними. Они переформовывают значение — обрезают пробелы, удаляют HTML, меняют регистр, разбивают/склеивают, форматируют даты, сопоставляют одну строку другой, извлекают индикаторы и многое другое.
Аргументы операторов. Операторы, которым нужны аргументы, экспонируют их в
мастере как типизированные вводы. Обязательные аргументы помечены *. Аргумент
regex валидируется при сохранении — невалидный или небезопасный (с катастрофическим
бэктрекингом) паттерн отклоняется заранее, а не падает молча в момент ingest.
Расширенное поведение на уровне правила (несётся на правиле, задаётся через диалог реестра):
| Настройка | Эффект |
|---|---|
| Overwrite policy | always (по умолчанию), if_empty (только когда цель ещё пуста) или never (оставить существующее значение в покое). |
| Required | Если правило не производит значения, ingest фиксирует предупреждение (кейс всё равно создаётся). |
| On error | Если фильтр/трансформер бросает: skip_field (по умолчанию — оставить поле незаданным), use_raw_value, set_default или fail_rule. |
Каталог операторов велик — 138 трансформеров (семейства string, array, object,
date/time, math, encoding и security/IOC) плюс 10 фильтров (compact,
drop_empty, unique, first, where_exists, where_equals, filter,
If-Then-Else, RegexExtractAll, SetByIndex) — 148 записей реестра всего.
Полный справочник — каждый оператор, его аргументы и его поведение — живёт в
файле-спутнике
mapper-operators-reference.ru.md; разобранный
пример в §4.11 использует лишь горстку из них.
Один и тот же движок повсюду. Фильтры и трансформеры оцениваются одним общим движком, используемым воркером ingest, превью редактора и инструментами теста. «Приближения превью» нет — превью и есть рантайм.
4.7. Типы полей и приведение
#Маппер не заставляет сопоставленное значение принять тип цели; он пишет то, что произвёл конвейер, а проектор кейса нормализует встроенные поля:
- Severity нормализуется к одному из
critical/high/medium/low/informational(без учёта регистра, пробелы в подчёркивания;info→informational). Числовая severity — число или числовая строка — отображается на шкалу по нижней границе диапазона:0/0.5→informational,1→low,2→medium,3→high,≥ 4→critical(значения выше шкалы обрезаются; дробные округляются вниз, так что2.7→medium). Только значение, которое не является ни распознанным термином, ни неотрицательным конечным числом, откатывается к severity по умолчанию типа инцидента. - Status нормализуется к одному из
new/open/in_progress/pending_approval/resolved/closed, иначе откатывается кnew. Числовой статус не приводится — единой межвендорной числовой конвенции статусов нет, поэтому числовой статус откатывается, а не угадывается. Отобразите его явно трансформером маппера (MapPattern) в принятый термин. - Tags принимают массив или строку через запятую; каждый становится обрезанным тегом.
- Title ограничен 500 символами. Если на текстовое поле (title/description)
маппится не-строковое значение, оно сериализуется в JSON-строку, а не
отбрасывается — вот почему маппинг целого объекта на
nameпроизводит JSON-кляксу как заголовок. Маппьте скалярный лист вместо этого.
Для кастомных полей приведения по схеме нет — значение хранится, как произведено.
Вот почему важно предупреждение о несовпадении типа в редакторе: оно
сигнализирует, например, о массиве, смапленном на одно-значное поле, чтобы вы могли
вставить трансформер joinComma или first до сохранения.
4.8. Диалог правил маппера (реестр / исходящий)
#Создание исходящего маппера или редактирование любого маппера из таблицы реестра без JSON-дерева использует диалог таблицы правил. Он экспонирует поля, которые визуальный редактор прячет за своим мастером, и это поверхность, где значения по умолчанию и сырые цепочки трансформеров вводятся напрямую:
| Поле диалога | Назначение |
|---|---|
| Mapper Name | Имя маппера. |
| Integration Brand | Source key коннектора, для которого этот маппер. |
| Schema Source | Как маппер обнаружил свою форму: Instance / Schema / JSON sample. |
| Content Source | System / Marketplace / Custom (новые мапперы по умолчанию Custom). |
| System denylist | Имена атрибутов, никогда не материализуемые в метки автоматически (по умолчанию включают dbot_status, close_notes, …). |
| Enabled | Участвует ли маппер. |
| Common Mapping rules | Правила, гоняющиеся для каждого типа инцидента. Каждая строка: Target field, JSON path, Transformers (как JSON-вызовы операторов), Default value, Rule enabled. |
| Specific Mapping rules | То же плюс Incident Type — правило гоняется только для этого типа. |
Два способа добраться до одного объекта. Визуальный редактор и этот диалог редактируют один и тот же подлежащий маппер; визуальный редактор — более богатый способ собрать входящий маппер по живым данным, диалог — компактный способ просмотреть или отредактировать правила вручную (и единственный редактор для исходящих мапперов).
4.9. Управление мапперами
#Таблица реестра объектов маппинга перечисляет классификаторы и оба направления мапперов вместе. Колонки:
| Колонка | Значение |
|---|---|
| Name | Кликните, чтобы открыть объект в его редакторе. |
| Type | Classifier, Mapper (incoming) или Mapper (outgoing). |
| Instances | Сколько инстансов коннекторов сейчас привязывают этот объект. |
| Description | Сводка (для маппера: направление, число common-правил, число specific-типов). |
| System | True, когда объект принадлежит system/marketplace (а не Custom). |
Действия панели инструментов: Edit, Clone, Delete и меню New (New Incident Classifier / New Incoming Mapper / New Outgoing Mapper). Поле поиска фильтрует по имени, бренду или описанию.
Clone / duplicate. Clone копирует выбранный маппер в новый редактируемый
объект: к имени добавляется суффикс (copy) ((copy 2), (copy 3), … при
необходимости), правила копируются, а Content Source копии сбрасывается на
Custom, так что маппер, принадлежащий system или marketplace, становится свободно
редактируемым. Clone — рекомендуемый способ адаптировать поставленный маппер.
Мапперы, поставленные паком. Content-паки из Marketplace могут поставлять мапперы; они приходят помеченными как принадлежащие system/marketplace (Content Source не Custom), и реестр помечает их System: True. Предпочитайте Clone редактированию pack-owned маппера на месте — последующее обновление пака может перезаписать маппер, которым он владеет, отбросив правки на месте, тогда как ваш Custom-клон ваш и останется.
Удаление маппера. Маппер, который всё ещё привязан к одному или нескольким инстансам коннекторов, удалить нельзя — платформа отказывает с ошибкой конфликта. Сначала отвяжите его от каждого инстанса (очистите настройку Incoming/Outgoing Mapper инстанса).
4.10. Сквозное тестирование маппера
#У вас есть две возможности проверки, и они проверяют разное.
1. Живое превью редактора. По мере сборки редактор непрерывно симулирует текущий собираемый маппер против выбранного события превью и показывает, по полям, точное значение, которое он произвёл бы (строка Result:), сырые атрибуты, всё ещё несопоставленные, и какие из них станут метками. Поскольку превью гоняет тот же движок, что и ingest, значение, появляющееся здесь, — это значение, которое получил бы реальный кейс. Вытяните несколько живых событий (или вставьте репрезентативное) и пройдитесь по ним, чтобы подтвердить, что маппер держится поперёк вариаций.
2. Вкладка Test. Objects Setup → Incident Types & Pipelines → Classification →
Test (/admin/incident-types?tab=classification&classificationTab=test) гоняет
весь фронт конвейера вместе: выберите коннектор и инстанс, вставьте образец payload
ingest ({ source, sourceInstance, payload }) и Run Test. Результат показывает:
- Classification — какой тип инцидента победил и по какому правилу (или fallback-тип), с построчной трассировкой условий.
- Mapped Fields Preview — вывод маппера для разрешённого типа инцидента, поле за полем.
Это самый быстрый способ подтвердить, что классификатор и его маппер согласны — что тип, который выбирает классификатор, — это тип, чьи specific-правила вы ожидаете запустить.
Проверяйте, прежде чем полагаться. Тестируйте на реальных (или реалистичных) событиях, а не на идеализированном. Вендоры варьируют форму поля между видами алертов — адрес, который иногда строка, а иногда объект, severity, которое иногда числовое — и только реальный образец это вскрывает.
4.11. Разобранный пример
#Допустим, коннектор почтового ящика Microsoft 365 доставляет отчёты о фишинге, и вы хотите чистый кейс Phishing. Репрезентативный payload события:
{
"source": "o365",
"sourceInstance": "o365-soc-mailbox",
"payload": {
"subject": " Re: Invoice overdue — please verify ",
"severity": "High",
"categories": ["phishing", "", "external"],
"body": { "content": "<p>Click <a href='http://bad.example'>here</a></p>" },
"sender": { "emailAddress": { "address": "Billing@BAD.example", "name": "Billing" } },
"toRecipients": [
{ "emailAddress": { "address": "alice@corp.local", "name": "Alice" } },
{ "emailAddress": { "address": "bob@corp.local", "name": "Bob" } }
]
}
}
Входящий маппер из шести правил (scope показан по строкам; все используют overwrite
policy always):
| # | Путь источника | Фильтры (Where) | Трансформеры | Целевое поле |
|---|---|---|---|---|
| 1 | payload.subject |
— | trim |
name (заголовок кейса) |
| 2 | payload.severity |
— | toLowerCase |
severity |
| 3 | payload.body.content |
— | htmlToText |
details (описание) |
| 4 | payload.sender.emailAddress.address |
— | toLowerCase |
emailfrom (custom) |
| 5 | payload.toRecipients.emailAddress.address |
— | joinComma |
emailto (custom) |
| 6 | payload.categories |
compact |
— | tags |
Что производит каждое правило:
- Title →
Re: Invoice overdue — please verify(пробелы обрезаны). - Severity →
high(в нижний регистр, затем нормализовано к enum). - Description → HTML, ободранный до читаемого текста.
- emailfrom (custom) →
billing@bad.example, хранится вcustom_fields. - emailto (custom) →
alice@corp.local, bob@corp.local— проекция массива собирает оба адреса получателей,joinCommaскладывает их в одну строку. - Tags →
["phishing", "external"]—compactотбрасывает пустую строку.
Всё, что шесть правил не сопоставили (например payload.sender.name),
становится меткой на кейсе, а весь payload выше сохраняется дословно в raw_json.
Каждый использованный здесь оператор (trim, toLowerCase, htmlToText,
joinComma, compact) существует в каталоге операторов; об остальных см.
mapper-operators-reference.ru.md и работу по
операторному конвейеру в главе 5.
4.12. Исходящие мапперы
#Исходящий маппер — зеркальное отражение: он отрабатывает, когда изменение кейса
зеркалится обратно в систему-источник. Он привязан к outgoingMapperId
инстанса коннектора и выполняется только для инстансов, чей режим зеркалирования —
outgoing или both. Когда кейс создаётся или меняется зеркалируемое поле,
платформа ставит в очередь задачу зеркалирования; сервис коннектора загружает
привязанный исходящий маппер, проверяет его направление, гоняет его правила по полям
кейса (тот же движок правил, что и у входящего) и передаёт получившийся payload
интеграции для проталкивания наверх. Действие preview mirroring позволяет
увидеть исходящий payload для конкретного кейса до включения потока.
Исходящие мапперы авторятся в диалоге таблицы правил (§4.8) — JSON-дерева нет, потому что «источник» — это кейс, а не входящее событие. Выражения путей, фильтры, трансформеры, значения по умолчанию и политики на уровне правил работают ровно так же, как во входящем.
Гоняется только то, что использует зеркалирование. Исходящий маппер, не привязанный к инстансу с включённым зеркалированием, инертен — он хранится и редактируется, но никакой рантайм-путь его не выполняет, пока инстанс не начнёт зеркалить через него.
Распространённые ошибки
#- Маппер сохранён, но в момент ingest ничего не меняется. Маппер гоняется,
только когда инстанс коннектора его привязывает (
Incoming Mapperв advanced settings инстанса). Непривязанные мапперы ничего не делают; инстанс откатывается к проекции только по конверту. - Обязательное поле выходит пустым. Классификатор выбирает тип инцидента, и только specific-правила этого типа гоняются рядом с common-правилами. Если поле смаплено только в specific-ветке для другого типа, оно не заполнится. Кладите type-агностичные маппинги в Common.
- Путь резолвится в ничто. Следите за неверным префиксом (поля события под
payload.*), массивом там, где вы ждали объект (используйте числовой индекс или положитесь на проекцию), или полем, которое присутствует в одном виде алерта и отсутствует в другом. Строка Result: редактора и панель несопоставленных полей показывают промахи немедленно. - Заголовок — JSON-клякса. Не-строковое значение, смапленное на
name/details, сериализуется в JSON, а не отбрасывается. Маппьте скалярный лист или добавьте трансформер (напр.first,joinComma), чтобы свести массив/объект к тексту. - Severity или status «игнорируются». Эти встроенные нормализуются к
фиксированному enum. Severity также принимает числовую шкалу
(
0→informational …≥4→critical, §4.7); status числа не приводит. Значение вне набора (или числовой статус) откатывается к умолчанию — маппьте вендорское значение через трансформерMapPattern/SetIfEmpty, чтобы перевести его в принимаемый термин. - Редактирование pack-owned маппера. Правки на месте system/marketplace-маппера (System: True) могут быть перезаписаны более поздним обновлением пака. Сначала Clone его — копия Custom и её безопасно менять.
- Маппер не удаляется. Он всё ещё привязан к инстансу коннектора. Очистите настройку маппера инстанса везде, где он используется, затем удаляйте.
- Превью выглядело хорошо, но прод отличается. Проверяйте на реальных, разнообразных событиях. Движок превью идентичен рантайму, так что расхождение почти всегда означает, что живое событие отличается по форме от вашего образца.