Skip to main content

aion_core/
status.rs

1//! Workflow status projection from authoritative event history.
2
3use serde::{Deserialize, Serialize};
4
5use crate::{Event, RunId};
6
7/// Projected lifecycle status for a workflow execution.
8///
9/// Status must be obtained only by projecting from event history with
10/// [`status_from_events`], never assigned directly or stored as an independent
11/// mutable field. Event history remains authoritative for every workflow state.
12#[derive(Serialize, Deserialize, ts_rs::TS, Clone, Copy, Debug, PartialEq, Eq)]
13pub enum WorkflowStatus {
14    /// The workflow has not recorded a terminal lifecycle event.
15    Running,
16    /// The workflow recorded a [`Event::WorkflowCompleted`] terminal event.
17    Completed,
18    /// The workflow recorded a [`Event::WorkflowFailed`] terminal event.
19    Failed,
20    /// The workflow recorded a [`Event::WorkflowCancelled`] terminal event.
21    Cancelled,
22    /// The workflow recorded a [`Event::WorkflowTimedOut`] terminal event.
23    TimedOut,
24    /// The workflow recorded a [`Event::WorkflowContinuedAsNew`] terminal event.
25    ContinuedAsNew,
26    /// The workflow recorded a [`Event::WorkflowPaused`] marker with no later
27    /// [`Event::WorkflowResumed`]. NON-terminal: the run has recorded no terminal
28    /// event and can still complete/fail/cancel or be resumed.
29    Paused,
30}
31
32impl WorkflowStatus {
33    /// Returns whether this status represents a terminal workflow execution state.
34    #[must_use]
35    pub const fn is_terminal(self) -> bool {
36        match self {
37            // Paused is non-terminal: complete/fail/cancel stay reachable, and a
38            // paused run is excluded from the active set without being terminal.
39            Self::Running | Self::Paused => false,
40            Self::Completed
41            | Self::Failed
42            | Self::Cancelled
43            | Self::TimedOut
44            | Self::ContinuedAsNew => true,
45        }
46    }
47}
48
49/// Projects workflow status from an event history.
50///
51/// The last terminal workflow lifecycle event determines the projected status.
52/// Histories without a terminal workflow event are considered running.
53/// When a history contains multiple runs for continue-as-new, a later
54/// [`Event::WorkflowStarted`] begins the current run and supersedes earlier
55/// terminal events from the previous run.
56#[must_use]
57pub fn status_from_events(events: &[Event]) -> WorkflowStatus {
58    events
59        .iter()
60        .rev()
61        .find_map(|event| match event {
62            // A run start and a reopen both put the run in Running. A reopen
63            // supersedes the run's prior terminal event under this same
64            // last-lifecycle-event-wins scan.
65            // A run start, a reopen, and a resume all put the run in Running. A
66            // resume supersedes the run's prior WorkflowPaused under this same
67            // last-lifecycle-event-wins scan.
68            Event::WorkflowStarted { .. }
69            | Event::WorkflowReopened { .. }
70            | Event::WorkflowResumed { .. } => Some(WorkflowStatus::Running),
71            Event::WorkflowCompleted { .. } => Some(WorkflowStatus::Completed),
72            Event::WorkflowFailed { .. } => Some(WorkflowStatus::Failed),
73            Event::WorkflowCancelled { .. } => Some(WorkflowStatus::Cancelled),
74            Event::WorkflowTimedOut { .. } => Some(WorkflowStatus::TimedOut),
75            Event::WorkflowContinuedAsNew { .. } => Some(WorkflowStatus::ContinuedAsNew),
76            // Paused is the one non-terminal lifecycle event that projects a
77            // distinct status; a later WorkflowResumed supersedes it above.
78            Event::WorkflowPaused { .. } => Some(WorkflowStatus::Paused),
79            Event::SearchAttributesUpdated { .. }
80            | Event::ActivityScheduled { .. }
81            | Event::ActivityStarted { .. }
82            | Event::ActivityAdoptionOffered { .. }
83            | Event::ActivityCompleted { .. }
84            | Event::ActivityFailed { .. }
85            // The advisory warning says a SIDE CHANNEL failed; it says
86            // nothing about the run's outcome, so it projects no status.
87            | Event::ActivityAdvisoryExhausted { .. }
88            // A fallback hop is an open-trail routing fact, not a run outcome.
89            | Event::ActivityFallbackRouted { .. }
90            | Event::ActivityCancelled { .. }
91            | Event::TimerStarted { .. }
92            | Event::TimerFired { .. }
93            | Event::TimerCancelled { .. }
94            | Event::WithTimeoutCompleted { .. }
95            | Event::SignalReceived { .. }
96            | Event::SignalSent { .. }
97            | Event::ChildWorkflowStarted { .. }
98            | Event::ChildWorkflowCompleted { .. }
99            | Event::ChildWorkflowFailed { .. }
100            | Event::ChildWorkflowCancelled { .. }
101            | Event::ScheduleCreated { .. }
102            | Event::ScheduleUpdated { .. }
103            | Event::SchedulePaused { .. }
104            | Event::ScheduleResumed { .. }
105            | Event::ScheduleDeleted { .. }
106            | Event::ScheduleTriggered { .. } => None,
107        })
108        .unwrap_or(WorkflowStatus::Running)
109}
110
111/// Returns the terminal lifecycle event of the run's current lease, or `None`
112/// when the run is not currently terminal — either it never recorded a terminal
113/// event, or a later [`Event::WorkflowReopened`] reopened it.
114///
115/// This is the single reset-aware terminal predicate every site derives from:
116/// close-time is its `recorded_at`, the terminal outcome is a match on the
117/// returned event, and "is the run terminal now" is `is_some()`. Scanning back
118/// from the end it stops at the first reset point (a run start or a reopen), so
119/// terminality is scoped to "since the last reopen point" — a run holds exactly
120/// one terminal event per lease.
121#[must_use]
122pub fn current_lease_terminal(events: &[Event]) -> Option<&Event> {
123    events
124        .iter()
125        .rev()
126        .find_map(|event| match event {
127            Event::WorkflowCompleted { .. }
128            | Event::WorkflowFailed { .. }
129            | Event::WorkflowCancelled { .. }
130            | Event::WorkflowTimedOut { .. }
131            | Event::WorkflowContinuedAsNew { .. } => Some(Some(event)),
132            // Reset points: the current lease has no terminal before them.
133            Event::WorkflowStarted { .. } | Event::WorkflowReopened { .. } => Some(None),
134            // Pause/resume are neither a terminal nor a run-start reset — they
135            // fall through like SearchAttributesUpdated, so a paused (or resumed)
136            // run keeps whatever current-lease terminal state it otherwise has
137            // (None while live), leaving complete/fail/cancel reachable.
138            Event::WorkflowPaused { .. }
139            | Event::WorkflowResumed { .. }
140            | Event::SearchAttributesUpdated { .. }
141            | Event::ActivityScheduled { .. }
142            | Event::ActivityStarted { .. }
143            | Event::ActivityAdoptionOffered { .. }
144            | Event::ActivityCompleted { .. }
145            | Event::ActivityFailed { .. }
146            // The advisory warning says a SIDE CHANNEL failed; it says
147            // nothing about the run's outcome, so it projects no status.
148            | Event::ActivityAdvisoryExhausted { .. }
149            // A fallback hop is an open-trail routing fact, not a run outcome.
150            | Event::ActivityFallbackRouted { .. }
151            | Event::ActivityCancelled { .. }
152            | Event::TimerStarted { .. }
153            | Event::TimerFired { .. }
154            | Event::TimerCancelled { .. }
155            | Event::WithTimeoutCompleted { .. }
156            | Event::SignalReceived { .. }
157            | Event::SignalSent { .. }
158            | Event::ChildWorkflowStarted { .. }
159            | Event::ChildWorkflowCompleted { .. }
160            | Event::ChildWorkflowFailed { .. }
161            | Event::ChildWorkflowCancelled { .. }
162            | Event::ScheduleCreated { .. }
163            | Event::ScheduleUpdated { .. }
164            | Event::SchedulePaused { .. }
165            | Event::ScheduleResumed { .. }
166            | Event::ScheduleDeleted { .. }
167            | Event::ScheduleTriggered { .. } => None,
168        })
169        .flatten()
170}
171
172/// Returns the slice of `events` belonging to the run identified by `run_id`:
173/// from that run's [`Event::WorkflowStarted`] up to (but excluding) the next
174/// run's start, or an empty slice when the run is absent.
175///
176/// Scoping [`current_lease_terminal`] to a `run_segment` answers "is this
177/// particular run currently terminal" without a separate bespoke scan per call
178/// site.
179#[must_use]
180pub fn run_segment<'a>(events: &'a [Event], run_id: &RunId) -> &'a [Event] {
181    let Some(start) = events.iter().position(
182        |event| matches!(event, Event::WorkflowStarted { run_id: id, .. } if id == run_id),
183    ) else {
184        return &[];
185    };
186    let end = events[start + 1..]
187        .iter()
188        .position(|event| matches!(event, Event::WorkflowStarted { .. }))
189        .map_or(events.len(), |offset| start + 1 + offset);
190    &events[start..end]
191}
192
193#[cfg(test)]
194mod tests {
195    use std::collections::HashMap;
196
197    use chrono::{DateTime, Utc};
198    use serde_json::json;
199
200    use super::{WorkflowStatus, current_lease_terminal, run_segment, status_from_events};
201    use crate::{
202        ActivityId, Event, EventEnvelope, Payload, RunId, ScheduleId, SearchAttributeValue,
203        WorkflowError, WorkflowId,
204    };
205
206    fn recorded_at(offset: i64) -> DateTime<Utc> {
207        DateTime::from_timestamp(1_700_000_000 + offset, 0).unwrap_or_default()
208    }
209
210    fn envelope(seq: u64) -> EventEnvelope {
211        EventEnvelope {
212            seq,
213            recorded_at: recorded_at(i64::try_from(seq).unwrap_or(0)),
214            workflow_id: WorkflowId::new(uuid::Uuid::nil()),
215        }
216    }
217
218    fn payload(label: &str) -> Result<Payload, crate::PayloadError> {
219        Payload::from_json(&json!({ "label": label }))
220    }
221
222    fn workflow_started(seq: u64) -> Result<Event, crate::PayloadError> {
223        Ok(Event::WorkflowStarted {
224            envelope: envelope(seq),
225            workflow_type: String::from("checkout"),
226            input: payload("input")?,
227            run_id: RunId::new(uuid::Uuid::from_u128(1)),
228            parent_run_id: None,
229            parent_workflow_id: None,
230            package_version: crate::PackageVersion::new("a".repeat(64)),
231        })
232    }
233
234    fn workflow_error(message: &str) -> WorkflowError {
235        WorkflowError {
236            message: String::from(message),
237            details: None,
238        }
239    }
240
241    #[test]
242    fn empty_history_projects_to_running() {
243        assert_eq!(status_from_events(&[]), WorkflowStatus::Running);
244    }
245
246    #[test]
247    fn replacement_start_projects_continue_as_new_chain_running() -> Result<(), crate::PayloadError>
248    {
249        let parent_run_id = RunId::new(uuid::Uuid::from_u128(7));
250        let events = vec![
251            workflow_started(1)?,
252            Event::WorkflowContinuedAsNew {
253                envelope: envelope(2),
254                input: payload("replacement")?,
255                workflow_type: None,
256                parent_run_id: parent_run_id.clone(),
257            },
258            Event::WorkflowStarted {
259                envelope: envelope(3),
260                workflow_type: String::from("checkout"),
261                input: payload("replacement")?,
262                run_id: RunId::new(uuid::Uuid::from_u128(1)),
263                parent_run_id: Some(parent_run_id),
264                parent_workflow_id: None,
265                package_version: crate::PackageVersion::new("a".repeat(64)),
266            },
267        ];
268
269        assert_eq!(status_from_events(&events), WorkflowStatus::Running);
270        Ok(())
271    }
272
273    #[test]
274    fn completed_terminal_event_projects_to_completed() -> Result<(), Box<dyn std::error::Error>> {
275        let events = vec![
276            workflow_started(1)?,
277            Event::WorkflowCompleted {
278                envelope: envelope(2),
279                result: payload("result")?,
280            },
281        ];
282
283        assert_eq!(status_from_events(&events), WorkflowStatus::Completed);
284        Ok(())
285    }
286
287    #[test]
288    fn failed_terminal_event_projects_to_failed() -> Result<(), Box<dyn std::error::Error>> {
289        let events = vec![
290            workflow_started(1)?,
291            Event::WorkflowFailed {
292                envelope: envelope(2),
293                error: workflow_error("failed"),
294            },
295        ];
296
297        assert_eq!(status_from_events(&events), WorkflowStatus::Failed);
298        Ok(())
299    }
300
301    #[test]
302    fn cancelled_terminal_event_projects_to_cancelled() -> Result<(), Box<dyn std::error::Error>> {
303        let events = vec![
304            workflow_started(1)?,
305            Event::WorkflowCancelled {
306                envelope: envelope(2),
307                reason: String::from("caller requested cancellation"),
308            },
309        ];
310
311        assert_eq!(status_from_events(&events), WorkflowStatus::Cancelled);
312        Ok(())
313    }
314
315    #[test]
316    fn timed_out_terminal_event_projects_to_timed_out() -> Result<(), Box<dyn std::error::Error>> {
317        let events = vec![
318            workflow_started(1)?,
319            Event::WorkflowTimedOut {
320                envelope: envelope(2),
321                timeout: String::from("execution"),
322            },
323        ];
324
325        assert_eq!(status_from_events(&events), WorkflowStatus::TimedOut);
326        Ok(())
327    }
328
329    #[test]
330    fn continued_as_new_projects_status() -> Result<(), Box<dyn std::error::Error>> {
331        let events = vec![
332            workflow_started(1)?,
333            Event::WorkflowContinuedAsNew {
334                envelope: envelope(2),
335                input: payload("continued-input")?,
336                workflow_type: Some(String::from("checkout-v2")),
337                parent_run_id: RunId::new(uuid::Uuid::from_u128(2)),
338            },
339        ];
340
341        assert_eq!(status_from_events(&events), WorkflowStatus::ContinuedAsNew);
342        Ok(())
343    }
344
345    #[test]
346    fn workflow_status_terminality_classifies_running_and_terminal_statuses() {
347        assert!(!WorkflowStatus::Running.is_terminal());
348        assert!(WorkflowStatus::Completed.is_terminal());
349        assert!(WorkflowStatus::Failed.is_terminal());
350        assert!(WorkflowStatus::Cancelled.is_terminal());
351        assert!(WorkflowStatus::TimedOut.is_terminal());
352        assert!(WorkflowStatus::ContinuedAsNew.is_terminal());
353    }
354
355    #[test]
356    fn started_then_continued_as_new_projects_status() -> Result<(), Box<dyn std::error::Error>> {
357        let events = vec![
358            workflow_started(1)?,
359            Event::WorkflowContinuedAsNew {
360                envelope: envelope(2),
361                input: payload("continued-input")?,
362                workflow_type: None,
363                parent_run_id: RunId::new(uuid::Uuid::from_u128(3)),
364            },
365        ];
366
367        assert_eq!(status_from_events(&events), WorkflowStatus::ContinuedAsNew);
368        Ok(())
369    }
370
371    #[test]
372    fn non_terminal_history_projects_to_running() -> Result<(), Box<dyn std::error::Error>> {
373        let events = vec![
374            workflow_started(1)?,
375            Event::SearchAttributesUpdated {
376                envelope: envelope(2),
377                workflow_id: WorkflowId::new(uuid::Uuid::nil()),
378                attributes: HashMap::from([(
379                    String::from("customer_id"),
380                    SearchAttributeValue::String(String::from("customer-123")),
381                )]),
382            },
383            Event::ActivityScheduled {
384                envelope: envelope(3),
385                activity_id: ActivityId::from_sequence_position(3),
386                activity_type: String::from("charge-card"),
387                input: payload("activity-input")?,
388                task_queue: String::from("default"),
389                node: None,
390            },
391        ];
392
393        assert_eq!(status_from_events(&events), WorkflowStatus::Running);
394        Ok(())
395    }
396
397    #[test]
398    fn schedule_events_do_not_change_workflow_status() -> Result<(), Box<dyn std::error::Error>> {
399        let events = vec![
400            workflow_started(1)?,
401            Event::SchedulePaused {
402                envelope: envelope(2),
403                schedule_id: ScheduleId::new(uuid::Uuid::from_u128(2)),
404            },
405        ];
406
407        assert_eq!(status_from_events(&events), WorkflowStatus::Running);
408        Ok(())
409    }
410
411    #[test]
412    fn projection_is_deterministic() -> Result<(), Box<dyn std::error::Error>> {
413        let events = vec![
414            workflow_started(1)?,
415            Event::WorkflowCompleted {
416                envelope: envelope(2),
417                result: payload("result")?,
418            },
419        ];
420
421        let first = status_from_events(&events);
422        let second = status_from_events(&events);
423
424        assert_eq!(first, second);
425        Ok(())
426    }
427
428    #[test]
429    fn last_terminal_lifecycle_event_determines_status() -> Result<(), Box<dyn std::error::Error>> {
430        let events = vec![
431            workflow_started(1)?,
432            Event::WorkflowCompleted {
433                envelope: envelope(2),
434                result: payload("result")?,
435            },
436            Event::WorkflowTimedOut {
437                envelope: envelope(3),
438                timeout: String::from("execution"),
439            },
440        ];
441
442        assert_eq!(status_from_events(&events), WorkflowStatus::TimedOut);
443        Ok(())
444    }
445
446    fn run_id() -> RunId {
447        RunId::new(uuid::Uuid::from_u128(1))
448    }
449
450    fn workflow_reopened(seq: u64, reopened: Vec<ActivityId>) -> Event {
451        Event::WorkflowReopened {
452            envelope: envelope(seq),
453            run_id: run_id(),
454            reopened,
455        }
456    }
457
458    #[test]
459    fn reopen_after_failure_projects_running() -> Result<(), Box<dyn std::error::Error>> {
460        let events = vec![
461            workflow_started(1)?,
462            Event::WorkflowFailed {
463                envelope: envelope(2),
464                error: workflow_error("transient"),
465            },
466            workflow_reopened(3, vec![ActivityId::from_sequence_position(2)]),
467        ];
468
469        assert_eq!(status_from_events(&events), WorkflowStatus::Running);
470        Ok(())
471    }
472
473    #[test]
474    fn reopen_then_new_terminal_projects_that_terminal() -> Result<(), Box<dyn std::error::Error>> {
475        let events = vec![
476            workflow_started(1)?,
477            Event::WorkflowFailed {
478                envelope: envelope(2),
479                error: workflow_error("transient"),
480            },
481            workflow_reopened(3, vec![ActivityId::from_sequence_position(2)]),
482            Event::WorkflowCompleted {
483                envelope: envelope(4),
484                result: payload("result")?,
485            },
486        ];
487
488        assert_eq!(status_from_events(&events), WorkflowStatus::Completed);
489        Ok(())
490    }
491
492    #[test]
493    fn current_lease_terminal_is_none_for_running_and_reopened()
494    -> Result<(), Box<dyn std::error::Error>> {
495        let running = vec![workflow_started(1)?];
496        assert!(current_lease_terminal(&running).is_none());
497
498        let failed = vec![
499            workflow_started(1)?,
500            Event::WorkflowFailed {
501                envelope: envelope(2),
502                error: workflow_error("boom"),
503            },
504        ];
505        assert!(matches!(
506            current_lease_terminal(&failed),
507            Some(Event::WorkflowFailed { .. })
508        ));
509
510        let mut reopened = failed.clone();
511        reopened.push(workflow_reopened(
512            3,
513            vec![ActivityId::from_sequence_position(2)],
514        ));
515        assert!(
516            current_lease_terminal(&reopened).is_none(),
517            "a reopened run has no current-lease terminal"
518        );
519        Ok(())
520    }
521
522    #[test]
523    fn current_lease_terminal_returns_terminal_after_reopen_and_retermination()
524    -> Result<(), Box<dyn std::error::Error>> {
525        let events = vec![
526            workflow_started(1)?,
527            Event::WorkflowFailed {
528                envelope: envelope(2),
529                error: workflow_error("boom"),
530            },
531            workflow_reopened(3, vec![ActivityId::from_sequence_position(2)]),
532            Event::WorkflowCompleted {
533                envelope: envelope(4),
534                result: payload("result")?,
535            },
536        ];
537
538        assert!(matches!(
539            current_lease_terminal(&events),
540            Some(Event::WorkflowCompleted { .. })
541        ));
542        Ok(())
543    }
544
545    fn workflow_paused(seq: u64) -> Event {
546        Event::WorkflowPaused {
547            envelope: envelope(seq),
548            run_id: run_id(),
549            reason: None,
550            operator: None,
551        }
552    }
553
554    fn workflow_resumed(seq: u64) -> Event {
555        Event::WorkflowResumed {
556            envelope: envelope(seq),
557            run_id: run_id(),
558            operator: None,
559        }
560    }
561
562    #[test]
563    fn pause_projects_paused_and_is_non_terminal() -> Result<(), Box<dyn std::error::Error>> {
564        let events = vec![workflow_started(1)?, workflow_paused(2)];
565        assert_eq!(status_from_events(&events), WorkflowStatus::Paused);
566        assert!(!WorkflowStatus::Paused.is_terminal());
567        // Paused is non-terminal, so the run has no current-lease terminal and can
568        // still complete/fail/cancel.
569        assert!(current_lease_terminal(&events).is_none());
570        Ok(())
571    }
572
573    #[test]
574    fn resume_after_pause_projects_running() -> Result<(), Box<dyn std::error::Error>> {
575        let events = vec![
576            workflow_started(1)?,
577            workflow_paused(2),
578            workflow_resumed(3),
579        ];
580        assert_eq!(status_from_events(&events), WorkflowStatus::Running);
581        assert!(current_lease_terminal(&events).is_none());
582        Ok(())
583    }
584
585    #[test]
586    fn complete_after_resume_projects_completed() -> Result<(), Box<dyn std::error::Error>> {
587        let events = vec![
588            workflow_started(1)?,
589            workflow_paused(2),
590            workflow_resumed(3),
591            Event::WorkflowCompleted {
592                envelope: envelope(4),
593                result: payload("result")?,
594            },
595        ];
596        assert_eq!(status_from_events(&events), WorkflowStatus::Completed);
597        assert!(matches!(
598            current_lease_terminal(&events),
599            Some(Event::WorkflowCompleted { .. })
600        ));
601        Ok(())
602    }
603
604    #[test]
605    fn complete_while_paused_still_projects_completed() -> Result<(), Box<dyn std::error::Error>> {
606        // The drain case: a paused run reaches a terminal via drained work.
607        // Last-lifecycle-event-wins projects the terminal, not Paused.
608        let events = vec![
609            workflow_started(1)?,
610            workflow_paused(2),
611            Event::WorkflowCompleted {
612                envelope: envelope(3),
613                result: payload("result")?,
614            },
615        ];
616        assert_eq!(status_from_events(&events), WorkflowStatus::Completed);
617        Ok(())
618    }
619
620    #[test]
621    fn run_segment_scopes_to_the_named_run() -> Result<(), Box<dyn std::error::Error>> {
622        let first_run = RunId::new(uuid::Uuid::from_u128(10));
623        let second_run = RunId::new(uuid::Uuid::from_u128(20));
624        let events = vec![
625            Event::WorkflowStarted {
626                envelope: envelope(1),
627                workflow_type: String::from("checkout"),
628                input: payload("input")?,
629                run_id: first_run.clone(),
630                parent_run_id: None,
631                parent_workflow_id: None,
632                package_version: crate::PackageVersion::new("a".repeat(64)),
633            },
634            Event::WorkflowContinuedAsNew {
635                envelope: envelope(2),
636                input: payload("again")?,
637                workflow_type: None,
638                parent_run_id: first_run.clone(),
639            },
640            Event::WorkflowStarted {
641                envelope: envelope(3),
642                workflow_type: String::from("checkout"),
643                input: payload("input")?,
644                run_id: second_run.clone(),
645                parent_run_id: Some(first_run.clone()),
646                parent_workflow_id: None,
647                package_version: crate::PackageVersion::new("a".repeat(64)),
648            },
649            Event::WorkflowCompleted {
650                envelope: envelope(4),
651                result: payload("result")?,
652            },
653        ];
654
655        let first = run_segment(&events, &first_run);
656        assert_eq!(first.len(), 2, "first run spans its start through its CAN");
657        assert!(matches!(
658            current_lease_terminal(first),
659            Some(Event::WorkflowContinuedAsNew { .. })
660        ));
661
662        let second = run_segment(&events, &second_run);
663        assert_eq!(
664            second.len(),
665            2,
666            "second run spans its start through completion"
667        );
668        assert!(matches!(
669            current_lease_terminal(second),
670            Some(Event::WorkflowCompleted { .. })
671        ));
672
673        assert!(
674            run_segment(&events, &RunId::new(uuid::Uuid::from_u128(99))).is_empty(),
675            "absent run yields an empty segment"
676        );
677        Ok(())
678    }
679}