Skip to content

fix(telemetry): cap cli_error per kind per day, flush app_close on quit#746

Merged
iamtoruk merged 1 commit into
getagentseal:mainfrom
ozymandiashh:pr/741-robustness
Jul 18, 2026
Merged

fix(telemetry): cap cli_error per kind per day, flush app_close on quit#746
iamtoruk merged 1 commit into
getagentseal:mainfrom
ozymandiashh:pr/741-robustness

Conversation

@ozymandiashh

Copy link
Copy Markdown
Collaborator

Part of #741 (the cli_error rate-limit and app_close race items). Together with #745 this covers the three remaining items of the ticket (the skills/MCP verification result is in the #741 thread).

cli_error rate limit

One 0.9.15 install emitted 804 timeout cli_error 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 existing telemetry state file (same mechanism as lastSnapshotDay), defensively loaded so malformed or pre-upgrade state files fall back clean, which means app relaunches inside the same day cannot reset the budget (a crash-looping install stays capped). Other event names are unaffected, and the counter never reaches the POST body.

app_close flush race

app_close almost never fired (1 close vs 48 opens): before-quit queued the event and started an async POST that Electron never waited for. The quit path now defers quit exactly once, tracks the close, flushes with a bounded wait (1500ms Promise.race), then quits for real. Hardened after adversarial review:

  • every step of the handler is independently guarded, so a synchronous failure anywhere (child cleanup, telemetry lookup, trackClose) can neither skip the flush nor wedge quitting
  • a full queue (offline all day) evicts its oldest event rather than dropping app_close
  • disabled or not-onboarded telemetry quits instantly, no timeout wait

Validation

  • npx tsc --noEmit clean; both Electron suites green (includes new tests for the cap, day rollover, restart persistence over the same state dir, malformed persisted state, full-queue eviction, hung-endpoint quit bound, no-consent instant quit, and synchronous-failure quit paths).
  • Behavioral spot check: 100 same-kind cli_error events queue exactly 20; a fresh Telemetry instance over the same state dir and day queues 0 more.
  • Privacy invariants untouched: consent gating, sanitizer, day-granularity timestamps, no new fields in the POST body, state file stays 0600.

Two robustness fixes from the getagentseal#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.
@iamtoruk
iamtoruk merged commit d00b33b into getagentseal:main Jul 18, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants