Problem
Cache writes are correctly atomic (temp file, fsync, rename), but nothing coordinates across processes. daily-cache serializes only in-process via a promise chain (src/daily-cache.ts:184-190); session-cache, cursor-cache, and codex-cache do read-mutate-rename with no lockfile. CodeBurn deliberately runs as several concurrent processes: CLI, menubar refresh (every 30s), the guard statusline daemon, and the MCP server. Last-writer-wins means a full parse can overwrite a concurrent incremental append; nothing corrupts, but both processes re-parse next run. It is an invisible throughput tax that peaks exactly when the tool is used most, and it can make first-paint feel slow for no visible reason.
Evidence
- src/daily-cache.ts:184-190 (in-process lock chain only)
- No O_EXCL/flock usage in src/session-cache.ts or src/daily-cache.ts; the only lockfile in the repo is src/act/journal.ts:56.
- Verified on main at 1a75484.
Proposed fix
Reuse the act journal's lockfile pattern: acquire an O_EXCL lockfile with a stale-lock timeout around saveCache/saveDailyCache (and optionally around the expensive parse itself so concurrent processes share one result instead of racing). The orphaned-temp GC already in session-cache.ts is the model for stale-lock cleanup.
Problem
Cache writes are correctly atomic (temp file, fsync, rename), but nothing coordinates across processes. daily-cache serializes only in-process via a promise chain (src/daily-cache.ts:184-190); session-cache, cursor-cache, and codex-cache do read-mutate-rename with no lockfile. CodeBurn deliberately runs as several concurrent processes: CLI, menubar refresh (every 30s), the guard statusline daemon, and the MCP server. Last-writer-wins means a full parse can overwrite a concurrent incremental append; nothing corrupts, but both processes re-parse next run. It is an invisible throughput tax that peaks exactly when the tool is used most, and it can make first-paint feel slow for no visible reason.
Evidence
Proposed fix
Reuse the act journal's lockfile pattern: acquire an O_EXCL lockfile with a stale-lock timeout around saveCache/saveDailyCache (and optionally around the expensive parse itself so concurrent processes share one result instead of racing). The orphaned-temp GC already in session-cache.ts is the model for stale-lock cleanup.