Commit d07d3b1
feat(usage): default-on telemetry, and the emitters it was missing
Three separate defects, all of which had to be fixed for a single row to
reach production.
1. THE CLIENT FLAG COULD NEVER BE SET
UsageOutbox.isEnabled() read NATIVELY_USAGE_OUTBOX_ENABLED from process.env.
An app launched from the Dock or the Start menu inherits no environment and
nothing in this repo set it, so the outbox shipped inert on 2026-08-14 and
record() returned 'disabled' — the events were never even written locally, so
they are gone rather than undelivered. Polarity is inverted: absent means ON,
an explicit 0/false/off/no disables, and '' reads as absent so a mis-templated
launcher config cannot silently kill it.
Be honest about what that costs: =0 is now reachable only in dev, CI and a
terminal launch, so the client half is NOT a production kill switch and the
docblock that promised "a client can stop emitting without a server change" is
gone. The lever that reaches a shipped fleet is the server's
BYOK_CLIENT_EVENTS_ENABLED=0 → 503, which the outbox retries for ~15 days
rather than acking away. One working lever is enough.
2. operational_telemetry_events HAD ZERO EMITTERS
A migration, a route, an allowlist, a 45-day sweep — and nothing in this
application ever called usageOutbox.recordTelemetry(). runTracked neither calls
tracker.telemetry() nor hands the tracker to the handler. Turning
OPS_TELEMETRY_ENABLED on would have changed nothing, because "enabled" and
"emitting" are different facts and only one had been built.
recordTurnTelemetry(trace) now maps the AnswerTrace the pipeline already
produces, called from recordTurnMetrics() — the one funnel where both engines
hand over a finished trace, so it needs no new instrumentation on the answer
path and cannot miss a surface.
That hook was chosen carefully. recordLegacyTurn() looks live (three call sites
in ipcHandlers and IntelligenceEngine) but is gated on NATIVELY_CI_V3_TRACE,
which a packaged app never sees — an emitter there would have shipped into dead
code, the exact bug this commit exists to fix. recordTurnMetrics is reached via
buildV3Prompt → orchestrate() because DEFAULT_ENABLED has been true since
2026-07-30.
SUPERSEDED maps to 'interrupted', never 'completed': auto-answer supersedes
turns routinely and counting them as completions inflates every rate built on
the table. Metadata is 5 keys with 3 spare under MAX_METADATA_KEYS=8, because
overflow does not strip — the server rejects the whole event and the outbox
then drops it permanently as a poison row. llm_ttfb_ms is named for what the
trace measures (time to first byte), not the llm_duration_ms the migration
comment suggested.
3. recordAppStarted / recordAppShutdown HAD ZERO CALLERS
Both written 2026-08-14, both unreferenced. Wired in main.ts: started once the
outbox is up, shutdown as the FIRST statement in will-quit — ahead of
checkpointDatabase('will-quit'), because record() is a synchronous INSERT into
the file about to be checkpointed and it swallows its own errors, so writing
afterwards would lose the row with no signal. SIGTERM/SIGINT call app.exit()
and bypass will-quit, so a killed app records no shutdown; that is the honest
outcome, not a bug to fix.
KNOWN LIMITATION: the telemetry row and the _tracked() ledger row for one turn
share no feature_session_id — different wrappers. Correlate on time plus
app_session_id until that matters enough to thread an id.
TESTING. UsageTelemetryEmission.test.mjs imports natively-api's REAL
validateAuditBatch and asserts every emitted payload is accepted: the two
allowlists live in different repos and drift, and a refused event is dropped
rather than retried. Mutation-probed — injecting a prose metadata value turns
it red with metadata_bad_value. It is a separate FILE because the emitter
reaches DatabaseManager through the bundle inlined into usageInstrumentation.js,
which holds its own per-process singleton; sharing a process meant earlier
describes deleted the userData dir out from under it and every assertion read
zero rows.
Verified on macOS: 30/30 UsageOutbox + 12/12 UsageTelemetryEmission under
ELECTRON_RUN_AS_NODE=1 electron, 1897/1897 test:intelligence, typecheck clean.
No process.platform branch exists in this path (it appears once, as a data
field), but the packaged-launch environment and the Windows shutdown path were
reviewed, not executed.
Submodule: natively-api 6217f1f..35e5a4d (the three server flags, same
polarity).
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013FjZgLYK8eDRv9zRMBVLVS1 parent 95fdc24 commit d07d3b1
7 files changed
Lines changed: 581 additions & 10 deletions
File tree
- electron
- context-intelligence/observability
- services
- __tests__
Lines changed: 14 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
127 | 127 | | |
128 | 128 | | |
129 | 129 | | |
| 130 | + | |
| 131 | + | |
| 132 | + | |
| 133 | + | |
| 134 | + | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
| 140 | + | |
| 141 | + | |
| 142 | + | |
| 143 | + | |
130 | 144 | | |
131 | 145 | | |
132 | 146 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
8425 | 8425 | | |
8426 | 8426 | | |
8427 | 8427 | | |
8428 | | - | |
8429 | | - | |
8430 | | - | |
| 8428 | + | |
| 8429 | + | |
| 8430 | + | |
| 8431 | + | |
| 8432 | + | |
| 8433 | + | |
| 8434 | + | |
| 8435 | + | |
| 8436 | + | |
8431 | 8437 | | |
8432 | 8438 | | |
8433 | 8439 | | |
8434 | 8440 | | |
8435 | 8441 | | |
8436 | 8442 | | |
| 8443 | + | |
| 8444 | + | |
| 8445 | + | |
| 8446 | + | |
| 8447 | + | |
| 8448 | + | |
| 8449 | + | |
| 8450 | + | |
| 8451 | + | |
8437 | 8452 | | |
8438 | 8453 | | |
8439 | 8454 | | |
| |||
8992 | 9007 | | |
8993 | 9008 | | |
8994 | 9009 | | |
| 9010 | + | |
| 9011 | + | |
| 9012 | + | |
| 9013 | + | |
| 9014 | + | |
| 9015 | + | |
| 9016 | + | |
| 9017 | + | |
| 9018 | + | |
| 9019 | + | |
| 9020 | + | |
| 9021 | + | |
| 9022 | + | |
8995 | 9023 | | |
8996 | 9024 | | |
8997 | 9025 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
32 | 32 | | |
33 | 33 | | |
34 | 34 | | |
35 | | - | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
36 | 38 | | |
37 | 39 | | |
38 | 40 | | |
| |||
93 | 95 | | |
94 | 96 | | |
95 | 97 | | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
96 | 113 | | |
97 | 114 | | |
98 | 115 | | |
| |||
143 | 160 | | |
144 | 161 | | |
145 | 162 | | |
146 | | - | |
147 | | - | |
148 | | - | |
| 163 | + | |
| 164 | + | |
| 165 | + | |
| 166 | + | |
| 167 | + | |
| 168 | + | |
| 169 | + | |
| 170 | + | |
| 171 | + | |
| 172 | + | |
| 173 | + | |
| 174 | + | |
| 175 | + | |
| 176 | + | |
| 177 | + | |
149 | 178 | | |
150 | 179 | | |
151 | | - | |
152 | | - | |
| 180 | + | |
153 | 181 | | |
154 | 182 | | |
155 | 183 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
400 | 400 | | |
401 | 401 | | |
402 | 402 | | |
| 403 | + | |
| 404 | + | |
| 405 | + | |
| 406 | + | |
| 407 | + | |
| 408 | + | |
| 409 | + | |
| 410 | + | |
| 411 | + | |
| 412 | + | |
| 413 | + | |
| 414 | + | |
| 415 | + | |
| 416 | + | |
| 417 | + | |
| 418 | + | |
| 419 | + | |
| 420 | + | |
| 421 | + | |
| 422 | + | |
| 423 | + | |
| 424 | + | |
| 425 | + | |
| 426 | + | |
| 427 | + | |
| 428 | + | |
| 429 | + | |
| 430 | + | |
| 431 | + | |
| 432 | + | |
| 433 | + | |
| 434 | + | |
| 435 | + | |
| 436 | + | |
| 437 | + | |
| 438 | + | |
| 439 | + | |
| 440 | + | |
| 441 | + | |
| 442 | + | |
| 443 | + | |
| 444 | + | |
| 445 | + | |
| 446 | + | |
| 447 | + | |
| 448 | + | |
| 449 | + | |
| 450 | + | |
| 451 | + | |
| 452 | + | |
| 453 | + | |
| 454 | + | |
| 455 | + | |
| 456 | + | |
| 457 | + | |
| 458 | + | |
| 459 | + | |
| 460 | + | |
| 461 | + | |
| 462 | + | |
| 463 | + | |
| 464 | + | |
| 465 | + | |
| 466 | + | |
| 467 | + | |
| 468 | + | |
| 469 | + | |
| 470 | + | |
| 471 | + | |
| 472 | + | |
| 473 | + | |
| 474 | + | |
| 475 | + | |
| 476 | + | |
| 477 | + | |
| 478 | + | |
| 479 | + | |
| 480 | + | |
| 481 | + | |
| 482 | + | |
| 483 | + | |
| 484 | + | |
| 485 | + | |
| 486 | + | |
0 commit comments