mirror of
https://github.com/AgentSeal/codeburn.git
synced 2026-08-23 15:34:19 +00:00
A lock file whose body never parses — the zero-byte leftover of a crash between open and the body write, or a heartbeat truncated by a full disk — was classified as 'unavailable'. Every later refresh then took the read-only path, permanently. Nothing on the machine repairs that file, so new sessions stopped being ingested, the menubar served the snapshot from before the crash forever, and the only remedy was deleting the lock by hand. Corruption is now its own class. A body that fails to parse is recovered through the unmodified staleness gate, exactly like an abandoned lock: waited out while fresh, because it may belong to a live owner whose heartbeat is about to repair it, then taken over once its mtime ages past the stale window. That bounds the freeze to one stale window instead of forever. 'unavailable' is reserved for locks that genuinely cannot be read. The takeover stability check now compares the raw bytes as well as token and mtime: on filesystems with coarse mtime granularity a live owner's heartbeat can rewrite a body without moving mtime, and token equality alone could not tell "unchanged" from "rewritten". The other half of the freeze was in the daily cache. A timed-out refresh serves the prior snapshot; when anything changed underneath, that snapshot is partial, and finalizing history off it advanced the watermark past days the parse never covered. Since the gap scan starts after the watermark, the hole became invisible to it forever and empty days froze into the trend. The parser now reports a stale read-only serve as an incomplete hydration, and the daily cache refuses to advance its watermark or mark itself complete unless the parse behind it was complete. Caches already corrupted this way heal once: a watermark that outruns its newest populated day is pulled back so the ordinary gap parse re-derives the tail, and a trust stamp keeps a legitimately idle tail from being re-derived on every launch. That covers every file-backed source. The network-backed one (Vercel AI Gateway) cannot be fingerprinted at all, so the staleness signal had to be different: it has no file whose mtime proves the cached rows are current — the report moves on the API's side, and the read-only path must never re-fetch it. A read-only serve of a network source is therefore always unverifiable, and is now always marked stale: it serves the cached rows (the snapshot is what read-only runs are for) but reports an incomplete hydration, so a timed-out refresh can no longer finalize daily history off network totals frozen at an old report. The next full parse re-fetches and advances the watermark. Two satellite fixes ride along. The context budget counted every skill and the home CLAUDE.md twice when the scanned project IS the home directory; dedup is now by resolved path, so a symlinked home is caught too. And the optimize result-cache key was a projection of project count and api-call sum, so any two datasets agreeing on those collided and served stale findings within the TTL; it now folds in cost, savings and proxied cost. Being accurate about that last one: the key is still a projection of five aggregates, so datasets agreeing on all five — same totals, different per-model distribution — can still collide, and the detectors that key off token ratios and tool counts would differ. The 60-second TTL bounds it. The comment says so rather than claiming the collision is closed. |
||
|---|---|---|
| .. | ||
| src | ||
| tests | ||
| package.json | ||
| tsconfig.json | ||
| tsup.config.ts | ||
| vitest.config.ts | ||