Политика версионирования
До версии 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_* — второй провайдер не ломает конфигурацию тех,
кто уже настроил первый.