Gotcha: A test that depends on Set iteration order often won't fail locally — which is exactly what makes it dangerous.
Two roles masked the same field with equal strictness, differing only in placeholder text:
ANALYST → ssn: REDACT as "***" SUPPORT → ssn: REDACT as "[hidden]"
My merge broke ties with "keep the first one seen." First by what? By iterating principal.roles — a Set, whose contract promises no order. So the winner was undefined.
I expected the test to flake. It didn't. Green every run. The trap:
setOf("ANALYST", "SUPPORT") // Kotlin returns a LinkedHashSet → insertion-orderedsetOf is secretly ordered, so my tests always saw ANALYST first — by accident. Build the same elements as a plain HashSet (which is what you get when roles arrive deserialized from JSON) and the order shifts:
setOf order = [ANALYST, SUPPORT, MANAGER, AUDITOR]
HashSet order = [SUPPORT, ANALYST, MANAGER, AUDITOR]
first(setOf) = ANALYST
first(HashSet) = SUPPORT
Same four strings. Different first element. So my ssn placeholder is "***" in tests and "[hidden]" in production — and every test still passes.
The bug was never "Set is random." It was relying on an order the type never promised, and getting away with it locally because the implementation happened to oblige.
Fix: one word.
principal.roles.sorted().forEach { ... }Takeaway: Never branch on an order your type doesn't guarantee. If it's green locally but the contract says "undefined," it isn't passing — it's hiding.