aaif-goose / aaif-goose/goose

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

Đang mở Phù hợp với người mới
#12,003 0 bình luận 0 reaction 1 người được giao Được @jbg nhận Xem trên GitHub
Ngôn ngữ chính
Rust
Star
54.2k
Fork
6.2k
Merge trung bình
3 ngày 4 giờ
Pull request đã merge (30 ngày)
240

Mô tả

## 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.

Hướng dẫn đóng góp

Mở hướng dẫn đóng góp

Hướng nghiên cứu

The bug is in crates/goose/src/session/session_manager.rs around line 1925. Start by reading the session persistence logic and the Message struct. Run the reproduction steps to see the timestamp mismatch. The fix involves normalizing the `latest` timestamp using the `MILLISECOND_TIMESTAMP_THRESHOLD` constant before the max comparison. Done looks like new messages after a resume get correct integer timestamps.

Do mô hình lập chỉ mục viết ra từ nội dung của issue.

Đánh giá

Công nghệ
sqlite
Lĩnh vực
backend, databases
Loại issue
Lỗi
Độ khó
2/5
Thời gian dự kiến
1-3 giờ
Mức độ hoạt động
Sôi nổi
Độ rõ ràng
Đặc tả rõ ràng
Mức phù hợp với người mới
75/100

Nhận issue mới trong hộp thư của bạn

Bản tóm tắt ngắn những issue GitHub phù hợp với người mới.