Skip to content

Commit b7ad5c5

Browse files
committed
fix: source cache empty-session poisoning, TUI refresh, menubar stale data
Source cache entries with zero sessions now treated as cache misses instead of serving stale empty data. Date range skip moved after fingerprint check so changed files are never incorrectly excluded. TUI refresh timer bypasses in-memory CachedWindow cache. Menubar-json forces noCache. Swift menubar adds explicit refreshStatusButton calls to avoid observation race.
1 parent 508edcd commit b7ad5c5

4 files changed

Lines changed: 12 additions & 13 deletions

File tree

mac/Sources/CodeBurnMenubar/CodeBurnApp.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,9 +78,9 @@ final class AppDelegate: NSObject, NSApplicationDelegate, NSPopoverDelegate {
7878
// regardless of whether the user is currently viewing Today or a
7979
// different period / provider.
8080
await self.store.refreshQuietly(period: .today)
81-
// Refresh the currently-viewed payload. Optimize is fast (~1s warm-cache)
82-
// so include findings on every refresh.
81+
self.refreshStatusButton()
8382
await self.store.refresh(includeOptimize: true)
83+
self.refreshStatusButton()
8484
try? await Task.sleep(nanoseconds: refreshIntervalNanos)
8585
}
8686
}

src/cli.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -388,7 +388,7 @@ program
388388
.option('--no-cache', 'Rebuild the parsed source cache for this run')
389389
.action(async (opts) => {
390390
await loadPricing()
391-
const noCache = noCacheRequested(opts)
391+
const noCache = noCacheRequested(opts) || opts.format === 'menubar-json'
392392
const parseOptions = buildParseOptions(noCache, opts.format === 'terminal')
393393
const pf = opts.provider
394394
const fp = (p: ProjectSummary[]) => filterProjectsByName(p, opts.project, opts.exclude)

src/dashboard.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -706,11 +706,11 @@ function InteractiveDashboard({ initialProjects, initialPeriod, initialProvider,
706706
}
707707
}, [findCachedWindow, makeCacheToken, noCache, storeCachedWindow])
708708

709-
const reloadData = useCallback(async (p: Period, prov: string, options?: { silent?: boolean }) => {
709+
const reloadData = useCallback(async (p: Period, prov: string, options?: { silent?: boolean; skipCache?: boolean }) => {
710710
const range = getDateRange(p)
711711
const request = ++reloadSeqRef.current
712712
const token = makeCacheToken(prov, p)
713-
const cachedWindow = findCachedWindow(prov, range)
713+
const cachedWindow = options?.skipCache ? undefined : findCachedWindow(prov, range)
714714
if (!options?.silent) {
715715
setOptimizeResult(null)
716716
}
@@ -835,7 +835,7 @@ function InteractiveDashboard({ initialProjects, initialPeriod, initialProvider,
835835

836836
useEffect(() => {
837837
if (!refreshSeconds || refreshSeconds <= 0) return
838-
const id = setInterval(() => { reloadData(period, activeProvider) }, refreshSeconds * 1000)
838+
const id = setInterval(() => { reloadData(period, activeProvider, { skipCache: true }) }, refreshSeconds * 1000)
839839
return () => clearInterval(id)
840840
}, [refreshSeconds, period, activeProvider, reloadData])
841841

src/parser.ts

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -671,11 +671,6 @@ async function evaluateSourceManifestState(
671671
return state
672672
}
673673

674-
const overlap = isManifestDateRangeOverlap(manifestEntry, dateRange)
675-
if (overlap === false) {
676-
return { source, parserVersion, manifestEntry, action: 'skip', reason: 'range-miss' }
677-
}
678-
679674
if (!manifestEntry.fingerprint || manifestEntry.fingerprintPath !== fingerprintPath) {
680675
const state: SourceManifestState = { source, parserVersion, manifestEntry, action: 'refresh', reason: 'fingerprint-miss' }
681676
logCacheDebug(source.provider, source.path, state.reason!)
@@ -690,6 +685,10 @@ async function evaluateSourceManifestState(
690685
}
691686

692687
if (fingerprintMatches(currentFingerprint, manifestEntry.fingerprint)) {
688+
const overlap = isManifestDateRangeOverlap(manifestEntry, dateRange)
689+
if (overlap === false) {
690+
return { source, parserVersion, manifestEntry, action: 'skip', reason: 'range-miss' }
691+
}
693692
return { source, parserVersion, manifestEntry, action: 'use-cache', currentFingerprint }
694693
}
695694

@@ -767,7 +766,7 @@ async function refreshClaudeCacheUnit(
767766

768767
if (state.action === 'use-cache') {
769768
const cached = await readSourceCacheEntry(manifest, 'claude', state.source.path, { allowStaleFingerprint: true })
770-
if (cached) {
769+
if (cached && cached.sessions.length > 0) {
771770
addSeenDeduplicationKeysFromSessions(cached.sessions, localSeenMsgIds)
772771
return { session: cached.sessions[0] ?? null, wrote: false, refreshed: false }
773772
}
@@ -969,7 +968,7 @@ async function parseProviderSources(
969968
let fullSessions: SessionSummary[] | null = null
970969
if (state.action === 'use-cache') {
971970
const cached = await readSourceCacheEntry(cacheManifest, providerName, state.source.path, { allowStaleFingerprint: true })
972-
if (cached) fullSessions = cached.sessions
971+
if (cached && cached.sessions.length > 0) fullSessions = cached.sessions
973972
}
974973

975974
if (!fullSessions) {

0 commit comments

Comments
 (0)