Open the session a notification is about, and say the two dividers plainly

Tapping a notification landed on whatever the app was last showing. It now
opens the session it named. The id rides in the intent's data rather than an
extra, because PendingIntent identity is Intent.filterEquals -- with an extra
every session's notification would share one PendingIntent and every tap would
open whichever session was notified last. MainActivity sorts the aiapp:// URI
by host, so enrollment and this are one entry point rather than two.

The notification carries only an id, so the session is fetched before there is
a screen; a fetch that fails says so and offers to try again, since somebody
deliberately tapped and an app that opens to the list explains nothing.

That made session-to-session navigation reachable for the first time, and it
crashed: SessionScreen remembers a transcript and an event stream, and without
a key Compose kept both across the change and merged two conversations into
duplicate list keys. Keyed on the session id.

The two transcript dividers now say only what they are, centred between two
rules: "Compacted <bullet> 128,402 -> 9,617 tok" in blue, and "Context cleared"
in red. The rules stay the ordinary divider colour -- they are framing, and the
words are what carries the meaning.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
irisandClaude Opus 5 committed 2026-08-30 01:23:37 -04:00
1 parent 03a8d7d3d3
commit ea2da0896d
7 files changed
+192 -65

No files matched your search

@@ -123,6 +123,18 @@ val failedColor: Color
val commandColor: Color
@Composable get() = Mocha.Blue
/**
* A clear: the conversation taken out of what the session is given.
*
* Red because of what it does, not because anything went wrong -- somebody asked for this, and a
* deliberate choice is not a problem to report. It is the same red as [failedColor] and [stopColor]
* for a third reason, which is worth naming rather than collapsing: this is neither a fault nor a
* button, it is the mark left where something was taken away. The reader never has to tell the
* three apart, because no two of them can appear as the same kind of thing.
*/
val clearedColor: Color
@Composable get() = Mocha.Red
/** Waiting on a person: a question, a permission, a turn that is theirs. */
val awaitingColor: Color
@Composable get() = Mocha.Peach