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 realtime_attachment_status(
163        &self,
164        session_id: &SessionId,
165    ) -> Result<crate::meerkat_machine_types::RealtimeAttachmentStatus, RuntimeDriverError> {
166        match self
167            .execute_meerkat_machine_command(
168                None,
169                MeerkatMachineCommand::RuntimeRealtimeAttachmentStatus {
170                    session_id: session_id.clone(),
171                },
172            )
173            .await
174            .map_err(MeerkatMachine::driver_error_from_command_error)?
175        {
176            MeerkatMachineCommandResult::RealtimeAttachmentStatus(status) => Ok(status),
177            other => Err(RuntimeDriverError::Internal(format!(
178                "unexpected MeerkatMachineCommandResult for SessionServiceRuntimeExt::realtime_attachment_status: {other:?}"
179            ))),
180        }
181    }
182
183    async fn resolved_session_llm_capabilities(
184        &self,
185        session_id: &SessionId,
186    ) -> Result<Option<SessionLlmCapabilitySurface>, RuntimeDriverError> {
187        match self
188            .execute_meerkat_machine_command(
189                None,
190                MeerkatMachineCommand::ResolvedSessionLlmCapabilities {
191                    session_id: session_id.clone(),
192                },
193            )
194            .await
195            .map_err(MeerkatMachine::driver_error_from_command_error)?
196        {
197            MeerkatMachineCommandResult::ResolvedSessionLlmCapabilities(capabilities) => {
198                Ok(capabilities)
199            }
200            other => Err(RuntimeDriverError::Internal(format!(
201                "unexpected MeerkatMachineCommandResult for SessionServiceRuntimeExt::resolved_session_llm_capabilities: {other:?}"
202            ))),
203        }
204    }
205
206    /// Fully-projected public channel status. Reads DSL state (attachment plus
207    /// machine-owned reconnect lifecycle/progress) and returns a
208    /// ready-to-serialize `RealtimeChannelStatus`.
209    async fn realtime_channel_status(
210        &self,
211        session_id: &SessionId,
212    ) -> Result<meerkat_contracts::RealtimeChannelStatus, RuntimeDriverError> {
213        match self
214            .execute_meerkat_machine_command(
215                None,
216                MeerkatMachineCommand::RuntimeRealtimeChannelStatus {
217                    session_id: session_id.clone(),
218                },
219            )
220            .await
221            .map_err(MeerkatMachine::driver_error_from_command_error)?
222        {
223            MeerkatMachineCommandResult::RealtimeChannelStatus(status) => Ok(status),
224            other => Err(RuntimeDriverError::Internal(format!(
225                "unexpected MeerkatMachineCommandResult for SessionServiceRuntimeExt::realtime_channel_status: {other:?}"
226            ))),
227        }
228    }
229
230    async fn realtime_bootstrap_eligibility(
231        &self,
232        session_id: &SessionId,
233    ) -> Result<crate::meerkat_machine_types::RealtimeBootstrapEligibility, RuntimeDriverError>
234    {
235        MeerkatMachine::realtime_bootstrap_eligibility(self, session_id).await
236    }
237
238    async fn configure_model_routing_baseline(
239        &self,
240        session_id: &SessionId,
241        baseline_model: meerkat_core::lifecycle::run_primitive::ModelId,
242        realtime_capable: bool,
243    ) -> Result<(), RuntimeDriverError> {
244        match self
245            .execute_meerkat_machine_command(
246                None,
247                MeerkatMachineCommand::ConfigureModelRoutingBaseline {
248                    session_id: session_id.clone(),
249                    baseline_model,
250                    realtime_capable,
251                },
252            )
253            .await
254            .map_err(MeerkatMachine::driver_error_from_command_error)?
255        {
256            MeerkatMachineCommandResult::Unit => Ok(()),
257            other => Err(RuntimeDriverError::Internal(format!(
258                "unexpected MeerkatMachineCommandResult for SessionServiceRuntimeExt::configure_model_routing_baseline: {other:?}"
259            ))),
260        }
261    }
262
263    async fn session_model_routing_status(
264        &self,
265        session_id: &SessionId,
266    ) -> Result<meerkat_core::image_generation::SessionModelRoutingStatus, RuntimeDriverError> {
267        match self
268            .execute_meerkat_machine_command(
269                None,
270                MeerkatMachineCommand::SessionModelRoutingStatus {
271                    session_id: session_id.clone(),
272                },
273            )
274            .await
275            .map_err(MeerkatMachine::driver_error_from_command_error)?
276        {
277            MeerkatMachineCommandResult::SessionModelRoutingStatus(status) => Ok(status),
278            other => Err(RuntimeDriverError::Internal(format!(
279                "unexpected MeerkatMachineCommandResult for SessionServiceRuntimeExt::session_model_routing_status: {other:?}"
280            ))),
281        }
282    }
283
284    async fn request_switch_turn(
285        &self,
286        session_id: &SessionId,
287        request: crate::meerkat_machine_types::SwitchTurnRequest,
288    ) -> Result<meerkat_core::image_generation::SwitchTurnControlResult, RuntimeDriverError> {
289        match self
290            .execute_meerkat_machine_command(
291                None,
292                MeerkatMachineCommand::RequestSwitchTurn {
293                    session_id: session_id.clone(),
294                    request: Box::new(request),
295                },
296            )
297            .await
298            .map_err(MeerkatMachine::driver_error_from_command_error)?
299        {
300            MeerkatMachineCommandResult::SwitchTurnControlResult(result) => Ok(result),
301            other => Err(RuntimeDriverError::Internal(format!(
302                "unexpected MeerkatMachineCommandResult for SessionServiceRuntimeExt::request_switch_turn: {other:?}"
303            ))),
304        }
305    }
306
307    async fn admit_model_routing_assistant_turn(
308        &self,
309        session_id: &SessionId,
310    ) -> Result<(), RuntimeDriverError> {
311        match self
312            .execute_meerkat_machine_command(
313                None,
314                MeerkatMachineCommand::AdmitModelRoutingAssistantTurn {
315                    session_id: session_id.clone(),
316                },
317            )
318            .await
319            .map_err(MeerkatMachine::driver_error_from_command_error)?
320        {
321            MeerkatMachineCommandResult::Unit => Ok(()),
322            other => Err(RuntimeDriverError::Internal(format!(
323                "unexpected MeerkatMachineCommandResult for SessionServiceRuntimeExt::admit_model_routing_assistant_turn: {other:?}"
324            ))),
325        }
326    }
327
328    async fn begin_image_operation(
329        &self,
330        session_id: &SessionId,
331        request: crate::meerkat_machine_types::ImageOperationRoutingRequest,
332    ) -> Result<crate::meerkat_machine_types::ImageOperationRoutingResult, RuntimeDriverError> {
333        match self
334            .execute_meerkat_machine_command(
335                None,
336                MeerkatMachineCommand::BeginImageOperation {
337                    session_id: session_id.clone(),
338                    request: Box::new(request),
339                },
340            )
341            .await
342            .map_err(MeerkatMachine::driver_error_from_command_error)?
343        {
344            MeerkatMachineCommandResult::ImageOperationRoutingResult(result) => Ok(result),
345            other => Err(RuntimeDriverError::Internal(format!(
346                "unexpected MeerkatMachineCommandResult for SessionServiceRuntimeExt::begin_image_operation: {other:?}"
347            ))),
348        }
349    }
350
351    async fn activate_image_operation_override(
352        &self,
353        session_id: &SessionId,
354        operation_id: meerkat_core::image_generation::ImageOperationId,
355    ) -> Result<meerkat_core::image_generation::ImageOperationPhase, RuntimeDriverError> {
356        match self
357            .execute_meerkat_machine_command(
358                None,
359                MeerkatMachineCommand::ActivateImageOperationOverride {
360                    session_id: session_id.clone(),
361                    operation_id,
362                },
363            )
364            .await
365            .map_err(MeerkatMachine::driver_error_from_command_error)?
366        {
367            MeerkatMachineCommandResult::ImageOperationPhase(phase) => Ok(phase),
368            other => Err(RuntimeDriverError::Internal(format!(
369                "unexpected MeerkatMachineCommandResult for SessionServiceRuntimeExt::activate_image_operation_override: {other:?}"
370            ))),
371        }
372    }
373
374    async fn complete_image_operation(
375        &self,
376        session_id: &SessionId,
377        operation_id: meerkat_core::image_generation::ImageOperationId,
378        terminal: meerkat_core::image_generation::ImageOperationTerminalClass,
379    ) -> Result<meerkat_core::image_generation::ImageOperationPhase, RuntimeDriverError> {
380        match self
381            .execute_meerkat_machine_command(
382                None,
383                MeerkatMachineCommand::CompleteImageOperation {
384                    session_id: session_id.clone(),
385                    operation_id,
386                    terminal,
387                },
388            )
389            .await
390            .map_err(MeerkatMachine::driver_error_from_command_error)?
391        {
392            MeerkatMachineCommandResult::ImageOperationPhase(phase) => Ok(phase),
393            other => Err(RuntimeDriverError::Internal(format!(
394                "unexpected MeerkatMachineCommandResult for SessionServiceRuntimeExt::complete_image_operation: {other:?}"
395            ))),
396        }
397    }
398
399    async fn restore_image_operation_override(
400        &self,
401        session_id: &SessionId,
402        operation_id: meerkat_core::image_generation::ImageOperationId,
403    ) -> Result<meerkat_core::image_generation::ImageOperationPhase, RuntimeDriverError> {
404        match self
405            .execute_meerkat_machine_command(
406                None,
407                MeerkatMachineCommand::RestoreImageOperationOverride {
408                    session_id: session_id.clone(),
409                    operation_id,
410                },
411            )
412            .await
413            .map_err(MeerkatMachine::driver_error_from_command_error)?
414        {
415            MeerkatMachineCommandResult::ImageOperationPhase(phase) => Ok(phase),
416            other => Err(RuntimeDriverError::Internal(format!(
417                "unexpected MeerkatMachineCommandResult for SessionServiceRuntimeExt::restore_image_operation_override: {other:?}"
418            ))),
419        }
420    }
421}
422
423// ---------------------------------------------------------------------------
424// RuntimeControlPlane implementation
425// ---------------------------------------------------------------------------
426
427impl MeerkatMachine {
428    pub(crate) fn logical_runtime_id(session_id: &SessionId) -> LogicalRuntimeId {
429        LogicalRuntimeId::for_session(session_id)
430    }
431
432    pub(super) fn post_admission_signal_from_effects(
433        effects: &[crate::meerkat_machine::dsl::MeerkatMachineEffect],
434    ) -> crate::driver::ephemeral::PostAdmissionSignal {
435        effects
436            .iter()
437            .find_map(|effect| match effect {
438                crate::meerkat_machine::dsl::MeerkatMachineEffect::PostAdmissionSignal {
439                    signal,
440                } => Some(match signal {
441                    crate::meerkat_machine::dsl::PostAdmissionSignalKind::WakeLoop => {
442                        crate::driver::ephemeral::PostAdmissionSignal::WakeLoop
443                    }
444                    crate::meerkat_machine::dsl::PostAdmissionSignalKind::InterruptYielding => {
445                        crate::driver::ephemeral::PostAdmissionSignal::InterruptYielding
446                    }
447                    crate::meerkat_machine::dsl::PostAdmissionSignalKind::RequestImmediateProcessing => {
448                        crate::driver::ephemeral::PostAdmissionSignal::RequestImmediateProcessing
449                    }
450                }),
451                _ => None,
452            })
453            .unwrap_or(crate::driver::ephemeral::PostAdmissionSignal::None)
454    }
455
456    pub(super) fn driver_error_from_command_error(
457        err: MeerkatMachineCommandError,
458    ) -> RuntimeDriverError {
459        match err {
460            MeerkatMachineCommandError::Driver(err) => err,
461            MeerkatMachineCommandError::Control(err) => {
462                Self::driver_error_from_control_plane_error(err)
463            }
464        }
465    }
466
467    pub(super) fn control_plane_error_from_command_error(
468        err: MeerkatMachineCommandError,
469    ) -> RuntimeControlPlaneError {
470        match err {
471            MeerkatMachineCommandError::Control(err) => err,
472            MeerkatMachineCommandError::Driver(err) => {
473                RuntimeControlPlaneError::Internal(err.to_string())
474            }
475        }
476    }
477
478    pub(super) fn driver_error_from_control_plane_error(
479        err: RuntimeControlPlaneError,
480    ) -> RuntimeDriverError {
481        match err {
482            RuntimeControlPlaneError::NotFound(_) => RuntimeDriverError::NotReady {
483                state: RuntimeState::Destroyed,
484            },
485            RuntimeControlPlaneError::InvalidState { state } => {
486                RuntimeDriverError::NotReady { state }
487            }
488            RuntimeControlPlaneError::StoreError(message)
489            | RuntimeControlPlaneError::Internal(message) => RuntimeDriverError::Internal(message),
490        }
491    }
492
493    /// Resolve a LogicalRuntimeId to a registered SessionId for internal lookup.
494    pub(super) async fn resolve_session_id(
495        &self,
496        runtime_id: &LogicalRuntimeId,
497    ) -> Result<SessionId, RuntimeControlPlaneError> {
498        let sessions = self.sessions.read().await;
499        sessions
500            .iter()
501            .find_map(|(session_id, entry)| {
502                (&entry.runtime_id == runtime_id).then(|| session_id.clone())
503            })
504            .ok_or_else(|| RuntimeControlPlaneError::NotFound(runtime_id.clone()))
505    }
506
507    pub(super) async fn existing_session_runtime_state(
508        &self,
509        session_id: &SessionId,
510    ) -> Option<RuntimeState> {
511        let sessions = self.sessions.read().await;
512        let entry = sessions.get(session_id)?;
513        // DSL remains the transition authority for live, non-terminal states.
514        // Persistent drivers use the published control projection as the
515        // visibility barrier when DSL has crossed a run-return or terminal
516        // lifecycle boundary before the durable commit has published it.
517        let control = entry.control_snapshot();
518        let authority = entry
519            .dsl_authority
520            .lock()
521            .unwrap_or_else(std::sync::PoisonError::into_inner);
522        let dsl_phase = dsl_authority::runtime_phase_from_authority(&authority);
523        let dsl_pre_run_phase = dsl_authority::pre_run_phase_from_authority(&authority);
524        if self.has_runtime_persistence()
525            && dsl_authority::should_publish_control_over_dsl(
526                control.phase,
527                dsl_phase,
528                dsl_pre_run_phase,
529            )
530        {
531            Some(control.phase)
532        } else {
533            Some(dsl_phase)
534        }
535    }
536
537    pub(super) async fn existing_session_visible_runtime_state(
538        &self,
539        session_id: &SessionId,
540    ) -> Option<RuntimeState> {
541        let sessions = self.sessions.read().await;
542        let entry = sessions.get(session_id)?;
543        let control = entry.control_snapshot();
544        let authority = entry
545            .dsl_authority
546            .lock()
547            .unwrap_or_else(std::sync::PoisonError::into_inner);
548        let dsl_phase = dsl_authority::runtime_phase_from_authority(&authority);
549        let dsl_pre_run_phase = dsl_authority::pre_run_phase_from_authority(&authority);
550        if self.has_runtime_persistence()
551            && dsl_authority::should_publish_control_over_dsl(
552                control.phase,
553                dsl_phase,
554                dsl_pre_run_phase,
555            )
556        {
557            Some(dsl_authority::visible_runtime_phase(
558                control.phase,
559                control.pre_run_phase,
560            ))
561        } else {
562            Some(dsl_authority::visible_runtime_phase(
563                dsl_phase,
564                dsl_pre_run_phase,
565            ))
566        }
567    }
568
569    /// Look up the session entry for a runtime ID, returning a control-plane error
570    /// if not found.
571    pub(super) async fn lookup_entry(
572        &self,
573        runtime_id: &LogicalRuntimeId,
574    ) -> Result<
575        (
576            SessionId,
577            SharedDriver,
578            SharedCompletionRegistry,
579            Option<mpsc::Sender<()>>,
580        ),
581        RuntimeControlPlaneError,
582    > {
583        let sessions = self.sessions.read().await;
584        let (session_id, entry) = sessions
585            .iter()
586            .find(|(_, entry)| &entry.runtime_id == runtime_id)
587            .ok_or_else(|| RuntimeControlPlaneError::NotFound(runtime_id.clone()))?;
588        Ok((
589            session_id.clone(),
590            entry.driver.clone(),
591            entry.completions.clone(),
592            entry.wake_sender(),
593        ))
594    }
595}
596
597#[cfg_attr(not(target_arch = "wasm32"), async_trait::async_trait)]
598#[cfg_attr(target_arch = "wasm32", async_trait::async_trait(?Send))]
599impl crate::traits::RuntimeControlPlane for MeerkatMachine {
600    async fn ingest(
601        &self,
602        runtime_id: &LogicalRuntimeId,
603        input: Input,
604    ) -> Result<AcceptOutcome, RuntimeControlPlaneError> {
605        match self
606            .execute_meerkat_machine_command(
607                None,
608                MeerkatMachineCommand::Ingest {
609                    runtime_id: runtime_id.clone(),
610                    input,
611                },
612            )
613            .await
614            .map_err(MeerkatMachine::control_plane_error_from_command_error)?
615        {
616            MeerkatMachineCommandResult::AcceptOutcome(outcome) => Ok(outcome),
617            other => Err(RuntimeControlPlaneError::Internal(format!(
618                "unexpected MeerkatMachineCommandResult for ingest: {other:?}"
619            ))),
620        }
621    }
622
623    async fn publish_event(
624        &self,
625        event: crate::runtime_event::RuntimeEventEnvelope,
626    ) -> Result<(), RuntimeControlPlaneError> {
627        match self
628            .execute_meerkat_machine_command(None, MeerkatMachineCommand::PublishEvent { event })
629            .await
630            .map_err(MeerkatMachine::control_plane_error_from_command_error)?
631        {
632            MeerkatMachineCommandResult::Unit => Ok(()),
633            other => Err(RuntimeControlPlaneError::Internal(format!(
634                "unexpected MeerkatMachineCommandResult for publish_event: {other:?}"
635            ))),
636        }
637    }
638
639    async fn retire(
640        &self,
641        runtime_id: &LogicalRuntimeId,
642    ) -> Result<RetireReport, RuntimeControlPlaneError> {
643        match self
644            .execute_meerkat_machine_command(
645                None,
646                MeerkatMachineCommand::Retire {
647                    runtime_id: runtime_id.clone(),
648                },
649            )
650            .await
651            .map_err(MeerkatMachine::control_plane_error_from_command_error)?
652        {
653            MeerkatMachineCommandResult::RetireReport(report) => Ok(report),
654            other => Err(RuntimeControlPlaneError::Internal(format!(
655                "unexpected MeerkatMachineCommandResult for retire: {other:?}"
656            ))),
657        }
658    }
659
660    async fn recycle(
661        &self,
662        runtime_id: &LogicalRuntimeId,
663    ) -> Result<RecycleReport, RuntimeControlPlaneError> {
664        match self
665            .execute_meerkat_machine_command(
666                None,
667                MeerkatMachineCommand::Recycle {
668                    runtime_id: runtime_id.clone(),
669                },
670            )
671            .await
672            .map_err(MeerkatMachine::control_plane_error_from_command_error)?
673        {
674            MeerkatMachineCommandResult::RecycleReport(report) => Ok(report),
675            other => Err(RuntimeControlPlaneError::Internal(format!(
676                "unexpected MeerkatMachineCommandResult for recycle: {other:?}"
677            ))),
678        }
679    }
680
681    async fn reset(
682        &self,
683        runtime_id: &LogicalRuntimeId,
684    ) -> Result<crate::traits::ResetReport, RuntimeControlPlaneError> {
685        match self
686            .execute_meerkat_machine_command(
687                None,
688                MeerkatMachineCommand::Reset {
689                    runtime_id: runtime_id.clone(),
690                },
691            )
692            .await
693            .map_err(MeerkatMachine::control_plane_error_from_command_error)?
694        {
695            MeerkatMachineCommandResult::ResetReport(report) => Ok(report),
696            other => Err(RuntimeControlPlaneError::Internal(format!(
697                "unexpected MeerkatMachineCommandResult for reset: {other:?}"
698            ))),
699        }
700    }
701
702    async fn recover(
703        &self,
704        runtime_id: &LogicalRuntimeId,
705    ) -> Result<RecoveryReport, RuntimeControlPlaneError> {
706        match self
707            .execute_meerkat_machine_command(
708                None,
709                MeerkatMachineCommand::Recover {
710                    runtime_id: runtime_id.clone(),
711                },
712            )
713            .await
714            .map_err(MeerkatMachine::control_plane_error_from_command_error)?
715        {
716            MeerkatMachineCommandResult::RecoveryReport(report) => Ok(report),
717            other => Err(RuntimeControlPlaneError::Internal(format!(
718                "unexpected MeerkatMachineCommandResult for recover: {other:?}"
719            ))),
720        }
721    }
722
723    async fn destroy(
724        &self,
725        runtime_id: &LogicalRuntimeId,
726    ) -> Result<DestroyReport, RuntimeControlPlaneError> {
727        match self
728            .execute_meerkat_machine_command(
729                None,
730                MeerkatMachineCommand::Destroy {
731                    runtime_id: runtime_id.clone(),
732                },
733            )
734            .await
735            .map_err(MeerkatMachine::control_plane_error_from_command_error)?
736        {
737            MeerkatMachineCommandResult::DestroyReport(report) => Ok(report),
738            other => Err(RuntimeControlPlaneError::Internal(format!(
739                "unexpected MeerkatMachineCommandResult for destroy: {other:?}"
740            ))),
741        }
742    }
743
744    async fn runtime_state(
745        &self,
746        runtime_id: &LogicalRuntimeId,
747    ) -> Result<RuntimeState, RuntimeControlPlaneError> {
748        match self
749            .execute_meerkat_machine_command(
750                None,
751                MeerkatMachineCommand::RuntimeState {
752                    runtime_id: runtime_id.clone(),
753                },
754            )
755            .await
756            .map_err(MeerkatMachine::control_plane_error_from_command_error)?
757        {
758            MeerkatMachineCommandResult::RuntimeState(state) => Ok(state),
759            other => Err(RuntimeControlPlaneError::Internal(format!(
760                "unexpected MeerkatMachineCommandResult for runtime_state: {other:?}"
761            ))),
762        }
763    }
764
765    async fn load_boundary_receipt(
766        &self,
767        runtime_id: &LogicalRuntimeId,
768        run_id: &RunId,
769        sequence: u64,
770    ) -> Result<Option<meerkat_core::lifecycle::RunBoundaryReceipt>, RuntimeControlPlaneError> {
771        match self
772            .execute_meerkat_machine_command(
773                None,
774                MeerkatMachineCommand::LoadBoundaryReceipt {
775                    runtime_id: runtime_id.clone(),
776                    run_id: run_id.clone(),
777                    sequence,
778                },
779            )
780            .await
781            .map_err(MeerkatMachine::control_plane_error_from_command_error)?
782        {
783            MeerkatMachineCommandResult::BoundaryReceipt(receipt) => Ok(receipt),
784            other => Err(RuntimeControlPlaneError::Internal(format!(
785                "unexpected MeerkatMachineCommandResult for load_boundary_receipt: {other:?}"
786            ))),
787        }
788    }
789}