Local-first does not mean failure-proof.
A Claude Code or Codex usage scanner can hit a huge embedded payload, a partial JSONL line, or a scan task that never commits. The first problem threatens memory. The last problem can freeze every later refresh behind one boolean.
Use two bounds
line-size policy -> protects memory
scan-age policy -> protects liveness
Do not replace both with one generic timeout.
Line policy comes from the data contract
On macOS, Agent Island's Claude reader streams lines with a 64 MiB backstop. That ceiling is intentionally high because a valid assistant usage event can share a line with a large tool payload.
On Windows, the reader skips lines above one million characters before JSON parsing. It is a stricter filter. The two platforms should not be described as having an identical parser.
After that boundary, the reader keeps only assistant records with a usage object, a real model, a timestamp, and at least one non-zero token field. Stable message and request IDs provide deduplication.
Expire a wedged loading gate
This guard looks harmless:
if loading:
return
If the task never clears loading, all scheduled refreshes return forever.
The released store tracks when a scan started. A gate older than ten minutes is treated as wedged, so a later refresh can start a replacement. macOS keeps separate gates for Claude and Codex; one slow provider does not block the other.
The threshold is a recovery boundary, not a normal performance target.
Protect commit order too
Once replacements are allowed, an older task can finish late and overwrite newer data. The general fix is a generation token: only the latest generation may commit. This is worth testing even if the original incident was only a stuck latch.
I help run Agent Island. The line bounds and ten-minute wedge escape are released in v1.7.1. The full article includes the parser contract and failure-test list:
Top comments (0)