In iOS 17, Data has changed how it performs equality.
Actually what apparently changed is the behavior of JSON encoding, which now produces Data objects that are indeed different in your example. Remember that a Data object is just a blob of bytes with no concept of JSON keys.
I've noticed if I modify the test case to use a JSONEncoder setting of encoder.outputFormatting = .sortedKeys, then it passes.
That’s the crucial clue. If you don’t use .sortedKeys then the order of the keys after encoding is undefined. And it’s important to never make assumptions about undefined behavior. Unfortunately this test case makes such an assumption: that the undefined key order will happen to be the same if you perform the same encoding twice.
So in iOS 16 and earlier it (apparently) just so happens that the keys are ordered the same when encoding twice in row, but in iOS 17 it just so happens that they are not. Both behaviors conform to the documented behavior. The bug is the test case’s unintentional reliance on the undefined key order.
I noticed that in WWDC, Apple said they rewrote the entire JSONEncoder & JSONDecoder implementations [in Swift].
This may be the root of the behavior change. Swift's Dictionary can have different (undefined) key orderings even between dictionaries that have identical contents, whereas this may not be the case for Objective-C’s NSDictionary. And if the new JSONEncoder implementation in Swift uses Dictionary internally, well, there you go.