@@ -224,4 +224,62 @@ static string CreateTempDir()
224224 Directory . CreateDirectory ( dir ) ;
225225 return dir ;
226226 }
227+
228+ [ Fact ]
229+ public void Remote_stale_2week_re_download_refreshes_mtime_immediate_followup_does_not ( )
230+ {
231+ var scratch = @"C:\Users\kzu\AppData\Local\Temp\grok-goal-4376de8fe197\implementer" ;
232+ Directory . CreateDirectory ( scratch ) ;
233+ var remoteRef = "gist.github.com/kzu/0ac826dc7de666546aaedd38e5965381" ;
234+ var logPath = Path . Combine ( scratch , "stale-download.log" ) ;
235+
236+ // Ensure clean-ish start for this ref's cache dir (best effort)
237+ try { RunGo ( "clean" , remoteRef ) ; } catch { }
238+
239+ // Warm-up download
240+ var warm = RunGo ( remoteRef , "--" , "-v:q" ) ;
241+ Assert . Equal ( 0 , warm . ExitCode ) ;
242+ Assert . Contains ( "run.cs" , warm . Output ) ;
243+
244+ // Locate the downloaded source cs for this ref (uses the same base as production)
245+ var goRoot = GetTempRoot ( ) ;
246+ var gistRoot = Directory . GetDirectories ( goRoot , "*" , SearchOption . AllDirectories )
247+ . FirstOrDefault ( d => d . Replace ( '\\ ' , '/' ) . Contains ( "gist.github.com/kzu/0ac826dc7de666546aaedd38e5965381" ) ) ;
248+ Assert . False ( string . IsNullOrEmpty ( gistRoot ) , "expected download dir for gist ref" ) ;
249+ var sourceCs = Directory . GetFiles ( gistRoot , "run.cs" , SearchOption . AllDirectories ) . FirstOrDefault ( )
250+ ?? Directory . GetFiles ( gistRoot , "*.cs" , SearchOption . AllDirectories ) . FirstOrDefault ( ) ;
251+ Assert . False ( string . IsNullOrEmpty ( sourceCs ) , "expected source .cs under download" ) ;
252+ var srcInfo = new FileInfo ( sourceCs ) ;
253+
254+ // Artificially age it >14 days
255+ var staleTime = DateTime . UtcNow . AddDays ( - 20 ) ;
256+ srcInfo . LastWriteTimeUtc = staleTime ;
257+ Assert . True ( ( DateTime . UtcNow - srcInfo . LastWriteTimeUtc ) . TotalDays > 14 ) ;
258+
259+ // Re-invoke: should detect stale, (re)download/touch mtime to recent, succeed with marker
260+ var ( exitStale , outStale ) = RunGo ( remoteRef , "--" , "-v:q" ) ;
261+ File . WriteAllText ( logPath , "STALE-RE-INVOKE:\n " + outStale ) ;
262+ Assert . Equal ( 0 , exitStale ) ;
263+ Assert . Contains ( "run.cs" , outStale ) ;
264+
265+ srcInfo . Refresh ( ) ;
266+ var afterStaleMtime = srcInfo . LastWriteTimeUtc ;
267+ File . AppendAllText ( logPath , $ "\n SOURCE-MTIME-AFTER-STALE: { afterStaleMtime : O} \n ") ;
268+ Assert . True ( ( DateTime . UtcNow - afterStaleMtime ) . TotalMinutes < 5 , "source mtime should be refreshed to recent by re-dl" ) ;
269+
270+ // Immediate follow-up: must NOT update the source mtime (plan requirement)
271+ var mtimeBeforeImmediate = srcInfo . LastWriteTimeUtc ;
272+ var ( exitImm , outImm ) = RunGo ( remoteRef , "--" , "-v:q" ) ;
273+ File . AppendAllText ( logPath , "IMMEDIATE-FOLLOWUP:\n " + outImm ) ;
274+ Assert . Equal ( 0 , exitImm ) ;
275+ Assert . Contains ( "run.cs" , outImm ) ;
276+
277+ srcInfo . Refresh ( ) ;
278+ var mtimeAfterImmediate = srcInfo . LastWriteTimeUtc ;
279+ File . AppendAllText ( logPath , $ "SOURCE-MTIME-AFTER-IMMEDIATE: { mtimeAfterImmediate : O} \n ") ;
280+
281+ var deltaSeconds = ( mtimeAfterImmediate - mtimeBeforeImmediate ) . TotalSeconds ;
282+ // The immediate run (cache hit, no dl) must not have updated the source mtime via our logic or observable change.
283+ Assert . True ( deltaSeconds < 2.0 , $ "immediate follow-up must not update source mtime (delta={ deltaSeconds } s)") ;
284+ }
227285}
0 commit comments