The same pass the server had, on the Kotlin side: comments restating what the code says are gone, and the ones recording a measurement, a constraint or an incident are kept but cut to a few lines each. 6540 comment lines to 5674, and 920 lines off the app. Two doc comments had drifted onto the item above the one they describe -- `contextAfter`'s onto `sessionWorking` in Events.kt, and `UsageMonitor`'s equivalent on the server was fixed in the previous commit. Each is back on its own item, which is the only non-comment line this diff moves. The comments are reflowed to the column limit at their own indentation: several were written wide, and ktfmt re-wrapped them into lines holding a single orphan word. `/tmp` script, not kept -- ktfmt is idempotent over the result, which is the check. Left alone deliberately: this codebase's remaining comment density is high because the comments carry things the code cannot say -- what a null means, what a number was measured against, which bug a guard exists for. Of the 238 one-line doc comments in the app, five were pure restatement of the name and were removed; the rest each say something the signature does not. ktfmtFormat, compileDebugKotlin, lintDebug and testDebugUnitTest pass; cargo test (127), clippy --all-targets and fmt still clean. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
41 lines
2.0 KiB
Kotlin
41 lines
2.0 KiB
Kotlin
package com.example.aiapp
|
|
|
|
import androidx.compose.foundation.lazy.LazyItemScope
|
|
import androidx.compose.foundation.lazy.LazyListScope
|
|
import androidx.compose.foundation.lazy.items
|
|
import androidx.compose.runtime.Composable
|
|
|
|
/**
|
|
* Keyed [items], with anything repeating a key already used left out.
|
|
*
|
|
* A lazy list throws when two of its items claim the same key, and the throw happens during measure
|
|
* on the main thread -- so it is not an error the screen can show, it closes the app. That is a
|
|
* disproportionate answer to a list with a repeat in it, and it lands on the reader rather than on
|
|
* whoever produced the repeat: on 2026-08-31 the import list crashed on a Claude Code session id
|
|
* recorded under two project directories, which is an ordinary state of a machine.
|
|
*
|
|
* Every list in this app keyed on an id keyed it on an id *the server chose*, so all of them shared
|
|
* the hazard and none could rule it out locally. Hence one function they all go through.
|
|
*
|
|
* Dropping the repeat is right here because the key is the whole identity: two rows with one id are
|
|
* two rows every action would treat as the same thing. Where the duplicate means something, the fix
|
|
* belongs at the source, and this is only what stops a data problem from being a crash. It is
|
|
* counted so the render report says it happened rather than leaving a silently shorter list.
|
|
*
|
|
* The transcript's own list is deliberately not on this: its keys are made here rather than
|
|
* received, and it is the one list where an extra pass over the items is measurable.
|
|
*/
|
|
inline fun <T> LazyListScope.uniqueItems(
|
|
items: List<T>,
|
|
crossinline key: (T) -> Any,
|
|
noinline contentType: (T) -> Any? = { null },
|
|
crossinline itemContent: @Composable LazyItemScope.(T) -> Unit,
|
|
) {
|
|
val seen = HashSet<Any>(items.size)
|
|
val unique = items.filter { seen.add(key(it)) }
|
|
if (unique.size != items.size) {
|
|
DebugStats.count("list items dropped for a repeated key")
|
|
}
|
|
items(unique, key = { key(it) }, contentType = contentType) { itemContent(it) }
|
|
}
|