🤖 feat: emit compaction_completed telemetry #1201
Merged
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.
Backend now emits a
compaction_completedtelemetry event (PostHog) after successful history compaction, including privacy-preserving (base-2 rounded) token bucket metrics.Also adds typed payload + oRPC schema validation and unit coverage for the backend emission.
📋 Implementation Plan
🤖 Compaction completed telemetry (PostHog)
Goals
Non-goals (for this change)
Recommended approach (backend-only capture in
CompactionHandler.handleCompletion())Why: Compaction already happens in the main process, and you explicitly want the backend to be the sole emitter (no renderer dependency).
Net new LoC (product code): ~120–180
1) Define a new telemetry event payload (transparency + typing)
Add a new payload type + union member:
src/common/telemetry/payload.tsexport interface CompactionCompletedPayload { ... }TelemetryEventPayloadwith:{ event: "compaction_completed"; properties: CompactionCompletedPayload }Suggested properties (privacy-preserving, base-2 rounded):
model: stringduration_b2: number(seconds)input_tokens_b2: number(proxy for pre-compaction history size)output_tokens_b2: number(proxy for post-compaction history size)compaction_source: "manual" | "idle"Token source of truth: prefer provider-reported usage from the compaction stream metadata (same tokenizer/model as the compaction):
inputTokens=event.metadata.contextUsage?.inputTokens ?? event.metadata.usage?.inputTokens ?? 0outputTokens=event.metadata.contextUsage?.outputTokens ?? event.metadata.usage?.outputTokens ?? 02) Keep Zod telemetry schema in sync (even if the renderer never emits this event)
src/common/orpc/schemas/telemetry.tsCompactionCompletedPropertiesSchema{ event: z.literal("compaction_completed"), properties: ... }toTelemetryEventSchema3) Emit from the backend after successful compaction
src/node/services/compactionHandler.tsCompactionHandlerOptionswith optionaltelemetryService?: TelemetryService.performCompaction(...)succeeds (and after the dedupe check), call:telemetryService?.capture({ event: "compaction_completed", properties: { ... } })roundToBase2(src/common/telemetry/utils.ts).compaction_sourceshould be derived from the already-existingisIdleCompactioncheck.processedCompactionRequestIds).Wire the TelemetryService through:
WorkspaceService→new AgentSession({ telemetryService: ... })AgentSession→new CompactionHandler({ telemetryService: ... })Alternative approach (renderer-emitted) — NOT recommended per requirements
The existing telemetry pipeline is renderer → oRPC → backend → PostHog. While that’s usually fine (and still avoids classic adblocker problems because it’s not PostHog JS), you explicitly want only backend emission, so this plan does not rely on
trackEvent()from the renderer.Tests + validation
Unit tests (recommended): extend
src/node/services/compactionHandler.test.tstelemetryServicewith a spycapture().compaction_completedis captured exactly once on successful compaction.Repo checks:
make fmt-check && make lint && make typecheck && make testManual smoke test:
MUX_ENABLE_TELEMETRY_IN_DEV=1./compact.compaction_completedappears in PostHog with rounded properties.PostHog: create dashboard + insights (via MCP tools)
Net new LoC (product code): 0 (PostHog objects only)
1) Identify the correct PostHog org/project
Use the MCP tools to confirm we’re operating in the PostHog project that receives mux telemetry:
posthog_organizations-getposthog_projects-get2) Create a dashboard
posthog_dashboard-createwith:name:Mux • Compactiondescription:Compaction completion volume and effectivenesspinned:true(optional)tags:["mux", "compaction"]3) Create insights (query-run → create → attach to dashboard)
For each insight:
posthog_query-run(validate the query returns successfully)posthog_insight-create-from-queryposthog_insight-updateto attach it to the new dashboard (setdashboard: <id>)Suggested insights:
compaction_completed(last 30 days)compaction_completedbycompaction_source(manual vs idle)modelandcompaction_sourceExample HogQL for the effectiveness table
4) Verify dashboard wiring
posthog_dashboard-get(ensure the dashboard exists)posthog_insight-queryfor each insight (ensure the query executes; it may legitimately be empty until events arrive)Future follow-ups (not in scope)
ExperimentsService), then record survey answers to PostHog as a separate event.Generated with
mux• Model:openai:gpt-5.2• Thinking:high