aaif-goose / aaif-goose/goose

Resumed sessions stamp new messages with stale timestamp from previous last message

Offen
#12,003 0 Kommentare 0 Reaktionen 1 zugewiesene Person Beansprucht von @jbg Auf GitHub ansehen
Vorherrschende Sprache
Rust
Sterne
54.2k
Forks
6.2k
Ø Merge
3 T. 2 Std.
Gemergte PRs (30 T.)
262

Beschreibung

## Summary

When a user reopens an existing chat session after restarting Goose, every new message's integer column gets stamped with the timestamp of the session's last pre-resume message instead of the actual current time. The string column remains correct. Since the UI sorts and filters by the integer column, hours or days of new conversation sort into the past and appear missing from the chat view.

## Root cause

In `crates/goose/src/session/session_manager.rs`, line ~1925:

```rust
let latest: Option =
sqlx::query_scalar("SELECT MAX(created_timestamp) FROM messages WHERE session_id = ?")
.bind(session_id)
.fetch_one(&mut *tx)
.await?;
let created = message.created.max(latest.unwrap_or(message.created));
```

`Message::user()` and `Message::assistant()` both set `created = Utc::now().timestamp()` (current time in seconds). But the persist code takes `.max()` of the new message's timestamp and `MAX(created_timestamp)` from existing messages to ensure messages never sort ahead of what's already stored.

The bug fires when the existing max timestamp is stale or uses a different unit (milliseconds from an older Goose version). If `MAX(created_timestamp)` returns a stale value that is larger than the current time (e.g. a millisecond timestamp from an older version, or a previously corrupted value), `.max()` picks the stale value and every new message inherits it.

## Reproduction

1. Create a session and send several messages
2. Note the last message's `created_timestamp` value
3. Quit Goose
4. Reopen Goose and resume the same session
5. Send new messages
6. Check `created_timestamp` vs `timestamp` in the messages table for the new rows

All new rows carry the same stale value from the session's last pre-resume message, while the string `timestamp` column shows correct per-message times.

## Evidence

- 32 of 319 sessions on the reporting machine exhibit this stale-stamp signature
- The stale value always equals the session's final pre-resume message timestamp
- The behavior recurs on every resume of affected sessions, surviving upgrades from 1.48.0 to 1.50.0
- Users believe data is lost because the UI sorts by the corrupted column, hiding recent messages

## Proposed fix

Normalize the `latest` value to seconds before comparing with `message.created`, using the existing `MILLISECOND_TIMESTAMP_THRESHOLD` constant (10_000_000_000):

```rust
let latest_normalized = latest.map(|t| {
if t > MILLISECOND_TIMESTAMP_THRESHOLD { t / 1000 } else { t }
}).unwrap_or(message.created);
let created = message.created.max(latest_normalized);
```

This ensures the `.max()` comparison operates on the same unit scale, preventing stale or mismatched-unit values from clobbering new timestamps.

Beitragsleitfaden

Beitragsleitfaden öffnen

Bewertung

Dieses Issue wurde noch nicht bewertet.

Neue Issues direkt in Ihr Postfach

Eine kurze Übersicht über anfängerfreundliche GitHub-Issues.