flang компилятор доказывает, что программа не зациклится 0.6.2 GitHub

Ромб у Unison ломается не от подъёма версии, а от правки типа: за семь версий base не изменился ни один тип

Поправка к unison-measured, и она в пользу Unison. Замер прогоном там верен, но поставлен на худший случай: тип нарочно переписали (Money NatMoney Nat Text), и ошибка типов на границе — правильный ответ на такую правку. Вопрос, который замер не задал: как часто версия вообще меняет тип.

Ответ — почти никогда, и это проверено по хешам в Unison Share.

что сравнивалиразличающихся типов
@unison/base 7.12.0 против 7.19.2 (семь минорных версий)0
в том числе data.List — 170 сущностей0 (изменился один терм документации)
в том числе Text — 108 сущностей0 (два терма, три добавленных)
systemfw_concurrent 8.2.0 против 9.0.0 (мажор)0: ConcurrentMap, Signal, Threads — хеш в хеш

Причина названа самим Unison и она нарочная. Заголовок их же теста unique-type-churn.md: «unique types no longer always get a fresh GUID: they share GUIDs with already-saved unique types of the same name». Пол Кьюзано формулирует правило (unison#2196): «if the type has the same structure and the same name, it gets the same guid and hash».

Иначе говоря, чисто структурная адресация типов оказалась негодной, туда подмешали GUID — а потом обнаружили, что случайный GUID тоже негоден, и привязали его к имени. Круг замкнулся: идентичность типа в языке, построенном на содержимом, определяется именем и структурой. Это стоит запомнить прежде, чем повторять их схему у себя (what-goes-into-the-hash говорит о том же с другой стороны).

Второй демпфер: базовые типы basestructural (Optional, Either, кортежи), а structural хешируется чисто по форме и потому одинаков во всех версиях всех библиотек.

Честный итог по ромбу, в три строки.

И три вещи, которые обещание не покрывает вовсе.

  1. upgrade чинит только ваш код. Дословно из PR 4386: перепарсить и перепроверить «all of their dependents … outside lib». Если библиотека A внутри себя держит lib.a.lib.c_v1, ваш upgrade до c_v2 на неё не влияет никак — надо форкать A. Механизм при этом не миграция типов, а перепривязка имён через текст: код рендерится в исходник и парсится заново в окружении с новыми именами.
  2. Сборщика мусора нет. Официальный FAQ: «The codebase stores its complete history … In the future, we may introduce a "prune" operation». Команд gc, prune, compact, vacuum в InputPatterns.hs не существует. Единственное средство — сплющивание истории при релизе. Отчёт пользователя: «my sqlite file is currently just above 500MB» (unison#5544, открыт с января 2025) — там же беда, что каждая миграция схемы оставляет полную копию файла рядом и не убирает её.
  3. Разрешения совместимости у Unison Share нет. Хранилище нормализовано по хешу содержимого (Postgres, таблица bytes с content_hash), а сверху — обычный SemVer отдельными колонками major_version/minor_version/patch_version (share-api), тип в компиляторе жёсткий: data Semver = Semver !Int !Int !Int. Но диапазонов версий, решателя ограничений и замка нет: версия только упорядочивает, она не контракт. Живая проверка: latestRelease у @unison/base7.19.2, то есть шесть ломающих мажоров у стандартной библиотеки языка, который «избавился от версий».

Чем подтверждено. Разбор внешних источников 2026-08-18: сравнение хешей типов через публичный API api.unison-lang.org по двум парам версий; цитаты и ссылки приведены построчно выше. Замер на этой машине (ucm release/1.3.0, 2026-08-15) не отменяется — он про другой случай.

Чем ограничено.

Связано: unison-measured, unison-pull-brings-all-the-code-not-references, what-goes-into-the-hash, names-not-hashes, other-peoples-packages-must-be-stored