Гайд · TNWS AI

Как найти hreflang-ссылку на неопубликованный AI-перевод

8 мин—

Практический аудит hreflang: сравниваем альтернативные URL с опубликованным каталогом и блокируем ссылку на отсутствующий AI-перевод.

Практическая задача

Не выпускать страницу, в hreflang которой указан перевод, отсутствующий в опубликованном каталоге. Такой дефект отличается от недостающей обратной ссылки: целевой URL ещё не существует в снимке релиза, поэтому его нельзя считать доступной локализованной версией. Google требует полностью квалифицированные URL и взаимные аннотации локализованных версий. Проверка ниже сначала убеждается, что каждый href вообще принадлежит известному набору опубликованных страниц, и только после этого позволяет выполнять проверки self-link и возвратных ссылок. Она работает по подготовленному снимку, не делает сетевых запросов и не доказывает индексацию. Этот сценарий применим, когда у команды есть контроль над входом или выходом AI-приложения и требуется конкретный сигнал о нарушении правила, а не общее впечатление от нескольких ответов. Все входы ниже вымышлены; числовые результаты относятся только к этим примерам.

Документация методов Python и синтаксиса workflow сверена 26.09.2026. Если вы используете другое окружение, проверьте совместимость до копирования команд. Статья не утверждает, что показанный код измеряет качество конкретной модели или заменяет ручную проверку.

Подготовка и проверяемый контракт

Перед запуском запишите, какие данные считаются входом, что является ожидаемым результатом, что именно означает отказ и кому предстоит разбирать расхождение. Для такой проверки храните тестовый вход, ожидаемый результат и фактический исход раздельно: если они смешаны, тест может подтверждать сам себя. Используйте стабильные синтетические ID, чтобы видеть ошибку в журнале, не раскрывая содержимое клиентских обращений.

Сначала прогоните тест на маленьком входе, где правильное поведение известно вручную. Затем внесите одну контролируемую ошибку и убедитесь, что код её замечает. После этого верните корректный набор и только тогда расширяйте проверку до реальных данных. Не переносите демонстрационные численные значения или пороги в производство без отдельного обоснования: они выбраны для наглядности, а не рассчитаны по вашей аудитории.

Вход и ожидаемый результат

Русская страница содержит ru-ссылку на себя и en-ссылку на будущий /en/guide, которого нет в наборе published. После удаления преждевременной en-аннотации список unknown становится пустым. Для фикстуры published содержит только https://example.org/ru/guide, а hreflang указывает также https://example.org/en/guide. Первый вызов возвращает английский URL. После удаления ещё не готовой альтернативы программа печатает unknown hreflang targets: []. Когда перевод будет опубликован, добавьте EN в published и верните обе взаимные аннотации. Перед тем как применять правило к закрытым данным, обсудите пограничные случаи, которые могут поменять интерпретацию входа. Запись в документации о границах теста не менее важна, чем зелёный check.

Пошаговые действия

  1. Создайте scripts/check.py в корне репозитория и вставьте код из блока ниже. Он использует названия функций стандартной библиотеки, указанные в официальных ссылках в конце статьи.
  2. Выполните python scripts/check.py локально. Не продолжайте, если уже демонстрационная фикстура даёт иной результат: сначала проверьте копирование кода и кодировку файла.
  3. Экспортируйте список канонических URL именно из релиза, который собираетесь публиковать, и отдельно извлеките все href из hreflang-аннотаций. Запустите отрицательный пример: будущий английский URL должен появиться в отчёте. Удалите преждевременную аннотацию либо добавьте действительно готовую страницу в тот же релиз, затем повторите проверку. После выкладки дополнительно запросите целевые URL и проверьте HTTP-ответ, canonical и содержимое: присутствие адреса в CMS не гарантирует корректной публичной страницы.
  4. Создайте .github/workflows/ai-corpus-check.yml из YAML-шаблона. Событие pull_request полезно для проверки данных до слияния; чтение репозитория ограничено permissions: contents: read. Скрипт не должен получать ключ внешней модели или реальные секреты.
  5. В разделе Actions откройте job check, сопоставьте его код завершения с локальным прогоном и зафиксируйте ссылку на проверенный коммит в PR. Не принимайте зелёный результат на старой ревизии за проверку последнего изменения.
# scripts/check.py
RU='https://example.org/ru/guide'
EN='https://example.org/en/guide'
published={RU}
alternates={RU:{'ru':RU,'en':EN}}
def unknown_targets(published, alternates):
    return sorted({href for links in alternates.values() for href in links.values() if href not in published})
assert unknown_targets(published, alternates)==[EN]
del alternates[RU]['en']
assert unknown_targets(published, alternates)==[]
print('unknown hreflang targets:', unknown_targets(published, alternates))
name: AI corpus checks
on:
  pull_request:
permissions:
  contents: read
jobs:
  check:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v7
      - uses: actions/setup-python@v7
        with:
          python-version: '3.13'
      - run: python scripts/check.py

Как превратить фикстуру в блокирующий контроль

Приведённый Python намеренно содержит локальную демонстрацию с заранее известным ответом. Успешное завершение команды означает лишь то, что правило распознало показанный пример; оно не означает, что реальные опубликованные страницы прошли аудит. Перед использованием предложенного workflow замените учебные словари и XML на снимок данных вашего генератора страниц. Для задачи «Как найти hreflang-ссылку на неопубликованный AI-перевод» сохраните эталон отдельно от проверяемого вывода, посчитайте найденные нарушения и завершайте программу ненулевым кодом, если список ошибок непустой: после диагностического вывода добавьте проверку вида if errors: raise SystemExit(1), где errors — результат именно вашего контроля. Проверьте этот переход двумя отдельными прогонами: сначала подайте намеренно испорченный экспорт и убедитесь, что job красный, затем исправьте экспорт и дождитесь зелёного результата. Не меняйте ожидаемый результат вместе с данными лишь ради прохождения CI. Отдельно проверяйте доступность URL и полноту выгрузки, иначе пустой снимок даст ложное спокойствие.

Ошибки интерпретации и границы

Снимок каталога должен отражать один и тот же релиз, иначе проверка даст ложную ошибку во время поэтапной выкладки. Код не проверяет HTTP-статусы, качество перевода, canonical или обратные ссылки; для них нужны отдельные контроли. Не подменяйте опубликованный каталог списком всех черновиков. Если вы расширяете набор случаев, добавляйте не только новые примеры, но и отрицательные случаи, на которых тест обязан упасть. Проверяйте, что изменение expected прошло ревью отдельно от изменения кода: иначе можно незаметно изменить правило под текущий ответ системы. Избегайте вывода полного приватного набора в CI и не сохраняйте в артефактах ответ закрытой модели без решения о доступе и хранении.

Ошибка выполнения самого Python, нераспознанный формат входа и обнаруженный бизнес-дефект — разные ситуации. В сообщении теста указывайте тип проблемы и безопасный ID. Если тест требует внешний сервис, вынесите его из PR с недоверенным кодом и явно ограничьте доступ к токенам; этот пример намеренно работает локально. Перед публикацией каких-либо результатов опишите методику, область применения и происхождение примеров, иначе читатель воспримет демонстрационную арифметику как характеристику продукта.

Практический разбор именно этого контроля

Не выпускать страницу, в hreflang которой указан перевод, отсутствующий в опубликованном каталоге. Такой дефект отличается от недостающей обратной ссылки: целевой URL ещё не существует в снимке релиза, поэтому его нельзя считать доступной локализованной версией. Для самостоятельной проверки сначала выпишите три наблюдаемых состояния: допустимый вход, намеренно недопустимый вход и видимый сигнал отказа. В данной фикстуре это выглядит так: Русская страница содержит ru-ссылку на себя и en-ссылку на будущий /en/guide, которого нет в наборе published. После удаления преждевременной en-аннотации список unknown становится пустым. При успешном тесте ожидается: Для фикстуры published содержит только https://example.org/ru/guide, а hreflang указывает также https://example.org/en/guide. Первый вызов возвращает английский URL. После удаления ещё не готовой альтернативы программа печатает unknown hreflang targets: []. Когда перевод будет опубликован, добавьте EN в published и верните обе взаимные аннотации. Не превращайте это в числовой KPI: здесь проверяется контракт на конкретных примерах, а не поведение модели на пользовательском трафике.

Снимок каталога должен отражать один и тот же релиз, иначе проверка даст ложную ошибку во время поэтапной выкладки. Код не проверяет HTTP-статусы, качество перевода, canonical или обратные ссылки; для них нужны отдельные контроли. Не подменяйте опубликованный каталог списком всех черновиков. Подключая проверку к продукту, расположите её до той операции, ради которой она написана: парсинга, сохранения, отображения или экспорта. Для каждого нового формата добавляйте отдельный негативный пример и письменное решение, почему он отклоняется. Отдельно просмотрите обработку ошибок: система должна отличать невалидный ответ AI от сбоя тестовой инфраструктуры, а пользователь не должен видеть сырой стек или приватное содержимое.

Чек-лист финальной проверки

  • Синтетический вход и ожидаемый исход согласованы предметным владельцем.
  • Команда python scripts/check.py работает локально и в CI на одной версии файлов.
  • Негативный случай обнаруживается, а не только успешный случай проходит.
  • Имена ID и меток уникальны там, где этого требует контракт.
  • В репозитории, логах и артефактах нет реальных секретов и приватных текстов.
  • Понятно, какой дефект тест находит и каких выводов о качестве AI он не даёт.
  • Ссылки на применённые функции и синтаксис workflow перепроверены при переносе.

FAQ

Можно ли заранее оставить hreflang на будущий перевод?

Не стоит считать непубличный URL полноценной альтернативой. Добавляйте аннотацию вместе с доступной версией и взаимной ссылкой.

Достаточно ли наличия URL в CMS?

Нет. Для релизного контроля используйте набор действительно публикуемых страниц и после выкладки отдельно проверяйте HTTP-ответ.

Что делать при поэтапном деплое?

Собирайте hreflang из одного согласованного манифеста релиза либо включайте аннотации после доступности всех целей.

Проверяет ли этот скрипт обратные ссылки?

Нет. Он намеренно отвечает только на вопрос, существует ли целевой URL в снимке; взаимность проверяйте следующим независимым тестом.

Что делать после обнаружения сбоя

Сохраните конкретный ID, воспроизведите его на текущей ревизии и отделите ошибку входных данных от ошибки функции. Если неверен контракт, исправьте её после предметного ревью; если неверен код, сначала оставьте проваливающийся тест, затем вносите исправление. После зелёного запуска просмотрите соседние случаи с похожими признаками, чтобы локальная правка не изменила другое согласованное поведение. Сохраните версии кода, набора и параметров запуска рядом с выводом: без них сравнивать результаты в будущем нельзя. Не приводите цифру из синтетического примера как измеренный показатель продукта.

Официальные первоисточники

Проверено 26.09.2026: 1, 2, 3, 4, 5. Описание переписано своими словами; изменяемые версии и поля нужно повторно сверять перед дальнейшим использованием.

Читайте также

Комментарии

Пока тихо. Скажите первое слово