The stricter the types and contracts, the fewer degrees of freedom generation has to get it wrong: Rust or strict mypy give the assistant the compiler as an immediate feedback loop, and the tests a human wrote say what “right” means.
A generator produces plausible text; a checker decides which plausible text is acceptable. Every rule the checker enforces is a mistake the generator cannot hand to a reviewer. If amount_cents is a Cents type and not an int, a generated function that adds cents to a percentage fails to compile instead of failing in an invoice. If an order state is a closed enum (3), a generated handler that forgets Refunded fails exhaustiveness. If input is parsed into a validated type at the boundary (2), the generator cannot reach the core with an unchecked string. The loop also gets faster: a compile error in two seconds beats a failing integration test in four minutes, and an agent iterates against it without a person in the loop.
Tests are written and reviewed by a human with particular care — a generated test fitted to a generated bug is green and useless. The test is the oracle; if the same process writes both the code and the oracle, they share the same misunderstanding. A cheap check of a test suite’s strength is mutation testing, an idea from DeMillo, Lipton and Sayward (“Hints on Test Data Selection”, IEEE Computer, 1978): flip a comparison or drop a line, and see whether some test fails. Generated tests that survive every mutant assert nothing. Property-based tests (9) state invariants rather than examples, which makes them harder to fit to a bug by accident.
Limits. Types check what is expressible in them: they say an amount is in cents, not that the tax rate is the right one for the jurisdiction. A strict type system can also push a generator into casts and unwrap() to make errors go away — so a review rule that flags new escapes (as, # type: ignore, unsafe) belongs with the strictness.