Перейти к основному содержимому

Телеметрия

MailCopilot может отправлять небольшое количество диагностических данных и сведений об использовании — но только после того, как вы активно на это согласитесь. В них нет содержимого вашей почты, но есть случайный идентификатор этой установки, поэтому полностью анонимными они не являются: что именно этот идентификатор позволяет и не позволяет узнать, см. в разделе Идентификатор установки ниже. На этой странице описано ровно то, что собирается, и — что не менее важно — то, что не собирается никогда.

Согласие при первом запуске

При первом запуске MailCopilot, ещё до открытия мастера настройки аккаунта, вы видите экран согласия с заголовком Отправлять диагностические данные?. Он перечисляет, что будет отправляться, если вы разрешите, и что не отправляется никогда, и предлагает две одинаковые по размеру кнопки: Разрешить и Не разрешать. Ни одна из кнопок не выделена и не выбрана заранее, и нет никакого предустановленного флажка — вам нужно сделать активный выбор.

Из этого следует несколько вещей:

  • До вашего ответа ничего не собирается, а не только не отправляется. Счётчики и буферы диагностики и использования не открываются, пока согласие не получено, — MailCopilot не копит данные тихо про запас, чтобы отправить их разом после разрешения. Всё, что произошло до вашего ответа, просто пропадает; в момент, когда вы разрешите отправку, отсчёт начинается заново именно с этого момента (например, замер длительности сессии начинает считать с момента согласия, а не с запуска приложения).
  • Закрытие экрана или нажатие Escape равносильно ответу «Не разрешать». Закрыть экран так, чтобы согласие оказалось дано, невозможно.
  • Ваше решение запоминается вместе с версией этого перечня. MailCopilot покажет экран повторно только если список собираемых данных действительно расширится — появится новая категория данных, новый получатель или более широкий охват, чем раньше. Обычные обновления приложения, правки формулировок и исправления ошибок никогда не вызывают повторный запрос.
  • Если вы уже отключили диагностику в Настройках → О программе до появления этого экрана, этот отказ учитывается, и вопрос вам больше не задаётся. Всем остальным диагностика автоматически отключается, и вопрос задаётся один раз при следующем запуске.
  • Вы можете изменить решение в любой момент в Настройках → О программе. Пока вы не ответили на первоначальный вопрос, переключатель там показан выключенным и заблокированным, с пояснением, что он вступит в силу только после того, как вы ответите на экране согласия.

Что мы отправляем

Если вы разрешите, MailCopilot отправляет:

  • Ошибки и сбои — тип ошибки и стек вызовов, показывающий, в каком месте кода это произошло. Некоторые пути сбоев уже проходят через закрытый набор структурных полей, который полностью исключает сторонний серверный текст — например, когда не удаётся сохранить копию отправленного письма в папку «Отправленные», диагностика несёт роль папки (sent, но никогда её название), солёный SHA-256-хеш идентификатора письма, усечённый до 12 шестнадцатеричных знаков (но никогда сам идентификатор — это псевдонимная метка, а не анонимизация: тот, у кого есть предполагаемый идентификатор письма, может подтвердить совпадение, пересчитав хеш), длину ответа сервера и закрытый набор протокольных кодов (например, AUTHENTICATIONFAILED или OVERQUOTA). Другие отчёты об ошибках, ещё не переведённые на эту структурную форму, всё ещё могут передавать сторонний серверный текст — его перехватывает только вычистка адресов и путей, описанная ниже, а не структурная гарантия, — см. Как вычищаются адреса и пути.
  • Версии — версию MailCopilot, вашу операционную систему и её версию.
  • Производительность — длительность операций: синхронизации почты, поиска, отправки и запросов к ИИ.
  • Использование функций — какими функциями вы пользовались в сессии и как часто (поиск, написание писем, ИИ, правила, шаблоны, откладывание и другое), а также, при использовании ИИ-ассистента, какой поставщик и модель обработали запрос и во сколько примерно он обошёлся. Подробности об ИИ-полях — в разделе Лог использования ИИ ниже.
  • Действия с хранилищем AI-ключей — операции с хранилищем, где лежат ваши API-ключи ИИ: какой провайдер, читался ли ключ, сохранялся или удалялся, и чем это закончилось, включая то, был ли ключ там найден. Само значение ключа никогда не отправляется — ни как текст, ни как длина, ни как хеш.
  • Настроечный контекст — сколько у вас подключено учётных записей, какого типа почтовая служба у каждой (например, Gmail или Outlook), способ входа (OAuth или пароль), язык интерфейса и тема оформления.
  • Идентификатор установки — случайный идентификатор, создаваемый при первом запуске, подробно описан ниже. Он связывает данные из разных сеансов между собой — именно поэтому данные не являются полностью анонимными.

Что мы никогда не собираем

MailCopilot не проектирует ни один путь в коде так, чтобы отправлять следующее. Для типизированных метрик и диагностики сохранения копии письма это абсолютная гарантия: она обеспечена закрытым набором структурных полей, которые код вообще имеет право заполнить. Все остальные диагностические отчёты полагаются в первую очередь на то, что точка отправки просто не кладёт туда содержимое, а вычистка распознаваемых форм адресов и путей — это подстраховочный второй рубеж, а не универсальный фильтр содержимого. Что именно делает и чего не делает этот второй рубеж — см. Как вычищаются адреса и пути ниже.

  • Текст ваших писем (тема, тело, вложения, черновики)
  • Ваши email-адреса или адреса ваших контактов — форма обратной связи в Настройках → О программе является единственным местом, куда адрес отправляется намеренно, когда вы сами вписываете его, чтобы получить ответ.
  • Имена и пути папок на вашем IMAP-сервере — в данные попадает только общий тип папки (например, «Входящие», «Отправленные» или «Корзина»), но никогда название, которое вы ей дали
  • Имена файлов вложений
  • То, что вы вводите в поиск, — учитываются только длина запроса и число результатов, но никогда сам текст
  • Содержимое чатов с AI или AI-памяти
  • Хосты серверов, порты или учётные данные
  • Ваш IP-адрес как прикреплённые данные — каждое событие явно указывает Sentry не записывать его. Само сетевое соединение неизбежно раскрывает ваш IP всем, через кого проходит трафик; что с ним делает принимающий сервер, прокси или его журналы — это настройка инфраструктуры получателя, а не то, чем управляет полезная нагрузка MailCopilot.
  • Имя вашей учётной записи операционной системы в диагностических отчётах, которые мы формируем — задокументированные пробелы см. в Как вычищаются адреса и пути

Как маршрутизируются данные

Вся телеметрия отправляется в Sentry — нашу платформу мониторинга ошибок и производительности, и только после того, как вы разрешили это на экране согласия (либо позже, включив переключатель в Настройках → О программе). Когда диагностика выключена — потому ли что вы отказались, ещё не ответили, или позже отключили переключатель — конвейер обходится полностью, и ничего не отправляется. Если включить отладочное логирование, те же события дополнительно появляются в локальном main.log, чтобы вы могли просмотреть, что именно было бы отправлено.

Идентификатор установки

При первом запуске MailCopilot генерирует случайный UUID и сохраняет его в локальном конфигурационном файле. Этот UUID никогда не покидает ваше устройство. Вместо него передаётся SHA-256 хеш — обрезанный до 16 шестнадцатеричных символов — который мы называем install_id_hash. Он прикрепляется к каждому телеметрическому событию как Sentry user id — к каждому событию и транзакции, а не только к событиям уровня сессии, — чтобы мы могли отвечать на вопросы вроде «сколько уникальных установок работает на версии X» или «на сколько пользователей повлиял краш Y — на одного или сотню». Хеш:

  • Псевдонимный, не идентифицирующий, но и не несвязываемый — он не выводится из email аккаунта, отпечатка устройства, IP-адреса или аппаратного идентификатора, и на нашей стороне нет способа сопоставить его обратно с UUID или вашим устройством. Но он намеренно устроен как стабильный идентификатор конкретной установки: он связывает воедино каждое событие и транзакцию, которые эта установка когда-либо отправит, — и, как любой псевдонимный идентификатор, переданный третьей стороне, в принципе может быть сопоставлен с другими данными, доступными Sentry или нам. Именно поэтому экран согласия называет данные «не полностью анонимными», а не анонимными.
  • Стабилен между релизами — одна и та же установка сохраняет тот же хеш при автообновлении приложения, поэтому метрики удержания переживают апдейты версий.
  • Сбрасывается при выключении телеметрии — переключение тумблера в Настройках в положение «выкл» немедленно очищает идентификатор у Sentry-клиента и останавливает дальнейшие передачи.

Мы используем этот идентификатор так же, как веб-аналитика использует visitor id: он позволяет считать уникальные инсталляции, а не общее число событий. Эта разница и есть причина, по которой телеметрия вообще полезна — без неё одна шумная установка выглядела бы так же, как сотня тихих.

Как вычищаются адреса и пути

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

  • Текст в форме email-адреса заменяется на <email>. Шаблон распознаёт практичную, распространённую форму адреса (буквы, цифры и небольшой набор знаков препинания до @, домен с точкой после) — а не полную формальную грамматику email. Намеренное исключение: root@localhost и похожие адреса без домена с точкой оставляются как есть, чтобы обычный текст со упоминанием пакета вроде @types/node не искажался. Локальная часть, построенная из необычных знаков препинания, может оставить после себя обрывок текста после того, как её @domain.tld вырезан.
  • Пути к домашней директории (/home/<имя>/..., /Users/<имя>/..., C:\Users\<имя>\...) — сегмент с именем учётной записи заменяется на <user>. Единственный документированный остаточный случай: имя учётной записи с пробелом внутри, стоящее в самом конце пути без закрывающей кавычки или разделителя после него, может оставить свою вторую часть (C:\Users\Иван Петров в конце строки сохранит «Петров»). Основной процесс дополнительно подставляет вместо буквального пути к вашей домашней директории плейсхолдер везде, где он встречается дословно, — это то, что песочница рендерера сделать не может.
  • Оба фильтра обходят известный, ограниченный набор полей события (текст стека вызовов, сообщения, данные запроса, breadcrumbs и подобное), плюс ограниченный по глубине и размеру обход свободных контейнеров (не глубже 4 уровней и не более 500 посещённых узлов, где в этот бюджет засчитывается каждый элемент контейнера и каждый ключ объекта, а не только реально переписанные строки) — а не безграничную развёртку всего события целиком, поэтому содержимое глубже или шире этого предела не осматривается. Одно поле намеренно не трогается: имя хоста машины, которое сам SDK Sentry прикрепляет к каждому событию (server_name), — потому что на macOS и Windows оно часто выводится из имени учётной записи, а никакое правило вычистки не может надёжно отличить это от несвязанного имени хоста.
  • Утечка в форме, которую ни один из фильтров не распознаёт, — имя папки, тема письма, произвольный текст сервера — здесь не перехватывается. Именно поэтому таблицы метрик ниже и диагностика сохранения копии построены из закрытых структурных полей, а не полагаются на вычистку свободного текста.

Лог использования ИИ

Каждый раз, когда вы отправляете сообщение ИИ-ассистенту, после завершения запроса MailCopilot записывает одну структурную запись лога — в дополнение к булеву флагу в сводке использования, описанной выше. В этой записи: поставщик ИИ (поставщик вашего API-ключа), модель, обработавшая запрос, общее число вызовов инструментов и имена вызванных инструментов (например, send_email или mail_action, но никогда — переданные им аргументы), был ли запрос прерван или завершился ошибкой, и примерная стоимость запроса в долларах США, если поставщик раскрывает цены. Ничего из этого не включает текст вашего запроса, ответ ИИ или содержимое писем — полный разбор того, что сам ИИ-ассистент отправляет поставщикам (это отдельная и гораздо более обширная тема, не связанная с этой структурной записью лога), см. в разделе Данные ИИ и журнал аудита. Отдельные замеры задержки для конкретных функций ИИ несут собственные агрегатные поля (тип контекста разговора, был ли уже сформирован контекст переписки, счётчики токенов, выбранный пресет переписывания, число сгенерированных вариантов ответа и подобное) — см. Замеры производительности ниже.

События

Жизненный цикл приложения

СобытиеТипАгрегируетсяТегиНазначение
app.session_startedeventнетversion, platform, theme, lang, accounts_count, install_id_hashОдин раз при запуске приложения. Несёт install_id_hash для DAU/MAU.
app.session_endedhistogramнетreason, install_id_hashОдин раз при штатном завершении. value_ms = длительность сессии.
app.updatedeventнетfrom_version, to_versionОдин раз после установки автообновлением новой версии.
app.startup_mshistogramнетaccounts_countВремя от app.whenReady до первого видимого BrowserWindow.
window.rescuedeventнетwindows_moved, passПроход спасения окон вернул хотя бы одно окно, ушедшее за пределы экрана, обратно в видимую область после изменения конфигурации дисплеев (подключение монитора, смена разрешения, выход из сна).
tray.createdeventнетoutcome, platformИтог попытки создать объект значка в трее (при запуске или при повторном включении трея в настройках) — outcome равен created или failed. Исход failed — это отказ на нашей стороне (пустое или нечитаемое изображение значка, ошибка при конструировании) и он ничего не говорит о вашем рабочем столе: показывает ли рабочий стол значок на самом деле, MailCopilot не проверяет. Причина отказа не различается.
tray.menu_actioneventнетactionКакой пункт меню трея вызван (открыть / новое письмо / проверить почту / выход) — прямой щелчок по значку в трее на Linux и Windows тоже записывается как open (на macOS обработчик щелчка по значку не регистрируется, там щелчок сам открывает меню).
notification.showneventда (окно 10 с)batchedПоказано уведомление о новой почте; batched — покрывало ли одно уведомление несколько писем. Без аккаунта, папки, темы и отправителя.
notification.suppressedeventда (окно 10 с)reasonУведомление о новой почте было подготовлено, но не показано, потому что вы и так смотрели в приложение.
notification.clickedeventда (окно 10 с)По уведомлению о новой почте кликнули. Без идентификаторов.
badge.updatedeventда (окно 10 с)has_unreadИзменился счётчик непрочитанного на бейдже / в подсказке трея. Только признак «есть непрочитанное», без самого числа.

Согласие на телеметрию

СобытиеТипАгрегируетсяТегиНазначение
telemetry.consent_grantedeventнетversionСрабатывает только когда вы нажали «Разрешить» на экране согласия, с тегом версии перечня, который вы видели. Отказ не порождает событие вовсе — измерение «нет» само по себе было бы отправкой, которую отказ призван предотвратить. Повторное включение переключателя в Настройках → О программе после выключения тоже не порождает это событие — только ответ на экран согласия.

Сводка использования

СобытиеТипАгрегируетсяТегиНазначение
usage.session_summaryeventнетsearch_used, compose_used, snooze_used, read_later_used, ai_used, rules_used, templates_used, followup_used, install_id_hashБитовая карта «какие фичи хотя бы раз использовали в сессии», на её конец.

Онбординг

СобытиеТипАгрегируетсяТегиНазначение
onboarding.wizard_openedeventнетfirst_runПользователь открыл мастер добавления аккаунта.
onboarding.method_selectedeventнетmethodПользователь выбрал OAuth или ручную IMAP/SMTP-настройку.
onboarding.autoconfig_resulteventнетsuccess, providerЗавершилась автоконфигурация — нашли ли мы IMAP/SMTP-настройки?
onboarding.connection_test_resulteventнетkind, success, failure_kindЗавершился тест связи IMAP или SMTP.
onboarding.google_oauth_resulteventнетsuccess, failure_kindЗавершился Google OAuth2-поток.
onboarding.account_savedeventнетprovider, auth_typeУчётные данные аккаунта записаны в keytar/electron-store.
onboarding.first_headers_sync_completedhistogramнетprovider, folder_count_bucketВремя от account_saved до завершения первой синхронизации заголовков (value_ms).
onboarding.first_message_openedeventнетtime_since_sync_bucketПользователь открыл своё первое письмо после входа в аккаунт.

Написание

СобытиеТипАгрегируетсяТегиНазначение
compose.openedeventнетsource, has_draftОкно написания открыто; отслеживается точка входа.

Очередь отправки

СобытиеТипАгрегируетсяТегиНазначение
send_queue.enqueuedeventнетscheduled, send_and_archive, has_attachments, body_size_bucketИсходящее письмо добавлено в send_queue (немедленно или по расписанию).
send_queue.senthistogramнетscheduledВремя от постановки в очередь до успешной SMTP-доставки (value_ms).
send_queue.failedeventнетfailure_kindПопытка SMTP-отправки окончательно провалилась (очередь сдалась).
send_queue.retriedeventнетattempt_numberВременная ошибка SMTP-отправки — письмо переставлено в очередь.
send_queue.append_failedeventнетreason, provider_idSMTP-доставка прошла успешно, но сохранение копии письма в папку «Отправленные» по IMAP не удалось. См. диагностику сохранения копии, описанную выше в разделе «Что мы отправляем».

Предупреждения о неверном получателе

СобытиеТипАгрегируетсяТегиНазначение
misdirection.promptedeventнетkindВ Compose показан диалог-предупреждение о возможной отправке не туда.
misdirection.outcomeeventнетoutcome, kindПользователь отреагировал на это предупреждение.

Шаблоны

СобытиеТипАгрегируетсяТегиНазначение
template.appliedeventнетvar_countПользователь вставил шаблон в окно написания.

Напоминания follow-up

СобытиеТипАгрегируетсяТегиНазначение
followup.createdeventнетduration_days_bucketК исходящему письму прикреплено follow-up-напоминание.

Поиск

СобытиеТипАгрегируетсяТегиНазначение
search.duration_mshistogramнетscope, folder_role, account_count, sort, pagination, len_bucket, token_count, result_bucket, duration_bucket, zero_resultsСколько времени занял поиск по письмам, сохранённым на этом устройстве, — без учёта результатов, которые позже догружаются с почтового сервера.
search.erroreventнетscope, kindОбработчик поиска бросил исключение — пользователь отменил или реальный сбой.

Индексатор тел

СобытиеТипАгрегируетсяТегиНазначение
body_indexer.tick.duration_mshistogramнетindexed, folders_scannedОдин полный тик индексатора по всем папкам.
body_indexer.coverage_pctgaugeнетtotal_messages, indexed_messagesДоля кэшированных писем, у которых проиндексирован body_text.
body_indexer.backloggaugeнетАбсолютное число кэшированных писем, у которых ещё нет body_text.
body_indexer.folder_erroreventнетfolder_role, error_streak, backoff_msИндексатор столкнулся с серией ошибок по папке и ушёл на backoff.

Обслуживание полнотекстового индекса

СобытиеТипАгрегируетсяТегиНазначение
fts.merge.work_mshistogramнетoutcome, steps, max_step_ms, segments_before, segments_afterЦикл инкрементального слияния FTS5: суммарное время синхронных слияний, самый долгий шаг, количество сегментов до/после.
fts.merge.failedeventнетreasonИнкрементальное слияние FTS5 упало с ошибкой.

Синхронизация заголовков

СобытиеТипАгрегируетсяТегиНазначение
sync.headers.wall_mshistogramнетfolder_role, upsert_ms, other_ms, batches, rows, max_batch_msПолный прогон syncFolderHeaders — разделение upsert и прочего для профилирования.
sync.headers.coalescedeventнетfolder_roleПараллельная попытка syncFolderHeaders подцепилась к уже идущему прогону.

Инструментирование открытия писем

СобытиеТипАгрегируетсяТегиНазначение
mail.openhistogramнетcache_hit_level, body_size_bucket, attachments_countСквозная задержка открытия письма, наблюдаемая со стороны renderer (от клика до отрисовки тела). Тег cache_hit_level кодирует, из какого уровня кэша получено тело: memory, db, eml, imap или imap_timeout.
net.message_details.wall_mshistogramнетcache_hit_levelWalltime IPC-обработчика net:messageDetails на стороне основного процесса. Изолирует серверную латентность от шума round-trip renderer→main. Одна выборка на терминальный путь (memory, db, eml, imap, imap_timeout).
imap.pool_queue_wait_mseventнетrequester, wait_ms_bucketВремя ожидания получения соединения из per-account пула IMAP. Испускается только при ожидании свыше 500 мс, поэтому дашборды видят длинный хвост без шума от быстрых захватов.

Разбор EML-файлов

СобытиеТипАгрегируетсяТегиНазначение
eml.parse_dispatcheventнетpath, size_bucketОдин разбор EML-файла с отметкой, каким путём он пошёл: worker (разобран вне основного потока), worker_failed (воркер был доступен, но именно этот разбор завершился ошибкой), worker_aborted (вы закрыли письмо раньше, чем воркер закончил), inline_below_threshold (достаточно маленький, чтобы по замыслу разбираться в основном потоке), либо inline_unavailable (разобран в основном потоке, потому что сам воркер в этой сессии непригоден).
eml.parse_worker_unavailableeventнетreasonСрабатывает не более одного раза за сессию — в момент, когда становится ясно, что разбор EML вне основного потока невозможен до конца этой сессии; все последующие разборы пойдут по пути inline_unavailable выше. reasonscript_missing, spawn_failed, startup_failed или not_main_thread.
eml.parse_cap_hardeventнетsize_bucketПисьмо, чей исходный размер превысил жёсткий предел разбора: его тело и вложения не читались. Обычно это означает, что письмо открылось заглушкой по одним заголовкам, но то же событие срабатывает и тогда, когда фоновая офлайн-синхронизация отказывается от слишком большой загрузки на середине, — в этом случае ничего не открывалось и заглушка не показывалась, потому что не было самого открытия, на которое нужно было бы ответить. Передаётся только грубая полоса размера, описанная выше, — ничего о содержимом. Показывает, получает ли кто-то в реальности письма такого размера, то есть верно ли выбран предел.
eml.parse_cap_softeventнетsize_bucket, tierРаскодированное тело письма, обрезанное по мягкому пределу. Обычно это означает, что в области чтения появилась плашка о том, что показано только начало, но то же событие срабатывает и тогда, когда инструмент ИИ-ассистента для списка вложений в фоне разбирает локально сохранённое письмо, — в этом случае плашка не показывается, поскольку нет самой области чтения, где её показывать. tierdefault для предела, с которым открывается любое письмо, и full, если даже поднятый предел (вы запросили его кнопкой «Показать письмо целиком») оказался мал. Ни текста, ни длины в байтах, ни темы — только полоса размера и то, какой из двух пределов действовал.

Ни одно из этих четырёх событий не агрегируется: каждое записывается по отдельности, а не схлопывается с другими из той же серии, — иначе поле, которое нужно разработчику (какой путь занял разбор, почему упал воркер или сработал ли вообще предел), терялось бы в счётчике. eml.parse_dispatch и eml.parse_worker_unavailable описывают, как прошёл разбор; eml.parse_cap_hard и eml.parse_cap_soft фиксируют, что был превышен предел размера — для мягкого предела это происходит во время самого разбора, а для жёсткого — возможно, ещё до того, как разбор вообще начался, — и возникают не в том же ритме, что событие разбора: письмо, превысившее жёсткий предел, вообще не передаётся парсеру, поэтому для него возникает eml.parse_cap_hard и не возникает eml.parse_dispatch; письмо, задевшее только мягкий предел, разбирается как обычно, поэтому для него возникает и обычное eml.parse_dispatch, и eml.parse_cap_soft вместе с ним.

Гарантируется одно событие eml.parse_dispatch на каждый EML-файл, который MailCopilot действительно передаёт парсеру, — а не одно событие на каждое открытое вами письмо, и, как сказано выше, ни одного — для письма, остановленного жёстким пределом ещё до начала разбора. Открытие письма, которое уже лежит в кэше подробностей в памяти или на диске (уровни memory и db тега cache_hit_level, описанные выше в разделе Инструментирование открытия писем), никогда не разбирает EML-файл, поэтому ни одно из этих четырёх событий для такого открытия не возникает. За рамками этого исключения для кэш-попаданий eml.parse_dispatch, eml.parse_worker_unavailable и eml.parse_cap_soft возникают только тогда, когда письмо читается из локально сохранённого EML-файла или только что скачано и должно быть разобрано, — сюда входят и фоновые обращения ИИ-ассистента за списком вложений, которые точно так же читают локально сохранённый EML-файл, как и обычное открытие. eml.parse_cap_hard возникает в тех же случаях, а также ещё в одном, где EML-файла вообще не существует: когда фоновая офлайн-синхронизация отказывается от слишком большой загрузки на середине, ещё до того, как что-либо сохранено на диск. Каждое событие eml.parse_dispatch несёт path именно этого разбора и size_bucket именно этого письма; каждое событие eml.parse_cap_hard или eml.parse_cap_soft несёт size_bucket письма, на котором сработал предел, — а также, как и любое другое событие, которое отправляет приложение, идентификатор установки, описанный в разделе Идентификатор установки, который связывает его с остальными событиями вашей сессии. Тег size_bucket использует тот же принцип грубых диапазонов, что уже применяется к размеру письма в других местах этой страницы (см. body_size_bucket в разделах Очередь отправки и Инструментирование открытия писем): один из пяти диапазонов — <1KB, 1-10KB, 10-100KB, 100KB-1MB, 1MB+ — а не точный размер в байтах, не размер с более тонкой точностью и никогда не тема, отправитель, имя вложения или идентификатор письма.

Приглашения календаря

СобытиеТипАгрегируетсяТегиНазначение
mail.invite_rsvpeventнетmethod, hadLocationСрабатывает после успешной отправки ответа на приглашение календаря (Принять / Под вопросом / Отклонить). hadLocation фиксирует только было ли у исходного приглашения поле места проведения, а не что в нём написано. Неудачные отправки ответа не учитываются.

Обновление OAuth-токенов IMAP

СобытиеТипАгрегируетсяТегиНазначение
imap.auth_refresh_attempteventнетproviderЗапущено обновление OAuth-токена в ответ на ошибку аутентификации IMAP (XOAUTH2 / AUTHENTICATE).
imap.auth_refresh_successeventнетproviderОбновление успешно — повтор IMAP-запроса пойдёт уже со свежим токеном.
imap.auth_refresh_failureeventнетprovider, reasonОбновление не удалось — исходная ошибка аутентификации поднимается выше.
imap.auth_refresh_suppressedeventнетreasonPer-account cooldown подавил попытку обновления, чтобы не штормить запросами /token, когда refresh-токен отозван.
imap.idle_auth_refreshedeventнетproviderЦикл IDLE восстановился после mid-cycle ошибки аутентификации через in-loop обновление токена — push-доставка вернулась без 60-минутного auth-backoff.
imap.auth_refresh_exhaustedeventнетprovider, consecutiveЦикл IDLE сработал на storm-brake — N подряд успешных обновлений на стороне провайдера, но IMAP всё равно отверг свежие токены, поэтому переходим к обычному auth-backoff.

Восстановление доверия к сертификату

СобытиеТипАгрегируетсяТегиНазначение
imap.cert_erroreventда (окно 10 с)providerОперация IMAP завершилась ошибкой TLS, классифицированной как сертификатная (самоподписанный, недоверенная цепочка, несовпадение пина, несовпадение имени хоста).
cert.recovery_dialog_showneventнетproviderПоказан диалог восстановления сертификата для хоста — не чаще одного раза за окно storm-guard.
cert.trust_clickedeventнетprovider, pemВы приняли предъявленный сертификат, что сохранило TLS-пин и запустило ресинхронизацию аккаунта. pem фиксирует только то, было ли тело сертификата захвачено вместе с пином, — от этого зависит, можно ли доверять самоподписанному серверу в дальнейшем.
cert.trust_rejectedeventнетprovider, reasonПопытка доверия не завершилась сохранением пина — например, вы отклонили подтверждение, или сертификат, предъявленный сервером, не совпал с тем, что показывал диалог восстановления.
cert.interception_notice_showneventнетproviderПоказано разовое уведомление о том, что цепочка сертификата вашего почтового сервера проверяется только через системное хранилище сертификатов ОС, а не через встроенный список публичных корневых центров, — признак антивируса или корпоративного прокси, инспектирующего соединение.

Ни один из этих тегов никогда не несёт имя хоста, отпечаток сертификата, имя издателя или сырой текст ошибки — только перечисляемая классификация provider и закрытые коды причин.

Значок повторного входа в аккаунт

СобытиеТипАгрегируетсяТегиНазначение
account.reauth_flaggedeventнетflagged_accounts_bucketЯщик превысил порог подряд идущих ошибок аутентификации, и теперь для него показывается значок «Войти снова». Отправляется один раз в момент появления значка, а не на каждую неудачную попытку синхронизации, — так фиксируются именно сломанные учётные данные, а не обычные сетевые сбои.
account.reauth_badge_clickedeventнетВы нажали «Войти снова» на значке. Записывается в момент клика, а не по результату: запись сохраняется, даже если окно настроек аккаунта после этого не открылось.
account.reauth_clearedeventнетreason, flag_durationЗначок для ящика перестал показываться — с пометкой почему (signed_in, то есть ящик снова начал аутентифицироваться, или account_removed, то есть вы вместо этого удалили аккаунт) и как долго значок был показан (flag_duration: <1min, 1-10min, 10-60min, 1-6h, 6-24h, 24h+ или unknown для редкого случая, когда время появления не было зафиксировано).

Ни одно из этих трёх событий не несёт идентификатор аккаунта, адрес электронной почты, почтового провайдера или текст с сервера. flagged_accounts_bucket — это грубая корзина числа одновременно отмеченных ящиков по всей установке, а не то, какие именно.

Удержание кэша

СобытиеВидАгрегированТегиНазначение
cache.eml_prunedeventнетcount_bucket, freed_bytes_bucketПлановая очистка удалила файлы .eml старше настроенного срока хранения. Количества и объёмы передаются только в виде диапазонов — точные пути и числа не передаются.
cache.folder_index_disabledeventнетcount, roleПапка была исключена из полнотекстового поиска — автоматически для Junk/Spam/Trash при первой регистрации или вручную через контекстное меню папки. role: spam, trash или manual.

Сигналы безопасности кэша и потери данных

СобытиеТипАгрегируетсяТегиНазначение
db.mass_delete_messageseventнетfolder_role, reason, deleted_count_bucket, watermark_preservedВыполнен папочный DELETE FROM messages. Каждый call site сообщает причину, чтобы регрессию-«потеря кэша» можно было отличить от штатного UIDVALIDITY-bump.
imap.stale_wipe_guard_trippedeventнетfolder_role, providerЗащита от mass-delete отказала в очистке локального кэша папки, потому что mailbox.exists вернулся не-числом. Всплеск означает проблему провайдера/связи, а не реальную потерю данных.
imap.header_response_unaddressableeventнетfolder_role, providerОтвет FETCH с заголовком не содержал пригодного UID, письмо не сохранено, а проход синхронизации отчитался как неполный. Считает проходы, а не письма; показывает провайдера, чей поток FETCH теряет UID.
db.shutdown_wal_checkpoint_mshistogramнетbusy, reclaimed_kb_bucket, okДлительность PRAGMA wal_checkpoint(TRUNCATE) перед закрытием — гарантирует, что закоммиченные, но не чекпойнтнутые записи переживут перезапуск.

Лимиты расходов на ИИ

СобытиеТипАгрегируетсяТегиНазначение
db.ai_reserve_deniedeventда (окно 10 с)reasonРезервирование бюджета ИИ отклонено до того, как мог произойти хоть какой-то расход, — чаще всего потому что достигнут настроенный вами лимит трат.
ai.request_budget.stoppedeventнетprovider, stepsЗапрос к чату остановлен раньше срока, потому что накопленная стоимость достигла настроенного вами потолка на один запрос. steps — число завершённых агентных шагов до остановки, но никогда не их содержимое.

Шлюз stdio MCP (защита renderer-to-RCE)

СобытиеТипАгрегируетсяТегиНазначение
mcp.stdio.connect_attemptedeventнетapproved_sourceТранспорт stdio MCP вот-вот будет запущен — фиксируется один раз на успешный connect после прохождения approval и allowlist гейтов.
mcp.stdio.connect_blockedeventнетreasonПодключение или сохранение stdio отклонено гейтом (not_approved, unapproved_command, forbidden_field, forbidden_env_key, env_disabled).
mcp.stdio.approval_grantedeventнетsource, scopeПользователь дал согласие на stdio MCP (глобальное включение или per-connection); source различает env vs native-confirm, scope — global vs per-connection.
mcp.stdio.env_sanitized_on_loadeventнетcount_bucketМиграция настроек удалила запрещённые loader-hook env-ключи из сохранённых MCP-подключений при загрузке. Срабатывает не более одного раза на запуск.

Аудит AI-действий (барьер preview → apply)

СобытиеТипАгрегируетсяТегиНазначение
ai.action.preview_createdeventнетkind*_preview MCP-инструмент зарегистрировал ожидающее мутирующее действие, ждущее клика «Apply».
ai.action.appliedeventнетkind*_apply MCP-инструмент успешно выполнил ранее подтверждённое мутирующее действие.
ai.action.rejectedeventнетkind, reasonВызов *_apply отклонён на гейте валидации — preview отсутствует или истёк, токен подтверждения отсутствует, не совпал или истёк, тип действия не совпал с preview, отсутствует callback, либо превышен rate-limit.
ai.action.expiredeventнетkindОжидающее мутирующее действие истекло, не дождавшись клика Apply (TTL).
ai.action.apply_duration_mshistogramнетkindДлительность успешного apply — сколько занимает базовая мутация (DB / IMAP / SMTP).
ai.action.preview_skippedeventнетkind, reason*_preview MCP-инструмент отказался регистрировать ожидающее действие, потому что итоговый набор целей оказался пустым (нет совпадений после разрешения запроса).
ai.action.batch_sizeeventнетkind, accounts_count_bucket, emails_count_bucket, folders_count_bucketФиксируется, когда регистрация preview охватывает пакет писем. Все три счётчика — грубые диапазоны, а не точные числа.
ai.turn.action_not_preparedeventнетrole, search_calls_bucketХод AI-чата задействовал механизм деструктивных действий (вызов preview или apply), но завершился без регистрации нового действия и без успешно принятого ранее подтверждённого (действителен только принятый MailCopilot токен подтверждения — устаревшее или неверное подтверждение не считается, а успешно принятое исключает это событие, даже если само действие затем не выполнилось): кнопка подтверждения не появилась и ничего не изменилось. То же самое панель сообщает вам словами. role — какая половина пары была вызвана: preview или apply. search_calls_bucket — грубый диапазон числа поисков в этом ходе. Ни ваш запрос, ни ответ ассистента, ни поисковые строки не передаются: определение опирается только на то, какие инструменты были вызваны.

Шлюз исходящего egress AI

СобытиеТипАгрегируетсяТегиНазначение
ai.egress.blockedeventнетtool_name, account_idВнешний egress-вызов (например, WebSearch, WebFetch, общий внешний MCP-тул) был отклонён, пока пользовательские email-данные находились в области видимости — либо отфильтрован из toolset SDK, либо остановлен runtime-гейтом.
ai.egress.allowed_onceeventнетtool_name, account_idПользователь дал одноразовое согласие на egress, и AI этим воспользовался. Помогает отделить «пользователи регулярно переопределяют» от «гейт держит, попытки в основном инъекционные».
ai.egress.interceptedeventнетtool_name, outcome, was_consented_for_turnОдин вызов интернет-инструмента (веб-поиск, веб-запрос, внешний MCP-инструмент) перехвачен модальным окном подтверждения, описанным в Политике исходящих запросов ИИ, с фиксацией того, был ли он разрешён или отклонён и не покрывался ли он уже ранее данным согласием на весь ход диалога. Никогда — сам запрос, URL или аргументы инструмента: они лишь хешируются в локальном журнале аудита ИИ.

Действия на панели аудита приватности ИИ

СобытиеТипАгрегируетсяТегиНазначение
ai.audit.export_requestedeventнетformatВы нажали «Экспорт JSON» или «Экспорт CSV» на панели журнала аудита ИИ.
ai.audit.entry_deletedeventнетscopeВы мягко удалили одну запись журнала аудита или очистили их все. Сами строки не удаляются, а только скрываются — см. Журнал аудита.

Фоновые правила ИИ

СобытиеТипАгрегируетсяТегиНазначение
ai.rule.appliedeventнетactionКонвейер фоновых правил ИИ автоматически применил к письму обратимое действие (архивировать, переместить, отметить прочитанным или отметить звёздочкой).
ai.rule.destructive_previeweventнетactionКонвейер фоновых правил ИИ предложил деструктивное действие (удалить в корзину или отметить как спам), но зафиксировал его как ожидающий preview вместо автоматического применения.

Быстрые действия в окне письма

СобытиеТипАгрегируетсяТегиНазначение
ai.quick_action.input_too_longeventнетpreset, length_bucketБыстрое действие («Улучшить» / «Короче» / «Формально») отклонило черновик, потому что он длиннее допустимого для этой функции предела, — провайдеру ИИ ничего не отправлялось. preset — какую из трёх кнопок вы нажали. length_bucket — грубая корзина размера: <=8k, 8k-12k, 12k-20k, 20k-50k, 50k-100k или 100k+ символов, никогда не точная длина и ни одного символа самого черновика. Нужно, чтобы понимать, не слишком ли тесен этот предел для обычных длинных писем. Значение <=8k объявлено для полноты, но сегодня недостижимо: это событие возникает только выше предела быстрых действий в 8000 знаков, поэтому корзина существует лишь на случай, если предел когда-нибудь понизят, — чтобы значение не оказалось вне объявленного набора.
ai.proofread.input_too_longeventнетlength_bucketПроверка корректором отклонила черновик, потому что он длиннее допустимого предела, и провайдеру ИИ ничего не отправлялось. length_bucket — та же грубая полоса размера, что и выше: никогда не точная длина и ни одного символа самого черновика. Нужно, чтобы понять, не слишком ли тесен предел для обычных длинных писем.
ai.quick_action.preview_outcomeeventнетpreset, outcomeЧто вы сделали с правкой быстрого действия, показанной в панели проверки. preset — какую из трёх кнопок вы нажали. outcome — ровно одно из трёх значений: replaced, inserted или cancelled. О тексте не передаётся ничего: ни черновик, ни правка, ни их длина, ни число найденных изменений. Нужно, чтобы понимать, берут ли люди эти правки или отклоняют их. Панель, закрытая без выбора (вы закрыли окно или запустили поверх другой пресет), не фиксируется вовсе.

Автообновления

СобытиеТипАгрегируетсяТегиНазначение
update.check_triggeredeventнетsourceЗапущена проверка обновлений — либо часовым фоновым таймером, либо вашим кликом в Настройки → О программе.
update.check_resulteventнетresult, error_classПроверка обновлений завершилась: версия актуальна, обновление доступно или проверка не удалась.
update.download_startedeventнетsourceНачалась загрузка обновления — автоматически или по вашему клику.
update.download_completedeventнетЗагрузка обновления завершилась успешно и готова к установке при следующем перезапуске.
update.download_failedeventнетerror_classЗагрузка обновления не завершилась (обрыв сети, нехватка места на диске, несовпадение подписи и подобное).
update.install_outcomeeventнетresult, error_classЧто произошло после того, как вы нажали «Перезапустить и установить».

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

Шлюз внешних ссылок

СобытиеТипАгрегируетсяТегиНазначение
links.external_open_suppressedeventда (окно 10 с)sourceЗапрос на открытие ссылки в браузере по умолчанию был ограничен шлюзом открытия внешних ссылок. source указывает, какая часть приложения сделала запрос (например, диалог обновления или ссылка отписки), но никогда саму ссылку.

Резервный режим хранилища секретов

СобытиеТипАгрегируетсяТегиНазначение
secret_store.fallback_activeeventнетsurface, platformЧтение из хранилища секретов вашей ОС (keytar / libsecret / Secret Service) завершилось неудачей — эта установка работает без доступной связки ключей. surface указывает, какой тип чтения учётных данных не удался, но никогда сами учётные данные, аккаунт или его email-адрес.

Хранение API-ключей AI

СобытиеТипАгрегируетсяТегиНазначение
ai.api_key_store_opeventда (окно 10с)op, provider, outcomeСохранённый API-ключ AI был прочитан из системного хранилища ключей, записан в него или удалён из него. opread, write или delete. provideranthropic-api, openai-api или gemini-api. outcomefound или absent для чтения (ключ есть или его сейчас нет), ok для успешной записи или удаления, либо store_error, когда до самого хранилища не удалось достучаться. Значение ключа никогда не передаётся — ни как текст, ни как длина, ни как хеш.

Подтверждение адреса AI

СобытиеТипАгрегируетсяТегиНазначение
ai.destination_confirmeventнетfield, outcomeРезультат работы шлюза подтверждения адреса назначения, который стоит перед изменением адреса эндпоинта AI или прокси (см. Подтверждение нового адреса для AI). fieldendpoint или proxy. outcomeaccepted, declined (изменение не было одобрено — вы нажали «Отмена» или Esc, окно подтверждения закрылось до вашего ответа, либо сам диалог не удалось открыть), blocked_invalid (новый адрес не был пригодным http(s)-URL, отклонён без показа диалога) либо blocked_busy (изменение пришло, пока уже было открыто другое подтверждение — во всём приложении может быть открыт только один диалог одновременно, поэтому это может случиться даже для того же самого поля). Счётчик declined — это не только счётчик осознанных отказов: он также учитывает случаи, когда диалог вообще не удалось показать. Ни адрес, ни хост никогда не передаются.

Сохранение настроек

СобытиеТипАгрегируетсяТегиНазначение
settings.field_refusedeventда (окно 10 с)field, codeНастройки сохранены, но одно поле пропущено: присланное для него значение выходит за пределы того, что принимает эта версия. Все остальные принятые поля того же сохранения применены, а у пропущенного поля осталось прежнее значение. field — имя пропущенного поля (mcpExportWhitelist). code — машинная причина (unknown_export_tool — в списке было имя MCP-инструмента, который эта версия не экспортирует, обычно оставшееся от более старой версии). Само пропущенное значение никогда не передаётся.

Производительность IPC

СобытиеТипАгрегируетсяТегиНазначение
ipc.slow_mshistogramда (окно 10 с)channel, duration_bucketIPC-обработчик длился дольше порога «медленно».

Отзывчивость UI

СобытиеТипАгрегируетсяТегиНазначение
ui.freeze.renderer_mshistogramда (окно 10 с)duration_bucket, inflight_count, oldest_inflightЦикл событий renderer'а был заблокирован дольше порога заморозки.
ui.freeze.main_mshistogramда (окно 10 с)duration_bucket, inflight_count, oldest_inflight, top_sql, sql_msЦикл событий main-процесса был заблокирован (через perf_hooks delay). Тег top_sql — это свёртка <глагол> <таблица> самого медленного SQL-запроса, измеренного в том же окне: только форма запроса, без значений параметров.

Контекстное меню

СобытиеТипАгрегируетсяТегиНазначение
ui.context_menu_showneventда (окно 10 с)contextПоказано нативное контекстное меню по правому клику. context фиксирует, какой раздел меню был предложен: link (ссылка), editable (текстовое поле) или selection (выделенный нередактируемый текст).
ui.context_menu_link_actioneventда (окно 10 с)actionАктивирован один из двух пунктов меню для ссылки. actionopen (Открыть ссылку в браузере) или copy_address (Копировать адрес ссылки). URL и видимый текст ссылки в событие никогда не попадают.
ui.context_menu_spell_actioneventда (окно 10 с)actionИспользован пункт проверки орфографии в контекстном меню. actionreplace (подставлен предложенный вариант) или add_to_dictionary (слово добавлено в ваш словарь). Ни само слово, ни замена в событие никогда не попадают.

Проверка орфографии

СобытиеТипАгрегируетсяТегиНазначение
spellcheck.configuredeventда (окно 10 с)enabled, language_count, platform_ownedСостояние проверки орфографии, применённое к приложению при запуске и после каждого сохранения настроек: включена ли она, СКОЛЬКО словарей включено и владеет ли списком языков сама операционная система (macOS). Какие именно языки вы выбрали, в событие не попадает — только их число.
spellcheck.dictionary_consenteventнетoutcome, language_countЧем закончился запрос разрешения на загрузку словаря: accepted (согласие), declined (отказ), blocked_busy (другой запрос уже был открыт), failed (диалог не удалось показать) или unconsented_download (загрузка началась без записанного ответа — это дефект, о котором мы хотим знать). Названия языков не передаются.

Замеры производительности

Помимо дискретных событий и гистограмм выше, MailCopilot замеряет фиксированный набор операций как спаны производительности Sentry — механизм, который Sentry использует для трассировки задержек, а не для счётчиков. Каждое значение атрибута ниже — агрегат: перечисление, счётчик, длительность или булево значение. Ни одно из них не несёт содержимое письма, адрес, поисковый запрос, URL или промпт.

Синхронизация и доставка почты

СпанТипАгрегируетсяАтрибутыНазначение
imap.idlespanнетfolder_role, provider, exit_reason, duration_bucketОдин цикл IDLE: подключение, ожидание push-уведомления, обновление или выход.
imap.syncspanнетfolder_role, provider, changed_since_present, fetched_headers_bucket, skipped, erroredОдин проход синхронизации заголовков для папки — через CONDSTORE или полную выборку.
smtp.sendspanнетprovider, size_bucket, has_attachmentsОдна попытка отправки по SMTP.

Фоновая обработка

СпанТипАгрегируетсяАтрибутыНазначение
body_indexer.batchspanнетfolder_role, batch_size_bucket, fetched_ok_bucket, failed_bucketОдин пакет писем, обработанный внутри тика индексатора тел.
offline.replayspanнетops_count_bucket, failed_bucket, uidvalidity_mismatchОдин повтор отложенных офлайн-действий для аккаунта после восстановления соединения.
search.ftsspanнетquery_len_bucket, result_count_bucketОдин запуск полнотекстового поиска, переданный в поисковый воркер.
net.message_detailsspanнетcache_hit_level, body_size_bucket, attachments_countОбработчик основного процесса, который получает полное содержимое письма — от попадания в кэш в памяти до свежей выборки по IMAP.

Задержка функций ИИ

СпанТипАгрегируетсяАтрибутыНазначение
ai.chatspanнетai.provider, ai.model, ai.context_type, ai.has_history, ai.session_resumed, ai.tool_call_count, ai.tools_used, ai.aborted, ai.cost_usdОдин запрос к чату с ИИ-ассистентом — от открытия потока провайдера до завершения или отмены. ai.context_type и флаги истории/возобновления описывают, с какого места начался разговор и продолжает ли он предыдущий, но никогда — его содержимое.
ai.thread_summary.generatespanнетprovider, was_local, tokens_in, tokens_out, latency_ms, error_classОдна генерация AI-резюме цепочки. Срабатывает только при реальном обращении к провайдеру, никогда — при попадании в кэш.
ai.quick_action.rewritespanнетpreset, provider, was_local, tokens_in, tokens_out, latency_ms, error_classОдна переписка через быстрые действия при написании письма. preset фиксирует, какой из пресетов (Улучшить / Короче / Формально) вы выбрали, но никогда текст вашего черновика.
ai.instant_reply.generatespanнетprovider, was_local, tokens_in, tokens_out, latency_ms, error_class, draft_countОдин вызов генерации быстрого ответа. draft_count — сколько вариантов ответа сгенерировано, но никогда их текст.
ai.proofread.checkspanнетprovider, was_local, tokens_in, tokens_out, latency_ms, error_class, edit_count, dropped_countОдна проверка черновика корректором. edit_count — сколько правок вам предложено; dropped_count — сколько предложенных моделью правок не удалось сопоставить с вашим текстом и они были отброшены. Это только счётчики: ни самой правки, ни фрагмента черновика, ни пояснения к правке здесь никогда нет.
ai.translate.messagespanнетprovider, was_local, tokens_in, tokens_out, latency_ms, error_class, source_labeled, target_lang, cache_hitОдин перевод письма. Фиксируется и при попадании в кэш — cache_hit отличает такие случаи, а попадание в кэш не несёт токенов и стоимости; отказ по причине выключенного перевода, пустого текста, слишком большого письма, отсутствия провайдера или исчерпанного бюджета не создаёт запись. target_lang — код языка из закрытого списка шестнадцати значений, что предлагается в выборе целевого языка. source_labeled — булево значение, фиксирующее только то, удалось ли локальному определению (или вашему собственному выбору) назвать исходный язык для подписи — но никогда какой именно, поскольку это был бы факт, выведенный из содержимого вашего письма.
ai.translate.draftspanнетprovider, was_local, tokens_in, tokens_out, latency_ms, error_class, target_langОдин перевод черновика письма: собственный текст, написанный в окне создания письма, переведённый по запросу. Фиксируется только если провайдер был выбран; отказ по причине выключенного перевода, пустого текста, отсутствия собственного текста, слишком большого объёма, отсутствия провайдера или исчерпанного бюджета не создаёт запись. target_lang — код языка из того же закрытого списка шестнадцати значений, который вы выбрали в окне создания письма — никогда не язык, который MailCopilot мог подсказать для ответа, и никогда признак того, что выбор пришёл из этой подсказки: такого признака здесь нет намеренно, поскольку в паре с target_lang он слабо раскрывал бы язык письма, на которое вы отвечаете, — ту же самую сущность, которую скрывает спан выше, на стороне чтения.

Атрибут provider у спанов задержки AI-функций выше, где он присутствует (у всех, кроме ai.chat, который использует отдельный атрибут ai.provider), принимает одно из фиксированного набора значений: anthropic-api, openai-api, gemini-api, local (будущий путь для локальной модели на устройстве) или unknown. Любое нераспознанное значение отображается как unknown перед записью, поэтому этот атрибут никогда не может расшириться до произвольной или неожиданной строки.

Локальная база данных

СпанТипАгрегируетсяАтрибутыНазначение
db.upsert_messagesspanнетrow_count_bucket, folder_roleОдна пакетная транзакция upsert писем.
db.reconcile_uidsspanнетrow_count_bucket, folder_role, uidvalidity_changedОдин проход сверки, который убирает из локального кэша письма, которых больше нет на сервере.
db.search_messagesspanнетquery_len_bucket, folder_role, result_count_bucketОдин вызов поиска по локальному кэшу, каким бы внутренним путём он ни был выполнен.

Контакты

Вопросы или сомнения по поводу того, что мы собираем? Откройте issue на github.com/mailcopilot/mailcopilot или свяжитесь с командой напрямую через форму обратной связи в Настройки → О программе.