First let me briefly define how I'm using terms (I might be bending their typical use a little):
When I talk about semantic breaking changes, I'm referring to a change in the meaning/behavior of a public API. It may require changes to consumer code, but it isn't immediately obvious, since nothing 'broke'. Changes are only required because the assumptions made about preconditions/behavior are no longer valid.
This is in contrast to syntactic breaking changes by which I'm referring to changes in the public API that require the calling code to change the way it calls the API. This kind of breaking change is obvious since it usually results in compile errors which have to be fixed.
Let's say I'm writing a micro-ORM that given a POCO object, a database connection, and a query will map the results into the object for you. The public API, is fairly simple:
Query<T>(connection As IDbConnection, sql As String)
I'm very unlikely to have a syntactic change in how you interact this tool. However, since there is a lot of behavior bound up in that simple statement, I'm very likely to have semantic changes.
Since there's no syntax change, how do I effectively communicate to consumers of my API that there has been a semantic change? Should I always bundle up semantic changes in syntatic changes so there's no question that something has changed?
If semantic versioning encompasses semantic as well as syntactic changes, then that goes a long way to solving the issue. But it would still be possible for developers to build against a newer version, not notice any compile errors, assume things will be fine (since they haven't read the docs), and introduce bugs due to semantic changes in my API.