Политика версионирования

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

Что входит в обещание совместимости

С 1.0 ниже перечисленное меняется только назад совместимо либо мажорной версией:

ЧтоЧто именно обещано
Переменные окруженияимена переменных и форматы их значений (какие значения допустимы, не то, что стоит по умолчанию сегодня — дефолт может меняться)
Пути приёма и форматы тел/api/v1/* и остальные действующие пути приёма, формат тела запроса на каждом из них
Схема миграциймиграции вперёд совместимы — база, поднятая на N, доезжает до N+1 без ручной правки
Формат бэкаповснятый бэкап можно восстановить более новой версией
Имена self-метрикимена и метки метрик, описанных в мониторинге самого gotcha, — кроме отдельно помеченных временными
Тело исходящего вебхукасхема тела заморожена; добавление нового поля — не ломающее изменение, читайте тело терпимо к незнакомым полям
Контракт GOTCHA_AGENT_*переменные окружения агента и протокол, которым он говорит с сервером
Адреса уже существующих статус-страницопубликованный URL статус-страницы не меняется сам по себе

Что не входит в обещание

Ниже перечисленное может меняться в любом релизе, включая патч, без предупреждения в CHANGELOG как о ломающем:

  • внутренние Go-пакеты (internal/...) — это не публичный API, gotcha не библиотека;
  • вид и URL страниц веб-интерфейса;
  • схема таблиц PostgreSQL и ClickHouse — интеграция через прямые запросы к базе не поддерживается никогда, только через ingest-пути и API;
  • набор и порядок колонок в выгрузках (CSV/JSON из раздела «Выгрузки»);
  • порядок и точный текст сообщений в логах самого gotcha.

Если вам нужна стабильность в одной из этих зон — постройте её через то, что уже в обещании (self-метрику, ingest-путь), а не через парсинг лога или прямой SELECT к базе.

Что считается ломающим изменением

Применительно к любому пункту из «что входит в обещание» ломающим считается:

  • удаление или переименование покрытого элемента (имени переменной, ingest-пути, self-метрики, поля протокола агента);
  • сужение множества принимаемых значений (то, что раньше принималось, теперь отклоняется);
  • смена смысла значения при том же имени (тот же ключ конфигурации теперь значит другое);
  • удаление ingest-пути.

Расширение — новое необязательное поле в теле, новая переменная окружения, новый необязательный параметр — ломающим не считается и мажорной версии не требует.

Даунгрейд не поддерживается

Обещание работает только в одну сторону: новая версия понимает данные и конфигурацию, оставленные старой. Обратное не гарантируется, и откат на предыдущий релиз — не безопасная операция «на всякий случай», а действие с риском тихой порчи данных.

Прецедент — ротация ключа secretbox в v0.25.0. Секреты в базе стали храниться в конверте enc:v2:<key-id>:...; версия, которая писала конверты, понимает и старый формат, и новый. Но версия ДО этой миграции формата конверта не знает вовсе: она читает enc:v2:... как обычную строку и отдаёт его наружу, будто это и есть расшифрованный секрет — тихо, без ошибки. Откат на дореверсионный бинарь после того, как через инстанс прошла ротация, ломает секреты молча.

Отсюда практическое правило: прежде чем обновляться, снимайте бэкап (см. Резервное копирование и восстановление) и восстанавливайтесь из него, если релиз не подошёл, а не откатывайте бинарь на живой базе.

Процедура депрекации

У устаревания есть две формы — для путей приёма и для переменных окружения, — и обе требуют минимум один мажорный релиз жизни между объявлением об устаревании и удалением.

Путь приёма. Старый путь продолжает работать, но:

  • ответ на запрос к нему несёт заголовок Deprecation и Link; rel="deprecation" (RFC 9745) со ссылкой на актуальный путь;
  • каждый такой запрос считается self-метрикой gotcha_ingest_deprecated_path_total{path="…"} — см. мониторинг самого gotcha;
  • путь удаляется не раньше следующего мажора.

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

Сроки текущего устаревшего

На момент 1.0 в контракте два открытых устаревания:

Что устарелоКогда удаляется
Три ingest-алиаса приёма — /logs, /profiles/pprof, /api/{project}/deployments/ (замены — /api/v1/logs, /api/v1/profiles/pprof, /api/v1/{project}/deployments)живут до 2.0
Реестр переименованных переменных окружения (отказ старта на старом имени; полный список — в обновлении)живёт до 2.0

Три алиаса приёма — счётчик gotcha_ingest_deprecated_path_total{path="…"} в мониторинге самого gotcha показывает, ходит ли кто-то ещё по старому пути; ненулевой поток после обновления — сигнал перевести отправителя на новый путь до 2.0. Тот же вопрос про КОНКРЕТНЫЙ проект (а не инстанс целиком) виден и без наблюдаемости: на странице настроек проекта показывается, что он ещё стучится на устаревший адрес, если это было в последние 7 дней.

Путь расширения OIDC

Сегодня gotcha поддерживает ровно одного generic-OIDC провайдера на инстанс — переменные GOTCHA_OIDC_* (см. конфигурацию). Когда появится поддержка второго провайдера одновременно с первым, она придёт отдельным именованным неймспейсом переменных, а не изменением смысла существующих GOTCHA_OIDC_* — второй провайдер не ломает конфигурацию тех, кто уже настроил первый.