@@ -7,6 +7,7 @@ import type {
77} from '@codetime/shared'
88import type { BackfillSourceDefinition } from './lib/backfill.js'
99import type { BackfillImportCounts , BackfillIncrementalState , BackfillSourceFile , ParsedArgs , RunContext , SyncLocalLock , SyncLocalTriggerState , WritableLike } from './lib/types.js'
10+ import { BACKFILL_STATE_SCHEMA_VERSION } from './lib/types.js'
1011import { spawn } from 'node:child_process'
1112import { mkdir , rm , stat , writeFile } from 'node:fs/promises'
1213import os from 'node:os'
@@ -973,26 +974,33 @@ function syncLocalTriggerLockPath(home: string): string {
973974
974975async function readBackfillIncrementalState ( home : string , ctx ?: RunContext ) : Promise < BackfillIncrementalState > {
975976 // Corrupt JSON now surfaces from readJsonIfExists; a missing file
976- // resolves to null. Anything else (wrong shape, future schema
977+ // resolves to null. Anything else (wrong shape, mismatched schema
977978 // version, manual edits that dropped `sources`) lands here and would
978979 // previously vanish silently — log via debug so the user can see
979980 // when watermarks were dropped.
981+ //
982+ // When the on-disk schema version doesn't match the CLI's current
983+ // BACKFILL_STATE_SCHEMA_VERSION we deliberately drop every watermark.
984+ // The next sync-local-runner then re-parses every jsonl from scratch
985+ // and the server upserts via `replace: true`, so a CLI upgrade that
986+ // changed parser semantics (e.g. v2's dedup fix) silently rewrites
987+ // historical rollups without the user knowing.
980988 const statePath = backfillIncrementalStatePath ( home )
981989 const state = await readJsonIfExists ( statePath )
982990 if ( state === null ) {
983- return { version : 1 , sources : { } }
991+ return { version : BACKFILL_STATE_SCHEMA_VERSION , sources : { } }
984992 }
985993 if ( ! isPlainObject ( state ) || ! isPlainObject ( state . sources ) ) {
986994 if ( ctx ) {
987995 debug ( ctx , `backfill-state malformed at ${ statePath } ; ignoring watermarks\n` )
988996 }
989- return { version : 1 , sources : { } }
997+ return { version : BACKFILL_STATE_SCHEMA_VERSION , sources : { } }
990998 }
991- if ( state . version !== undefined && state . version !== 1 ) {
999+ if ( state . version !== BACKFILL_STATE_SCHEMA_VERSION ) {
9921000 if ( ctx ) {
993- debug ( ctx , `backfill-state version ${ String ( state . version ) } at ${ statePath } is not supported; ignoring watermarks\n` )
1001+ debug ( ctx , `backfill-state version ${ String ( state . version ) } at ${ statePath } differs from current v ${ BACKFILL_STATE_SCHEMA_VERSION } ; dropping watermarks so the next sync re-imports under the new parser \n` )
9941002 }
995- return { version : 1 , sources : { } }
1003+ return { version : BACKFILL_STATE_SCHEMA_VERSION , sources : { } }
9961004 }
9971005
9981006 const sources : BackfillIncrementalState [ 'sources' ] = { }
@@ -1003,7 +1011,7 @@ async function readBackfillIncrementalState(home: string, ctx?: RunContext): Pro
10031011 }
10041012 }
10051013
1006- return { version : 1 , sources }
1014+ return { version : BACKFILL_STATE_SCHEMA_VERSION , sources }
10071015}
10081016
10091017async function updateBackfillIncrementalState (
0 commit comments