OpenEval v0.1.2 is a performance, stability, and dashboard-UX release. At ~1,300 local sessions, warm Collection loads drop from ~2.3 s to ~0.15 s, idle Live polls shrink from ~2.3 MB to 71 bytes, and the Collection table can now browse the entire session history instead of the newest 80.
Performance
- One shared full-history parse + fingerprint cache — Collection, home, and Timeline used to run three independent full-history parses per page load; they now share a single pass, and a corpus fingerprint (per-file path/mtime/size from the discovery walk) serves warm loads without re-parsing at all. Warm
/collection~2.34 s → ~0.15 s, home ~1.63 s → ~0.1 s; Rescan revalidates the fingerprint instead of forcing a recompute. (#32) - Live parser fast paths — strict ISO-timestamp fast path, single-pass token sets, cursor line scanning: claude-format corpora parse 11–22% faster, codex 7–17%, with byte-identical output (116/116 sha256-verified corpora + 700k-string fuzz). (#26)
- Scan pipeline — archived-session merge reads went from 144.9 ms to 8.1 ms (17.8×) via a paths-first two-step read; prepared-statement cache in the SQLite layer; in-process session cache upgraded to a 4,000-entry LRU; one stat per file and one directory walk per pass, now shared between discovery and the recompute path. (#26, #35)
- aggregate() single pass — fourteen full-array filter passes folded into the main loop plus a per-call pricing memo; warm scan path 7–16% faster. (#28)
- Pricing memo at the source — model→rate resolution memoized inside
lib/pricing.ts(~8×: 26.3 → 3.2 ms per 100k lookups), covering every hot caller. (#34) - Timeline & judge insights — binary-search marker windows and sliding-window medians: impact stage 43–63 ms → ~4 ms, metric series ~10×, judge window sampling 171 ms → 1.9 ms on a 50k-point stress corpus. (#31, #33)
- Live polling — a content signature lets unchanged 10-second polls return a 71-byte response instead of the full ~2.3 MB payload; per-session reference identity is preserved across polls so unchanged rows skip re-rendering, and the redundant mount poll is gone. (#30)
Stability
- Transient filesystem errors during a parse are no longer cached as permanent null tombstones — previously a session could silently vanish from every dashboard until its file changed. (#26)
- Torn or garbage cache rows now read as misses instead of crashing consumers, and a corrupt live-cache DB is renamed aside and rebuilt automatically. (#26)
- Four flaky tests pinned (week-boundary clock, killed-run settings poison, pid-reuse workdirs, shared test-DB races) and the live API tests are now isolated from the operator's home directories. (#26, #36)
Dashboard UX
- Loading skeletons for every primary route — navigation no longer freezes on the previous page while a scan runs — and error boundaries for
/collectionand/collection/timeline, which previously rendered silent zeros on scan failure. (#27) - Collection sessions table: load-more through the full history (limit-aware retention replaces the old per-source 100-session cap — all ~1,300 sessions reachable), sort pills, harness/model filters, a prominent error banner, and a "scanned Xs ago" freshness indicator. (#29, #35)
- Live: "updated Xs ago" indicator and flicker-free polling. (#30)
Verification
Every performance change shipped with byte-identical output-equivalence proof (sha256 over golden corpora, scan-layer hash gates, differential fuzzing), the full node:test suite (297 tests), zero-warning lint, and end-to-end route checks against a real ~1,300-session corpus.
Known note: the bundled OpenRouter pricing catalog has drifted for three models since 2026-07-15 (glm-5.2, deepseek-v4-flash, kimi-k2.7-code). Refreshing rates changes inferred cost estimates, so it is deferred to a deliberate follow-up rather than bundled into equivalence-gated changes.
Full changelog: v0.1.1...v0.1.2