In general, we do not change semantics, so they don't break. :)
We do add new semantics and sometimes change error cases into new working semantics. The #1 way we avoid breakage is that we think really hard about what we're doing, which I know is out of fashion in software development, but we have a pretty good track record.
From a binary compatibility perspective, there are a few policies we follow. We never make changes in Java implementation classes that may be invoked by compiled Clojure code (this is primarily code in RT and Reflector) - although we do add new methods or arities as needed. We also have similar policies around serialization changes, and around macros that introduce calls to new functions. We do not guarantee binary or serialization compatibility across versions (but we try hard to maintain that as much as possible).
And also there are tests of course, although there are not a ton of those that directly check compilation for example, although all Clojure code is compiled so this is kind of implicitly checked in all tests.