Address PR review: inline propagation helpers, always include traceparent
- Remove traceparent_from_span and context_from_traceparent helper
  functions — each had one call site and added indirection without
  meaningful abstraction
- Inline the W3C propagation logic directly at each call site
- Always extract and pass traceparent regardless of Sentry DSN, since
  OTEL spans exist independently of Sentry

https://claude.ai/code/session_01Tbgz29e8A9KS4Bh94skkFX
change
commit 9851548e57ec2f96b86e89759ddce561959c2b27
author Claude <noreply@anthropic.com>
date
parent 4d8ce142
diff --git a/Cargo.lock b/Cargo.lock
index b35f36a..1fbda02 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -2554,6 +2554,8 @@ dependencies = [
  "jiff",
  "miette",
  "mlua",
+ "opentelemetry",
+ "opentelemetry_sdk",
  "quire-core",
  "reqwest",
  "sentry",
@@ -2608,6 +2610,8 @@ dependencies = [
  "jiff",
  "miette",
  "mlua",
+ "opentelemetry",
+ "opentelemetry_sdk",
  "petgraph",
  "predicates",
  "quire-core",
@@ -2626,6 +2630,7 @@ dependencies = [
  "tokio",
  "tower",
  "tracing",
+ "tracing-opentelemetry",
  "uuid",
  "walkdir",
 ]
diff --git a/quire-ci/Cargo.toml b/quire-ci/Cargo.toml
index a99f364..76a758b 100644
--- a/quire-ci/Cargo.toml
+++ b/quire-ci/Cargo.toml
@@ -18,5 +18,7 @@ serde_json = { workspace = true }
 tempfile = { workspace = true }
 thiserror = { workspace = true }
 tokio = { workspace = true, features = ["rt-multi-thread"] }
+opentelemetry = { workspace = true }
+opentelemetry_sdk = { workspace = true }
 tracing = { workspace = true }
 tracing-opentelemetry = { workspace = true }
diff --git a/quire-ci/src/main.rs b/quire-ci/src/main.rs
index 89017e6..16d2d93 100644
--- a/quire-ci/src/main.rs
+++ b/quire-ci/src/main.rs
@@ -17,6 +17,7 @@ use quire_core::ci::run::RunMeta;
 use quire_core::ci::runtime::{Runtime, RuntimeError, RuntimeEvent, RuntimeHandle};
 use quire_core::fennel::FennelError;
 use quire_core::secret::{Error as SecretError, Result as SecretResult, SecretRegistry};
+use opentelemetry::propagation::TextMapPropagator as _;
 use quire_core::telemetry::{self, FmtMode, MietteLayer};
 use tracing_opentelemetry::OpenTelemetrySpanExt as _;
 use reqwest::header::{AUTHORIZATION, HeaderMap, HeaderValue};
@@ -368,7 +369,11 @@ fn main() -> Result<()> {
             let run_span =
                 tracing::info_span!("quire.ci.run", sha = %meta.sha, r#ref = %meta.r#ref);
             if let Some(tp) = sentry_ctx.traceparent.as_deref() {
-                run_span.set_parent(telemetry::context_from_traceparent(tp));
+                let mut carrier = std::collections::HashMap::new();
+                carrier.insert("traceparent".to_string(), tp.to_string());
+                run_span.set_parent(
+                    opentelemetry_sdk::propagation::TraceContextPropagator::new().extract(&carrier),
+                );
             }
             let _run_span = run_span.entered();
 
diff --git a/quire-core/src/telemetry.rs b/quire-core/src/telemetry.rs
index ecac6aa..01731fb 100644
--- a/quire-core/src/telemetry.rs
+++ b/quire-core/src/telemetry.rs
@@ -4,9 +4,7 @@ use std::io::IsTerminal;
 use std::sync::Arc;
 
 use miette::IntoDiagnostic;
-use opentelemetry::propagation::TextMapPropagator as _;
 use opentelemetry::trace::TracerProvider as _;
-use tracing_opentelemetry::OpenTelemetrySpanExt as _;
 use tracing_subscriber::EnvFilter;
 use tracing_subscriber::Layer;
 use tracing_subscriber::layer::SubscriberExt;
@@ -201,24 +199,6 @@ impl Drop for TracingGuard {
     }
 }
 
-/// Extract the W3C traceparent from a tracing span's OTEL context.
-/// Returns None when the span has no valid OTEL context (e.g. OTEL not initialised).
-pub fn traceparent_from_span(span: &tracing::Span) -> Option<String> {
-    let propagator = opentelemetry_sdk::propagation::TraceContextPropagator::new();
-    let cx = span.context();
-    let mut carrier = std::collections::HashMap::new();
-    propagator.inject_context(&cx, &mut carrier);
-    carrier.remove("traceparent")
-}
-
-/// Decode a W3C traceparent string into an OTEL context suitable for
-/// passing to [`tracing_opentelemetry::OpenTelemetrySpanExt::set_parent`].
-pub fn context_from_traceparent(traceparent: &str) -> opentelemetry::Context {
-    let propagator = opentelemetry_sdk::propagation::TraceContextPropagator::new();
-    let mut carrier = std::collections::HashMap::new();
-    carrier.insert("traceparent".to_string(), traceparent.to_string());
-    propagator.extract(&carrier)
-}
 
 /// Initialize the global tracing subscriber with `QUIRE_LOG`-driven filtering,
 /// a stderr fmt layer per `fmt_mode`, the `sentry-tracing` bridge, the
diff --git a/quire-server/Cargo.toml b/quire-server/Cargo.toml
index 84925d5..42fc8ce 100644
--- a/quire-server/Cargo.toml
+++ b/quire-server/Cargo.toml
@@ -28,7 +28,10 @@ serde = { workspace = true }
 serde_json = { workspace = true }
 tempfile = { workspace = true }
 thiserror = { workspace = true }
+opentelemetry = { workspace = true }
+opentelemetry_sdk = { workspace = true }
 tracing = { workspace = true }
+tracing-opentelemetry = { workspace = true }
 
 askama = "*"
 axum = "*"
diff --git a/quire-server/src/ci/mod.rs b/quire-server/src/ci/mod.rs
index e59511f..0487ec0 100644
--- a/quire-server/src/ci/mod.rs
+++ b/quire-server/src/ci/mod.rs
@@ -11,7 +11,8 @@ pub use quire_core::ci::pipeline::{
 pub use quire_core::ci::run::ApiSession;
 pub use quire_core::ci::run::RunMeta;
 pub use quire_core::ci::{pipeline, registration, runtime};
-use quire_core::telemetry;
+use opentelemetry::propagation::TextMapPropagator as _;
+use tracing_opentelemetry::OpenTelemetrySpanExt as _;
 pub use run::{Executor, Run, RunState, Runs, materialize_workspace, reconcile_orphans};
 
 /// A resolved commit reference.
@@ -168,10 +169,12 @@ fn run_ref(ctx: &TriggerContext<'_>, pushed_at: jiff::Timestamp, push_ref: &Push
     let session = ApiSession::new(ctx.port);
 
     let span = tracing::info_span!("quire.ci.run", repo = %ctx.event_repo);
-    let traceparent = ctx
-        .sentry_dsn
-        .as_ref()
-        .and_then(|_| telemetry::traceparent_from_span(&span));
+    let traceparent = {
+        let mut carrier = std::collections::HashMap::new();
+        opentelemetry_sdk::propagation::TraceContextPropagator::new()
+            .inject_context(&span.context(), &mut carrier);
+        carrier.remove("traceparent")
+    };
     let _guard = span.enter();
 
     sentry::with_scope(