Skip to main content

meerkat_runtime/meerkat_machine/
traits.rs

1use super::*;
2use crate::input_state::StoredInputState;
3
4#[cfg_attr(not(target_arch = "wasm32"), async_trait::async_trait)]
5#[cfg_attr(target_arch = "wasm32", async_trait::async_trait(?Send))]
6impl SessionServiceRuntimeExt for MeerkatMachine {
7    fn runtime_mode(&self) -> RuntimeMode {
8        self.mode
9    }
10
11    async fn accept_input(
12        &self,
13        session_id: &SessionId,
14        input: Input,
15    ) -> Result<AcceptOutcome, RuntimeDriverError> {
16        let runtime_id = MeerkatMachine::logical_runtime_id(session_id);
17        match self
18            .execute_meerkat_machine_command(
19                None,
20                MeerkatMachineCommand::Ingest { runtime_id, input },
21            )
22            .await
23            .map_err(MeerkatMachine::driver_error_from_command_error)?
24        {
25            MeerkatMachineCommandResult::AcceptOutcome(outcome) => Ok(outcome),
26            other => Err(RuntimeDriverError::Internal(format!(
27                "unexpected MeerkatMachineCommandResult for SessionServiceRuntimeExt::accept_input: {other:?}"
28            ))),
29        }
30    }
31
32    async fn accept_input_with_completion(
33        &self,
34        session_id: &SessionId,
35        input: Input,
36    ) -> Result<(AcceptOutcome, Option<crate::completion::CompletionHandle>), RuntimeDriverError>
37    {
38        Box::pin(MeerkatMachine::accept_input_with_completion(
39            self, session_id, input,
40        ))
41        .await
42    }
43
44    async fn runtime_state(
45        &self,
46        session_id: &SessionId,
47    ) -> Result<RuntimeState, RuntimeDriverError> {
48        let runtime_id = MeerkatMachine::logical_runtime_id(session_id);
49        match self
50            .execute_meerkat_machine_command(
51                None,
52                MeerkatMachineCommand::RuntimeState { runtime_id },
53            )
54            .await
55            .map_err(MeerkatMachine::driver_error_from_command_error)?
56        {
57            MeerkatMachineCommandResult::RuntimeState(state) => Ok(state),
58            other => Err(RuntimeDriverError::Internal(format!(
59                "unexpected MeerkatMachineCommandResult for SessionServiceRuntimeExt::runtime_state: {other:?}"
60            ))),
61        }
62    }
63
64    async fn retire_runtime(
65        &self,
66        session_id: &SessionId,
67    ) -> Result<RetireReport, RuntimeDriverError> {
68        let runtime_id = MeerkatMachine::logical_runtime_id(session_id);
69        match self
70            .execute_meerkat_machine_command(None, MeerkatMachineCommand::Retire { runtime_id })
71            .await
72            .map_err(MeerkatMachine::driver_error_from_command_error)?
73        {
74            MeerkatMachineCommandResult::RetireReport(report) => Ok(report),
75            other => Err(RuntimeDriverError::Internal(format!(
76                "unexpected MeerkatMachineCommandResult for SessionServiceRuntimeExt::retire_runtime: {other:?}"
77            ))),
78        }
79    }
80
81    async fn reset_runtime(
82        &self,
83        session_id: &SessionId,
84    ) -> Result<ResetReport, RuntimeDriverError> {
85        let runtime_id = MeerkatMachine::logical_runtime_id(session_id);
86        match self
87            .execute_meerkat_machine_command(None, MeerkatMachineCommand::Reset { runtime_id })
88            .await
89            .map_err(MeerkatMachine::driver_error_from_command_error)?
90        {
91            MeerkatMachineCommandResult::ResetReport(report) => Ok(report),
92            other => Err(RuntimeDriverError::Internal(format!(
93                "unexpected MeerkatMachineCommandResult for SessionServiceRuntimeExt::reset_runtime: {other:?}"
94            ))),
95        }
96    }
97
98    async fn input_state(
99        &self,
100        session_id: &SessionId,
101        input_id: &InputId,
102    ) -> Result<Option<StoredInputState>, RuntimeDriverError> {
103        match self
104            .execute_meerkat_machine_command(
105                None,
106                MeerkatMachineCommand::InputState {
107                    session_id: session_id.clone(),
108                    input_id: input_id.clone(),
109                },
110            )
111            .await
112            .map_err(MeerkatMachine::driver_error_from_command_error)?
113        {
114            MeerkatMachineCommandResult::InputState(state) => Ok(state),
115            other => Err(RuntimeDriverError::Internal(format!(
116                "unexpected MeerkatMachineCommandResult for SessionServiceRuntimeExt::input_state: {other:?}"
117            ))),
118        }
119    }
120
121    async fn list_active_inputs(
122        &self,
123        session_id: &SessionId,
124    ) -> Result<Vec<InputId>, RuntimeDriverError> {
125        match self
126            .execute_meerkat_machine_command(
127                None,
128                MeerkatMachineCommand::ListActiveInputs {
129                    session_id: session_id.clone(),
130                },
131            )
132            .await
133            .map_err(MeerkatMachine::driver_error_from_command_error)?
134        {
135            MeerkatMachineCommandResult::ActiveInputs(inputs) => Ok(inputs),
136            other => Err(RuntimeDriverError::Internal(format!(
137                "unexpected MeerkatMachineCommandResult for SessionServiceRuntimeExt::list_active_inputs: {other:?}"
138            ))),
139        }
140    }
141
142    async fn reconfigure_session_llm_identity(
143        &self,
144        session_id: &SessionId,
145        request: SessionLlmReconfigureRequest,
146    ) -> Result<SessionLlmReconfigureReport, RuntimeDriverError> {
147        let command = self
148            .prepare_reconfigure_session_llm_command(session_id, request)
149            .await?;
150        match self
151            .execute_meerkat_machine_command(None, command)
152            .await
153            .map_err(MeerkatMachine::driver_error_from_command_error)?
154        {
155            MeerkatMachineCommandResult::LlmReconfigured(report) => Ok(report),
156            other => Err(RuntimeDriverError::Internal(format!(
157                "unexpected MeerkatMachineCommandResult for SessionServiceRuntimeExt::reconfigure_session_llm_identity: {other:?}"
158            ))),
159        }
160    }
161
162    async fn resolved_session_llm_capabilities(
163        &self,
164        session_id: &SessionId,
165    ) -> Result<Option<SessionLlmCapabilitySurface>, RuntimeDriverError> {
166        match self
167            .execute_meerkat_machine_command(
168                None,
169                MeerkatMachineCommand::ResolvedSessionLlmCapabilities {
170                    session_id: session_id.clone(),
171                },
172            )
173            .await
174            .map_err(MeerkatMachine::driver_error_from_command_error)?
175        {
176            MeerkatMachineCommandResult::ResolvedSessionLlmCapabilities(capabilities) => {
177                Ok(capabilities)
178            }
179            other => Err(RuntimeDriverError::Internal(format!(
180                "unexpected MeerkatMachineCommandResult for SessionServiceRuntimeExt::resolved_session_llm_capabilities: {other:?}"
181            ))),
182        }
183    }
184
185    async fn configure_model_routing_baseline(
186        &self,
187        session_id: &SessionId,
188        baseline_model: meerkat_core::lifecycle::run_primitive::ModelId,
189        realtime_capable: bool,
190    ) -> Result<(), RuntimeDriverError> {
191        match self
192            .execute_meerkat_machine_command(
193                None,
194                MeerkatMachineCommand::ConfigureModelRoutingBaseline {
195                    session_id: session_id.clone(),
196                    baseline_model,
197                    realtime_capable,
198                },
199            )
200            .await
201            .map_err(MeerkatMachine::driver_error_from_command_error)?
202        {
203            MeerkatMachineCommandResult::Unit => Ok(()),
204            other => Err(RuntimeDriverError::Internal(format!(
205                "unexpected MeerkatMachineCommandResult for SessionServiceRuntimeExt::configure_model_routing_baseline: {other:?}"
206            ))),
207        }
208    }
209
210    async fn session_model_routing_status(
211        &self,
212        session_id: &SessionId,
213    ) -> Result<meerkat_core::image_generation::SessionModelRoutingStatus, RuntimeDriverError> {
214        match self
215            .execute_meerkat_machine_command(
216                None,
217                MeerkatMachineCommand::SessionModelRoutingStatus {
218                    session_id: session_id.clone(),
219                },
220            )
221            .await
222            .map_err(MeerkatMachine::driver_error_from_command_error)?
223        {
224            MeerkatMachineCommandResult::SessionModelRoutingStatus(status) => Ok(status),
225            other => Err(RuntimeDriverError::Internal(format!(
226                "unexpected MeerkatMachineCommandResult for SessionServiceRuntimeExt::session_model_routing_status: {other:?}"
227            ))),
228        }
229    }
230
231    async fn request_switch_turn(
232        &self,
233        session_id: &SessionId,
234        request: crate::meerkat_machine_types::SwitchTurnRequest,
235    ) -> Result<meerkat_core::image_generation::SwitchTurnControlResult, RuntimeDriverError> {
236        match self
237            .execute_meerkat_machine_command(
238                None,
239                MeerkatMachineCommand::RequestSwitchTurn {
240                    session_id: session_id.clone(),
241                    request: Box::new(request),
242                },
243            )
244            .await
245            .map_err(MeerkatMachine::driver_error_from_command_error)?
246        {
247            MeerkatMachineCommandResult::SwitchTurnControlResult(result) => Ok(result),
248            other => Err(RuntimeDriverError::Internal(format!(
249                "unexpected MeerkatMachineCommandResult for SessionServiceRuntimeExt::request_switch_turn: {other:?}"
250            ))),
251        }
252    }
253
254    async fn admit_model_routing_assistant_turn(
255        &self,
256        session_id: &SessionId,
257    ) -> Result<(), RuntimeDriverError> {
258        match self
259            .execute_meerkat_machine_command(
260                None,
261                MeerkatMachineCommand::AdmitModelRoutingAssistantTurn {
262                    session_id: session_id.clone(),
263                },
264            )
265            .await
266            .map_err(MeerkatMachine::driver_error_from_command_error)?
267        {
268            MeerkatMachineCommandResult::Unit => Ok(()),
269            other => Err(RuntimeDriverError::Internal(format!(
270                "unexpected MeerkatMachineCommandResult for SessionServiceRuntimeExt::admit_model_routing_assistant_turn: {other:?}"
271            ))),
272        }
273    }
274
275    async fn begin_image_operation(
276        &self,
277        session_id: &SessionId,
278        request: crate::meerkat_machine_types::ImageOperationRoutingRequest,
279    ) -> Result<crate::meerkat_machine_types::ImageOperationRoutingResult, RuntimeDriverError> {
280        match self
281            .execute_meerkat_machine_command(
282                None,
283                MeerkatMachineCommand::BeginImageOperation {
284                    session_id: session_id.clone(),
285                    request: Box::new(request),
286                },
287            )
288            .await
289            .map_err(MeerkatMachine::driver_error_from_command_error)?
290        {
291            MeerkatMachineCommandResult::ImageOperationRoutingResult(result) => Ok(result),
292            other => Err(RuntimeDriverError::Internal(format!(
293                "unexpected MeerkatMachineCommandResult for SessionServiceRuntimeExt::begin_image_operation: {other:?}"
294            ))),
295        }
296    }
297
298    async fn activate_image_operation_override(
299        &self,
300        session_id: &SessionId,
301        operation_id: meerkat_core::image_generation::ImageOperationId,
302    ) -> Result<meerkat_core::image_generation::ImageOperationPhase, RuntimeDriverError> {
303        match self
304            .execute_meerkat_machine_command(
305                None,
306                MeerkatMachineCommand::ActivateImageOperationOverride {
307                    session_id: session_id.clone(),
308                    operation_id,
309                },
310            )
311            .await
312            .map_err(MeerkatMachine::driver_error_from_command_error)?
313        {
314            MeerkatMachineCommandResult::ImageOperationPhase(phase) => Ok(phase),
315            other => Err(RuntimeDriverError::Internal(format!(
316                "unexpected MeerkatMachineCommandResult for SessionServiceRuntimeExt::activate_image_operation_override: {other:?}"
317            ))),
318        }
319    }
320
321    async fn complete_image_operation(
322        &self,
323        session_id: &SessionId,
324        operation_id: meerkat_core::image_generation::ImageOperationId,
325        terminal: meerkat_core::image_generation::ImageOperationTerminalClass,
326    ) -> Result<meerkat_core::image_generation::ImageOperationPhase, RuntimeDriverError> {
327        match self
328            .execute_meerkat_machine_command(
329                None,
330                MeerkatMachineCommand::CompleteImageOperation {
331                    session_id: session_id.clone(),
332                    operation_id,
333                    terminal,
334                },
335            )
336            .await
337            .map_err(MeerkatMachine::driver_error_from_command_error)?
338        {
339            MeerkatMachineCommandResult::ImageOperationPhase(phase) => Ok(phase),
340            other => Err(RuntimeDriverError::Internal(format!(
341                "unexpected MeerkatMachineCommandResult for SessionServiceRuntimeExt::complete_image_operation: {other:?}"
342            ))),
343        }
344    }
345
346    async fn restore_image_operation_override(
347        &self,
348        session_id: &SessionId,
349        operation_id: meerkat_core::image_generation::ImageOperationId,
350    ) -> Result<meerkat_core::image_generation::ImageOperationPhase, RuntimeDriverError> {
351        match self
352            .execute_meerkat_machine_command(
353                None,
354                MeerkatMachineCommand::RestoreImageOperationOverride {
355                    session_id: session_id.clone(),
356                    operation_id,
357                },
358            )
359            .await
360            .map_err(MeerkatMachine::driver_error_from_command_error)?
361        {
362            MeerkatMachineCommandResult::ImageOperationPhase(phase) => Ok(phase),
363            other => Err(RuntimeDriverError::Internal(format!(
364                "unexpected MeerkatMachineCommandResult for SessionServiceRuntimeExt::restore_image_operation_override: {other:?}"
365            ))),
366        }
367    }
368}
369
370// ---------------------------------------------------------------------------
371// RuntimeControlPlane implementation
372// ---------------------------------------------------------------------------
373
374impl MeerkatMachine {
375    pub(crate) fn logical_runtime_id(session_id: &SessionId) -> LogicalRuntimeId {
376        LogicalRuntimeId::for_session(session_id)
377    }
378
379    pub(super) fn post_admission_signal_from_effects(
380        effects: &[crate::meerkat_machine::dsl::MeerkatMachineEffect],
381    ) -> crate::driver::ephemeral::PostAdmissionSignal {
382        effects
383            .iter()
384            .find_map(|effect| match effect {
385                crate::meerkat_machine::dsl::MeerkatMachineEffect::PostAdmissionSignal {
386                    signal,
387                } => Some(match signal {
388                    crate::meerkat_machine::dsl::PostAdmissionSignalKind::WakeLoop => {
389                        crate::driver::ephemeral::PostAdmissionSignal::WakeLoop
390                    }
391                    crate::meerkat_machine::dsl::PostAdmissionSignalKind::InterruptYielding => {
392                        crate::driver::ephemeral::PostAdmissionSignal::InterruptYielding
393                    }
394                    crate::meerkat_machine::dsl::PostAdmissionSignalKind::RequestImmediateProcessing => {
395                        crate::driver::ephemeral::PostAdmissionSignal::RequestImmediateProcessing
396                    }
397                }),
398                _ => None,
399            })
400            .unwrap_or(crate::driver::ephemeral::PostAdmissionSignal::None)
401    }
402
403    pub(super) fn driver_error_from_command_error(
404        err: MeerkatMachineCommandError,
405    ) -> RuntimeDriverError {
406        match err {
407            MeerkatMachineCommandError::Driver(err) => err,
408            MeerkatMachineCommandError::Control(err) => {
409                Self::driver_error_from_control_plane_error(err)
410            }
411        }
412    }
413
414    pub(super) fn control_plane_error_from_command_error(
415        err: MeerkatMachineCommandError,
416    ) -> RuntimeControlPlaneError {
417        match err {
418            MeerkatMachineCommandError::Control(err) => err,
419            MeerkatMachineCommandError::Driver(err) => {
420                RuntimeControlPlaneError::Internal(err.to_string())
421            }
422        }
423    }
424
425    pub(super) fn driver_error_from_control_plane_error(
426        err: RuntimeControlPlaneError,
427    ) -> RuntimeDriverError {
428        match err {
429            RuntimeControlPlaneError::NotFound(_) => RuntimeDriverError::NotReady {
430                state: RuntimeState::Destroyed,
431            },
432            RuntimeControlPlaneError::InvalidState { state } => {
433                RuntimeDriverError::NotReady { state }
434            }
435            RuntimeControlPlaneError::StoreError(message)
436            | RuntimeControlPlaneError::Internal(message) => RuntimeDriverError::Internal(message),
437        }
438    }
439
440    /// Resolve a LogicalRuntimeId to a registered SessionId for internal lookup.
441    pub(super) async fn resolve_session_id(
442        &self,
443        runtime_id: &LogicalRuntimeId,
444    ) -> Result<SessionId, RuntimeControlPlaneError> {
445        let sessions = self.sessions.read().await;
446        sessions
447            .iter()
448            .find_map(|(session_id, entry)| {
449                (&entry.runtime_id == runtime_id).then(|| session_id.clone())
450            })
451            .ok_or_else(|| RuntimeControlPlaneError::NotFound(runtime_id.clone()))
452    }
453
454    pub(super) async fn existing_session_runtime_state(
455        &self,
456        session_id: &SessionId,
457    ) -> Option<RuntimeState> {
458        let sessions = self.sessions.read().await;
459        let entry = sessions.get(session_id)?;
460        // DSL remains the transition authority for live, non-terminal states.
461        // Persistent drivers use the published control projection as the
462        // visibility barrier when DSL has crossed a run-return or terminal
463        // lifecycle boundary before the durable commit has published it.
464        let control = entry.control_snapshot();
465        let authority = entry
466            .dsl_authority
467            .lock()
468            .unwrap_or_else(std::sync::PoisonError::into_inner);
469        let dsl_phase = dsl_authority::runtime_phase_from_authority(&authority);
470        let dsl_pre_run_phase = dsl_authority::pre_run_phase_from_authority(&authority);
471        if self.has_runtime_persistence()
472            && dsl_authority::should_publish_control_over_dsl(
473                control.phase,
474                dsl_phase,
475                dsl_pre_run_phase,
476            )
477        {
478            Some(control.phase)
479        } else {
480            Some(dsl_phase)
481        }
482    }
483
484    pub(super) async fn existing_session_visible_runtime_state(
485        &self,
486        session_id: &SessionId,
487    ) -> Option<RuntimeState> {
488        let sessions = self.sessions.read().await;
489        let entry = sessions.get(session_id)?;
490        let control = entry.control_snapshot();
491        let authority = entry
492            .dsl_authority
493            .lock()
494            .unwrap_or_else(std::sync::PoisonError::into_inner);
495        let dsl_phase = dsl_authority::runtime_phase_from_authority(&authority);
496        let dsl_pre_run_phase = dsl_authority::pre_run_phase_from_authority(&authority);
497        if self.has_runtime_persistence()
498            && dsl_authority::should_publish_control_over_dsl(
499                control.phase,
500                dsl_phase,
501                dsl_pre_run_phase,
502            )
503        {
504            Some(dsl_authority::visible_runtime_phase(
505                control.phase,
506                control.pre_run_phase,
507            ))
508        } else {
509            Some(dsl_authority::visible_runtime_phase(
510                dsl_phase,
511                dsl_pre_run_phase,
512            ))
513        }
514    }
515
516    /// Look up the session entry for a runtime ID, returning a control-plane error
517    /// if not found.
518    pub(super) async fn lookup_entry(
519        &self,
520        runtime_id: &LogicalRuntimeId,
521    ) -> Result<
522        (
523            SessionId,
524            SharedDriver,
525            SharedCompletionRegistry,
526            Option<mpsc::Sender<()>>,
527        ),
528        RuntimeControlPlaneError,
529    > {
530        let sessions = self.sessions.read().await;
531        let (session_id, entry) = sessions
532            .iter()
533            .find(|(_, entry)| &entry.runtime_id == runtime_id)
534            .ok_or_else(|| RuntimeControlPlaneError::NotFound(runtime_id.clone()))?;
535        Ok((
536            session_id.clone(),
537            entry.driver.clone(),
538            entry.completions.clone(),
539            entry.wake_sender(),
540        ))
541    }
542}
543
544#[cfg_attr(not(target_arch = "wasm32"), async_trait::async_trait)]
545#[cfg_attr(target_arch = "wasm32", async_trait::async_trait(?Send))]
546impl crate::traits::RuntimeControlPlane for MeerkatMachine {
547    async fn ingest(
548        &self,
549        runtime_id: &LogicalRuntimeId,
550        input: Input,
551    ) -> Result<AcceptOutcome, RuntimeControlPlaneError> {
552        match self
553            .execute_meerkat_machine_command(
554                None,
555                MeerkatMachineCommand::Ingest {
556                    runtime_id: runtime_id.clone(),
557                    input,
558                },
559            )
560            .await
561            .map_err(MeerkatMachine::control_plane_error_from_command_error)?
562        {
563            MeerkatMachineCommandResult::AcceptOutcome(outcome) => Ok(outcome),
564            other => Err(RuntimeControlPlaneError::Internal(format!(
565                "unexpected MeerkatMachineCommandResult for ingest: {other:?}"
566            ))),
567        }
568    }
569
570    async fn publish_event(
571        &self,
572        event: crate::runtime_event::RuntimeEventEnvelope,
573    ) -> Result<(), RuntimeControlPlaneError> {
574        match self
575            .execute_meerkat_machine_command(None, MeerkatMachineCommand::PublishEvent { event })
576            .await
577            .map_err(MeerkatMachine::control_plane_error_from_command_error)?
578        {
579            MeerkatMachineCommandResult::Unit => Ok(()),
580            other => Err(RuntimeControlPlaneError::Internal(format!(
581                "unexpected MeerkatMachineCommandResult for publish_event: {other:?}"
582            ))),
583        }
584    }
585
586    async fn retire(
587        &self,
588        runtime_id: &LogicalRuntimeId,
589    ) -> Result<RetireReport, RuntimeControlPlaneError> {
590        match self
591            .execute_meerkat_machine_command(
592                None,
593                MeerkatMachineCommand::Retire {
594                    runtime_id: runtime_id.clone(),
595                },
596            )
597            .await
598            .map_err(MeerkatMachine::control_plane_error_from_command_error)?
599        {
600            MeerkatMachineCommandResult::RetireReport(report) => Ok(report),
601            other => Err(RuntimeControlPlaneError::Internal(format!(
602                "unexpected MeerkatMachineCommandResult for retire: {other:?}"
603            ))),
604        }
605    }
606
607    async fn recycle(
608        &self,
609        runtime_id: &LogicalRuntimeId,
610    ) -> Result<RecycleReport, RuntimeControlPlaneError> {
611        match self
612            .execute_meerkat_machine_command(
613                None,
614                MeerkatMachineCommand::Recycle {
615                    runtime_id: runtime_id.clone(),
616                },
617            )
618            .await
619            .map_err(MeerkatMachine::control_plane_error_from_command_error)?
620        {
621            MeerkatMachineCommandResult::RecycleReport(report) => Ok(report),
622            other => Err(RuntimeControlPlaneError::Internal(format!(
623                "unexpected MeerkatMachineCommandResult for recycle: {other:?}"
624            ))),
625        }
626    }
627
628    async fn reset(
629        &self,
630        runtime_id: &LogicalRuntimeId,
631    ) -> Result<crate::traits::ResetReport, RuntimeControlPlaneError> {
632        match self
633            .execute_meerkat_machine_command(
634                None,
635                MeerkatMachineCommand::Reset {
636                    runtime_id: runtime_id.clone(),
637                },
638            )
639            .await
640            .map_err(MeerkatMachine::control_plane_error_from_command_error)?
641        {
642            MeerkatMachineCommandResult::ResetReport(report) => Ok(report),
643            other => Err(RuntimeControlPlaneError::Internal(format!(
644                "unexpected MeerkatMachineCommandResult for reset: {other:?}"
645            ))),
646        }
647    }
648
649    async fn recover(
650        &self,
651        runtime_id: &LogicalRuntimeId,
652    ) -> Result<RecoveryReport, RuntimeControlPlaneError> {
653        match self
654            .execute_meerkat_machine_command(
655                None,
656                MeerkatMachineCommand::Recover {
657                    runtime_id: runtime_id.clone(),
658                },
659            )
660            .await
661            .map_err(MeerkatMachine::control_plane_error_from_command_error)?
662        {
663            MeerkatMachineCommandResult::RecoveryReport(report) => Ok(report),
664            other => Err(RuntimeControlPlaneError::Internal(format!(
665                "unexpected MeerkatMachineCommandResult for recover: {other:?}"
666            ))),
667        }
668    }
669
670    async fn destroy(
671        &self,
672        runtime_id: &LogicalRuntimeId,
673    ) -> Result<DestroyReport, RuntimeControlPlaneError> {
674        match self
675            .execute_meerkat_machine_command(
676                None,
677                MeerkatMachineCommand::Destroy {
678                    runtime_id: runtime_id.clone(),
679                },
680            )
681            .await
682            .map_err(MeerkatMachine::control_plane_error_from_command_error)?
683        {
684            MeerkatMachineCommandResult::DestroyReport(report) => Ok(report),
685            other => Err(RuntimeControlPlaneError::Internal(format!(
686                "unexpected MeerkatMachineCommandResult for destroy: {other:?}"
687            ))),
688        }
689    }
690
691    async fn runtime_state(
692        &self,
693        runtime_id: &LogicalRuntimeId,
694    ) -> Result<RuntimeState, RuntimeControlPlaneError> {
695        match self
696            .execute_meerkat_machine_command(
697                None,
698                MeerkatMachineCommand::RuntimeState {
699                    runtime_id: runtime_id.clone(),
700                },
701            )
702            .await
703            .map_err(MeerkatMachine::control_plane_error_from_command_error)?
704        {
705            MeerkatMachineCommandResult::RuntimeState(state) => Ok(state),
706            other => Err(RuntimeControlPlaneError::Internal(format!(
707                "unexpected MeerkatMachineCommandResult for runtime_state: {other:?}"
708            ))),
709        }
710    }
711
712    async fn load_boundary_receipt(
713        &self,
714        runtime_id: &LogicalRuntimeId,
715        run_id: &RunId,
716        sequence: u64,
717    ) -> Result<Option<meerkat_core::lifecycle::RunBoundaryReceipt>, RuntimeControlPlaneError> {
718        match self
719            .execute_meerkat_machine_command(
720                None,
721                MeerkatMachineCommand::LoadBoundaryReceipt {
722                    runtime_id: runtime_id.clone(),
723                    run_id: run_id.clone(),
724                    sequence,
725                },
726            )
727            .await
728            .map_err(MeerkatMachine::control_plane_error_from_command_error)?
729        {
730            MeerkatMachineCommandResult::BoundaryReceipt(receipt) => Ok(receipt),
731            other => Err(RuntimeControlPlaneError::Internal(format!(
732                "unexpected MeerkatMachineCommandResult for load_boundary_receipt: {other:?}"
733            ))),
734        }
735    }
736}