feat(android): resume from the seq, and walk back through the session
The chat screen asked the claw for everything the cache did not hold by counting events, and a session that ran for weeks cost the whole record the first time it opened here. The stream now names each frame's seq and the cache stores it, so a reopening screen sends since=<seq> and receives only the gap. The cache migrates in place: the old count of events is exactly the last seq plus one, because the record numbers densely. A screen with no cache opens on the newest turn and walks back through the new history route when the reader reaches the top, one whole turn per page, so the phone does not hold a weeks-long transcript to show the last few messages. Pages are folded through the same reducer the stream uses and prepended, since the list runs oldest first: appended, they would land at the newest end. A reset comment (the record no longer holds the cursor) drops the mirror, and the tail that follows rebuilds it. The outcome tag colours a steered turn as an accent rather than a failure, matching the web UI.
This commit is contained in:
1 parent
70d9bb0d34
commit
fa0e3d4470
7 files changed
+277
-51
No files matched your search
@@ -12,17 +12,39 @@ import rs.rhema.phone.net.ClawEvent
|
||||
|
||||
// One session's cached transcript tail: the events this device has
|
||||
// applied, persisted as they stream. Opening a session seeds the screen
|
||||
// from here instead of watching the claw's whole replay again, and the
|
||||
// stream opens with `total` as its `since` cursor so the claw sends only
|
||||
// from here instead of watching the claw replay the session again, and
|
||||
// the stream opens with [cursor] as its `since` so the claw sends only
|
||||
// the events past the cache.
|
||||
@Serializable
|
||||
data class CachedSession(
|
||||
// The session's full event count — the `since` cursor. Can exceed
|
||||
// [events]: the list keeps only the newest [SESSION_WINDOW] events,
|
||||
// the count counts from the session's first.
|
||||
val total: Long = 0,
|
||||
// The seq of the newest event in [events] — the `since` cursor. -1
|
||||
// when nothing is cached.
|
||||
val cursor: Long = -1,
|
||||
// The seq of the oldest event in [events]: the anchor the walk back
|
||||
// through /history ends at.
|
||||
val first: Long = -1,
|
||||
val events: List<ClawEvent> = emptyList(),
|
||||
)
|
||||
// The cursor of a cache written before the stream named seqs: a
|
||||
// count of the session's events. Read only to migrate one, see
|
||||
// [resumeCursor]; -1 for every cache written since.
|
||||
val total: Long = -1,
|
||||
) {
|
||||
// A cache from before seqs still resumes exactly: the record numbers
|
||||
// events densely from zero, so the last one it applied is `total - 1`,
|
||||
// and the window above it is contiguous. The first open after the
|
||||
// upgrade costs nothing.
|
||||
val resumeCursor: Long
|
||||
get() = if (cursor >= 0) cursor else if (total > 0) total - 1 else -1
|
||||
|
||||
val oldestSeq: Long
|
||||
get() = if (first >= 0) {
|
||||
first
|
||||
} else if (events.isNotEmpty() && resumeCursor >= 0) {
|
||||
resumeCursor - events.size + 1
|
||||
} else {
|
||||
-1
|
||||
}
|
||||
}
|
||||
|
||||
// How many events the cache keeps per session. A resident session runs
|
||||
// for weeks; a bounded window keeps the DataStore write flat, and a tail
|
||||
|
||||
Reference in new issue
Block a user