Code change:
migrates away from a local address SHOULD retire all connection IDs used on that address once it no longer plans to use that address. <del> An endpoint can request that its peer retire connection IDs by sending a NEW_CONNECTION_ID frame with an increased Retire Prior To field.  Upon receipt, the peer SHOULD retire the corresponding connection IDs and send the corresponding RETIRE_CONNECTION_ID frames in a timely manner.  Failing to do so can cause packets to be delayed, lost, or cause the original endpoint to send a stateless reset in response to a connection ID it can no longer route </del> <ins> An endpoint can cause its peer to retire connection IDs by sending a NEW_CONNECTION_ID frame with an increased Retire Prior To field. Upon receipt, the peer MUST retire the corresponding connection IDs and send corresponding RETIRE_CONNECTION_ID frames.  Failing to retire the connection IDs within approximately one PTO can cause packets to be delayed, lost, or cause the original endpoint to send a stateless reset in response to a connection ID it can no longer route </ins> correctly. An endpoint MAY discard a connection ID for which retirement has been requested once an interval of no less than 3 PTO has elapsed since an acknowledgement is received for the NEW_CONNECTION_ID frame <del> requesting that retirement.  Subsequent incoming packets using that </del> <ins> requesting that retirement.  Until then, the endpoint SHOULD be prepared to receive packets that contain the connection ID that it has requested be retired.  Subsequent incoming packets using that </ins> connection ID could elicit a response with the corresponding stateless reset token.

Related discussion:
text: NAME Yeah we already state that "an endpoint MAY discard a connection ID for which retirement has been requested once an interval of no less than 3 PTO has elapsed since an acknowledgement is received for the NEWCONNECTIONID frame requesting that retirement." So I think it's testable. Considering that we have a MAY on the side that initiates the retirement, I think we can have a MUST on the receiver side (assuming that we want to).
That almost works, except that PTO isn't a shared variable. It's subjective and so endpoints might disagree on where this line is. At 3PTO, that's probably not a disagreement worth having, but you are effectively recommending instant compliance if you set the bar that low, as packet loss on any packet sent that attempts to comply might cause it to take up to 3PTO to get through.
IIRC, the base of the SHOULD was that we didn't have a specific timeout anyone felt comfortable enforcing in the absence of shared timers between peers. We've had a general principle that requirements you can't tell whether the peer violated are probably SHOULDs instead of MUSTs. As Nick says, the SHOULD is intended to refer to doing so promptly, not to doing so at all.
While I agree that we have tried to make MUST requirements testable, I am not certain if it is a good idea to avoid use of MUST when a requirement cannot be tested (or if doing so is a good idea, per the definition of the keywords in RFC 2119). At least for this particular case, isn't it a requirement for an endpoint to drop the old connection IDs? Though I could well be wrong though in how the keywords are used in practice.
I'm fine saying MUST drop in a timely manner, and being explicit about what we mean by timely manner (3 PTO from the peer's perspective). Obviously, from the peer's perspective, that is enforceable. Locally though, it's obviously not as clear cut.
We need a PR. NAME do you think that you can do this? As discussed, should be that the receiving side will retire within one PTO. The sending side can enforce at 3PTO, by dropping the connection.
Discussed in Cupertino. NAME to quickly rev the PR to incorporate NAME suggestion.