I can't help with the trigger, and I want that out of the way first — I've never reproduced a keychain reset deliberately either, and this thread is already further along that than I got. The ADP precondition above is new to me.
But there's something worth knowing before anyone tries this in the default zone, as suggested above, because there it decides whether the test can tell you anything. The documented handling in https://developer.apple.com/documentation/cloudkit/encrypting-user-data is three steps, and the first is "Delete the relevant zones." If the affected records are in the default zone of the private database, that step can't execute — the default zone is the catch-all for every record that didn't name a zone, so deleting it is either refused or far broader than the recovery you're attempting. You'd trigger the reset successfully, watch the recovery fail, and have every reason to think the trigger was still wrong.
I found that by accident rather than by looking for it. Two unrelated-looking errors, both only visible against a real container on a device, both the default zone:
Field 'recordName' is not marked queryable
AppDefaultZone does not support getChanges call
The first is the one with a thousand search results, all saying to mark recordName queryable in CloudKit Console. That works, in development — schema is per-environment, and the docs say plainly to "Promote this schema change to your production environment before deploying any app changes to the App Store that rely on the new schema." So it converts a code problem into a release-checklist problem. The second is what you hit if you switch to recordZoneChanges to avoid the index entirely, and it is documented in an easy place to miss: CKFetchRecordZoneChangesOperation's own page doesn't say which zones support it, while CKRecordZone.default() does — in terms of CKFetchRecordChangesOperation, deprecated back in iOS 10. For the operation you'd actually write the only statement I can find is in the documentation archive, on a deprecated web-services endpoint: "Fetching record changes is supported only for custom zones."
Moving to a custom zone fixed all three at once, and the third is the reason it isn't a style preference — it's the only one of them that makes the recovery path above executable at all.
Two smaller things for anyone landing here from a search, which you've both got right already but the error strings are worth having in one place. CKErrorUserDidResetEncryptedDataKey is a userInfo key, not a CKError.Code case — the code is zoneNotFound, and checking for it as a case doesn't compile, which is lucky. And on the testing problem itself: constructing a CKContainer for an identifier the host has no matching entitlement for traps rather than throwing, so a unit test that touches one takes the process down instead of failing. Whatever harness you end up with for this probably can't be a plain unit test.
If anyone does find a reliable way to trigger the reset I'd like to know too — the recovery path is the one piece of this I can reason about but not exercise.
Full write-up, with the two errors and why the console fix for the first one is a trap: https://mcmizzle.com/blog/cloudkit-default-zone-limits/