Skip to main content

outbound_child_diagnostic/
outbound_child_diagnostic.rs

1//! OC consumer: same Call/Event construction as Boundary invoke_routed_with_output.
2//! No network, generated Facade integration, or new diagnostic outlet.
3use saddle_core::{
4    BoundedDiagnosticCause, DiagnosticCategory, DiagnosticCode, DiagnosticOutcomeAxes,
5    DiagnosticStage, RpcCorrelationId,
6};
7use saddle_observability::{
8    DiagnosticSubmission, DiagnosticTaskId, DiagnosticZone, EventContext, Observer, ObserverConfig,
9    RequestDiagnosticScope, RequestIdentity, RouteIdentity,
10};
11
12fn main() {
13    let observer = Observer::with_writer(ObserverConfig::default(), std::io::sink()).unwrap();
14    let (incoming, _) = observer
15        .start_external_call_with_rpc(
16            "shop",
17            "ingress",
18            "orders",
19            "query",
20            Some("gateway-opaque"),
21            RpcCorrelationId::new("0.3").unwrap(),
22        )
23        .unwrap();
24    let ingress_event = EventContext::new(
25        RequestIdentity::new("request-7").unwrap(),
26        RouteIdentity::new("/incoming").unwrap(),
27        1,
28    )
29    .unwrap();
30    let parent = RequestDiagnosticScope::output_unavailable(incoming.context(), &ingress_event)
31        .with_task(DiagnosticTaskId::from_runtime_id("42").unwrap())
32        .unwrap_or_else(|_| panic!("task"))
33        .with_zone(DiagnosticZone::from_validated_ingress("zone-a").unwrap());
34
35    // programming.rs generates the wire child; Boundary uses its trace/rpc plus
36    // request_id/function. The adapter below does NOT generate these identities.
37    let wire_trace = "gateway-opaque";
38    let wire_rpc = "0.3.1";
39    let request_id = "request-7";
40    let function = "remote.query";
41    let (root, _) = observer
42        .start_external_call_with_rpc(
43            "saddle",
44            "zone-a",
45            "profusecontract",
46            "invoke",
47            Some(wire_trace),
48            RpcCorrelationId::new(wire_rpc).unwrap(),
49        )
50        .unwrap();
51    let event = EventContext::new(
52        RequestIdentity::new(request_id).unwrap(),
53        RouteIdentity::new(function).unwrap(),
54        1,
55    )
56    .unwrap();
57    let child = parent
58        .derive_outbound_child(root.context(), &event)
59        .unwrap();
60    let failure = child.fail(
61        std::io::ErrorKind::ConnectionRefused,
62        DiagnosticCategory::UnexpectedError,
63        BoundedDiagnosticCause::new(
64            DiagnosticStage::RequestDecode,
65            DiagnosticCode::new("outbound.connect_failed").unwrap(),
66        ),
67    );
68    let id = failure.source_diagnostic().id();
69    let (retained, delivery) =
70        failure.finish_boundary_retained(None, &DiagnosticOutcomeAxes::default());
71    assert_eq!(retained.source_diagnostic().id(), id);
72    assert_eq!(*retained.error(), std::io::ErrorKind::ConnectionRefused);
73    assert_eq!(
74        delivery.source_submission(),
75        DiagnosticSubmission::OutputUnavailable
76    );
77    assert_eq!(
78        delivery.boundary_submission(),
79        DiagnosticSubmission::OutputUnavailable
80    );
81    println!("GO: Boundary-shaped child Call/Event consumed; absent output retains same failure");
82}