Elm has well thought out versioning rules. Because of Elm's strong type system their package manager could (can?) enforce the rules. They already have a CLI command to generate a report of what's changed between any two versions of a module.
For example, to compare changes between elm-lang/core's module 3.0.0 vs 4.0.0, run: elm-package diff elm-lang/core 3.0.0 4.0.0 which will produce:
Comparing elm-lang/core 3.0.0 to 4.0.0...
This is a MAJOR change.
------ Added modules - MINOR ------
    Platform
    Platform.Cmd
    Platform.Sub
    Process
------ Removed modules - MAJOR ------
    Graphics.Collage
    Graphics.Element
    Graphics.Input
    Graphics.Input.Field
    Keyboard
    Mouse
    Signal
    Text
    Touch
    Trampoline
    Transform2D
    Window
------ Changes to module Basics - MINOR ------
    Added:
        type Never
------ Changes to module Date - MINOR ------
    Added:
        now : Task.Task x Date.Date
------ Changes to module Debug - MAJOR ------
    Removed:
        trace : String -> Graphics.Collage.Form -> Graphics.Collage.Form
        watch : String -> a -> a
        watchSummary : String -> (a -> b) -> a -> a
------ Changes to module Dict - MINOR ------
    Added:
        merge : (comparable -> a -> result -> result) -> (comparable -> a -> b -> result -> result) -> (comparable -> b -> result -> result) -> Dict.Dict comparable a -> Dict.Dict comparable b -> result -> result
------ Changes to module Random - MAJOR ------
    Added:
        step : Random.Generator a -> Random.Seed -> (a, Random.Seed)
    Changed:
      - generate : Random.Generator a -> Random.Seed -> (a, Random.Seed)
      + generate : (a -> msg) -> Random.Generator a -> Platform.Cmd.Cmd msg
------ Changes to module Task - MAJOR ------
    Added:
        type alias Task err ok = Platform.Task err ok
        perform : (x -> msg) -> (a -> msg) -> Task.Task x a -> Platform.Cmd.Cmd msg
    Removed:
        type Task x a
        type ThreadID
        sleep : Task.Time -> Task.Task x ()
        spawn : Task.Task x a -> Task.Task y Task.ThreadID
------ Changes to module Time - MAJOR ------
    Added:
        now : Task.Task x Time.Time
    Removed:
        delay : Time.Time -> Signal.Signal a -> Signal.Signal a
        fps : number -> Signal.Signal Time.Time
        fpsWhen : number -> Signal.Signal Bool -> Signal.Signal Time.Time
        since : Time.Time -> Signal.Signal a -> Signal.Signal Bool
        timestamp : Signal.Signal a -> Signal.Signal (Time.Time, a)
    Changed:
      - every : Time.Time -> Signal.Signal Time.Time
      + every : Time.Time -> (Time.Time -> msg) -> Platform.Sub.Sub msg
That is very damn cool. Wish we had this in node.js land. See the Elm Package Manager documentation here.