Отчёты, диффы и доставка
У движка две поверхности чтения. stats — снимок метрик по провайдерам для дашборда; report weekly собирает дайджест, сохраняет его и может доставить. Обе используют одни и те же окна с учётом часового пояса и одни и те же поля честности.
См. также: Источники данных и квоты, Обход и аудит, Автоматизация и доставка, MCP и навыки агентов.
stats и report weekly
stats | report weekly | |
|---|---|---|
| Назначение | Метрики по провайдерам для дашборда | Собранный недельный дайджест |
| Провайдеры | GSC, Yandex Webmaster, Metrika, Bing, CrUX, PSI, всегда в этом порядке | Те же провайдеры плюс сохранённые проблемы обхода |
| Запись | Ничего; SQLite не нужен | Сохраняет недельный снимок при наличии хранилища |
| Доставка | Никогда | Только с --send |
| Сравнение | Текущее и предыдущее окна по каждому провайдеру | Заголовочная дельта GSC, трафик по движкам, возможности |
| Вывод | JSON-конверт или короткая текстовая таблица | JSON, HTML, текст для email или Telegram |
lv24-seo stats --days 7 --lag-days 2 --json
lv24-seo report weekly --days 7 --lag-days 2 --out reports/
lv24-seo report weekly --days 7 --lag-days 2 --send --jsonstats сообщает status как ok, no_data, missing_token, not_configured или error и изолирует сбой провайдера: конверт остаётся ok: true, а coverage.failed увеличивается. metrics содержит только реально полученные значения, без заполнения нулями и без межмоторных итогов. previous есть только для сопоставимых окон GSC, Yandex Webmaster и Metrika; Bing, CrUX и PSI возвращают null.
coverage.complete истинно, только когда каждый настроенный сервис имеет статус ok, вернул строки, не усечён и ничего не пропало и не упало. Если ни один провайдер не настроен, значение ложно.
Окна и лимиты
--days— длина текущего окна от 1 до 3660. Большее значение завершается сINVALID_INPUTи кодом выхода 2, а не строит неограниченное окно.--lag-daysсдвигает оба окна назад и принимает 0 или больше. Предыдущее окно — такое же по длине окно непосредственно перед текущим.- Данные GSC отстают на 2–3 дня, поэтому отчёт в понедельник утром стабилен. По умолчанию 7 дней и задержка 2 дня.
- Окна используют
report.timezone. Даты провайдеров не конвертируются. - MCP
seo_weekly_reportограничиваетdaysсверху 90, аlag_days— 14, с предупреждением; значения ниже минимума отклоняются. CLI принимает полный диапазон 1–3660. Для длинного периода используйте CLI.
Что содержит недельный отчёт
Заголовок сравнивает клики, показы, CTR и среднюю позицию GSC на двух одинаковых окнах. Изменение CTR выражается в процентных пунктах (pp). Если сопоставимого окна GSC нет, отчёт сохраняет реальные текущие значения с previous: null и сообщает, что дельта недоступна; он не выдумывает базу и не объединяет движки в общий итог.
Цифры по движкам остаются раздельными:
- Yandex Webmaster: текущее окно топ-запросов, в недельном дайджесте ограничено 500 строками.
- Yandex Metrika: сессии, а не клики.
- Bing, CrUX и PSI: дополнительные строки движков, если настроены. CrUX — полевые данные, PSI — лабораторные, и они никогда не смешиваются.
Отчёт также содержит ранжированные возможности (близкая дистанция, разрыв CTR, падающие страницы), проблемы по серьёзности из последнего сохранённого обхода, раздел источников, заметки о данных и ограничения. Каждая возможность несёт реальные доказательства и ожидаемые клики — это оценка приоритета, а не обещание трафика.
JSON-конверт также содержит meta.complete, meta.sources, meta.sources_failed, meta.sources_missing, meta.sources_incomplete, meta.data_age_days, meta.truncated, meta.limitations, meta.locale и meta.snapshot_hash.
Вывод и сохранённые снимки
lv24-seo report weekly --out reports/--out DIR пишет два файла:
report.json— канонический английский, стабильный для диффа между запусками.report.html— отрисован вreport.locale.
Недельный запуск также сохраняет снимок в data/seo.sqlite3, если каталог данных существует. lv24-seo init создаёт <config dir>/data; относительный [storage] data_dir привязывается к файлу конфигурации, а LV24_SEO_DATA_DIR остаётся process-scoped переопределением. Без хранилища команда предупреждает, что снимок не сохранён.
Снимки ключуются по виду, свойству и периоду. Они питают report diff; журнал отправок живёт в том же файле SQLite. MCP держит последний отчёт в памяти для seo://report/latest. report.json, конверты --json и report diff --markdown остаются каноническим английским, даже когда язык отображения русский или китайский; машинные коды не переводятся.
Как читать truncated и limitations
Перед выводом проверьте конверт в таком порядке:
okиmeta.complete— вернул ли каждый настроенный источник пригодные строки?meta.truncated— ограничил ли провайдер данные?meta.data_age_days— насколько окно старше момента запроса?meta.limitations[]иwarnings[]— что неизвестно или приблизительно?
Метрика, присутствующая только в одном окне, неизвестна, а не равна нулю. Усечённый ответ не полон. Последняя страница GSC, точно заполнившая лимит 50 000 строк, помечается усечённой, а не полной: полная страница не доказывает отсутствие следующей строки. Сбой провайдера не валит отчёт: email называет отсутствующий источник, конверт выставляет complete: false, а остальные движки всё равно возвращают данные.
Локализация
report.locale принимает ru, en и zh; по умолчанию ru. Он управляет темой письма, HTML и простым текстом, человекочитаемой сводкой CLI, HTML из --out и сообщениями Telegram, включая форматирование чисел, процентов, позиций, дат и множественного числа.
Локаль влияет только на представление. JSON-конверты, payload MCP, сохранённые снимки и report diff остаются каноническим английским. Неподдерживаемая локаль отклоняется при валидации конфигурации с CONFIG_INVALID, а не подменяется молча.
Email и Telegram
Email использует SMTP на порту 587 с STARTTLS и проверяющим TLS-контекстом. Вход выполняется только после успешного TLS. Сообщение — multipart/alternative: HTML-шаблон продукта и тот же контент простым текстом в 78 колонок, с локализованной темой в одну строку не длиннее 78 символов.
Шаблон — карточка 600px с inline CSS, тёмной шапкой и текстовым словесным знаком. В нём нет внешних изображений, таблиц стилей, скриптов, трекинговых пикселей и удалённых шрифтов. Неизвестные KPI отображаются локализованным текстом «Нет данных», а не 0 и не длинным тире. Metrika показывается как сессии, а не клики. Пустой раздел проблем сообщает, что данных о проблемах нет, вместо заявления, что сайт чист. Ограничения и предупреждения сохраняются и дедуплицируются; текст провайдера остаётся на исходном языке и помечается как оригинал, когда отчёт локализован. В подвале — точный id свойства, время генерации в UTC и «generated by lv24-seo».
Telegram отправляет тот же локализованный текст в 78 колонок через метод Bot API sendMessage. Ответы HTTP 4xx/5xx, таймауты транспорта и некорректные ответы Bot API помечаются как failed и никогда не записываются как отправленные.
Существуют только каналы email и Telegram. Нет адаптеров Resend или Brevo и нет --channel github; отправка GitHub issues провайдером не реализована.
Идемпотентность и гарантии доставки
Журнал sends уникален по (kind, property, period, channel, content_hash). Хеш покрывает заголовок и разделы плюс нормализованную локаль рендера, а generated_at и диагностика исключены. Английский не включает локаль в хеш, поэтому обновление не переотправляет уже доставленный английский период.
only_on_change пропускает отправку, если хеш контента уже доставлялся (already_sent). Материальный фильтр пропускает её, если ни одно изменение не достигает report.thresholds (no_material_change). Фильтр работает до проверки хеша локали, поэтому чистое переключение языка может быть подавлено, когда в периоде нет материального изменения; оно доставляется, когда фильтр проходит или отключён.
Доставка — at-least-once на канал. Неоднозначный результат транспорта помечается failed и не записывается, поэтому следующий запуск может доставить дубль. Параллельные запуски дедуплицируются транзакцией SQLite вокруг проверки, отправки и записи в журнал; SMTP и Bot API не дают exactly-once после падения процесса. Держите одно расписание на период.
Сравнение сохранённых снимков
lv24-seo report diff --json
lv24-seo report diff --base 2026-11-02..2026-11-08 --head 2026-11-09..2026-11-15 --markdownreport diff сравнивает два сохранённых недельных снимка, не вызывая провайдеров. По умолчанию берутся два самых новых периода. Он показывает изменения заголовочных метрик, количество проблем по серьёзности, добавленные, решённые и неизменные возможности, а также добавленные и снятые ограничения.
Метрика, присутствующая только в одном снимке, попадает в unknown_metrics, а не в ноль. comparable и meta.complete ложны, если в одном из снимков нет заголовочного сравнения или длины периодов различаются. --markdown печатает только GitHub-flavoured Markdown, предупреждения идут в stderr, поэтому stdout остаётся валидным для комментария PR или сводки CI. Markdown-дифф перечисляет не более 20 возможностей на группу и сообщает, сколько ещё есть.
Команде нужны lv24-seo init и два запуска report weekly за разные периоды. Без хранилища она падает с CONFIG_INVALID; при менее чем двух снимках — с INVALID_INPUT. Оба случая несут next_action.
Source: _source/engine-cli.md, _source/engine-scheduling.md, _source/engine-releases-0.5.2.md.