Skip to content

feat(cymbal): add remote symbol resolution via gRPC service#60289

Merged
hpouillot merged 18 commits into
masterfrom
hp/cymbal-resolution
Jun 1, 2026
Merged

feat(cymbal): add remote symbol resolution via gRPC service#60289
hpouillot merged 18 commits into
masterfrom
hp/cymbal-resolution

Conversation

@hpouillot
Copy link
Copy Markdown
Contributor

@hpouillot hpouillot commented May 27, 2026

Problem

Cymbal currently runs symbol resolution inline on every event. That couples ingestion throughput to symbol-store I/O, makes warm caches pod-local rather than team-local, and prevents scaling resolution independently of the rest of the pipeline.

Changes

Introduces a standalone cymbal-resolution gRPC service and wires cymbal to call it. Five things:

  1. New cymbal-resolution service + cymbal.resolution.v1 proto contractResolve (server-streaming items + terminal BatchSummary) and Subscribe (long-lived load-event bus). Reuses cymbal's resolver stack via a new narrow constructor that connects only to Postgres and S3 — no Kafka, Redis, or signals
  2. Caller-owned endpoint pool with per-team rendezvous routing — DNS-driven reconciliation, per-attempt rotation for retries, exponential backoff with jitter, pool_empty consumes the retry budget so transient all-pods-degraded windows don't kill the batch
  3. Snapshot-required routing driven by the Subscribe stream — a pod is routable only when its server-reported LoadEvent is fresh AND not degraded/draining. No caller-side load-guess fallback. Freshness window derived from the subscription tick (twice the cadence)
  4. Server-driven batch sizingLoadEvent.suggested_max_batch_items lets the server tell callers how to chunk; client takes min(server suggestion, config ceiling). Chunking is event-atomic (an event's exceptions are never split across chunks)
  5. All-or-nothing data integrity + safe rollout default — per-item Error outcomes, missing BatchSummary, or any client-side parse failure fail the batch loudly (no silent passthrough of unresolved exceptions). Rollout gated by CYMBAL_REMOTE_RESOLUTION_ENABLED (false default) and SAMPLE_RATE (0.0 default), so flipping the enable flag alone is a no-op

Minimal observability surface (10 metrics, deliberately scoped) and a README per crate.

How did you test this code?

I'm an agent. Only automated tests below were run by me; no manual production testing.

  • 105 cymbal lib + 5 cymbal-resolution lib + 5 cymbal-proto contract tests pass
  • Integration suites all green: remote_resolution.rs (20), remote_resolution_hardening.rs (9 — connection refused, mid-stream interruption, missing items, no-summary truncation, per-item-error all-or-nothing, draining pool, cancellation), remote_resolution_parity.rs (2 — local vs remote produce identical output), remote_resolution_subscribe.rs (1 — load-driven routing), service_tests.rs (19 — end-to-end Resolve/Subscribe, accounting invariants)
  • cargo clippy clean on touched code

Publish to changelog?

no

🤖 Agent context

Authored with Claude Code across several iterative passes — initial assembly, then multi-agent code-quality/efficiency review, retry hardening, silent-truncation fix, data-flow refactor (typed RemoteChunk owning its events; replaced index bookkeeping + Option<>/mem::replace mutation), startup-time scoping (cymbal-resolution no longer connects to Kafka/Redis).

Decisions worth flagging:

  • All-or-nothing per-batch failure is intentionally strict for v1 — one corrupt event fails the whole cymbal batch (typically ≤100 events). Documented in code as "Revisit when partial-failure semantics are agreed"
  • Per-team routing trades older symbol-set / debug-image locality for one-team-one-pod affinity with degraded-driven spillover
  • SAMPLE_RATE=0.0 default makes ENABLED=true a no-op until rollout is ramped explicitly; dev script overrides to 1.0 so local exercises the path

Requires human review before merging.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 27, 2026

🎭 Playwright didn't run on this PR — your changes touch code that could affect E2E behavior, but Playwright is opt-in via label now to keep CI cost down.

Add the run-playwright label if you want an E2E sweep before merging — CI will pick it up automatically.

Most PRs don't need this. Real regressions still get caught on master and fix-forward.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 27, 2026

Size Change: 0 B

Total Size: 80.8 MB

ℹ️ View Unchanged
Filename Size
frontend/dist-report/decompression-worker/src/scenes/session-recordings/player/snapshot-processing/decompressionWorker 2.85 kB
frontend/dist-report/exporter/_chunks/chunk 8.43 MB
frontend/dist-report/exporter/_parent/products/actions/frontend/pages/Action 25 kB
frontend/dist-report/exporter/_parent/products/actions/frontend/pages/Actions 1.33 kB
frontend/dist-report/exporter/_parent/products/ai_observability/frontend/AIObservabilityScene 118 kB
frontend/dist-report/exporter/_parent/products/ai_observability/frontend/AIObservabilitySessionScene 19.8 kB
frontend/dist-report/exporter/_parent/products/ai_observability/frontend/AIObservabilityTraceScene 130 kB
frontend/dist-report/exporter/_parent/products/ai_observability/frontend/AIObservabilityUsers 872 B
frontend/dist-report/exporter/_parent/products/ai_observability/frontend/clusters/AIObservabilityClusterScene 21.7 kB
frontend/dist-report/exporter/_parent/products/ai_observability/frontend/clusters/AIObservabilityClustersScene 55.1 kB
frontend/dist-report/exporter/_parent/products/ai_observability/frontend/datasets/AIObservabilityDatasetScene 21 kB
frontend/dist-report/exporter/_parent/products/ai_observability/frontend/datasets/AIObservabilityDatasetsScene 3.64 kB
frontend/dist-report/exporter/_parent/products/ai_observability/frontend/evaluations/AIObservabilityEvaluation 59.9 kB
frontend/dist-report/exporter/_parent/products/ai_observability/frontend/evaluations/AIObservabilityEvaluationsScene 28.2 kB
frontend/dist-report/exporter/_parent/products/ai_observability/frontend/evaluations/EvaluationTemplates 915 B
frontend/dist-report/exporter/_parent/products/ai_observability/frontend/LLMASessionFeedbackDisplay 5.19 kB
frontend/dist-report/exporter/_parent/products/ai_observability/frontend/playground/AIObservabilityPlaygroundScene 37.8 kB
frontend/dist-report/exporter/_parent/products/ai_observability/frontend/prompts/LLMPromptScene 29.2 kB
frontend/dist-report/exporter/_parent/products/ai_observability/frontend/prompts/LLMPromptsScene 4.83 kB
frontend/dist-report/exporter/_parent/products/ai_observability/frontend/skills/LLMSkillScene 929 B
frontend/dist-report/exporter/_parent/products/ai_observability/frontend/skills/LLMSkillsScene 946 B
frontend/dist-report/exporter/_parent/products/ai_observability/frontend/tags/AIObservabilityTag 27.4 kB
frontend/dist-report/exporter/_parent/products/ai_observability/frontend/tags/AIObservabilityTagsScene 7.31 kB
frontend/dist-report/exporter/_parent/products/business_knowledge/frontend/scenes/BusinessKnowledgeScene 19 kB
frontend/dist-report/exporter/_parent/products/conversations/frontend/components/Assignee/CyclotronJobInputAssignee 1.67 kB
frontend/dist-report/exporter/_parent/products/conversations/frontend/components/SlaBusinessHours/CyclotronJobInputBusinessHours 3.06 kB
frontend/dist-report/exporter/_parent/products/conversations/frontend/components/TicketTags/CyclotronJobInputTicketTags 1.06 kB
frontend/dist-report/exporter/_parent/products/conversations/frontend/scenes/settings/SupportSettingsScene 1.82 kB
frontend/dist-report/exporter/_parent/products/conversations/frontend/scenes/ticket/SupportTicketScene 33.9 kB
frontend/dist-report/exporter/_parent/products/conversations/frontend/scenes/tickets/SupportTicketsScene 1.07 kB
frontend/dist-report/exporter/_parent/products/customer_analytics/frontend/CustomerAnalyticsScene 53.1 kB
frontend/dist-report/exporter/_parent/products/customer_analytics/frontend/scenes/CustomerAnalyticsConfigurationScene/CustomerAnalyticsConfigurationScene 2.65 kB
frontend/dist-report/exporter/_parent/products/customer_analytics/frontend/scenes/CustomerJourneyBuilderScene/CustomerJourneyBuilderScene 2.18 kB
frontend/dist-report/exporter/_parent/products/customer_analytics/frontend/scenes/CustomerJourneyTemplatesScene/CustomerJourneyTemplatesScene 7.86 kB
frontend/dist-report/exporter/_parent/products/data_warehouse/DataWarehouseScene 46.8 kB
frontend/dist-report/exporter/_parent/products/data_warehouse/frontend/scenes/NewSourceScene/NewSourceScene 1.12 kB
frontend/dist-report/exporter/_parent/products/data_warehouse/frontend/scenes/SchemaScene/SchemaScene 24.4 kB
frontend/dist-report/exporter/_parent/products/data_warehouse/frontend/scenes/SourceScene/SourceScene 1.06 kB
frontend/dist-report/exporter/_parent/products/data_warehouse/frontend/scenes/SourcesScene/SourcesScene 6.31 kB
frontend/dist-report/exporter/_parent/products/deployments/frontend/Deployment 4.05 kB
frontend/dist-report/exporter/_parent/products/deployments/frontend/DeploymentProject 5.58 kB
frontend/dist-report/exporter/_parent/products/deployments/frontend/Deployments 9.31 kB
frontend/dist-report/exporter/_parent/products/early_access_features/frontend/EarlyAccessFeature 1.02 kB
frontend/dist-report/exporter/_parent/products/early_access_features/frontend/EarlyAccessFeatures 3.24 kB
frontend/dist-report/exporter/_parent/products/endpoints/frontend/EndpointScene 40.6 kB
frontend/dist-report/exporter/_parent/products/endpoints/frontend/EndpointsScene 24.5 kB
frontend/dist-report/exporter/_parent/products/error_tracking/frontend/scenes/ErrorTrackingFingerprintsScene/ErrorTrackingIssueFingerprintsScene 7.41 kB
frontend/dist-report/exporter/_parent/products/error_tracking/frontend/scenes/ErrorTrackingIssueScene/ErrorTrackingIssueScene 104 kB
frontend/dist-report/exporter/_parent/products/error_tracking/frontend/scenes/ErrorTrackingScene/ErrorTrackingScene 27.1 kB
frontend/dist-report/exporter/_parent/products/feature_flags/frontend/FeatureFlagTemplatesScene 7.38 kB
frontend/dist-report/exporter/_parent/products/games/368Hedgehogs/368Hedgehogs 5.61 kB
frontend/dist-report/exporter/_parent/products/games/FlappyHog/FlappyHog 6.12 kB
frontend/dist-report/exporter/_parent/products/legal_documents/frontend/scenes/LegalDocumentNewScene 59.7 kB
frontend/dist-report/exporter/_parent/products/legal_documents/frontend/scenes/LegalDocumentsScene 5.31 kB
frontend/dist-report/exporter/_parent/products/links/frontend/LinkScene 25.2 kB
frontend/dist-report/exporter/_parent/products/links/frontend/LinksScene 4.55 kB
frontend/dist-report/exporter/_parent/products/live_debugger/frontend/LiveDebugger 19.5 kB
frontend/dist-report/exporter/_parent/products/logs/frontend/LogsScene 17.9 kB
frontend/dist-report/exporter/_parent/products/logs/frontend/scenes/LogsAlertDetailScene/LogsAlertDetailScene 17.3 kB
frontend/dist-report/exporter/_parent/products/logs/frontend/scenes/LogsSamplingDetailScene/LogsSamplingDetailScene 5.3 kB
frontend/dist-report/exporter/_parent/products/logs/frontend/scenes/LogsSamplingNewScene/LogsSamplingNewScene 2.25 kB
frontend/dist-report/exporter/_parent/products/managed_migrations/frontend/ManagedMigration 14.9 kB
frontend/dist-report/exporter/_parent/products/mcp_analytics/frontend/MCPAnalyticsScene 40.5 kB
frontend/dist-report/exporter/_parent/products/mcp_analytics/frontend/MCPAnalyticsToolDetail 18.5 kB
frontend/dist-report/exporter/_parent/products/metrics/frontend/MetricsScene 16.2 kB
frontend/dist-report/exporter/_parent/products/product_analytics/frontend/insights/stickiness/StickinessBarChart/StickinessBarChart 3.31 kB
frontend/dist-report/exporter/_parent/products/product_analytics/frontend/insights/stickiness/StickinessLineChart/StickinessLineChart 3.14 kB
frontend/dist-report/exporter/_parent/products/product_analytics/frontend/insights/trends/TrendsBarChart/TrendsBarChart 7.36 kB
frontend/dist-report/exporter/_parent/products/product_analytics/frontend/insights/trends/TrendsLifecycleChart/TrendsLifecycleChart 4.41 kB
frontend/dist-report/exporter/_parent/products/product_analytics/frontend/insights/trends/TrendsLineChart/TrendsLineChart 4.6 kB
frontend/dist-report/exporter/_parent/products/product_analytics/frontend/insights/trends/TrendsPieChart/TrendsPieChart 4.35 kB
frontend/dist-report/exporter/_parent/products/replay_vision/frontend/observations/ReplayObservation 8.14 kB
frontend/dist-report/exporter/_parent/products/replay_vision/frontend/replay_scanners/ReplayScanner 34 kB
frontend/dist-report/exporter/_parent/products/replay_vision/frontend/replay_scanners/ReplayScannersScene 11.6 kB
frontend/dist-report/exporter/_parent/products/replay_vision/frontend/replay_scanners/ScannerTemplatesScene 4.59 kB
frontend/dist-report/exporter/_parent/products/revenue_analytics/frontend/RevenueAnalyticsScene 26.5 kB
frontend/dist-report/exporter/_parent/products/session_summaries/frontend/SessionGroupSummariesTable 5.05 kB
frontend/dist-report/exporter/_parent/products/session_summaries/frontend/SessionGroupSummaryScene 19.2 kB
frontend/dist-report/exporter/_parent/products/tasks/frontend/SlackTaskContextScene 8.88 kB
frontend/dist-report/exporter/_parent/products/tasks/frontend/TaskDetailScene 23.8 kB
frontend/dist-report/exporter/_parent/products/tasks/frontend/TaskTracker 14.6 kB
frontend/dist-report/exporter/_parent/products/tracing/frontend/TracingScene 54.4 kB
frontend/dist-report/exporter/_parent/products/user_interviews/frontend/UserInterview 9.32 kB
frontend/dist-report/exporter/_parent/products/user_interviews/frontend/UserInterviewResponse 7.79 kB
frontend/dist-report/exporter/_parent/products/user_interviews/frontend/UserInterviews 6.08 kB
frontend/dist-report/exporter/_parent/products/visual_review/frontend/scenes/VisualReviewIndexScene 2.56 kB
frontend/dist-report/exporter/_parent/products/visual_review/frontend/scenes/VisualReviewRunScene 44.7 kB
frontend/dist-report/exporter/_parent/products/visual_review/frontend/scenes/VisualReviewRunsScene 7.32 kB
frontend/dist-report/exporter/_parent/products/visual_review/frontend/scenes/VisualReviewSettingsScene 11.1 kB
frontend/dist-report/exporter/_parent/products/visual_review/frontend/scenes/VisualReviewSnapshotHistoryScene 13.9 kB
frontend/dist-report/exporter/_parent/products/visual_review/frontend/scenes/VisualReviewSnapshotOverviewScene 19.6 kB
frontend/dist-report/exporter/_parent/products/workflows/frontend/TemplateLibrary/MessageTemplate 16.6 kB
frontend/dist-report/exporter/_parent/products/workflows/frontend/Workflows/WorkflowScene 111 kB
frontend/dist-report/exporter/_parent/products/workflows/frontend/WorkflowsScene 60.2 kB
frontend/dist-report/exporter/src/exporter/exporter 19.7 kB
frontend/dist-report/exporter/src/exporter/scenes/ExporterDashboardScene 2.02 kB
frontend/dist-report/exporter/src/exporter/scenes/ExporterHeatmapScene 19.9 kB
frontend/dist-report/exporter/src/exporter/scenes/ExporterInsightScene 3.02 kB
frontend/dist-report/exporter/src/exporter/scenes/ExporterInterviewScene 310 kB
frontend/dist-report/exporter/src/exporter/scenes/ExporterNotebookScene 2.71 MB
frontend/dist-report/exporter/src/exporter/scenes/ExporterRecordingScene 1.13 kB
frontend/dist-report/exporter/src/exporterSharedChunkAnchors 1.19 kB
frontend/dist-report/exporter/src/lib/components/Cards/TextCard/TextCardMarkdownEditor 11.3 kB
frontend/dist-report/exporter/src/lib/components/MonacoDiffEditor 471 B
frontend/dist-report/exporter/src/lib/lemon-ui/LemonMarkdown/MermaidDiagram 2.25 kB
frontend/dist-report/exporter/src/lib/lemon-ui/LemonTextArea/LemonTextAreaMarkdown 842 B
frontend/dist-report/exporter/src/lib/lemon-ui/Link/Link 359 B
frontend/dist-report/exporter/src/lib/monaco/CodeEditorInline 832 B
frontend/dist-report/exporter/src/lib/monaco/vimMode 211 kB
frontend/dist-report/exporter/src/lib/ui/Button/ButtonPrimitives 422 B
frontend/dist-report/exporter/src/queries/nodes/WebVitals/WebVitals 7.52 kB
frontend/dist-report/exporter/src/queries/nodes/WebVitals/WebVitalsPathBreakdown 4.09 kB
frontend/dist-report/exporter/src/queries/schema 852 kB
frontend/dist-report/exporter/src/scenes/approvals/changeRequestsLogic 884 B
frontend/dist-report/exporter/src/scenes/authentication/passkeyLogic 824 B
frontend/dist-report/exporter/src/scenes/data-pipelines/event-filtering/EventFilterScene 22.2 kB
frontend/dist-report/exporter/src/scenes/data-pipelines/TransformationsScene 6.54 kB
frontend/dist-report/exporter/src/scenes/insights/views/BoxPlot/BoxPlot 5.39 kB
frontend/dist-report/exporter/src/scenes/insights/views/CalendarHeatMap/CalendarHeatMap 8.84 kB
frontend/dist-report/exporter/src/scenes/insights/views/RegionMap/RegionMap 29.8 kB
frontend/dist-report/exporter/src/scenes/insights/views/WorldMap/WorldMap 1.04 MB
frontend/dist-report/exporter/src/scenes/models/ModelsScene 19 kB
frontend/dist-report/exporter/src/scenes/models/NodeDetailScene 17 kB
frontend/dist-report/monaco-editor-worker/src/lib/monaco/workers/monacoEditorWorker 288 kB
frontend/dist-report/monaco-json-worker/src/lib/monaco/workers/monacoJsonWorker 419 kB
frontend/dist-report/monaco-typescript-worker/src/lib/monaco/workers/monacoTsWorker 7.02 MB
frontend/dist-report/posthog-app/_chunks/chunk 8.63 MB
frontend/dist-report/posthog-app/_parent/products/actions/frontend/pages/Action 25.1 kB
frontend/dist-report/posthog-app/_parent/products/actions/frontend/pages/Actions 1.4 kB
frontend/dist-report/posthog-app/_parent/products/ai_observability/frontend/AIObservabilityScene 119 kB
frontend/dist-report/posthog-app/_parent/products/ai_observability/frontend/AIObservabilitySessionScene 19.8 kB
frontend/dist-report/posthog-app/_parent/products/ai_observability/frontend/AIObservabilityTraceScene 130 kB
frontend/dist-report/posthog-app/_parent/products/ai_observability/frontend/AIObservabilityUsers 906 B
frontend/dist-report/posthog-app/_parent/products/ai_observability/frontend/clusters/AIObservabilityClusterScene 21.7 kB
frontend/dist-report/posthog-app/_parent/products/ai_observability/frontend/clusters/AIObservabilityClustersScene 55.1 kB
frontend/dist-report/posthog-app/_parent/products/ai_observability/frontend/datasets/AIObservabilityDatasetScene 21 kB
frontend/dist-report/posthog-app/_parent/products/ai_observability/frontend/datasets/AIObservabilityDatasetsScene 3.67 kB
frontend/dist-report/posthog-app/_parent/products/ai_observability/frontend/evaluations/AIObservabilityEvaluation 59.9 kB
frontend/dist-report/posthog-app/_parent/products/ai_observability/frontend/evaluations/AIObservabilityEvaluationsScene 28.2 kB
frontend/dist-report/posthog-app/_parent/products/ai_observability/frontend/evaluations/EvaluationTemplates 949 B
frontend/dist-report/posthog-app/_parent/products/ai_observability/frontend/LLMASessionFeedbackDisplay 5.23 kB
frontend/dist-report/posthog-app/_parent/products/ai_observability/frontend/playground/AIObservabilityPlaygroundScene 37.8 kB
frontend/dist-report/posthog-app/_parent/products/ai_observability/frontend/prompts/LLMPromptScene 29.2 kB
frontend/dist-report/posthog-app/_parent/products/ai_observability/frontend/prompts/LLMPromptsScene 4.86 kB
frontend/dist-report/posthog-app/_parent/products/ai_observability/frontend/skills/LLMSkillScene 963 B
frontend/dist-report/posthog-app/_parent/products/ai_observability/frontend/skills/LLMSkillsScene 980 B
frontend/dist-report/posthog-app/_parent/products/ai_observability/frontend/tags/AIObservabilityTag 27.4 kB
frontend/dist-report/posthog-app/_parent/products/ai_observability/frontend/tags/AIObservabilityTagsScene 7.34 kB
frontend/dist-report/posthog-app/_parent/products/business_knowledge/frontend/scenes/BusinessKnowledgeScene 19 kB
frontend/dist-report/posthog-app/_parent/products/conversations/frontend/components/Assignee/CyclotronJobInputAssignee 1.71 kB
frontend/dist-report/posthog-app/_parent/products/conversations/frontend/components/SlaBusinessHours/CyclotronJobInputBusinessHours 3.09 kB
frontend/dist-report/posthog-app/_parent/products/conversations/frontend/components/TicketTags/CyclotronJobInputTicketTags 1.09 kB
frontend/dist-report/posthog-app/_parent/products/conversations/frontend/scenes/settings/SupportSettingsScene 1.85 kB
frontend/dist-report/posthog-app/_parent/products/conversations/frontend/scenes/ticket/SupportTicketScene 26.6 kB
frontend/dist-report/posthog-app/_parent/products/conversations/frontend/scenes/tickets/SupportTicketsScene 1.11 kB
frontend/dist-report/posthog-app/_parent/products/customer_analytics/frontend/CustomerAnalyticsScene 51.9 kB
frontend/dist-report/posthog-app/_parent/products/customer_analytics/frontend/scenes/CustomerAnalyticsConfigurationScene/CustomerAnalyticsConfigurationScene 2.68 kB
frontend/dist-report/posthog-app/_parent/products/customer_analytics/frontend/scenes/CustomerJourneyBuilderScene/CustomerJourneyBuilderScene 2.22 kB
frontend/dist-report/posthog-app/_parent/products/customer_analytics/frontend/scenes/CustomerJourneyTemplatesScene/CustomerJourneyTemplatesScene 7.9 kB
frontend/dist-report/posthog-app/_parent/products/data_warehouse/DataWarehouseScene 1.81 kB
frontend/dist-report/posthog-app/_parent/products/data_warehouse/frontend/scenes/NewSourceScene/NewSourceScene 1.18 kB
frontend/dist-report/posthog-app/_parent/products/data_warehouse/frontend/scenes/SchemaScene/SchemaScene 24.4 kB
frontend/dist-report/posthog-app/_parent/products/data_warehouse/frontend/scenes/SourceScene/SourceScene 1.1 kB
frontend/dist-report/posthog-app/_parent/products/data_warehouse/frontend/scenes/SourcesScene/SourcesScene 6.34 kB
frontend/dist-report/posthog-app/_parent/products/deployments/frontend/Deployment 4.08 kB
frontend/dist-report/posthog-app/_parent/products/deployments/frontend/DeploymentProject 5.61 kB
frontend/dist-report/posthog-app/_parent/products/deployments/frontend/Deployments 9.35 kB
frontend/dist-report/posthog-app/_parent/products/early_access_features/frontend/EarlyAccessFeature 1.2 kB
frontend/dist-report/posthog-app/_parent/products/early_access_features/frontend/EarlyAccessFeatures 3.28 kB
frontend/dist-report/posthog-app/_parent/products/endpoints/frontend/EndpointScene 40.7 kB
frontend/dist-report/posthog-app/_parent/products/endpoints/frontend/EndpointsScene 22.4 kB
frontend/dist-report/posthog-app/_parent/products/error_tracking/frontend/scenes/ErrorTrackingFingerprintsScene/ErrorTrackingIssueFingerprintsScene 7.48 kB
frontend/dist-report/posthog-app/_parent/products/error_tracking/frontend/scenes/ErrorTrackingIssueScene/ErrorTrackingIssueScene 103 kB
frontend/dist-report/posthog-app/_parent/products/error_tracking/frontend/scenes/ErrorTrackingScene/ErrorTrackingScene 27.2 kB
frontend/dist-report/posthog-app/_parent/products/feature_flags/frontend/FeatureFlagTemplatesScene 7.42 kB
frontend/dist-report/posthog-app/_parent/products/games/368Hedgehogs/368Hedgehogs 5.65 kB
frontend/dist-report/posthog-app/_parent/products/games/FlappyHog/FlappyHog 6.16 kB
frontend/dist-report/posthog-app/_parent/products/legal_documents/frontend/scenes/LegalDocumentNewScene 59.8 kB
frontend/dist-report/posthog-app/_parent/products/legal_documents/frontend/scenes/LegalDocumentsScene 5.35 kB
frontend/dist-report/posthog-app/_parent/products/links/frontend/LinkScene 25.2 kB
frontend/dist-report/posthog-app/_parent/products/links/frontend/LinksScene 4.58 kB
frontend/dist-report/posthog-app/_parent/products/live_debugger/frontend/LiveDebugger 19.5 kB
frontend/dist-report/posthog-app/_parent/products/logs/frontend/LogsScene 17.9 kB
frontend/dist-report/posthog-app/_parent/products/logs/frontend/scenes/LogsAlertDetailScene/LogsAlertDetailScene 17.4 kB
frontend/dist-report/posthog-app/_parent/products/logs/frontend/scenes/LogsSamplingDetailScene/LogsSamplingDetailScene 5.34 kB
frontend/dist-report/posthog-app/_parent/products/logs/frontend/scenes/LogsSamplingNewScene/LogsSamplingNewScene 2.29 kB
frontend/dist-report/posthog-app/_parent/products/managed_migrations/frontend/ManagedMigration 14.9 kB
frontend/dist-report/posthog-app/_parent/products/mcp_analytics/frontend/MCPAnalyticsScene 40.6 kB
frontend/dist-report/posthog-app/_parent/products/mcp_analytics/frontend/MCPAnalyticsToolDetail 18.6 kB
frontend/dist-report/posthog-app/_parent/products/metrics/frontend/MetricsScene 16.2 kB
frontend/dist-report/posthog-app/_parent/products/product_analytics/frontend/insights/stickiness/StickinessBarChart/StickinessBarChart 3.34 kB
frontend/dist-report/posthog-app/_parent/products/product_analytics/frontend/insights/stickiness/StickinessLineChart/StickinessLineChart 3.18 kB
frontend/dist-report/posthog-app/_parent/products/product_analytics/frontend/insights/trends/TrendsBarChart/TrendsBarChart 7.4 kB
frontend/dist-report/posthog-app/_parent/products/product_analytics/frontend/insights/trends/TrendsLifecycleChart/TrendsLifecycleChart 4.45 kB
frontend/dist-report/posthog-app/_parent/products/product_analytics/frontend/insights/trends/TrendsLineChart/TrendsLineChart 4.64 kB
frontend/dist-report/posthog-app/_parent/products/product_analytics/frontend/insights/trends/TrendsPieChart/TrendsPieChart 4.38 kB
frontend/dist-report/posthog-app/_parent/products/replay_vision/frontend/observations/ReplayObservation 8.18 kB
frontend/dist-report/posthog-app/_parent/products/replay_vision/frontend/replay_scanners/ReplayScanner 34 kB
frontend/dist-report/posthog-app/_parent/products/replay_vision/frontend/replay_scanners/ReplayScannersScene 11.6 kB
frontend/dist-report/posthog-app/_parent/products/replay_vision/frontend/replay_scanners/ScannerTemplatesScene 4.63 kB
frontend/dist-report/posthog-app/_parent/products/revenue_analytics/frontend/RevenueAnalyticsScene 26.6 kB
frontend/dist-report/posthog-app/_parent/products/session_summaries/frontend/SessionGroupSummariesTable 5.09 kB
frontend/dist-report/posthog-app/_parent/products/session_summaries/frontend/SessionGroupSummaryScene 19.3 kB
frontend/dist-report/posthog-app/_parent/products/tasks/frontend/SlackTaskContextScene 8.91 kB
frontend/dist-report/posthog-app/_parent/products/tasks/frontend/TaskDetailScene 23.9 kB
frontend/dist-report/posthog-app/_parent/products/tasks/frontend/TaskTracker 14.7 kB
frontend/dist-report/posthog-app/_parent/products/tracing/frontend/TracingScene 54.5 kB
frontend/dist-report/posthog-app/_parent/products/user_interviews/frontend/UserInterview 9.35 kB
frontend/dist-report/posthog-app/_parent/products/user_interviews/frontend/UserInterviewResponse 7.83 kB
frontend/dist-report/posthog-app/_parent/products/user_interviews/frontend/UserInterviews 6.12 kB
frontend/dist-report/posthog-app/_parent/products/visual_review/frontend/scenes/VisualReviewIndexScene 2.59 kB
frontend/dist-report/posthog-app/_parent/products/visual_review/frontend/scenes/VisualReviewRunScene 44.7 kB
frontend/dist-report/posthog-app/_parent/products/visual_review/frontend/scenes/VisualReviewRunsScene 7.36 kB
frontend/dist-report/posthog-app/_parent/products/visual_review/frontend/scenes/VisualReviewSettingsScene 11.1 kB
frontend/dist-report/posthog-app/_parent/products/visual_review/frontend/scenes/VisualReviewSnapshotHistoryScene 13.9 kB
frontend/dist-report/posthog-app/_parent/products/visual_review/frontend/scenes/VisualReviewSnapshotOverviewScene 19.6 kB
frontend/dist-report/posthog-app/_parent/products/workflows/frontend/TemplateLibrary/MessageTemplate 16.7 kB
frontend/dist-report/posthog-app/_parent/products/workflows/frontend/Workflows/WorkflowScene 104 kB
frontend/dist-report/posthog-app/_parent/products/workflows/frontend/WorkflowsScene 60.3 kB
frontend/dist-report/posthog-app/src/index 61.1 kB
frontend/dist-report/posthog-app/src/layout/panel-layout/ai-first/tabs/NavTabChat 7.19 kB
frontend/dist-report/posthog-app/src/lib/components/Cards/TextCard/TextCardMarkdownEditor 11.3 kB
frontend/dist-report/posthog-app/src/lib/components/MonacoDiffEditor 471 B
frontend/dist-report/posthog-app/src/lib/lemon-ui/LemonMarkdown/MermaidDiagram 2.29 kB
frontend/dist-report/posthog-app/src/lib/lemon-ui/LemonTextArea/LemonTextAreaMarkdown 876 B
frontend/dist-report/posthog-app/src/lib/lemon-ui/Link/Link 359 B
frontend/dist-report/posthog-app/src/lib/monaco/CodeEditorInline 866 B
frontend/dist-report/posthog-app/src/lib/monaco/vimMode 211 kB
frontend/dist-report/posthog-app/src/lib/ui/Button/ButtonPrimitives 426 B
frontend/dist-report/posthog-app/src/queries/nodes/WebVitals/WebVitals 7.55 kB
frontend/dist-report/posthog-app/src/queries/nodes/WebVitals/WebVitalsPathBreakdown 4.12 kB
frontend/dist-report/posthog-app/src/queries/schema 852 kB
frontend/dist-report/posthog-app/src/scenes/activity/explore/EventsScene 3.32 kB
frontend/dist-report/posthog-app/src/scenes/activity/explore/SessionsScene 4.72 kB
frontend/dist-report/posthog-app/src/scenes/activity/live/LiveEventsTable 5.62 kB
frontend/dist-report/posthog-app/src/scenes/agentic/AgenticAuthorize 5.87 kB
frontend/dist-report/posthog-app/src/scenes/approvals/ApprovalDetail 16.6 kB
frontend/dist-report/posthog-app/src/scenes/approvals/changeRequestsLogic 918 B
frontend/dist-report/posthog-app/src/scenes/audit-logs/AdvancedActivityLogsScene 42.1 kB
frontend/dist-report/posthog-app/src/scenes/AuthenticatedShell 165 kB
frontend/dist-report/posthog-app/src/scenes/authentication/AccountConnected 3.36 kB
frontend/dist-report/posthog-app/src/scenes/authentication/AgenticAccountMismatch 2.77 kB
frontend/dist-report/posthog-app/src/scenes/authentication/CLIAuthorize 11.8 kB
frontend/dist-report/posthog-app/src/scenes/authentication/CLILive 4.4 kB
frontend/dist-report/posthog-app/src/scenes/authentication/credential-review/CredentialReview 3.98 kB
frontend/dist-report/posthog-app/src/scenes/authentication/EmailMFAVerify 3.4 kB
frontend/dist-report/posthog-app/src/scenes/authentication/InviteSignup 15.4 kB
frontend/dist-report/posthog-app/src/scenes/authentication/Login 10.2 kB
frontend/dist-report/posthog-app/src/scenes/authentication/Login2FA 5.11 kB
frontend/dist-report/posthog-app/src/scenes/authentication/passkeyLogic 858 B
frontend/dist-report/posthog-app/src/scenes/authentication/PasswordReset 4.74 kB
frontend/dist-report/posthog-app/src/scenes/authentication/PasswordResetComplete 3.38 kB
frontend/dist-report/posthog-app/src/scenes/authentication/signup/SignupContainer 28.6 kB
frontend/dist-report/posthog-app/src/scenes/authentication/signup/verify-email/VerifyEmail 5.16 kB
frontend/dist-report/posthog-app/src/scenes/authentication/TwoFactorReset 4.41 kB
frontend/dist-report/posthog-app/src/scenes/authentication/VercelConnect 5.37 kB
frontend/dist-report/posthog-app/src/scenes/authentication/VercelLinkError 2.64 kB
frontend/dist-report/posthog-app/src/scenes/billing/AuthorizationStatus 1.1 kB
frontend/dist-report/posthog-app/src/scenes/billing/Billing 867 B
frontend/dist-report/posthog-app/src/scenes/billing/BillingSection 21.2 kB
frontend/dist-report/posthog-app/src/scenes/cohorts/Cohort 28.4 kB
frontend/dist-report/posthog-app/src/scenes/cohorts/CohortCalculationHistory 6.61 kB
frontend/dist-report/posthog-app/src/scenes/cohorts/Cohorts 9.81 kB
frontend/dist-report/posthog-app/src/scenes/coupons/Coupons 1.1 kB
frontend/dist-report/posthog-app/src/scenes/dashboard/Dashboard 1.68 kB
frontend/dist-report/posthog-app/src/scenes/dashboard/dashboards/Dashboards 19.9 kB
frontend/dist-report/posthog-app/src/scenes/dashboard/dashboards/templates/DashboardTemplateCopyScene 6.09 kB
frontend/dist-report/posthog-app/src/scenes/data-management/DataManagementScene 1.02 kB
frontend/dist-report/posthog-app/src/scenes/data-management/definition/DefinitionEdit 17.2 kB
frontend/dist-report/posthog-app/src/scenes/data-management/definition/DefinitionView 24.4 kB
frontend/dist-report/posthog-app/src/scenes/data-management/MaterializedColumns/MaterializedColumns 12 kB
frontend/dist-report/posthog-app/src/scenes/data-management/variables/SqlVariableEditScene 7.63 kB
frontend/dist-report/posthog-app/src/scenes/data-pipelines/batch-exports/BatchExportScene 61 kB
frontend/dist-report/posthog-app/src/scenes/data-pipelines/DataPipelinesNewScene 2.69 kB
frontend/dist-report/posthog-app/src/scenes/data-pipelines/DestinationsScene 3.06 kB
frontend/dist-report/posthog-app/src/scenes/data-pipelines/event-filtering/EventFilterScene 22.3 kB
frontend/dist-report/posthog-app/src/scenes/data-pipelines/legacy-plugins/LegacyPluginScene 21 kB
frontend/dist-report/posthog-app/src/scenes/data-pipelines/TransformationsScene 2.3 kB
frontend/dist-report/posthog-app/src/scenes/data-pipelines/WebScriptsScene 2.92 kB
frontend/dist-report/posthog-app/src/scenes/data-warehouse/DataWarehouseScene 1.75 kB
frontend/dist-report/posthog-app/src/scenes/data-warehouse/editor/EditorScene 1.52 kB
frontend/dist-report/posthog-app/src/scenes/debug/DebugScene 20.3 kB
frontend/dist-report/posthog-app/src/scenes/debug/hog/HogRepl 7.75 kB
frontend/dist-report/posthog-app/src/scenes/experiments/Experiment 207 kB
frontend/dist-report/posthog-app/src/scenes/experiments/Experiments 20.9 kB
frontend/dist-report/posthog-app/src/scenes/experiments/SharedMetrics/SharedMetric 6.45 kB
frontend/dist-report/posthog-app/src/scenes/experiments/SharedMetrics/SharedMetrics 923 B
frontend/dist-report/posthog-app/src/scenes/exports/ExportsScene 4.36 kB
frontend/dist-report/posthog-app/src/scenes/feature-flags/FeatureFlag 144 kB
frontend/dist-report/posthog-app/src/scenes/feature-flags/FeatureFlags 1.12 kB
frontend/dist-report/posthog-app/src/scenes/groups/Group 15.6 kB
frontend/dist-report/posthog-app/src/scenes/groups/Groups 4.29 kB
frontend/dist-report/posthog-app/src/scenes/groups/GroupsNew 7.73 kB
frontend/dist-report/posthog-app/src/scenes/health-alerts/HealthAlertsScene 4.17 kB
frontend/dist-report/posthog-app/src/scenes/health/categoryDetail/HealthCategoryDetailScene 7.64 kB
frontend/dist-report/posthog-app/src/scenes/health/HealthScene 12.8 kB
frontend/dist-report/posthog-app/src/scenes/health/pipelineStatus/PipelineStatusScene 11.5 kB
frontend/dist-report/posthog-app/src/scenes/heatmaps/scenes/heatmap/HeatmapNewScene 5.41 kB
frontend/dist-report/posthog-app/src/scenes/heatmaps/scenes/heatmap/HeatmapRecordingScene 4.31 kB
frontend/dist-report/posthog-app/src/scenes/heatmaps/scenes/heatmap/HeatmapScene 6.94 kB
frontend/dist-report/posthog-app/src/scenes/heatmaps/scenes/heatmaps/HeatmapsScene 4.27 kB
frontend/dist-report/posthog-app/src/scenes/hog-functions/HogFunctionScene 59.6 kB
frontend/dist-report/posthog-app/src/scenes/inbox/InboxScene 63.3 kB
frontend/dist-report/posthog-app/src/scenes/insights/InsightQuickStart/InsightQuickStart 5.81 kB
frontend/dist-report/posthog-app/src/scenes/insights/InsightScene 34.8 kB
frontend/dist-report/posthog-app/src/scenes/insights/views/BoxPlot/BoxPlot 5.43 kB
frontend/dist-report/posthog-app/src/scenes/insights/views/CalendarHeatMap/CalendarHeatMap 4.87 kB
frontend/dist-report/posthog-app/src/scenes/insights/views/RegionMap/RegionMap 29.8 kB
frontend/dist-report/posthog-app/src/scenes/insights/views/WorldMap/WorldMap 5.16 kB
frontend/dist-report/posthog-app/src/scenes/instance/AsyncMigrations/AsyncMigrations 13.5 kB
frontend/dist-report/posthog-app/src/scenes/instance/DeadLetterQueue/DeadLetterQueue 5.77 kB
frontend/dist-report/posthog-app/src/scenes/instance/QueryPerformance/QueryPerformance 9 kB
frontend/dist-report/posthog-app/src/scenes/instance/SystemStatus/SystemStatus 17.4 kB
frontend/dist-report/posthog-app/src/scenes/IntegrationsRedirect/IntegrationsRedirect 1.11 kB
frontend/dist-report/posthog-app/src/scenes/marketing-analytics/MarketingAnalyticsScene 42.1 kB
frontend/dist-report/posthog-app/src/scenes/max/Max 1.06 kB
frontend/dist-report/posthog-app/src/scenes/models/ModelsScene 19.1 kB
frontend/dist-report/posthog-app/src/scenes/models/NodeDetailScene 17.1 kB
frontend/dist-report/posthog-app/src/scenes/moveToPostHogCloud/MoveToPostHogCloud 4.84 kB
frontend/dist-report/posthog-app/src/scenes/new-tab/NewTabScene 1.85 kB
frontend/dist-report/posthog-app/src/scenes/notebooks/NotebookCanvasScene 3.92 kB
frontend/dist-report/posthog-app/src/scenes/notebooks/NotebookPanel/NotebookPanel 5.98 kB
frontend/dist-report/posthog-app/src/scenes/notebooks/NotebookScene 9.29 kB
frontend/dist-report/posthog-app/src/scenes/notebooks/NotebooksScene 7.98 kB
frontend/dist-report/posthog-app/src/scenes/oauth/OAuthAuthorize 1.01 kB
frontend/dist-report/posthog-app/src/scenes/onboarding/coupon/OnboardingCouponRedemption 1.58 kB
frontend/dist-report/posthog-app/src/scenes/onboarding/Onboarding 792 kB
frontend/dist-report/posthog-app/src/scenes/onboarding/sdks/SdkDoctorScene 10.2 kB
frontend/dist-report/posthog-app/src/scenes/organization/ConfirmOrganization/ConfirmOrganization 4.91 kB
frontend/dist-report/posthog-app/src/scenes/organization/Create/Create 1.03 kB
frontend/dist-report/posthog-app/src/scenes/organization/Deactivated 1.51 kB
frontend/dist-report/posthog-app/src/scenes/organization/PendingDeletion 2.48 kB
frontend/dist-report/posthog-app/src/scenes/persons/PersonScene 20.1 kB
frontend/dist-report/posthog-app/src/scenes/persons/PersonsScene 6.12 kB
frontend/dist-report/posthog-app/src/scenes/PreflightCheck/PreflightCheck 5.95 kB
frontend/dist-report/posthog-app/src/scenes/product-tours/ProductTour 275 kB
frontend/dist-report/posthog-app/src/scenes/product-tours/ProductTours 5.06 kB
frontend/dist-report/posthog-app/src/scenes/project-homepage/ProjectHomepage 19.1 kB
frontend/dist-report/posthog-app/src/scenes/project/Create/Create 1.21 kB
frontend/dist-report/posthog-app/src/scenes/resource-transfer/ResourceTransfer 9.56 kB
frontend/dist-report/posthog-app/src/scenes/saved-insights/SavedInsights 1.04 kB
frontend/dist-report/posthog-app/src/scenes/session-recordings/detail/SessionRecordingDetail 2.14 kB
frontend/dist-report/posthog-app/src/scenes/session-recordings/file-playback/SessionRecordingFilePlaybackScene 4.85 kB
frontend/dist-report/posthog-app/src/scenes/session-recordings/kiosk/SessionRecordingsKiosk 10.3 kB
frontend/dist-report/posthog-app/src/scenes/session-recordings/player/snapshot-processing/DecompressionWorkerManager 329 B
frontend/dist-report/posthog-app/src/scenes/session-recordings/playlist/SessionRecordingsPlaylistScene 5.49 kB
frontend/dist-report/posthog-app/src/scenes/session-recordings/SessionRecordings 1.15 kB
frontend/dist-report/posthog-app/src/scenes/session-recordings/settings/SessionRecordingsSettingsScene 2.35 kB
frontend/dist-report/posthog-app/src/scenes/sessions/SessionProfileScene 15.6 kB
frontend/dist-report/posthog-app/src/scenes/settings/SettingsScene 3.94 kB
frontend/dist-report/posthog-app/src/scenes/sites/Site 1.57 kB
frontend/dist-report/posthog-app/src/scenes/startups/StartupProgram 21.6 kB
frontend/dist-report/posthog-app/src/scenes/StripeConfirmInstall/StripeConfirmInstall 3.92 kB
frontend/dist-report/posthog-app/src/scenes/subscriptions/SubscriptionScene 14.4 kB
frontend/dist-report/posthog-app/src/scenes/subscriptions/SubscriptionsScene 5.23 kB
frontend/dist-report/posthog-app/src/scenes/surveys/forms/SurveyFormBuilder 1.93 kB
frontend/dist-report/posthog-app/src/scenes/surveys/Survey 1.39 kB
frontend/dist-report/posthog-app/src/scenes/surveys/Surveys 26.8 kB
frontend/dist-report/posthog-app/src/scenes/surveys/wizard/SurveyWizard 72.8 kB
frontend/dist-report/posthog-app/src/scenes/themes/CustomCssScene 3.94 kB
frontend/dist-report/posthog-app/src/scenes/toolbar-launch/ToolbarLaunch 2.85 kB
frontend/dist-report/posthog-app/src/scenes/Unsubscribe/Unsubscribe 2.04 kB
frontend/dist-report/posthog-app/src/scenes/web-analytics/SessionAttributionExplorer/SessionAttributionExplorerScene 7.01 kB
frontend/dist-report/posthog-app/src/scenes/web-analytics/WebAnalyticsScene 13.3 kB
frontend/dist-report/posthog-app/src/scenes/wizard/Wizard 4.83 kB
frontend/dist-report/posthog-app/src/sharedChunkAnchors 1.19 kB
frontend/dist-report/render-query/src/render-query/render-query 27.4 MB
frontend/dist-report/toolbar/src/toolbar/toolbar 15.7 MB

compressed-size-action

@hpouillot hpouillot force-pushed the hp/cymbal-resolution branch from 320ea2e to 1c171d2 Compare May 27, 2026 17:02
Introduces a standalone `cymbal-resolution` service that owns exception
symbol resolution behind a `cymbal.resolution.v1` gRPC contract, and
routes the cymbal pipeline's resolution stage through it via a
caller-owned endpoint pool when enabled. Local resolution remains the
fallback when the flag is off; there is no silent local fallback when
the remote pool is enabled — failures surface as batch-level errors so
upstream handling stays explicit.

New crates / services
- `cymbal-proto`: build-time proto contract crate with a `Resolve` +
  `Subscribe` stream split and contract tests
- `cymbal-resolution`: standalone gRPC service with admission gating
  (`MAX_ITEM_CONCURRENCY`), load-event bus (`Subscribe` stream reports
  `LoadEvent.in_flight / max_in_flight / degraded / draining`), and
  per-item Done/Error/Retry outcomes per `Resolve` stream

Client integration in cymbal
- `EndpointPool` with DNS-driven endpoint reconciliation,
  rendezvous-hashing per team for warm-cache affinity, exclusion of
  degraded/draining endpoints, and round-robin tie-breaking
- per-endpoint `Subscribe` task maintains a fresh load snapshot, with
  exponential reconnect backoff + jitter
- request grouping by team routing key, chunking by item count + byte
  budget, and per-attempt endpoint rotation for retries
- caller-side retries with exponential backoff + jitter; pool-empty
  consumes the retry budget rather than failing on the first attempt
- event-level deterministic sampling for graduated rollout

Data integrity (all-or-nothing rollout policy)
- clean stream end without `BatchSummary` triggers retry (guards
  against server spawn-task panic / mid-stream `tx.send` failure)
- per-item `Error` outcomes fail the batch loudly rather than silently
  downgrading affected exceptions to unresolved passthrough
- `RemoteEventSlot` uses `Option<>` + `take()` instead of a
  `mem::replace` placeholder so a regression can't leak a sentinel
- final `output[batch_index].ok_or_else(...)` fails the batch loud if
  any slot is left empty

Observability
- per-endpoint in-flight gauge correctly increments on select and
  decrements on handle Drop; emitted only for the chosen endpoint
- latency histogram drops the high-cardinality `endpoint` label
- routing fallback / no-summary / pool-empty / items-failed counters
- `last_error` preserved across all retryable cause classes

Local dev wiring
- `bin/mprocs.yaml` + `bin/start-rust-service` so cymbal-resolution
  comes up alongside cymbal in the local stack
- dev RUST_LOG scoping for cymbal crates

Tests
- parity suite (`remote_resolution_parity.rs`): local vs remote produce
  identical resolved `exception_list` for the same input
- hardening suite (`remote_resolution_hardening.rs`): connection
  refused, mid-stream interruption, missing items, no-summary
  truncation, per-item Error all-or-nothing, draining-only pool,
  cancellation releases pool slot
- core integration (`remote_resolution.rs`): grouping, chunking,
  retries, sampling, deadline cancellation, ordering, per-team affinity
- subscription routing (`remote_resolution_subscribe.rs`): pool routes
  to endpoint with lower server-reported load
- service tests (`cymbal-resolution/tests/service_tests.rs`):
  end-to-end Resolve + Subscribe behavior, accounting invariants,
  limiter pressure surfacing

Rollout
- `CYMBAL_REMOTE_RESOLUTION_ENABLED` gates the client side; all knobs
  documented in `rust/cymbal-resolution/README.md` including retry,
  deadline, batching, sampling, and admission/degraded thresholds

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@hpouillot hpouillot force-pushed the hp/cymbal-resolution branch from 1c171d2 to bcc7a49 Compare May 27, 2026 17:15
@hpouillot hpouillot marked this pull request as ready for review May 27, 2026 17:18
@hpouillot hpouillot requested review from a team, ablaszkiewicz and cat-ph May 27, 2026 17:18
@assign-reviewers-posthog assign-reviewers-posthog Bot requested a review from a team May 27, 2026 17:18
Comment thread .pi/settings.json Outdated
Comment thread rust/cymbal-resolution/src/main.rs Outdated
@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented May 27, 2026

Prompt To Fix All With AI
Fix the following 3 code review issues. Work through them one at a time, proposing concise fixes.

---

### Issue 1 of 3
rust/cymbal/src/stages/resolution/remote/client.rs:92-102
The stream-drain loop applies `tokio::time::timeout(deadline, stream.next())` per message, not as a single total wrapper. Each call to `stream.next()` gets a fresh `deadline`-length budget, so a server sending N items could hold this function for up to N × `deadline` (e.g. 64 items × 15 s = 960 s). The doc-comment above says "tokio `timeout` wrapping the entire stream drain", which is not what the code does. The only end-to-end budget is the `grpc-timeout` header sent to the server — if a proxy strips that header or the server has a slow-but-not-stalled item loop, there is no client-side cap on total wall time.

```suggestion
    let mut stream = response.into_inner();
    let mut outcomes: Vec<Outcome> = Vec::new();
    let drain_deadline = tokio::time::Instant::now() + deadline;
    loop {
        let remaining = drain_deadline.saturating_duration_since(tokio::time::Instant::now());
        if remaining.is_zero() {
            return Err(RemoteCallError::Deadline(deadline));
        }
        match tokio::time::timeout(remaining, stream.next()).await {
            Ok(Some(Ok(outcome))) => outcomes.push(outcome),
            Ok(Some(Err(status))) => return Err(classify_status(status)),
            Ok(None) => break,
            Err(_) => return Err(RemoteCallError::Deadline(deadline)),
        }
    }
    Ok(outcomes)
```

### Issue 2 of 3
rust/cymbal/src/stages/resolution/remote/pool.rs:417-433
`Notify::notified()` is constructed after `now().await`, so a `notify_waiters()` call that fires in between the two is silently dropped (tokio `Notify` does not store missed notifications from `notify_waiters`). A caller waiting on pool readiness at startup can miss the first `ready` signal and sit out the full `timeout` even though the pool already has healthy endpoints. The standard fix is to pin the `notified()` future before the condition check.

```suggestion
    pub async fn wait_ready(&self, timeout: Duration) -> Result<(), EndpointPoolError> {
        // Create the notified() future FIRST so we don't miss a notify_waiters()
        // that fires between the condition check and the await below.
        let notified = self.ready.notified();
        tokio::pin!(notified);
        if self
            .inner
            .lock()
            .await
            .endpoints
            .values()
            .any(|s| !s.draining)
        {
            return Ok(());
        }
        match tokio::time::timeout(timeout, notified).await {
            Ok(()) => Ok(()),
            Err(_) => Err(EndpointPoolError::Empty),
        }
    }
```

### Issue 3 of 3
rust/cymbal/src/app_context.rs:303
**Background task handle not stored**`spawn_refresh_task` returns a `JoinHandle<()>` that is immediately dropped. The task holds its own `Arc<EndpointPool>` clone, so it keeps running and keeps the pool alive even after `AppContext` is dropped. Storing the handle on `AppContext` or `RemoteResolutionContext` would enable graceful cancellation on teardown.

Reviews (1): Last reviewed commit: "feat(cymbal): add remote symbol resoluti..." | Re-trigger Greptile

Comment thread rust/cymbal/src/stages/resolution/remote/client.rs Outdated
Comment thread rust/cymbal/src/stages/resolution/remote/pool.rs Outdated
Comment thread rust/cymbal/src/app_context.rs
Comment thread rust/cymbal/src/stages/resolution/remote/resolver.rs Outdated
@veria-ai
Copy link
Copy Markdown

veria-ai Bot commented May 28, 2026

PR overview

This PR adds remote symbol resolution to cymbal using a gRPC-backed resolver path for processing sampled exception data. It extends the resolution stage so work can be delegated to a remote service rather than only handled through the existing local path.

There is one remaining security concern: the remote resolution path can launch work for every exception in a submitted event concurrently, instead of preserving the bounded concurrency used elsewhere. A crafted event with a very large exception list could therefore cause excessive remote work and retries, creating a resource-exhaustion risk. One prior issue has already been addressed, so the remaining posture is narrowed to this concurrency-control gap.

Open issues (1)

Fixed/addressed: 1 · PR risk: 6/10

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 28, 2026

🎭 Playwright report · View test results →

⚠️ 1 flaky test:

  • Creating a SQL insight with a variable and overriding it on a dashboard (chromium)

These issues are not necessarily caused by your changes.
Annoyed by this comment? Help fix flakies and failures and it'll disappear!

@cat-ph cat-ph closed this May 28, 2026
@cat-ph cat-ph reopened this May 28, 2026
@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented May 28, 2026

Prompt To Fix All With AI
Fix the following 1 code review issue. Work through them one at a time, proposing concise fixes.

---

### Issue 1 of 1
rust/cymbal/src/stages/resolution/remote/config.rs:87-92
`normalized_sample_rate` maps any non-finite float (including `f64::INFINITY` and `f64::NEG_INFINITY`) to `1.0`, which would silently enable full-rate remote routing. Notably, `f64::from_str("inf")` succeeds in Rust, so setting `CYMBAL_REMOTE_RESOLUTION_SAMPLE_RATE=inf` in an env file would parse without error and produce full remote traffic — bypassing the safety of the `0.0` default. A non-finite value more naturally signals a misconfiguration, so mapping it to `0.0` (fail-closed) is safer.

```suggestion
fn normalized_sample_rate(sample_rate: f64) -> f64 {
    if !sample_rate.is_finite() {
        return 0.0;
    }
    sample_rate.clamp(0.0, 1.0)
}
```

Reviews (2): Last reviewed commit: "chore: remove pi settings override" | Re-trigger Greptile

Copy link
Copy Markdown
Contributor

@cat-ph cat-ph left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

very solid & cool approach! :amaze:

this looks great, let's start testing it :shipit:

Comment thread bin/start-rust-service Outdated
Comment thread rust/cymbal/src/stages/resolution/remote/resolver.rs Outdated
Comment thread rust/cymbal/src/app_context.rs
Comment thread rust/cymbal-resolution/src/service.rs Outdated
Copy link
Copy Markdown
Contributor

@ablaszkiewicz ablaszkiewicz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks extremely solid. Left small nit and a question. Overall I think PR description could be more informative. Some diagrams explaining what's going on would be cool. Reviewing 8k lines of raw code with that description is extremely complicated but I did a lot of back and forth with Claude so I feel like I have a general understanding.

Small thing that worries me is that right now sometimes we have a hard time figuring out why something is not working as it should in cymbal and here we are adding new service, new communication layer and a whole 2-way communication. I'd be interested in seeing observability side of things for this new approach

Comment thread rust/cymbal-resolution/README.md Outdated
Comment thread rust/cymbal/src/stages/resolution/remote/resolver.rs Outdated
Drop in_flight/max_in_flight from the LoadEvent protocol in favor of a
degraded flag plus suggested_batch_size (renamed from
suggested_max_batch_items). The server now flips degraded at an absolute
in-flight threshold (DEGRADED_IN_FLIGHT_THRESHOLD) decoupled from
concurrency, and suggests remaining headroom as the batch size.

Also splits the cymbal-resolution service module into config/codes/
resolve/subscribe submodules and converts the Subscribe RPC to a lazy
async_stream, dropping its mpsc channel and background task.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown
Member

@rnegron rnegron left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

reviewed .github and bin changes

@hpouillot hpouillot force-pushed the hp/cymbal-resolution branch from 23809db to bbceb91 Compare June 1, 2026 08:47
.checked_add(ctx.config.request_deadline)
.unwrap_or_else(Instant::now);

let resolved = join_all(
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Medium: Unbounded remote exception fan-out

join_all starts one resolve_work_item future for every exception in the sampled remote batch. An attacker who can submit an error event with a large $exception_list can make cymbal create and retry all of those remote work items concurrently, bypassing the existing BATCH_APPLY_CONCURRENCY limit used by the local exception/frame resolution path. Please run these work items through a bounded stream, or another configurable semaphore, so remote mode preserves the same per-request concurrency ceiling.

@hpouillot hpouillot merged commit c3443bd into master Jun 1, 2026
185 of 191 checks passed
@hpouillot hpouillot deleted the hp/cymbal-resolution branch June 1, 2026 11:13
@deployment-status-posthog
Copy link
Copy Markdown

deployment-status-posthog Bot commented Jun 1, 2026

Deploy status

Environment Status Deployed At Workflow
dev ✅ Deployed 2026-06-01 11:35 UTC Run
prod-us ✅ Deployed 2026-06-01 12:01 UTC Run
prod-eu ✅ Deployed 2026-06-01 12:01 UTC Run

blitss added a commit to blitss/posthog-helm-chart that referenced this pull request Jun 3, 2026
#32)

Upstream split symbol/exception-frame resolution out of cymbal into a
separate `cymbal-resolution` rust service (PostHog/posthog#60289,
`bin/start-rust-service cymbal-resolution`). Add it to the chart so
self-hosters have it ready when the rollout ramps.

- New `cymbalResolution` component (Deployment + ClusterIP Service on gRPC
  50061 / metrics 9106), reusing the cymbal image in resolution mode. It
  needs only Postgres + S3, both supplied via the shared posthog env +
  the rustfs bucket init. Includes HPA / PDB / ServiceMonitor parity with
  the personhog gRPC services and a NetworkPolicy allow-list entry.
- New `cymbal.remoteResolution` knobs that wire CYMBAL_REMOTE_RESOLUTION_*
  onto the existing cymbal pods. These render ONLY when
  remoteResolution.enabled=true, so cymbal is byte-for-byte unchanged by
  default. SAMPLE_RATE defaults to 0.0 to match the upstream production
  default (flipping ENABLED is a no-op until ramped).

Disabled by default -> zero change to the rendered happy-path manifests
(verified via helm template). Resolves #30.

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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.

4 participants