@@ -2370,3 +2370,102 @@ func TestDeepSearchWithGroupSessions(t *testing.T) {
23702370 t .Fatalf ("expected 1 session matching file path in groups, got %d" , totalSessions )
23712371 }
23722372}
2373+
2374+ // ---------------------------------------------------------------------------
2375+ // lastActiveExpr regression tests — ensures the MAX-of-three logic picks
2376+ // the most recent timestamp regardless of which source it comes from.
2377+ // ---------------------------------------------------------------------------
2378+
2379+ func TestLastActive_StaleTurnsUsesUpdatedAt (t * testing.T ) {
2380+ // When turns are stale (not yet reindexed) but updated_at is recent,
2381+ // lastActiveAt should reflect updated_at.
2382+ s := newTestStore (t )
2383+ defer func () { _ = s .Close () }()
2384+
2385+ seedSession (t , s .db , "s1" , "/work" , "r" , "main" , "Stale turns" ,
2386+ "2026-04-20T00:00:00Z" , "2026-04-27T12:00:00Z" )
2387+ seedTurn (t , s .db , "s1" , 0 , "hello" , "hi" , "2026-04-20T10:00:00Z" )
2388+
2389+ sessions , err := s .ListSessions (FilterOptions {}, SortOptions {Field : SortByUpdated , Order : Descending }, 0 )
2390+ if err != nil {
2391+ t .Fatalf ("ListSessions: %v" , err )
2392+ }
2393+ if len (sessions ) != 1 {
2394+ t .Fatalf ("expected 1 session, got %d" , len (sessions ))
2395+ }
2396+ if sessions [0 ].LastActiveAt != "2026-04-27T12:00:00Z" {
2397+ t .Errorf ("LastActiveAt = %q, want updated_at %q" , sessions [0 ].LastActiveAt , "2026-04-27T12:00:00Z" )
2398+ }
2399+ }
2400+
2401+ func TestLastActive_FreshTurnsUsedOverUpdatedAt (t * testing.T ) {
2402+ // When turns are more recent than updated_at, lastActiveAt should
2403+ // use the turn timestamp.
2404+ s := newTestStore (t )
2405+ defer func () { _ = s .Close () }()
2406+
2407+ seedSession (t , s .db , "s1" , "/work" , "r" , "main" , "Fresh turns" ,
2408+ "2026-04-20T00:00:00Z" , "2026-04-22T00:00:00Z" )
2409+ seedTurn (t , s .db , "s1" , 0 , "hello" , "hi" , "2026-04-25T10:00:00Z" )
2410+
2411+ sessions , err := s .ListSessions (FilterOptions {}, SortOptions {Field : SortByUpdated , Order : Descending }, 0 )
2412+ if err != nil {
2413+ t .Fatalf ("ListSessions: %v" , err )
2414+ }
2415+ if len (sessions ) != 1 {
2416+ t .Fatalf ("expected 1 session, got %d" , len (sessions ))
2417+ }
2418+ if sessions [0 ].LastActiveAt != "2026-04-25T10:00:00Z" {
2419+ t .Errorf ("LastActiveAt = %q, want turn timestamp %q" , sessions [0 ].LastActiveAt , "2026-04-25T10:00:00Z" )
2420+ }
2421+ }
2422+
2423+ func TestLastActive_NoTurnsFallsBackToUpdatedAt (t * testing.T ) {
2424+ // Sessions with no turns should fall back to updated_at (or created_at).
2425+ s := newTestStore (t )
2426+ defer func () { _ = s .Close () }()
2427+
2428+ // Insert a session with a turn so it passes the "EXISTS turns" filter,
2429+ // then test a second session that does have turns but where updated_at
2430+ // is the winner. For the no-turns case the session is excluded by the
2431+ // zero-turn filter, so we test indirectly via GetSession.
2432+ seedSession (t , s .db , "s1" , "/work" , "r" , "main" , "No turns" ,
2433+ "2026-04-10T00:00:00Z" , "2026-04-15T00:00:00Z" )
2434+
2435+ detail , err := s .GetSession ("s1" )
2436+ if err != nil {
2437+ t .Fatalf ("GetSession: %v" , err )
2438+ }
2439+ if detail .Session .LastActiveAt != "2026-04-15T00:00:00Z" {
2440+ t .Errorf ("LastActiveAt = %q, want updated_at %q" , detail .Session .LastActiveAt , "2026-04-15T00:00:00Z" )
2441+ }
2442+ }
2443+
2444+ func TestLastActive_StaleTurnsVisibleInDayFilter (t * testing.T ) {
2445+ // Regression: a session with stale turn data but recent updated_at
2446+ // must appear under a "since 1 day ago" filter.
2447+ s := newTestStore (t )
2448+ defer func () { _ = s .Close () }()
2449+
2450+ now := time .Now ()
2451+ recent := now .Add (- 6 * time .Hour ).UTC ().Format (time .RFC3339 )
2452+ old := now .Add (- 72 * time .Hour ).UTC ().Format (time .RFC3339 )
2453+
2454+ seedSession (t , s .db , "s1" , "/msbench" , "r" , "main" , "MSBench" ,
2455+ old , recent ) // created 3d ago, updated 6h ago
2456+ seedTurn (t , s .db , "s1" , 0 , "build" , "ok" , old ) // turn from 3d ago
2457+
2458+ since := now .Add (- 24 * time .Hour )
2459+ sessions , err := s .ListSessions (
2460+ FilterOptions {Since : & since },
2461+ SortOptions {Field : SortByUpdated , Order : Descending }, 0 )
2462+ if err != nil {
2463+ t .Fatalf ("ListSessions: %v" , err )
2464+ }
2465+ if len (sessions ) != 1 {
2466+ t .Fatalf ("expected 1 session within day filter, got %d" , len (sessions ))
2467+ }
2468+ if sessions [0 ].ID != "s1" {
2469+ t .Errorf ("expected s1, got %s" , sessions [0 ].ID )
2470+ }
2471+ }
0 commit comments