mirror of
https://github.com/AgentSeal/codeburn.git
synced 2026-05-19 16:13:56 +00:00
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.
This commit is contained in:
parent
508edcd62b
commit
b7ad5c5505
4 changed files with 12 additions and 13 deletions
|
|
@ -78,9 +78,9 @@ final class AppDelegate: NSObject, NSApplicationDelegate, NSPopoverDelegate {
|
|||
// regardless of whether the user is currently viewing Today or a
|
||||
// different period / provider.
|
||||
await self.store.refreshQuietly(period: .today)
|
||||
// Refresh the currently-viewed payload. Optimize is fast (~1s warm-cache)
|
||||
// so include findings on every refresh.
|
||||
self.refreshStatusButton()
|
||||
await self.store.refresh(includeOptimize: true)
|
||||
self.refreshStatusButton()
|
||||
try? await Task.sleep(nanoseconds: refreshIntervalNanos)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -388,7 +388,7 @@ program
|
|||
.option('--no-cache', 'Rebuild the parsed source cache for this run')
|
||||
.action(async (opts) => {
|
||||
await loadPricing()
|
||||
const noCache = noCacheRequested(opts)
|
||||
const noCache = noCacheRequested(opts) || opts.format === 'menubar-json'
|
||||
const parseOptions = buildParseOptions(noCache, opts.format === 'terminal')
|
||||
const pf = opts.provider
|
||||
const fp = (p: ProjectSummary[]) => filterProjectsByName(p, opts.project, opts.exclude)
|
||||
|
|
|
|||
|
|
@ -706,11 +706,11 @@ function InteractiveDashboard({ initialProjects, initialPeriod, initialProvider,
|
|||
}
|
||||
}, [findCachedWindow, makeCacheToken, noCache, storeCachedWindow])
|
||||
|
||||
const reloadData = useCallback(async (p: Period, prov: string, options?: { silent?: boolean }) => {
|
||||
const reloadData = useCallback(async (p: Period, prov: string, options?: { silent?: boolean; skipCache?: boolean }) => {
|
||||
const range = getDateRange(p)
|
||||
const request = ++reloadSeqRef.current
|
||||
const token = makeCacheToken(prov, p)
|
||||
const cachedWindow = findCachedWindow(prov, range)
|
||||
const cachedWindow = options?.skipCache ? undefined : findCachedWindow(prov, range)
|
||||
if (!options?.silent) {
|
||||
setOptimizeResult(null)
|
||||
}
|
||||
|
|
@ -835,7 +835,7 @@ function InteractiveDashboard({ initialProjects, initialPeriod, initialProvider,
|
|||
|
||||
useEffect(() => {
|
||||
if (!refreshSeconds || refreshSeconds <= 0) return
|
||||
const id = setInterval(() => { reloadData(period, activeProvider) }, refreshSeconds * 1000)
|
||||
const id = setInterval(() => { reloadData(period, activeProvider, { skipCache: true }) }, refreshSeconds * 1000)
|
||||
return () => clearInterval(id)
|
||||
}, [refreshSeconds, period, activeProvider, reloadData])
|
||||
|
||||
|
|
|
|||
|
|
@ -671,11 +671,6 @@ async function evaluateSourceManifestState(
|
|||
return state
|
||||
}
|
||||
|
||||
const overlap = isManifestDateRangeOverlap(manifestEntry, dateRange)
|
||||
if (overlap === false) {
|
||||
return { source, parserVersion, manifestEntry, action: 'skip', reason: 'range-miss' }
|
||||
}
|
||||
|
||||
if (!manifestEntry.fingerprint || manifestEntry.fingerprintPath !== fingerprintPath) {
|
||||
const state: SourceManifestState = { source, parserVersion, manifestEntry, action: 'refresh', reason: 'fingerprint-miss' }
|
||||
logCacheDebug(source.provider, source.path, state.reason!)
|
||||
|
|
@ -690,6 +685,10 @@ async function evaluateSourceManifestState(
|
|||
}
|
||||
|
||||
if (fingerprintMatches(currentFingerprint, manifestEntry.fingerprint)) {
|
||||
const overlap = isManifestDateRangeOverlap(manifestEntry, dateRange)
|
||||
if (overlap === false) {
|
||||
return { source, parserVersion, manifestEntry, action: 'skip', reason: 'range-miss' }
|
||||
}
|
||||
return { source, parserVersion, manifestEntry, action: 'use-cache', currentFingerprint }
|
||||
}
|
||||
|
||||
|
|
@ -767,7 +766,7 @@ async function refreshClaudeCacheUnit(
|
|||
|
||||
if (state.action === 'use-cache') {
|
||||
const cached = await readSourceCacheEntry(manifest, 'claude', state.source.path, { allowStaleFingerprint: true })
|
||||
if (cached) {
|
||||
if (cached && cached.sessions.length > 0) {
|
||||
addSeenDeduplicationKeysFromSessions(cached.sessions, localSeenMsgIds)
|
||||
return { session: cached.sessions[0] ?? null, wrote: false, refreshed: false }
|
||||
}
|
||||
|
|
@ -969,7 +968,7 @@ async function parseProviderSources(
|
|||
let fullSessions: SessionSummary[] | null = null
|
||||
if (state.action === 'use-cache') {
|
||||
const cached = await readSourceCacheEntry(cacheManifest, providerName, state.source.path, { allowStaleFingerprint: true })
|
||||
if (cached) fullSessions = cached.sessions
|
||||
if (cached && cached.sessions.length > 0) fullSessions = cached.sessions
|
||||
}
|
||||
|
||||
if (!fullSessions) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue