asupersync 0.3.4

Spec-first, cancel-correct, capability-secure async runtime for Rust.
Documentation
//! OTLP-Trace exporter parent sampling decision propagation audit.
//!
//! **Audit Question**: Does child span inherit parent sampling decision (correct)
//! or independently sample (incorrect: trace fragmentation)?
//!
//! **W3C Trace Context Requirement**: Per W3C trace-context specification,
//! sampling decisions must be consistent within a trace to prevent trace
//! fragmentation across distributed service boundaries.
//!
//! **Expected Behavior**: When parent span is non-sampled (sampling=Drop),
//! all child spans MUST also be non-sampled, regardless of any independent
//! sampling logic.

#[cfg(test)]
mod tests {
    use crate::observability::w3c_trace_context::{W3CTraceContext, TraceFlags, TraceId, SpanId};

    #[test]
    fn otlp_parent_sampling_propagation_audit() {
        eprintln!("\n🔍 OTLP PARENT SAMPLING PROPAGATION AUDIT");
        eprintln!("===========================================");

        // Test 1: Parent SAMPLED → Child should be SAMPLED
        {
            let parent = W3CTraceContext::new_root(); // Root spans are sampled by default
            let child = parent.create_child();

            eprintln!("\n📋 Test 1: Sampled parent → sampled child");
            eprintln!("  Parent sampled: {}", parent.flags.is_sampled());
            eprintln!("  Child sampled:  {}", child.flags.is_sampled());

            assert!(
                parent.flags.is_sampled(),
                "Root span should be sampled by default"
            );
            assert!(
                child.flags.is_sampled(),
                "Child should inherit SAMPLED decision from parent"
            );

            eprintln!("  ✅ CORRECT: Child inherits SAMPLED decision");
        }

        // Test 2: Parent NOT SAMPLED → Child should NOT be SAMPLED
        {
            let mut parent = W3CTraceContext::new_root();
            parent.flags = TraceFlags::NONE; // Explicitly set to NOT sampled
            let child = parent.create_child();

            eprintln!("\n📋 Test 2: Non-sampled parent → non-sampled child");
            eprintln!("  Parent sampled: {}", parent.flags.is_sampled());
            eprintln!("  Child sampled:  {}", child.flags.is_sampled());

            assert!(
                !parent.flags.is_sampled(),
                "Parent should NOT be sampled when explicitly set to NONE"
            );
            assert!(
                !child.flags.is_sampled(),
                "Child should inherit NON-SAMPLED decision from parent"
            );

            eprintln!("  ✅ CORRECT: Child inherits NON-SAMPLED decision");
        }

        // Test 3: Multi-level inheritance (grandchild)
        {
            let mut parent = W3CTraceContext::new_root();
            parent.flags = TraceFlags::NONE; // Grandparent not sampled
            let child = parent.create_child();
            let grandchild = child.create_child();

            eprintln!("\n📋 Test 3: Multi-level inheritance");
            eprintln!("  Grandparent sampled: {}", parent.flags.is_sampled());
            eprintln!("  Parent sampled:      {}", child.flags.is_sampled());
            eprintln!("  Grandchild sampled:  {}", grandchild.flags.is_sampled());

            assert!(
                !parent.flags.is_sampled() && !child.flags.is_sampled() && !grandchild.flags.is_sampled(),
                "All generations should inherit NON-SAMPLED decision from root"
            );

            eprintln!("  ✅ CORRECT: Sampling decision propagates through multiple generations");
        }

        // Test 4: Trace ID consistency verification
        {
            let mut parent = W3CTraceContext::new_root();
            parent.flags = TraceFlags::NONE;
            let child = parent.create_child();

            eprintln!("\n📋 Test 4: Trace ID consistency with sampling");
            eprintln!("  Parent trace_id: {}", parent.trace_id.to_hex());
            eprintln!("  Child trace_id:  {}", child.trace_id.to_hex());

            assert_eq!(
                parent.trace_id.to_hex(),
                child.trace_id.to_hex(),
                "Child should maintain same trace_id as parent"
            );

            eprintln!("  ✅ CORRECT: Trace ID preserved with sampling decision");
        }

        eprintln!("\n🎯 AUDIT CONCLUSION");
        eprintln!("==================");
        eprintln!("✅ SOUND: Parent sampling decision properly propagates to children");
        eprintln!("✅ Prevents trace fragmentation per W3C trace-context specification");
        eprintln!("✅ Non-sampled parents produce non-sampled children (no independent sampling)");
        eprintln!("✅ Multi-generation inheritance works correctly");
        eprintln!("✅ Trace ID consistency maintained with sampling decisions");
        eprintln!("");
        eprintln!("📌 BEHAVIOR: Current implementation correctly implements option (a):");
        eprintln!("   Parent decision propagates (correct: prevents trace fragmentation)");
        eprintln!("   NOT option (b): Independent sampling (incorrect: causes fragmentation)");
    }

    #[test]
    fn w3c_trace_context_sampling_compliance() {
        eprintln!("\n🌐 W3C TRACE CONTEXT SAMPLING COMPLIANCE AUDIT");
        eprintln!("==============================================");

        // Verify TraceFlags behavior matches W3C specification
        {
            // Test SAMPLED flag
            let sampled_flags = TraceFlags::SAMPLED;
            assert!(sampled_flags.is_sampled());
            assert_eq!(sampled_flags.bits(), 0x01);

            // Test NONE flag (not sampled)
            let none_flags = TraceFlags::NONE;
            assert!(!none_flags.is_sampled());
            assert_eq!(none_flags.bits(), 0x00);

            eprintln!("✅ TraceFlags implementation matches W3C specification");
        }

        eprintln!("\n📋 COMPLIANCE VERIFIED:");
        eprintln!("  ✅ TraceFlags::SAMPLED = 0x01 (per W3C spec)");
        eprintln!("  ✅ TraceFlags::NONE = 0x00 (not sampled)");
        eprintln!("  ✅ is_sampled() correctly interprets flags");
        eprintln!("  ✅ W3CTraceContext::create_child() preserves parent flags");
    }

    /// Demonstrate DEFECTIVE independent sampling behavior (what we should NOT do).
    #[test]
    #[should_panic(expected = "DEFECTIVE: Independent sampling breaks W3C compliance")]
    fn demonstrate_defective_independent_sampling() {
        eprintln!("\n❌ DEMONSTRATING DEFECTIVE INDEPENDENT SAMPLING");
        eprintln!("==============================================");

        // This would be the WRONG way to handle child span sampling
        struct DefectiveSpan {
            sampled: bool,
        }

        impl DefectiveSpan {
            fn new_independent_sampled(_name: &str) -> Self {
                // ❌ DEFECTIVE: Independent sampling decision ignoring parent
                // This breaks W3C compliance and fragments traces!
                Self { sampled: true } // Always sample independently
            }
        }

        // Parent is explicitly NOT sampled
        let parent_sampled = false;

        // ❌ DEFECTIVE: Child ignores parent decision
        let child = DefectiveSpan::new_independent_sampled("defective_child");

        eprintln!("Parent sampled: {}", parent_sampled);
        eprintln!("Child sampled:  {}", child.sampled);

        // This creates trace fragmentation!
        if parent_sampled != child.sampled {
            eprintln!("💥 TRACE FRAGMENTATION: Parent and child have different sampling decisions!");
            eprintln!("This breaks distributed tracing and violates W3C trace-context spec!");
            panic!("DEFECTIVE: Independent sampling breaks W3C compliance");
        }
    }
}