@@ -148,7 +148,7 @@ test("a new event with a later timestamp backfills without duplicating prior eve
148148 }
149149} ) ;
150150
151- test ( "backfill writes source timestamps instead of importer runtime " , ( ) => {
151+ test ( "backfill source-dates analytics while preserving the sync mutation cursor " , ( ) => {
152152 const { db, cleanup } = openTempDb ( ) ;
153153 try {
154154 const importer = createImporter ( db . connection , {
@@ -177,10 +177,12 @@ test("backfill writes source timestamps instead of importer runtime", () => {
177177 const session = db . sessions . getById ( "old-session" ) ;
178178 assert . ok ( session ) ;
179179 assert . equal ( session . status , "completed" ) ;
180- assert . equal ( session . updatedAt , "2026-04-01T10:05:00.000Z" ) ;
180+ assert . equal ( session . startedAt , "2026-04-01T10:00:00.000Z" ) ;
181+ assert . equal ( session . endedAt , "2026-04-01T10:05:00.000Z" ) ;
182+ assert . equal ( session . updatedAt , "2026-06-06T12:00:00.000Z" ) ;
181183
182184 const agent = db . agents . getBySession ( "old-session" ) [ 0 ] ;
183- assert . equal ( agent . updatedAt , "2026-04-01T10:05 :00.000Z" ) ;
185+ assert . equal ( agent . updatedAt , "2026-06-06T12:00 :00.000Z" ) ;
184186
185187 const events = db . events . getBySession ( "old-session" ) ;
186188 assert . equal ( events . length , 3 ) ;
@@ -238,7 +240,134 @@ test("backfill falls back missing event timestamps to the source session date",
238240
239241 const events = db . events . getBySession ( "missing-event-ts" ) ;
240242 assert . equal ( events . length , 1 ) ;
241- assert . equal ( events [ 0 ] . createdAt , "2026-04-02T10:00:00.000Z" ) ;
243+ assert . equal ( events [ 0 ] . createdAt , "2026-04-02T10:05:00.000Z" ) ;
244+ } finally {
245+ cleanup ( ) ;
246+ }
247+ } ) ;
248+
249+ test ( "backfill appends new missing-timestamp events without high-water collision" , ( ) => {
250+ const { db, cleanup } = openTempDb ( ) ;
251+ try {
252+ const importer = createImporter ( db . connection , {
253+ tokenUsage : db . tokenUsage ,
254+ detectBillingMode : ( ) => "api" ,
255+ now : ( ) => "2026-06-06T12:00:00.000Z" ,
256+ } ) ;
257+
258+ importer . importSession (
259+ makeSession ( {
260+ sessionId : "missing-event-append" ,
261+ startedAt : "2026-04-02T10:00:00.000Z" ,
262+ endedAt : "2026-04-02T10:05:00.000Z" ,
263+ messageTimestamps : [ ] ,
264+ toolUses : [ { name : "Read" , timestamp : null , input : { file : "a" } } ] ,
265+ } ) ,
266+ "codex" ,
267+ ) ;
268+
269+ importer . importSession (
270+ makeSession ( {
271+ sessionId : "missing-event-append" ,
272+ startedAt : "2026-04-02T10:00:00.000Z" ,
273+ endedAt : "2026-04-02T10:05:00.000Z" ,
274+ messageTimestamps : [ ] ,
275+ toolUses : [
276+ { name : "Read" , timestamp : null , input : { file : "a" } } ,
277+ { name : "Read" , timestamp : null , input : { file : "b" } } ,
278+ ] ,
279+ } ) ,
280+ "codex" ,
281+ ) ;
282+
283+ const events = db . events . getBySession ( "missing-event-append" ) ;
284+ assert . equal ( events . length , 2 ) ;
285+ assert . deepEqual (
286+ events . map ( ( event ) => event . createdAt ) ,
287+ [
288+ "2026-04-02T10:05:00.000Z" ,
289+ "2026-04-02T10:05:00.001Z" ,
290+ ] ,
291+ ) ;
292+ } finally {
293+ cleanup ( ) ;
294+ }
295+ } ) ;
296+
297+ test ( "historical backfill imported after sync cursor remains visible to incremental sync" , ( ) => {
298+ const { db, cleanup } = openTempDb ( ) ;
299+ try {
300+ db . connection . prepare ( `
301+ INSERT INTO sessions (id, name, status, started_at, updated_at)
302+ VALUES (?, ?, ?, ?, ?)
303+ ` ) . run (
304+ "cursor-sentinel" ,
305+ "Cursor sentinel" ,
306+ "completed" ,
307+ "2026-06-06T11:59:00.000Z" ,
308+ "2026-06-06T12:00:00.000Z" ,
309+ ) ;
310+
311+ const importer = createImporter ( db . connection , {
312+ tokenUsage : db . tokenUsage ,
313+ detectBillingMode : ( ) => "api" ,
314+ now : ( ) => "2026-06-06T12:01:00.000Z" ,
315+ } ) ;
316+
317+ importer . importSession (
318+ makeSession ( {
319+ sessionId : "old-after-cursor" ,
320+ startedAt : "2026-04-01T10:00:00.000Z" ,
321+ endedAt : "2026-04-01T10:05:00.000Z" ,
322+ messageTimestamps : [ ] ,
323+ toolUses : [ ] ,
324+ } ) ,
325+ "codex" ,
326+ ) ;
327+
328+ const rows = db . connection . prepare ( `
329+ SELECT id
330+ FROM sessions
331+ WHERE updated_at >= ?
332+ ORDER BY updated_at DESC, id DESC
333+ ` ) . all ( "2026-06-06T12:00:00.000Z" ) as Array < { id : string } > ;
334+ assert . ok (
335+ rows . some ( ( row ) => row . id === "old-after-cursor" ) ,
336+ "new historical imports must remain visible to updated_at cursor sync" ,
337+ ) ;
338+ const session = db . sessions . getById ( "old-after-cursor" ) ;
339+ assert . equal ( session ?. startedAt , "2026-04-01T10:00:00.000Z" ) ;
340+ assert . equal ( session ?. updatedAt , "2026-06-06T12:01:00.000Z" ) ;
341+ } finally {
342+ cleanup ( ) ;
343+ }
344+ } ) ;
345+
346+ test ( "future-dated source activity does not mark a backfilled session active" , ( ) => {
347+ const { db, cleanup } = openTempDb ( ) ;
348+ try {
349+ const importer = createImporter ( db . connection , {
350+ tokenUsage : db . tokenUsage ,
351+ detectBillingMode : ( ) => "api" ,
352+ now : ( ) => "2026-06-06T12:00:00.000Z" ,
353+ } ) ;
354+
355+ importer . importSession (
356+ makeSession ( {
357+ sessionId : "future-source" ,
358+ startedAt : "2026-06-06T12:30:00.000Z" ,
359+ endedAt : "2026-06-06T12:35:00.000Z" ,
360+ fileModifiedAt : Date . parse ( "2026-06-06T11:59:00.000Z" ) ,
361+ messageTimestamps : [ ] ,
362+ toolUses : [ ] ,
363+ } ) ,
364+ "codex" ,
365+ ) ;
366+
367+ const session = db . sessions . getById ( "future-source" ) ;
368+ assert . ok ( session ) ;
369+ assert . equal ( session . status , "completed" ) ;
370+ assert . equal ( session . updatedAt , "2026-06-06T12:00:00.000Z" ) ;
242371 } finally {
243372 cleanup ( ) ;
244373 }
0 commit comments