Two robustness fixes from the #741 telemetry audit:
- cli_error had no rate limit: one install emitted 804 timeout events in a
single day (56% of all events ever received). track() now caps cli_error
at 20 per kind per calendar day. The day and per-kind counts persist in
the telemetry state file (defensively loaded), so app relaunches within
the same day cannot reset the budget; other event names are unaffected.
- app_close almost never fired (1 close vs 48 opens): the quit path raced
the outbound POST. before-quit now defers quit once, tracks the close and
flushes with a bounded wait (1500ms race), then quits. Every step of the
handler is independently guarded so a synchronous failure can neither
skip the flush nor wedge quitting, and a full queue evicts its oldest
event rather than dropping app_close. Disabled or not-onboarded telemetry
quits instantly.
A 4xx response means the server will never accept that payload;
retrying it wedges the queue at its cap and blocks all newer events.
Drop on 4xx, keep retrying on 5xx and network failures. Matches the
server's validation contract (batch cap 200).
Performance and coherence:
- Settings > General 'Refresh every' (Manual/30s/1m/3m/5m/10m), live via
RefreshCadenceContext; Manual polls only on demand
- usePolled memoKey LRU: provider/period switches paint the last-good
result instantly with a switching hairline while refreshing quietly
- quota TTL 5min + honest rate-limited copy on 429 backoff
- version-suffixed cache files (session-cache.v5.json, daily-cache.v12,
auto-minted on future bumps); legacy files never written or deleted,
adopted once when versions match: old and new binaries coexist
without clobbering (field-observed menubar-vs-desktop ping-pong)
- advisory hydration lock: concurrent cold starts share one scan
(wait-then-read-warm), stale/dead locks self-heal, never a
correctness gate
Telemetry v1 + onboarding (desktop only, per owner decisions):
- first-launch onboarding (3 feature screens + consent); region-split
default (EU/EEA/UK/CH off, elsewhere on, unknown off); nothing sends
before consent completion or while off; dev builds never send
- anonymous install UUID, rotated on opt-out; day-granularity events,
cost buckets only; whitelisted names; 200-event queue, 5min flush
- Settings > Privacy live toggle replaces the static claim
Zero computed-number changes. App 316/316, root 1805.
Wire contract targets api.codeburn.app/v1/telemetry (Worker follows).