Версии событий и сохранение истории
Сайт развивается: редактор меняет подписи, добавляет главы и улучшает примеры. Аналитика должна сохранять связь с прежними наблюдениями, но не скрывать изменение их смысла. Постоянный URL помогает удержать документ, однако одного адреса недостаточно, если событие после правки начинает обозначать другое действие.
Рассмотрим версии в analytics-lab. Наш договор пока имеет schema_version=1, маршрут reading-demo — course_version=1, а документы сохраняют ID xml и markdown. Добавим необязательную редакционную ревизию материала. Это изменение общего примера, которое не должно автоматически превратить старые строки W1/W2 в данные новой ревизии.
Три независимые версии
Версия схемы описывает форму и смысл сообщения. Версия маршрута описывает порядок учебных шагов. Ревизия содержания обозначает определённый выпуск текста и примера. Эти состояния меняются по разным причинам. Исправление опечатки не обязано менять договор события; вставка новой главы не обязана переименовывать все документы.
Предположим, в Markdown исправили объяснение копирования ресурсов. URL и ID остаются прежними, а ревизия становится r2. Событие открытия всё ещё означает подготовленный экземпляр страницы. Поэтому смысл lesson_open сохраняется. Если для исследования нужно различать ревизии, добавляется соответствующее необязательное поле, а не новое имя статьи.
Другой пример — между Markdown и XML появляется новый шаг. Это изменение маршрута, поэтому версия последовательности отличается. До изменения ссылка next вела прямо к XML, после — к новому документу. Сравнение прибытия в XML теперь относится к другой структуре, даже если определение lesson_next не поменялось.
Наконец, разработчик решает вызывать sample_download при показе ссылки вместо её активации. Это несовместимое изменение смысла. Событие перестало наблюдать действие посетителя и стало описывать доступность элемента. Оставить старое имя без новой модели означало бы незаметно смешать разные наблюдения. Лучше определить отдельное событие, если такой вопрос действительно нужен.
Совместимое добавление параметра
Добавим content_revision как необязательную строку небольшого формата. Текущий договор сохраняет версию 1, потому что прежние потребители продолжают понимать существующие поля, а значение события не меняется. Номер версии не назначается автоматически по числу правок файла; его изменение должно объяснять конкретную границу совместимости.
В полном events.js из второго урока вставьте следующий фрагмент после создания объекта event и перед условием lesson_next. Переменные fields и event уже определены этой функцией; это именно дополнение, а не самостоятельная программа.
if (fields.content_revision !== undefined) {
if (typeof fields.content_revision !== "string" ||
!/^[a-z0-9-]{1,32}$/.test(fields.content_revision)) {
throw new TypeError("Invalid content revision");
}
event.content_revision = fields.content_revision;
}
Так функция по-прежнему выбирает разрешённые поля. Новое значение не берётся из полного текста статьи и не содержит сведения о посетителе. Короткая ревизия может соответствовать редакционному выпуску или известному commit в собственном процессе, но её смысл нужно сохранить в реестре. Случайное время загрузки страницы не является ревизией содержания.
В HTML можно добавить data-content-revision="r2" на main. В обработчике из второго урока создайте общий объект {article_id, content_revision: root.dataset.contentRevision} и передавайте его поля во все три вызова вместе с соответствующими surface и назначением. Если атрибут отсутствует, значение undefined не включается в итоговое сообщение. Старые страницы не получают фиктивную ревизию по умолчанию.
Ожидаемый объект нового открытия содержит прежнее имя, тот же ID и дополнительное content_revision=r2. Это результат формы программы, не полученный замер платформы. Перед использованием проверьте доступность нового параметра в нужном представлении сервиса. Присутствие поля в вызове ещё не обещает, что оно автоматически станет отдельной колонкой каждого стандартного отчёта.
Исторические строки
Наш CSV W1/W2 не содержит ревизии. Нельзя добавить в него r1 и r2 только потому, что недели идут последовательно. Мы не знаем, какой текст видел каждый условный посетитель. Для такого сравнения нужен подтверждённый журнал выпуска или исходные параметры события. Отсутствующий признак остаётся неизвестным.
Если параметр появился с определённой даты, дальнейшие данные можно разделять по известным значениям. Прежние строки сохраняются отдельной группой без этого измерения. Это не делает историю бесполезной: основные события по стабильному ID по-прежнему сравнимы, если их смысл не менялся. Ограничение относится к вопросу о ревизии, а не ко всем сведениям сразу.
Настройки платформ тоже имеют историю. Специальное определение или новая цель не обязательно восстанавливают всю прежнюю детализацию задним числом. Перед выводом проверьте актуальные правила и дату настройки. Урок не обещает ретроактивную реконструкцию параметров, которых доступный экспорт не содержит. Специальные определения GA4, цели Метрики.
Несовместимое изменение
Для изменения смысла составьте новую запись договора: имя, момент, поля и отношение к старому наблюдению. Например, отдельное sample_link_visible может обозначать видимость ссылки, если проект выбрал нужный критерий. Оно не входит в текущий набор и здесь не реализуется; пример показывает, почему новое событие нельзя скрыть под прежним названием скачивания.
При переходе к новой схеме возможен период совместного получения разных версий. Потребитель должен прочитать schema_version и выбрать соответствующую обработку, а неизвестную версию — заметить. Простое сложение всех строк способно объединить несовместимые наблюдения. Сохранение исходного снимка позволит позже проверить, как выполнялся отбор.
Не нужно одновременно отправлять старое и новое сообщение без плана. Такая миграция может быть полезна для отдельной проверки, но потребует указать срок и способ отчёта. Иначе один пользовательский жест даст два события, которые кто-то сложит в общий результат. В нашем небольшом проекте сначала фиксируется совместимое добавление поля, без скрытого дублирования передачи.
Сверка между файлами
Изменение договора должно отражаться в HTML, клиентском модуле, адаптере, настройке сервиса и отчётном расчёте. Эти части не обязаны меняться одинаково, но их ожидания должны совпасть. Если HTML передаёт r2, а функция отбрасывает поле, отчёт по ревизии не появится. Если функция меняет смысл события, но описание осталось старым, цифры будут неправильно прочитаны.
Создайте короткую заметку изменения с причиной, совместимостью, ожидаемым сообщением и источником будущей проверки. Называйте состояние отдельно: подготовлено, размещено, наблюдалось. В нашей локальной серии код остаётся учебным исходником; дата создания файла не является датой фактического подключения или обработки данных сервисом.
В итоге мы сохранили личность документов и добавили ограниченную новую деталь, не переписав историю. Теперь понятно, какие сравнения допускает прежний набор и где начинается неизвестность. Завершающий урок соберёт эти договоры, условия и снимки данных в отчёт, который другой редактор сможет воспроизвести без догадок о настройках автора.