diff --git a/crates/session-metrics/README.md b/crates/session-metrics/README.md index 5bef618f..07284cef 100644 --- a/crates/session-metrics/README.md +++ b/crates/session-metrics/README.md @@ -24,7 +24,7 @@ use session_metrics::{ let metric = Metric::now("compact.start") .with_value(12_345.0) - .with_dimension("trigger", "automatic") + .with_dimension("trigger", "pre_run") .with_correlation_id("018f6f8a-9822-7b11-8b35-706f30313700"); record_metric( &store, diff --git a/crates/worker/src/compact/telemetry.rs b/crates/worker/src/compact/telemetry.rs index 799530d0..a171468e 100644 --- a/crates/worker/src/compact/telemetry.rs +++ b/crates/worker/src/compact/telemetry.rs @@ -266,7 +266,7 @@ impl CompactAttempt { self.source_segment_id.to_string(), ), ("mode".into(), self.mode.as_str().into()), - ("trigger".into(), self.mode.as_str().into()), + ("trigger".into(), self.threshold_policy.as_str().into()), ( "threshold_policy".into(), self.threshold_policy.as_str().into(), @@ -305,6 +305,15 @@ fn metric_with_context( metric } +pub(crate) fn new_compact_metric_correlation_id(lifecycle_id: &str) -> String { + loop { + let correlation_id = uuid::Uuid::now_v7().to_string(); + if correlation_id != lifecycle_id { + return correlation_id; + } + } +} + pub(crate) fn correlated_post_request_metric( kind: PostRequestMetric, correlation_id: &str, @@ -330,10 +339,10 @@ pub(crate) fn safe_metric_number(value: u64) -> f64 { fn estimate_source(source: EstimateSource) -> &'static str { match source { - EstimateSource::Measured => "measured", - EstimateSource::Interpolated => "interpolated", - EstimateSource::Extrapolated => "extrapolated", - EstimateSource::NoData => "no_data", + EstimateSource::Measured => "provider", + EstimateSource::Interpolated | EstimateSource::Extrapolated | EstimateSource::NoData => { + "fallback" + } } } @@ -357,14 +366,30 @@ mod tests { assert_eq!(start.name, "compact.start"); assert_eq!(start.value, Some(MAX_SAFE_INTEGER as f64)); assert_eq!(start.dimensions["mode"], "automatic"); - assert_eq!(start.dimensions["trigger"], "automatic"); + assert_eq!(start.dimensions["trigger"], "request_threshold"); assert_eq!(start.dimensions["threshold_policy"], "request_threshold"); - assert_eq!(start.dimensions["occupancy_source"], "measured"); + assert_eq!(start.dimensions["occupancy_source"], "provider"); assert!(start.correlation_id.is_some()); assert!(start.dimensions.keys().all(|key| key.len() <= 32)); assert!(start.dimensions.values().all(|value| value.len() <= 64)); } + #[test] + fn occupancy_sources_match_the_public_provider_fallback_schema() { + assert_eq!(estimate_source(EstimateSource::Measured), "provider"); + assert_eq!(estimate_source(EstimateSource::Interpolated), "fallback"); + assert_eq!(estimate_source(EstimateSource::Extrapolated), "fallback"); + assert_eq!(estimate_source(EstimateSource::NoData), "fallback"); + } + + #[test] + fn metric_correlation_id_is_distinct_from_lifecycle_identity() { + let lifecycle_id = uuid::Uuid::now_v7().to_string(); + let correlation_id = new_compact_metric_correlation_id(&lifecycle_id); + assert_ne!(correlation_id, lifecycle_id); + assert!(uuid::Uuid::parse_str(&correlation_id).is_ok()); + } + #[test] fn post_request_metric_saturates_values_above_json_safe_integer() { let record = UsageRecord { diff --git a/crates/worker/src/worker.rs b/crates/worker/src/worker.rs index 98787a98..febf0242 100644 --- a/crates/worker/src/worker.rs +++ b/crates/worker/src/worker.rs @@ -42,7 +42,7 @@ use manifest::{ use crate::compact::state::CompactState; use crate::compact::telemetry::{ CompactAttempt, CompactFailureCategory, CompactMode, CompactSuccessStats, - CompactThresholdPolicy, correlated_post_request_metric, + CompactThresholdPolicy, correlated_post_request_metric, new_compact_metric_correlation_id, }; use crate::compact::usage_tracker::UsageTracker; use crate::feature::background::{BackgroundTaskRewriteGuard, FeatureBackgroundTaskRegistry}; @@ -4991,8 +4991,9 @@ impl Worker { let history_items = self.session.history().items_cloned(); let usage_history = self.usage_history(); let pre_context = agen::token_counter::total_tokens(&history_items, &usage_history); + let metric_correlation_id = new_compact_metric_correlation_id(&lifecycle.compaction_id); let attempt = CompactAttempt::new( - lifecycle.compaction_id.clone(), + metric_correlation_id, source_location.session_id, source_location.segment_id, match trigger { diff --git a/crates/worker/tests/compact_events_test.rs b/crates/worker/tests/compact_events_test.rs index a0aa908c..673f4184 100644 --- a/crates/worker/tests/compact_events_test.rs +++ b/crates/worker/tests/compact_events_test.rs @@ -760,7 +760,7 @@ async fn compact_emits_session_start_carrying_summary_and_task_snapshot() { assert_eq!(starts.len(), 1); assert_eq!(starts[0].segment_id, source_segment_id); assert_eq!(starts[0].metric.dimensions["mode"], "automatic"); - assert_eq!(starts[0].metric.dimensions["trigger"], "automatic"); + assert_eq!(starts[0].metric.dimensions["trigger"], "request_threshold"); assert_eq!( starts[0].metric.dimensions["threshold_policy"], "request_threshold" @@ -970,7 +970,7 @@ async fn pre_run_compact_publishes_runtime_progress_phases() { .unwrap(); assert_eq!(start.segment_id, segment_before); assert_eq!(start.metric.dimensions["mode"], "automatic"); - assert_eq!(start.metric.dimensions["trigger"], "automatic"); + assert_eq!(start.metric.dimensions["trigger"], "pre_run"); assert_eq!(start.metric.dimensions["threshold_policy"], "pre_run"); let finish = metrics .iter() @@ -1027,7 +1027,7 @@ async fn request_threshold_compact_publishes_runtime_progress() { .iter() .find(|record| record.metric.name == "compact.start") .unwrap(); - assert_eq!(start.metric.dimensions["trigger"], "automatic"); + assert_eq!(start.metric.dimensions["trigger"], "request_threshold"); assert_eq!( start.metric.dimensions["threshold_policy"], "request_threshold" diff --git a/docs/design/compaction.md b/docs/design/compaction.md index 70479ba7..e6dd2b19 100644 --- a/docs/design/compaction.md +++ b/docs/design/compaction.md @@ -35,7 +35,7 @@ The important property is explainability: after compaction, records should still ## Metrics and comparison procedure Compaction measurements stay out of the ordinary transcript. They are appended as -`session.metrics` extensions and are read only through the explicit +`metrics` extensions and are read only through the explicit `session-metrics` reader/export path. `read_session_metrics` attaches the durable `segment_id` and `SegmentStart.compacted_from` lineage to each record.