TTL is a ceiling. Nothing schedules the flip.
The common read: The TTL is 300, so five minutes after I change the record every cache re-reads it, and a cutover is an event I can plan a maintenance window around.
Nothing in DNS pushes.
RFC 2181 settles what a TTL is in one clause, that it "specifies a maximum time to live, not a mandatory time to live", so the number you publish is permission to hold an answer for that long and never an instruction to re-ask the moment it elapses; a cache that fetched your record one second before you changed it is entitled to serve the old address for the whole window, and a cache that fetched it thirty seconds earlier is on a different clock for the same name.
There is also no single cache to reason about. RFC 9499 gives separate definitions to the stub resolver, the recursive resolver, the full-service resolver and the forwarder, and one request from a browser inside a container behind a corporate forwarder passes through one of each, every one of them holding its own copy with its own expiry, and you own maybe two.
Resolution succeeding is not evidence that any of them is fresh. RFC 8767 lets a recursive resolver answer from expired cache while the authoritative servers are unreachable, re-advertising a deliberately short TTL, so "DNS was fine during the incident" can describe a resolver serving data your zone had already stopped publishing.
That arrives as "the cutover finished twenty minutes ago and one percent of orders are still landing on the retired origin", filed against sticky sessions, or against the load balancer, or against the engineer who ran the migration, in a room watching a graph that flattens near zero and then refuses to touch it.
Lower the TTL days before you need it, keep the retired origin serving until the tail is actually empty rather than until the number says it should be, and price the tail honestly: you are not waiting for propagation, you are waiting out the longest clock owned by someone who has never heard of your deploy.
