The transaction that undoes your test data doesn't start where you think it does.
config.use_transactional_fixtures = true wraps each test in a database transaction, then rolls it back. That's the theory.
A describe block is just Ruby code that defines your tests. It runs once, up front, while RSpec is still figuring out what tests exist — before any test, and its transaction, has begun.
Ruby evaluates this line while RSpec is still building the example list — no transaction has opened.
This line only runs once the example itself is executing — already inside the open transaction.
let! looks like it lives in the describe block, but it's really a before hook in disguise: RSpec runs it at the start of each example, after the transaction has already opened. That's why let! data rolls back, but a bare line in describe does not.
Ask one question about any line that creates data: does it run while an example is executing, or before RSpec has even started one?
Code inside an it block, or reached via let/let!, since both only run once an example is under way.
Code written directly in a describe block, run at load time, before the first example's transaction has opened.