Check every state rather than argue
Both previous approaches need a human to supply the insight: an invariant, or a type design. That effort scales with the system, and it is the reason verification is expensive.
Model checking removes it by brute force. Build a model of the system as a finite set of states with transitions between them, state the property, and have a machine examine every reachable state.
The consequence is a completely different user experience. There is no proof to construct, no invariant to invent, and no interaction. You supply a model and a property, and the tool returns either a confirmation or a counterexample: a concrete sequence of steps that reaches a violating state.
That counterexample is the feature. A failed proof says the argument did not go through, which may mean the property is false or merely that the invariant was too weak. A model checker hands back a trace you can read and replay.
The constraint that makes this possible is finiteness. Undecidability applies to arbitrary programs; a finite state space is exhaustively searchable, so the question becomes decidable.

