Ограничения версий по умолчанию
- title
- Ограничения версий по умолчанию
- type
- concept
- summary
- Задаёт ли команда add пакетного менеджера верхнюю границу по SemVer по умолчанию и к чему приводит её отсутствие
- tags
- package-management, semver, developer-experience
- created
- 2026-05-22
- updated
- 2026-05-22
- lang
- ru
- translation_of
- default-version-bound-constraints
- source_updated
- 2026-05-22
- translated
- 2026-09-01
- translator
- lllm/antigravity/gemini-3.7-flash-medium
Когда вы запускаете npm add X, cargo add X, poetry add X или uv add X, инструмент сам выбирает ограничение версии, которое запишет в манифест. Этот выбор по умолчанию кажется мелочью, но влечёт долгосрочные последствия: большинство проектов просто оставляют то, что сгенерировал инструмент, и больше к этому не возвращаются.
Два лагеря:
| Экосистема | Поведение add X по умолчанию (текущая версия 1.2.3) |
Есть верхняя граница? |
|---|---|---|
| npm / pnpm / yarn | ^1.2.3 (карет = совместимая мажорная версия) |
Да - неявная на границе мажорной версии |
| Cargo (Rust) | 1.2.3 (подразумевается карет; то же, что ^1.2.3) |
Да |
| Poetry (Python) | >=1.2.3,<2.0.0 (или ^1.2.3 в свежих версиях) |
Да |
| Bundler (Ruby) | ~> 1.2 (пессимистичное ограничение) |
Да |
| uv (Python) | >=1.2.3 |
Нет |
| pip-tools (Python) | точная фиксация через compile |
Да (излишне строго) |
Аргумент в пользу неявной верхней границы: по правилам SemVer смена мажорной версии может ломать публичный API, поэтому инструмент без фиксации мажорной версии обрекает любой проект на потенциальные поломки при выполнении update или upgrade. Аргумент против верхней границы (выбор uv): соблюдение SemVer лишь декларируется, а не гарантируется; верхние границы создают проблемы resolver'у, когда зависимость выпускает мажорный релиз без реальных ломающих изменений; к тому же в Python накопилась долгая история бесполезных конфликтов из-за верхних границ (известно, как poetry add отказывался ставить многие библиотеки из-за транзитивных ограничений, которые самим библиотекам были не нужны).
Проблемы возникают в разные моменты:
- С верхними границами: чаще появляются ошибки вроде "resolver не может подобрать версии", чаще приходится поднимать версии вручную.
- Без верхних границ: рутинный
upgradeмолча подтягивает ломающие изменения, что приводит к падению сборок спустя дни или недели, когда выясняется, что в транзитивном обновлении что-то удалили.
uv сейчас по умолчанию находится в лагере без верхних границ и предлагает флаг --bounds major как экспериментальную опцию. Аргумент в loopwerk-uv-ux-mess заключается в том, что небезопасный вариант не должен быть поведением по умолчанию: большинство пользователей не станут настолько тщательно изучать diff'ы lockfile'ов, чтобы заметить мажорное обновление транзитивной зависимости, а цена слишком строгого ограничения (быстро поднять версию вручную) намного ниже цены незаметной поломки (сбоя, причину которого придётся искать бисекцией).
Это ещё и вопрос о том, кто несёт издержки. Авторы библиотек предпочитают отсутствие верхних границ у своих зависимостей, чтобы избежать взрыва конфликтов версий. Разработчики приложений предпочитают верхние границы, потому что именно им приходится чинить сломанные сборки. Поведение ограничений по умолчанию - это выбор пакетным менеджером стороны в данном конфликте.
См. также
- loopwerk-uv-ux-mess - подробные аргументы Kevin Renskers против поведения uv по умолчанию
- supply-chain-security - более широкий контекст безопасности цепочки поставок; период охлаждения (open-source-security-astral) служит ортогональной мерой защиты