Code coverage tells you which lines ran during the tests — not whether the tests would notice if those lines were wrong. Mutation testing closes that gap. It systematically alters the code: flips a `>` to `>=`, changes a `+` to a `-`, replaces `return true` with `return false`, deletes a statement. Each altered version is a mutant.
Then it reruns the test suite against each mutant. If a test fails, the mutant is 'killed' — your tests caught the injected bug, which is what you want. If every test still passes, the mutant 'survived' — meaning a real bug of that exact shape could ship and your suite would stay green. The mutation score is the percentage of mutants killed.
Surviving mutants are the most actionable signal in testing: each one points at a specific line where your assertions don't actually constrain behaviour. It is more expensive than coverage (you rerun the suite many times), so it is usually reserved for critical code paths.