P0: an interrupted cold hydration left partial caches that the
emptiness check read as warm — the daily backfill froze (missing older
days) while session parsing healed gradually (drifting totals),
poisoning every surface sharing the cache. Both caches now carry an
explicit complete marker: partial resumes cold under the hydration
lock; unmarked caches self-heal with one re-hydration. Regression test
seeds the exact frozen artifact and asserts bit-for-bit convergence
with a never-interrupted run.
- splash indexing reveals only on genuinely cold scans (explicit cold
flag in the progress protocol), never on warm incremental re-parses
- uncached filter switches clear to skeleton instead of showing the
previous filter's numbers; cached switches paint same-commit;
background prefetch warms every detected provider after idle
- build stamp (git sha + date) in splash and About ends build ambiguity
- payload parity test: identical payloads on identical cache, and
payload totals equal the CLI report path
- Sessions empty state keeps the provider filter row; zero savings
line hidden; TCC usage-description strings + Full Disk Access docs
- warm profile documented: optimize scan ~1.47s dominant (safe
refactor deferred), parse ~1s, aggregation ~30ms
Root 1848, app 320, typechecks clean.
The per-provider ingest list rendered a dozen stacked text rows on
machines with many detected providers. Now one status line with live
tabular-numeral counts (Indexing Claude · 240/699), a single strip of
15px provider logos (dim pending, pulse active, settled done), and a
muted one-time-scan note. ~3 lines of vertical footprint, 340px max
width; reduced motion drops the pulse; warm launches never see it.
Root cause of the field-reported 45s timeout + perpetual slowness: on
a cold cache all six sections spawned different CLI subcommands at
once, each running its own full-history parse (~11-31s, ~3GB RSS),
contending past the 45s kill so the rebuilt cache never persisted and
every poll restarted from zero.
- the first overview fetch runs as a warmup: 10-minute timeout,
re-arms until it succeeds, reverts to 45s after; section polls gate
on that first resolution (usePolled gains enabled), so cold
hydration happens exactly once
- warmup streams the CLI's progress protocol; the splash shows 'First
run: indexing your usage history' with a per-provider ingest list
(logo, live counts, check on done), static under reduced motion,
generic fallback without events; warm launches unchanged
- overview spawns pass --no-timeline (desktop never renders it)
Measured on real data: cold 31s once (was: killed at 45s forever),
warm 2.6s. 295/295 app, 1797 root.
New owner-approved art: the binary-digit flame. Checkerboard keyed out,
largest-component masking to drop glow-zone checker fringe, clean
synthetic ember glow rebuilt; composited to the Big Sur squircle as
app/build/icon.png and squared with alpha as the in-app FlameMark
raster (sidebar, About, static splash).
The supplied burn animation becomes the splash loader: checker keyed
per-frame and the splash's fixed dark canvas (#171310) baked in (h264
has no alpha), audio stripped, 944KB looping video shown while the
first scan runs. Splash canvas and text colors are now theme-fixed so
video and page never diverge; reduced motion/tests keep the static
mark, verified by test.
Flame/splash/motion suites green in isolation (full suite re-verified
when the in-flight quota batch commits); typecheck + build green.
- FlameMark: hand-traced inline SVG of the brand flame (~1.1KB, warm
3-stop gradients, useId-scoped), used at splash and sidebar sizes
- Splash: full-window first-load overlay echoing the menubar's
BurnLoadingOverlay ignite moment; 600ms floor so warm cache never
blinks, 250ms crossfade on first data, instant yield on error or
reduced motion, done-latch so it never reappears
- Sidebar logo replaced with the live FlameMark: 1-2% inner-tongue
flicker, 4.5s period, random phase; static under reduced motion
250/250, build green (+2.4KB JS, +1.8KB CSS).