pub struct RequestDiagnosticScope<'a> { /* private fields */ }Expand description
Bind once to the existing established request. No empty/default constructor.
use saddle_observability::{RequestDiagnosticScope, EmergencyDiagnosticHandle};
fn missing_context(output: &EmergencyDiagnosticHandle) {
let scope = RequestDiagnosticScope::established(output);
}Implementations§
Source§impl<'a> RequestDiagnosticScope<'a>
impl<'a> RequestDiagnosticScope<'a>
Sourcepub fn unassociated_transport(output: &'a EmergencyDiagnosticHandle) -> Self
pub fn unassociated_transport(output: &'a EmergencyDiagnosticHandle) -> Self
A direct transport operation has no established request. This preserves the original while marking every request fact as not established.
Sourcepub fn outbound_wire(
output: &'a EmergencyDiagnosticHandle,
event: &EventContext,
trace_id: &str,
rpc_id: &str,
zone: &str,
) -> Option<Self>
pub fn outbound_wire( output: &'a EmergencyDiagnosticHandle, event: &EventContext, trace_id: &str, rpc_id: &str, zone: &str, ) -> Option<Self>
Preserve validated wire association when the observer could not create a CallContext. Missing observer facts stay explicitly unavailable.
Sourcepub fn source_error_with_target<T: Serialize>(
&self,
error: &(dyn Error + 'static),
target: &T,
category: DiagnosticCategory,
cause: BoundedDiagnosticCause,
) -> RequestSourceReceipt
pub fn source_error_with_target<T: Serialize>( &self, error: &(dyn Error + 'static), target: &T, category: DiagnosticCategory, cause: BoundedDiagnosticCause, ) -> RequestSourceReceipt
Capture a borrowed foreign error and its caller-supplied, validated source target under this exact request projection and occurrence. Written means every original segment, including the terminator, was synchronously acknowledged by the existing emergency file writer.
Sourcepub fn source_borrowed_error_with_target<T: Serialize, E: Error>(
&self,
error: &E,
target: &T,
category: DiagnosticCategory,
cause: BoundedDiagnosticCause,
) -> RequestSourceReceipt
pub fn source_borrowed_error_with_target<T: Serialize, E: Error>( &self, error: &E, target: &T, category: DiagnosticCategory, cause: BoundedDiagnosticCause, ) -> RequestSourceReceipt
Capture a borrowed first error before traversing its static source chain.
Sourcepub fn early(
output: Option<&'a EmergencyDiagnosticHandle>,
early: EarlyRequestContext,
) -> Self
pub fn early( output: Option<&'a EmergencyDiagnosticHandle>, early: EarlyRequestContext, ) -> Self
Same source issuer for early and established requests. Output availability is independent of identity absence; None never skips source retention.
Examples found in repository?
32fn main() {
33 // Caller is at the accepted socket phase; no trace, span, request or task is
34 // fabricated to satisfy a constructor. The output may genuinely be absent.
35 let scope =
36 RequestDiagnosticScope::early(None, EarlyRequestContext::socket_accepted("example"))
37 .with_phase(DiagnosticRequestPhase::ReadingHead);
38 let failure = match read_head(&mut io::empty(), &scope) {
39 Err(failure) => failure,
40 Ok(()) => panic!("owned empty reader must fail"),
41 };
42 let id = failure.source_diagnostic().id();
43 let (retained, delivery) = failure.finish_boundary_retained(
44 None,
45 &DiagnosticOutcomeAxes {
46 operation: OperationOutcome::Failed,
47 ..Default::default()
48 },
49 );
50 assert_eq!(retained.error().kind(), io::ErrorKind::UnexpectedEof);
51 assert_eq!(retained.source_diagnostic().id(), id);
52 assert_eq!(
53 delivery.source_submission(),
54 DiagnosticSubmission::OutputUnavailable
55 );
56 assert_eq!(
57 delivery.boundary_submission(),
58 DiagnosticSubmission::OutputUnavailable
59 );
60 // Real consumer keeps `retained` in its task/response result, not just bool.
61 println!("GO: early source retained without invented identities or output");
62}Sourcepub fn with_output<'b>(
self,
output: Option<&'b EmergencyDiagnosticHandle>,
) -> RequestDiagnosticScope<'b>
pub fn with_output<'b>( self, output: Option<&'b EmergencyDiagnosticHandle>, ) -> RequestDiagnosticScope<'b>
Move the existing projection to an available/unavailable output without replacing any context. Useful when an owning task retains the handle.
Sourcepub fn reborrow(&self) -> RequestDiagnosticScope<'a>
pub fn reborrow(&self) -> RequestDiagnosticScope<'a>
Fixed read-only snapshot for a task’s parent/child observation sites. Copies no receipt or execution owner. Later enrichment is NOT retroactive; a join fallback can only claim facts actually retained at spawn time.
Sourcepub fn record_nonfailure(
&self,
axes: &DiagnosticOutcomeAxes,
) -> Result<DiagnosticSubmission, ()>
pub fn record_nonfailure( &self, axes: &DiagnosticOutcomeAxes, ) -> Result<DiagnosticSubmission, ()>
Observe an ordinary completed operation with the exact early/established projection. Technical failures still require their mandatory carrier.
Sourcepub fn with_task(
self,
task: DiagnosticTaskId,
) -> Result<Self, ContextBindingError<Self>>
pub fn with_task( self, task: DiagnosticTaskId, ) -> Result<Self, ContextBindingError<Self>>
Examples found in repository?
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}Sourcepub fn bind_request_identity(
self,
request: &RequestIdentity,
) -> Result<Self, ContextBindingError<Self>>
pub fn bind_request_identity( self, request: &RequestIdentity, ) -> Result<Self, ContextBindingError<Self>>
Bind only facts actually established by the ingress owner. On conflict no partial update occurs; task/zone/scope and prior receipts stay unchanged.
pub fn bind_established( self, call: &CallContext, event: &EventContext, ) -> Result<Self, ContextBindingError<Self>>
Sourcepub fn derive_outbound_child(
&self,
call: &CallContext,
event: &EventContext,
) -> Result<RequestDiagnosticScope<'a>, DiagnosticContextField>
pub fn derive_outbound_child( &self, call: &CallContext, event: &EventContext, ) -> Result<RequestDiagnosticScope<'a>, DiagnosticContextField>
Derive the actual outbound call without rewriting the inbound scope.
The caller supplies Boundary’s existing child Call/Event (not invented
identities). Trace and request must already be known and match exactly;
RPC must be a direct parent.<decimal sequence> child and span must differ.
Missing parent identity cannot establish this relationship. Request
comparison uses a private exact copy, never the redacted display value.
This validates diagnostic metadata, not execution/transport authority.
Examples found in repository?
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}Sourcepub fn with_phase(self, phase: DiagnosticRequestPhase) -> Self
pub fn with_phase(self, phase: DiagnosticRequestPhase) -> Self
Advances this projection only; retained source receipts are snapshots.
Examples found in repository?
32fn main() {
33 // Caller is at the accepted socket phase; no trace, span, request or task is
34 // fabricated to satisfy a constructor. The output may genuinely be absent.
35 let scope =
36 RequestDiagnosticScope::early(None, EarlyRequestContext::socket_accepted("example"))
37 .with_phase(DiagnosticRequestPhase::ReadingHead);
38 let failure = match read_head(&mut io::empty(), &scope) {
39 Err(failure) => failure,
40 Ok(()) => panic!("owned empty reader must fail"),
41 };
42 let id = failure.source_diagnostic().id();
43 let (retained, delivery) = failure.finish_boundary_retained(
44 None,
45 &DiagnosticOutcomeAxes {
46 operation: OperationOutcome::Failed,
47 ..Default::default()
48 },
49 );
50 assert_eq!(retained.error().kind(), io::ErrorKind::UnexpectedEof);
51 assert_eq!(retained.source_diagnostic().id(), id);
52 assert_eq!(
53 delivery.source_submission(),
54 DiagnosticSubmission::OutputUnavailable
55 );
56 assert_eq!(
57 delivery.boundary_submission(),
58 DiagnosticSubmission::OutputUnavailable
59 );
60 // Real consumer keeps `retained` in its task/response result, not just bool.
61 println!("GO: early source retained without invented identities or output");
62}Sourcepub fn with_missing(
self,
field: DiagnosticContextField,
reason: DiagnosticContextMissing,
) -> Self
pub fn with_missing( self, field: DiagnosticContextField, reason: DiagnosticContextMissing, ) -> Self
Missing assertions cannot erase known facts. No arbitrary key/value API.
Sourcepub fn live_db_scope(
output: Option<&'a EmergencyDiagnosticHandle>,
projection: &DbScopeDiagnosticContext<(&CallContext, &EventContext)>,
) -> Self
pub fn live_db_scope( output: Option<&'a EmergencyDiagnosticHandle>, projection: &DbScopeDiagnosticContext<(&CallContext, &EventContext)>, ) -> Self
Projection from a checked live request pair; no SQL-entry side effects.
Sourcepub fn with_db_operation(self, operation: DiagnosticDbOperation) -> Self
pub fn with_db_operation(self, operation: DiagnosticDbOperation) -> Self
Adds only the registered DB operation; original request/scope are intact.
Sourcepub fn set_db_operation(&mut self, operation: DiagnosticDbOperation)
pub fn set_db_operation(&mut self, operation: DiagnosticDbOperation)
Advances only this scope’s next-operation projection. Previously issued receipts own a value snapshot and are never rewritten.
pub fn with_db_operation_missing(self, reason: DiagnosticContextMissing) -> Self
Sourcepub fn with_zone(self, zone: DiagnosticZone) -> Self
pub fn with_zone(self, zone: DiagnosticZone) -> Self
Source owner supplies the original accepted zone before source capture. Every subsequent source/boundary projection includes it automatically.
Examples found in repository?
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}pub fn with_zone_missing(self, reason: DiagnosticContextMissing) -> Self
Sourcepub fn db_scope(
output: &'a EmergencyDiagnosticHandle,
observation: &DbScopeObservation<(Observer, CallContext, EventContext)>,
) -> Self
pub fn db_scope( output: &'a EmergencyDiagnosticHandle, observation: &DbScopeObservation<(Observer, CallContext, EventContext)>, ) -> Self
Takes BOTH context and scope from the same checked token, never a raw ID or a separately supplied CallContext. Borrowing leaves terminal use intact.
pub fn established( output: &'a EmergencyDiagnosticHandle, call: &CallContext, event: &EventContext, ) -> Self
Explicit degraded route. Context is still mandatory; no successful submission or writer readiness is inferred.
Examples found in repository?
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}Sourcepub fn ingress_deadline_bound(
&self,
ingress_deadline_unix_ms: i64,
) -> DiagnosticSubmission
pub fn ingress_deadline_bound( &self, ingress_deadline_unix_ms: i64, ) -> DiagnosticSubmission
Final bound ingress deadline; no clock reads or new identity.
Sourcepub fn capture_required(
&self,
diagnostic: BoundedDiagnostic,
) -> RequestSourceReceipt
pub fn capture_required( &self, diagnostic: BoundedDiagnostic, ) -> RequestSourceReceipt
Consumes existing source facts without capturing a replacement identity.
Sourcepub fn capture_existing(
&self,
diagnostic: Diagnostic,
observer: Option<&Observer>,
) -> ExistingDiagnosticReceipt
pub fn capture_existing( &self, diagnostic: Diagnostic, observer: Option<&Observer>, ) -> ExistingDiagnosticReceipt
First submission of an already captured panic/cleanup diagnostic.
Moves the original carrier, never recaptures or clones its stack.
observer preserves the existing main-log mirror when one is available.
Uses the legacy allocating 32KiB encoder, NOT the admitted bounded path.
Sourcepub fn fail<E>(
&self,
error: E,
category: DiagnosticCategory,
cause: BoundedDiagnosticCause,
) -> FrameworkRequestFailure<E>
pub fn fail<E>( &self, error: E, category: DiagnosticCategory, cause: BoundedDiagnosticCause, ) -> FrameworkRequestFailure<E>
Capture at the real source, before exposing its error to a caller. Submission degradation never changes the source error.
Examples found in repository?
14fn read_head(
15 reader: &mut impl Read,
16 scope: &RequestDiagnosticScope<'_>,
17) -> Result<(), FrameworkRequestFailure<io::Error>> {
18 reader.read_exact(&mut [0; 1]).map_err(|error| {
19 let kind = match error.kind() {
20 io::ErrorKind::UnexpectedEof => "io.unexpected_eof",
21 io::ErrorKind::TimedOut => "io.timed_out",
22 _ => "io.other",
23 };
24 let cause = BoundedDiagnosticCause::new(
25 DiagnosticStage::RequestDecode,
26 DiagnosticCode::new("request.read_failed").unwrap(),
27 )
28 .with_system(DiagnosticCode::new(kind).unwrap(), error.raw_os_error());
29 scope.fail(error, DiagnosticCategory::UnexpectedError, cause)
30 })
31}More examples
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}