The failure only shows up once the list is mutated, so it survives a demo on static data and then breaks in production the first time an item is removed.
List identified by position (index), three items:
index 0: "Alice" index 1: "Bob" index 2: "Carol"
Remove "Bob" (index 1). Framework re-diffs by index, not by identity:
index 0: "Alice" index 1: "Carol" <- was Bob's slot
The framework sees index 1's content change from "Bob" to "Carol" -
not "Bob's row was removed." Any local state that row was holding
(a text field draft, an expanded/collapsed flag, a checkbox) stays
attached to index 1 and now displays against Carol's row instead.
Nothing crashes and no error appears anywhere, which is why this is a recurring interview scenario rather than a rare one - it produces a subtle, hard-to-reproduce-on-demand bug report ("sometimes the wrong item is expanded after I delete something") that looks like a data bug and is actually a framework identity bug.
The fix in both ecosystems is the same shape: key by a value stable to the item, not to its position. In SwiftUI, conforming to Identifiable with a stable id (not an index) or passing id: \.someStableProperty to ForEach. In Compose, passing a key = { item -> item.id } lambda to LazyColumn's items(). Both tell the framework "this content moved" instead of "this content changed," which lets it correctly carry local state and animations with the item rather than leaving them behind at a now-stale position.
The detail worth adding unprompted: this identity mechanism is entirely separate from the equality-based skipping mechanism that decides whether a composable or view body re-executes at all. A correctly keyed row can still recompose unnecessarily if its parameters are unstable, and an unkeyed row can skip recomposition correctly while still misattributing local state on a list mutation - they are two different mechanisms solving two different problems, and fixing one does not fix the other.