feat(console): give connector events a failure reason and a duration - #488
Open
christian-mcdermott wants to merge 1 commit into
Open
christian-mcdermott wants to merge 1 commit into
christian-mcdermott wants to merge 1 commit into
Conversation
`connector_installed` carried an outcome and no reason, so a failed connector install was a bare count with nothing to act on — the one event of its kind in the catalogue without a `failure_reason`, and the underlying `SwitchSetupResult` carries only a message, which cannot be sent. Add `TelemetryConnectorFailure`, named at the point of failure rather than mapped from an error type. The codes separate walls that need different fixes: a marketplace that will not register, a host CLI that refuses the plugin, and the app's own file writing. The reinstall split is the one that matters most — Codex has no update verb, so an update is remove-then-add, and `was_reinstall` is true for both halves. It cannot tell "nothing changed" from "the agent now has no connector at all"; `uninstall_command_failed` vs `install_command_failed` can. Add `duration_ms` to the three connector events and to `agent_cli_action`, where a CLI install taking four minutes and one taking ten seconds were otherwise the same row. Measured on a monotonic clock so a clock step cannot yield a negative duration, in whole milliseconds, and deliberately uncapped: a capped duration is a number the operation did not take. Timed around the operation alone, excluding manager and SSH resolution, so the first measurement of a session is not systematically different from the rest. Along the way: - `connector_installed` uses `agentTypeOf()` like its siblings rather than an inline `isValidProviderId` ternary. - `runFiles` folds resolving into its own try on both drivers, which deletes the duplicated guard in `runInstall` and fixes `update` and `uninstall` on a files connector with no behavior — those threw out to the UI as a stack with nothing reported. - Remote's `resolveFiles` carries the connector version like local's, removing three `connectorVersion()` call sites. - The consent copy gains a line. Widening what is sent is a consent decision, not a code change. - `sentAttributes()` in the telemetry service test read only `stringValue`, so every number and boolean in a payload read back as `undefined` — an assertion that a numeric property was carried would have passed against a payload that dropped it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Two gaps in the Console's product events, both in the same area:
connector_installedhad an outcome and no reason. A failed connector install was a bare count with nothing to act on — the only action event of its kind in the catalogue without afailure_reason(compareagent_cli_action,agent_created,bridge_connected).TelemetryConnectorFailureNamed at the point of failure rather than mapped from an error type: these paths only produce a message, and a message cannot be sent.
noneunsupportedmarketplace_failedinstall_command_failedupdate_command_faileduninstall_command_failedfiles_write_failedfiles_unimplementedkind: 'files'and implements no behaviorerrorThe reinstall split is the one worth reviewing. Codex has no update verb, so an update is remove-then-add and
was_reinstallis true for both halves. It cannot tell "nothing changed" from "the agent now has no connector at all" —uninstall_command_failedvsinstall_command_failedcan, and that is the difference between a no-op and a broken agent.The codes also separate the two kinds of connector, which was the original question behind this change. A marketplace-driven host (Claude Code, Codex) and one whose connector the app writes (OpenCode) fail in entirely different places.
agent_typeimplies which today, 1:1 — but that mapping is a dashboard convention that breaks silently the day a secondfileshost lands, and the failure codes do not depend on it.duration_msOn the three connector events and on
agent_cli_action, where a CLI install taking four minutes and one taking ten seconds were otherwise the same row.performance.now(), notDate.now()— monotonic, so an NTP step or a machine waking mid-install cannot produce a negative duration or an hour that never passed. A negative number in a payload is worse than no number: nothing at the far end can tell it from real data.Nothing free-text, no new identifier: an elapsed time at this resolution names no path, host or command. The consent copy gains a line anyway —
console/AGENTS.mdtreats widening what is sent as a consent decision rather than a code change.Also in here
connector_installedusesagentTypeOf()like its siblings instead of an inlineisValidProviderIdternary.runFilesfolds resolving into its own try on both drivers. That deletes the duplicated guard inrunInstalland fixes a real bug:updateanduninstallon a files connector with no behavior threw out to the UI as a stack trace with nothing reported. Onlyinstallwas guarded.resolveFilescarries the connector version like local's, removing threeconnectorVersion()call sites.sentAttributes()in the telemetry service test read onlystringValue, so every number and boolean in a payload read back asundefined— an assertion that a numeric property was carried would have passed against a payload that dropped it. Now unwraps all three OTLP shapes.Testing
New
why a connector operation failedblock pinning each code, including both halves of the reinstall split;duration.test.ts; and the existing event assertions updated.pnpm run format,lint,typecheckandvitest --project node --project main-dbare clean. Three test failures and a handful of typecheck errors remain — all reproduce on untouchedmain(session-spawner,sidecar-runtime,room-connection;js-yamltypes,reapOrphanedRuntimes,onRoomRejected).Not in scope
catchUpConnectorscallsswitchSetupService.update(), so the automatic once-per-install catch-up emitsconnector_updatedindistinguishably from someone pressing Update. That predates this change, butduration_msmakes it worse — background catch-ups will skew the distribution and the failure counts. The catalogue already has the pattern for it (TelemetryAgentRemoveTrigger, which exists for exactly this reason); atrigger: 'user' | 'catch_up'would sort it. Happy to add it here or separately.Unrelated to #487, which defines a catalogue for the core server's own (not-yet-built) telemetry path. This is Console-side only.
🤖 Generated with Claude Code