You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
foldToSnapshot overwrites work.json after an unparseable snapshot or unreadable event log, with nothing recorded #2513
foldToSnapshot() publishes work.json from readSnapshot() + replayOntoSnapshot(). Both helpers turn "could not read" into "empty/unchanged" without recording it, and the fold then writes the result with a fresh _folded_at:
work.json exists but does not parse -> readSnapshot returns { sessions: {} }. After a compaction (log truncated to the suffix, older log in the archive directory), the fold writes a snapshot that only holds sessions from the surviving suffix. Everything folded before the compaction is gone from work.json, and nothing says so.
The event log cannot be stat'ed (permissions, EIO) -> replayOntoSnapshot returns the snapshot's sessions with offset: 0; the fold writes _events_offset: 0 and _folded_at: now. If the log cannot be read after a successful stat, it returns quietly with the old offset. Either way the snapshot is stamped "folded just now" over an input that was never read.
The header says a skipped fold is safe because "events stay in the log" and the next writer picks them up. That holds for lock contention (acquireLock fails -> return false), not for these two paths, which proceed and write.
Root cause
hooks/lib/work-events.ts:
:448-455readSnapshot catch returns an empty registry for any error, not only ENOENT.
:466-471 and :484-485replayOntoSnapshot catches return without any report.
:564-593foldToSnapshot has no way to know a read failed, so it publishes.
Suggestion
Report the failure and skip the publish. Only ENOENT is a legitimate quiet case.
// replayOntoSnapshot returns a `problem` when stat/read fail with anything but ENOENTreturn{ registry, offset,problem: `event log unreadable: ${e.code??e.message}`};
...
// foldToSnapshotconst{ registry, offset, problem }=replayOntoSnapshot(snapshot,logPath);if(problem){statvsAnomaly('work-events.fold-skipped',problem,logPath);returnfalse;}
and in readSnapshot, treat a parse error as a problem (anomaly + fold skipped) while ENOENT returns the empty registry. We carry a local patch with this shape for the log; the snapshot side is the same idea. Read, not run.
Activity