1use std::collections::BTreeMap;
8use std::sync::Arc;
9
10use crate::meerkat_machine::{CommsDrainMode, CommsDrainPhase, DrainExitReason, dsl};
11use indexmap::IndexSet;
12use meerkat_core::RuntimeEpochId;
13use meerkat_core::agent::CommsRuntime;
14use meerkat_core::image_generation::{
15 ImageOperationApprovalReason, ImageOperationDenialReason, ImageOperationId,
16 ImageOperationPhase, ImageOperationTerminalClass, SessionModelRoutingStatus,
17 SwitchTurnApprovalReason, SwitchTurnControlResult, SwitchTurnIntent, SwitchTurnRequestId,
18};
19use meerkat_core::lifecycle::WaitRequestId;
20use meerkat_core::lifecycle::core_executor::CoreApplyOutput;
21use meerkat_core::lifecycle::core_executor::CoreExecutor;
22use meerkat_core::lifecycle::run_primitive::{ModelId, RunPrimitive};
23use meerkat_core::lifecycle::{InputId, RunId};
24use meerkat_core::lifecycle::{RunBoundaryReceipt, RunId as LifecycleRunId};
25use meerkat_core::ops::OperationId;
26use meerkat_core::ops_lifecycle::OperationLifecycleSnapshot;
27use meerkat_core::types::HandlingMode;
28use meerkat_core::types::SessionId;
29use meerkat_machine_derive::CommandManifest;
30use meerkat_machine_schema::catalog::dsl::meerkat_machine::MeerkatMachineInputVariant;
31use serde::{Deserialize, Serialize};
32
33use crate::AcceptOutcome;
34use crate::identifiers::LogicalRuntimeId;
35use crate::ingress_types::{ContentShape, RequestId, ReservationKey};
36use crate::input::Input;
37use crate::input_state::InputLifecycleState;
38use crate::input_state::InputTerminalOutcome;
39use crate::input_state::StoredInputState;
40use crate::runtime_event::RuntimeEventEnvelope;
41use crate::runtime_state::RuntimeState;
42use crate::traits::{
43 DestroyReport, RecoveryReport, RecycleReport, ResetReport, RetireReport,
44 RuntimeControlPlaneError, RuntimeDriverError,
45};
46
47#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
48#[serde(rename_all = "snake_case")]
49pub struct SessionLlmReconfigureRequest {
50 #[serde(default, skip_serializing_if = "Option::is_none")]
51 pub model: Option<String>,
52 #[serde(default, skip_serializing_if = "Option::is_none")]
53 pub provider: Option<String>,
54 #[serde(default, skip_serializing_if = "Option::is_none")]
55 pub provider_params: Option<serde_json::Value>,
56 #[serde(default, skip_serializing_if = "is_false")]
60 pub clear_provider_params: bool,
61 #[serde(default, skip_serializing_if = "Option::is_none")]
66 pub auth_binding: Option<meerkat_core::AuthBindingRef>,
67 #[serde(default, skip_serializing_if = "is_false")]
71 pub clear_auth_binding: bool,
72}
73
74fn is_false(value: &bool) -> bool {
75 !*value
76}
77
78#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, Default)]
79#[serde(rename_all = "snake_case")]
80pub enum SessionLlmCapabilitySurfaceStatus {
81 Resolved,
82 #[default]
83 Unresolved,
84}
85
86#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
87#[serde(rename_all = "snake_case")]
88pub struct SessionLlmCapabilitySurface {
89 pub supports_temperature: bool,
90 pub supports_thinking: bool,
91 pub supports_reasoning: bool,
92 pub inline_video: bool,
93 pub vision: bool,
94 #[serde(default)]
95 pub image_input: bool,
96 pub image_tool_results: bool,
97 pub supports_web_search: bool,
98 #[serde(default)]
99 pub image_generation: bool,
100 #[serde(default)]
104 pub realtime: bool,
105 #[serde(default, skip_serializing_if = "Option::is_none")]
106 pub call_timeout_secs: Option<u64>,
107}
108
109impl SessionLlmCapabilitySurface {
110 #[must_use]
111 pub fn to_wire_resolved(&self) -> meerkat_contracts::WireResolvedModelCapabilities {
112 meerkat_contracts::WireResolvedModelCapabilities {
113 vision: self.vision,
114 image_input: self.image_input,
115 image_tool_results: self.image_tool_results,
116 inline_video: self.inline_video,
117 realtime: self.realtime,
118 web_search: self.supports_web_search,
119 image_generation: self.image_generation,
120 }
121 }
122}
123
124#[derive(Debug, Clone, PartialEq, Eq)]
125pub struct SessionLlmCapabilityDelta {
126 pub previous: Option<SessionLlmCapabilitySurface>,
127 pub current: Option<SessionLlmCapabilitySurface>,
128 pub changed: bool,
129}
130
131#[derive(Debug, Clone, PartialEq, Eq)]
132pub struct SessionToolVisibilityDelta {
133 pub previous_capability_base_filter: meerkat_core::ToolFilter,
134 pub current_capability_base_filter: meerkat_core::ToolFilter,
135 pub committed_visible_set_changed: bool,
136 pub revision_bumped: bool,
137}
138
139#[derive(Debug, Clone, PartialEq)]
140pub struct SessionLlmReconfigureReport {
141 pub previous_identity: meerkat_core::SessionLlmIdentity,
142 pub new_identity: meerkat_core::SessionLlmIdentity,
143 pub capability_delta: SessionLlmCapabilityDelta,
144 pub tool_visibility_delta: SessionToolVisibilityDelta,
145 pub rollback_occurred: bool,
146}
147
148#[derive(Debug, Clone)]
149pub struct HydratedSessionLlmState {
150 pub current_identity: meerkat_core::SessionLlmIdentity,
151 pub current_visibility_state: meerkat_core::SessionToolVisibilityState,
152 pub current_capability_surface: Option<SessionLlmCapabilitySurface>,
153 pub capability_surface_status: SessionLlmCapabilitySurfaceStatus,
154 pub base_tool_names: std::collections::BTreeSet<String>,
155}
156
157#[derive(Debug, Clone)]
158pub struct ResolvedSessionLlmReconfigure {
159 pub target_identity: meerkat_core::SessionLlmIdentity,
160 pub target_capability_surface: SessionLlmCapabilitySurface,
161}
162
163#[derive(Debug, Clone, Copy, PartialEq, Eq)]
164pub enum ModelRoutingApprovalDisposition {
165 NotRequired,
166 Approved,
167 DeniedByUser,
168 RequiredButUnavailable,
169}
170
171#[derive(Debug, Clone, Copy, PartialEq, Eq)]
172pub struct ModelRoutingRealtimePolicy {
173 pub target_realtime_capable: bool,
174 pub allow_realtime_detach: bool,
175}
176
177#[derive(Debug, Clone, PartialEq, Eq)]
178pub struct SwitchTurnRequest {
179 pub request_id: SwitchTurnRequestId,
180 pub intent: SwitchTurnIntent,
181 pub target_realtime: ModelRoutingRealtimePolicy,
182 pub approval: ModelRoutingApprovalDisposition,
183 pub approval_reason: Option<SwitchTurnApprovalReason>,
184}
185
186#[derive(Debug, Clone, PartialEq, Eq)]
187pub struct ImageOperationRoutingRequest {
188 pub operation_id: ImageOperationId,
189 pub target_model: ModelId,
190 pub target_realtime: ModelRoutingRealtimePolicy,
191 pub approval: ModelRoutingApprovalDisposition,
192 pub approval_reason: Option<ImageOperationApprovalReason>,
193 pub requires_scoped_override: bool,
194}
195
196#[derive(Debug, Clone, PartialEq, Eq)]
197pub enum ImageOperationRoutingResult {
198 Accepted {
199 operation_id: ImageOperationId,
200 phase: ImageOperationPhase,
201 },
202 Denied {
203 operation_id: ImageOperationId,
204 reason: ImageOperationDenialReason,
205 },
206}
207
208#[cfg_attr(not(target_arch = "wasm32"), async_trait::async_trait)]
209#[cfg_attr(target_arch = "wasm32", async_trait::async_trait(?Send))]
210pub trait SessionLlmReconfigureHost: Send + Sync {
211 async fn hydrate_session_llm_state(
212 &self,
213 session_id: &SessionId,
214 ) -> Result<HydratedSessionLlmState, RuntimeDriverError>;
215
216 async fn resolve_target_session_llm_identity(
217 &self,
218 request: &SessionLlmReconfigureRequest,
219 current_identity: &meerkat_core::SessionLlmIdentity,
220 ) -> Result<ResolvedSessionLlmReconfigure, RuntimeDriverError>;
221
222 async fn apply_live_session_llm_identity(
223 &self,
224 session_id: &SessionId,
225 identity: &meerkat_core::SessionLlmIdentity,
226 ) -> Result<(), RuntimeDriverError>;
227
228 async fn apply_live_session_tool_visibility_state(
229 &self,
230 session_id: &SessionId,
231 visibility_state: Option<meerkat_core::SessionToolVisibilityState>,
232 ) -> Result<(), RuntimeDriverError>;
233
234 async fn persist_live_session(&self, session_id: &SessionId) -> Result<(), RuntimeDriverError>;
235
236 async fn discard_live_session(&self, session_id: &SessionId) -> Result<(), RuntimeDriverError>;
237}
238
239#[derive(Debug, thiserror::Error)]
240pub(crate) enum MeerkatMachineCommandError {
241 #[error(transparent)]
242 Driver(#[from] RuntimeDriverError),
243 #[error(transparent)]
244 Control(#[from] RuntimeControlPlaneError),
245}
246
247#[derive(CommandManifest)]
253#[allow(clippy::large_enum_variant)]
254pub(crate) enum MeerkatMachineCommand {
255 RegisterSession {
256 session_id: SessionId,
257 },
258 UnregisterSession {
259 session_id: SessionId,
260 },
261 EnsureSessionWithExecutor {
262 session_id: SessionId,
263 executor: Box<dyn CoreExecutor>,
264 },
265 SetSilentIntents {
266 session_id: SessionId,
267 intents: Vec<String>,
268 },
269 CancelAfterBoundary {
270 session_id: SessionId,
271 },
272 StopRuntimeExecutor {
273 session_id: SessionId,
274 reason: String,
275 },
276 CommitServiceTurnTerminalReceipt {
277 session_id: SessionId,
278 },
279 ContainsSession {
280 session_id: SessionId,
281 },
282 SessionHasExecutor {
283 session_id: SessionId,
284 },
285 SessionHasComms {
286 session_id: SessionId,
287 },
288 OpsLifecycleRegistry {
289 session_id: SessionId,
290 },
291 PrepareBindings {
292 session_id: SessionId,
293 },
294 PrepareLocalSessionBindings {
295 session_id: SessionId,
296 },
297 InputState {
298 session_id: SessionId,
299 input_id: InputId,
300 },
301 ListActiveInputs {
302 session_id: SessionId,
303 },
304 ReconfigureSessionLlmIdentity {
305 session_id: SessionId,
306 previous_identity: Box<meerkat_core::SessionLlmIdentity>,
307 previous_visibility_state: Box<meerkat_core::SessionToolVisibilityState>,
308 previous_capability_surface: Option<SessionLlmCapabilitySurface>,
309 previous_capability_surface_status: SessionLlmCapabilitySurfaceStatus,
310 target_identity: Box<meerkat_core::SessionLlmIdentity>,
311 target_capability_surface: Box<SessionLlmCapabilitySurface>,
312 next_visibility_state: Box<meerkat_core::SessionToolVisibilityState>,
313 next_capability_base_filter: meerkat_core::ToolFilter,
314 next_active_visibility_revision: u64,
315 tool_visibility_delta: Box<SessionToolVisibilityDelta>,
316 },
317 StagePersistentFilter {
318 session_id: SessionId,
319 filter: meerkat_core::ToolFilter,
320 witnesses: std::collections::BTreeMap<String, meerkat_core::ToolVisibilityWitness>,
321 },
322 RequestDeferredTools {
323 session_id: SessionId,
324 authorities: Vec<meerkat_core::DeferredToolLoadAuthority>,
325 },
326 PublishCommittedVisibleSet {
332 session_id: SessionId,
333 visibility_state: Box<meerkat_core::SessionToolVisibilityState>,
334 },
335 SetPeerIngressContext {
336 session_id: SessionId,
337 keep_alive: bool,
338 comms_runtime: Option<Arc<dyn CommsRuntime>>,
339 mob_id: Option<crate::meerkat_machine::dsl::MobId>,
343 },
344 NotifyDrainExited {
345 session_id: SessionId,
346 reason: DrainExitReason,
347 },
348 AbortAll,
349 Abort {
350 session_id: SessionId,
351 },
352 Wait {
353 session_id: SessionId,
354 },
355 Ingest {
356 runtime_id: LogicalRuntimeId,
357 input: Input,
358 },
359 PublishEvent {
360 event: RuntimeEventEnvelope,
361 },
362 Retire {
363 runtime_id: LogicalRuntimeId,
364 },
365 Recycle {
366 runtime_id: LogicalRuntimeId,
367 },
368 Reset {
369 runtime_id: LogicalRuntimeId,
370 },
371 Recover {
372 runtime_id: LogicalRuntimeId,
373 },
374 Destroy {
375 runtime_id: LogicalRuntimeId,
376 },
377 RuntimeState {
378 runtime_id: LogicalRuntimeId,
379 },
380 ResolvedSessionLlmCapabilities {
381 session_id: SessionId,
382 },
383 ConfigureModelRoutingBaseline {
384 session_id: SessionId,
385 baseline_model: ModelId,
386 realtime_capable: bool,
387 },
388 SessionModelRoutingStatus {
389 session_id: SessionId,
390 },
391 RequestSwitchTurn {
392 session_id: SessionId,
393 request: Box<SwitchTurnRequest>,
394 },
395 AdmitModelRoutingAssistantTurn {
396 session_id: SessionId,
397 },
398 BeginImageOperation {
399 session_id: SessionId,
400 request: Box<ImageOperationRoutingRequest>,
401 },
402 ActivateImageOperationOverride {
403 session_id: SessionId,
404 operation_id: ImageOperationId,
405 },
406 CompleteImageOperation {
407 session_id: SessionId,
408 operation_id: ImageOperationId,
409 terminal: ImageOperationTerminalClass,
410 },
411 RestoreImageOperationOverride {
412 session_id: SessionId,
413 operation_id: ImageOperationId,
414 },
415 LoadBoundaryReceipt {
416 runtime_id: LogicalRuntimeId,
417 run_id: LifecycleRunId,
418 sequence: u64,
419 },
420 AcceptWithCompletion {
421 session_id: SessionId,
422 input: Input,
423 },
424 AcceptWithoutWake {
425 session_id: SessionId,
426 input: Input,
427 },
428 Prepare {
429 session_id: SessionId,
430 input: Input,
431 },
432 Commit {
433 session_id: SessionId,
434 input_id: InputId,
435 run_id: RunId,
436 output: CoreApplyOutput,
437 },
438 Fail {
439 session_id: SessionId,
440 run_id: RunId,
441 failure: MeerkatMachineRunFailure,
442 },
443}
444
445#[derive(Debug, Clone)]
446pub(crate) struct MeerkatMachineRunFailure {
447 pub terminal_outcome: meerkat_core::TurnTerminalOutcome,
448 pub terminal_cause_kind: meerkat_core::TurnTerminalCauseKind,
449 pub error: String,
450}
451
452impl MeerkatMachineRunFailure {
453 pub(crate) fn new(
454 terminal_cause_kind: meerkat_core::TurnTerminalCauseKind,
455 error: impl Into<String>,
456 ) -> Self {
457 Self::terminal(
458 meerkat_core::TurnTerminalOutcome::Failed,
459 terminal_cause_kind,
460 error,
461 )
462 }
463
464 pub(crate) fn terminal(
465 terminal_outcome: meerkat_core::TurnTerminalOutcome,
466 terminal_cause_kind: meerkat_core::TurnTerminalCauseKind,
467 error: impl Into<String>,
468 ) -> Self {
469 Self {
470 terminal_outcome,
471 terminal_cause_kind,
472 error: error.into(),
473 }
474 }
475}
476
477#[derive(Debug)]
478pub(crate) struct MeerkatMachineRunPrepared {
479 pub input_id: InputId,
480 pub run_id: RunId,
481 pub primitive: RunPrimitive,
482}
483
484#[derive(Debug)]
485#[allow(clippy::large_enum_variant)]
486pub(crate) enum MeerkatMachineCommandResult {
487 AcceptOutcome(AcceptOutcome),
488 AcceptWithCompletion {
489 outcome: AcceptOutcome,
490 handle: Option<crate::completion::CompletionHandle>,
491 #[cfg_attr(not(test), allow(dead_code))]
492 admission_signal: crate::driver::ephemeral::PostAdmissionSignal,
493 },
494 Unit,
495 Bool(bool),
496 Spawned(bool),
497 OpsLifecycleRegistry(Option<Arc<crate::ops_lifecycle::RuntimeOpsLifecycleRegistry>>),
498 Bindings(meerkat_core::SessionRuntimeBindings),
499 InputState(Option<StoredInputState>),
500 ActiveInputs(Vec<InputId>),
501 LlmReconfigured(SessionLlmReconfigureReport),
502 VisibilityRevision(meerkat_core::ToolScopeRevision),
503 VisibilityPublished(meerkat_core::SessionToolVisibilityState),
504 RetireReport(RetireReport),
505 RecycleReport(RecycleReport),
506 ResetReport(ResetReport),
507 RecoveryReport(RecoveryReport),
508 DestroyReport(DestroyReport),
509 RuntimeState(RuntimeState),
510 ResolvedSessionLlmCapabilities(Option<SessionLlmCapabilitySurface>),
511 SessionModelRoutingStatus(SessionModelRoutingStatus),
512 SwitchTurnControlResult(SwitchTurnControlResult),
513 ImageOperationRoutingResult(ImageOperationRoutingResult),
514 ImageOperationPhase(ImageOperationPhase),
515 BoundaryReceipt(Option<RunBoundaryReceipt>),
516 Prepared(MeerkatMachineRunPrepared),
517}
518
519#[doc(hidden)]
520#[must_use]
521pub fn canonical_meerkat_machine_command_manifest() -> IndexSet<&'static str> {
522 canonical_meerkat_machine_command_input_variant_manifest()
523 .into_iter()
524 .map(|variant| variant.as_str())
525 .collect()
526}
527
528#[doc(hidden)]
529#[must_use]
530pub fn canonical_meerkat_machine_command_input_variant_manifest()
531-> IndexSet<MeerkatMachineInputVariant> {
532 canonical_meerkat_machine_command_classifications()
533 .into_iter()
534 .flat_map(|record| record.classification.catalog_input_variants())
535 .collect()
536}
537
538#[doc(hidden)]
539#[must_use]
540pub fn canonical_meerkat_machine_runtime_internal_manifest() -> IndexSet<&'static str> {
541 canonical_meerkat_machine_runtime_internal_input_variant_manifest()
542 .into_iter()
543 .map(|variant| variant.as_str())
544 .collect()
545}
546
547#[doc(hidden)]
548#[must_use]
549pub fn canonical_meerkat_machine_runtime_internal_input_variant_manifest()
550-> IndexSet<MeerkatMachineInputVariant> {
551 canonical_meerkat_machine_runtime_internal_classifications()
552 .into_iter()
553 .map(|record| record.input.input_variant())
554 .collect()
555}
556
557#[doc(hidden)]
558#[must_use]
559pub fn canonical_meerkat_machine_runtime_internal_fieldless_input_variant_manifest()
560-> IndexSet<MeerkatMachineInputVariant> {
561 MeerkatMachineFieldlessRuntimeInternalInput::ALL
562 .iter()
563 .copied()
564 .map(MeerkatMachineFieldlessRuntimeInternalInput::input_variant)
565 .collect()
566}
567
568macro_rules! meerkat_machine_runtime_internal_inputs {
569 ($($reason:ident => [$($variant:ident),+ $(,)?]),+ $(,)?) => {
570 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
571 pub enum MeerkatMachineRuntimeInternalInput {
572 $($($variant),+),+
573 }
574
575 impl MeerkatMachineRuntimeInternalInput {
576 pub const ALL: &'static [Self] = &[
577 $($(Self::$variant),+),+
578 ];
579
580 pub const CLASSIFICATIONS: &'static [MeerkatMachineRuntimeInternalClassificationRecord] = &[
581 $($(
582 MeerkatMachineRuntimeInternalClassificationRecord {
583 input: Self::$variant,
584 reason: MeerkatMachineRuntimeInternalReason::$reason,
585 },
586 )+)+
587 ];
588
589 #[must_use]
590 pub const fn input_variant(self) -> MeerkatMachineInputVariant {
591 match self {
592 $($(Self::$variant => MeerkatMachineInputVariant::$variant,)+)+
593 }
594 }
595
596 #[must_use]
597 pub const fn reason(self) -> MeerkatMachineRuntimeInternalReason {
598 match self {
599 $(
600 $(Self::$variant)|+ => MeerkatMachineRuntimeInternalReason::$reason,
601 )+
602 }
603 }
604 }
605 };
606}
607
608#[derive(Debug, Clone, Copy, PartialEq, Eq)]
609pub enum MeerkatMachineRuntimeInternalReason {
610 InputQueueLifecycle,
611 OperationLifecycle,
612 RunExecutionLifecycle,
613 CancellationLifecycle,
614 LiveTopologyReconfiguration,
615 InteractionStreamLifecycle,
616 CommsIngressLifecycle,
617 SupervisorTrustLifecycle,
618 PeerRequestLifecycle,
619 VisibilityAuthorityLifecycle,
620 ExtractionLifecycle,
621 McpServerLifecycle,
622 ModelRoutingLifecycle,
623 ExternalSurfaceLifecycle,
624 FailureRecoveryLifecycle,
625 UserInterruptDispatch,
626}
627
628#[derive(Debug, Clone, Copy, PartialEq, Eq)]
629pub struct MeerkatMachineRuntimeInternalClassificationRecord {
630 pub input: MeerkatMachineRuntimeInternalInput,
631 pub reason: MeerkatMachineRuntimeInternalReason,
632}
633
634meerkat_machine_runtime_internal_inputs!(
635 InputQueueLifecycle => [
636 AbandonInput,
637 AdvanceSessionContext,
638 BudgetExhausted,
639 ChangeLane,
640 CoalesceInput,
641 ConsumeInput,
642 ConsumeOnAccept,
643 MarkApplied,
644 MarkAppliedPendingConsumption,
645 QueueAccepted,
646 RecoverInputLifecycle,
647 RetryRequested,
648 RollbackStaged,
649 StageForRun,
650 StartConversationRun,
651 StartImmediateAppend,
652 StartImmediateContext,
653 SteerAccepted,
654 SupersedeInput,
655 ],
656 OperationLifecycle => [
657 AbortOp,
658 CancelOp,
659 CancelWaitAll,
660 CompleteOp,
661 FailOp,
662 IncrementAttemptCount,
663 OpsBarrierSatisfied,
664 PeerReadyOp,
665 ProgressReportedOp,
666 RegisterOp,
667 RegisterPendingOps,
668 RequestWaitAll,
669 RetireCompletedOp,
670 RetireRequestedOp,
671 SatisfyWaitAll,
672 StartOp,
673 TerminateOp,
674 ],
675 RunExecutionLifecycle => [
676 AcknowledgeTerminal,
677 BoundaryComplete,
678 BoundaryContinue,
679 LlmReturnedTerminal,
680 LlmReturnedToolCalls,
681 PrimitiveApplied,
682 RecordBoundarySeq,
683 RollbackRun,
684 RunCompleted,
685 RunFailed,
686 RuntimeExecutorExited,
687 TimeBudgetExceeded,
688 ToolCallsResolved,
689 TurnLimitReached,
690 ],
691 CancellationLifecycle => [
692 CancelNow,
693 CancelRun,
694 CancellationObserved,
695 ForceCancelNoRun,
696 RequestCancelAfterBoundary,
697 RunCancelled,
698 ],
699 LiveTopologyReconfiguration => [
700 CompleteUntilChangedSwitchTurnReconfigure,
701 ],
702 InteractionStreamLifecycle => [
703 InteractionStreamAttached,
704 InteractionStreamClosedEarly,
705 InteractionStreamCompleted,
706 InteractionStreamExpired,
707 InteractionStreamReserved,
708 ],
709 CommsIngressLifecycle => [
710 AddDirectPeerEndpoint,
711 ApplyMobPeerOverlay,
712 AttachMobIngress,
713 AttachSessionIngress,
714 BindSupervisor,
715 ClearLocalEndpoint,
716 DetachIngress,
717 DrainExitedClean,
718 DrainExitedRespawnable,
719 PublishLocalEndpoint,
720 RemoveDirectPeerEndpoint,
721 SpawnDrain,
722 StopDrain,
723 ],
724 SupervisorTrustLifecycle => [
725 AuthorizeSupervisor,
726 RevokeSupervisor,
727 SupervisorTrustEdgePublishFailed,
728 SupervisorTrustEdgePublished,
729 SupervisorTrustEdgeRevokeFailed,
730 SupervisorTrustEdgeRevoked,
731 ],
732 PeerRequestLifecycle => [
733 PeerRequestReceived,
734 PeerRequestSent,
735 PeerRequestTimedOut,
736 PeerResponseProgressArrived,
737 PeerResponseReplied,
738 PeerResponseTerminalArrived,
739 ],
740 VisibilityAuthorityLifecycle => [
741 CommitDeferredNames,
742 CommitVisibilityFilter,
743 StageDeferredNames,
744 StageVisibilityFilter,
745 SyncVisibilityRevisions,
746 ],
747 ExtractionLifecycle => [
748 EnterExtraction,
749 ExtractionFailed,
750 ExtractionStart,
751 ExtractionValidationFailed,
752 ExtractionValidationPassed,
753 ],
754 McpServerLifecycle => [
755 McpServerConnectPending,
756 McpServerConnected,
757 McpServerDisconnected,
758 McpServerFailed,
759 McpServerReload,
760 ],
761 ModelRoutingLifecycle => [
762 ModelRoutingStatus,
763 RequestFiniteSwitchTurn,
764 RequestUntilChangedSwitchTurn,
765 SetModelRoutingBaseline,
766 ],
767 ExternalSurfaceLifecycle => [
768 SurfaceApplyBoundary,
769 SurfaceCallFinished,
770 SurfaceCallStarted,
771 SurfaceFinalizeRemovalClean,
772 SurfaceFinalizeRemovalForced,
773 SurfaceMarkPendingFailed,
774 SurfaceMarkPendingSucceeded,
775 SurfaceRegister,
776 SurfaceShutdown,
777 SurfaceSnapshotAligned,
778 SurfaceStageAdd,
779 SurfaceStageReload,
780 SurfaceStageRemove,
781 ],
782 FailureRecoveryLifecycle => [
783 FatalFailure,
784 RecoverableFailure,
785 ],
786 UserInterruptDispatch => [
787 InterruptCurrentRun,
788 ],
789);
790
791macro_rules! meerkat_machine_fieldless_runtime_internal_inputs {
792 ($($authority:ident => [$($variant:ident),+ $(,)?]),+ $(,)?) => {
793 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
794 pub enum MeerkatMachineFieldlessRuntimeInternalInput {
795 $($($variant),+),+
796 }
797
798 impl MeerkatMachineFieldlessRuntimeInternalInput {
799 pub const ALL: &'static [Self] = &[
800 $($(Self::$variant),+),+
801 ];
802
803 #[must_use]
804 pub const fn runtime_internal_input(self) -> MeerkatMachineRuntimeInternalInput {
805 match self {
806 $($(Self::$variant => MeerkatMachineRuntimeInternalInput::$variant,)+)+
807 }
808 }
809
810 #[must_use]
811 pub const fn input_variant(self) -> MeerkatMachineInputVariant {
812 self.runtime_internal_input().input_variant()
813 }
814
815 #[must_use]
816 pub const fn authority(self) -> MeerkatMachineFieldlessRuntimeInternalAuthority {
817 match self {
818 $(
819 $(Self::$variant)|+ => MeerkatMachineFieldlessRuntimeInternalAuthority::$authority,
820 )+
821 }
822 }
823
824 #[must_use]
825 pub const fn requires_typed_runtime_internal_stager(self) -> bool {
826 matches!(
827 self.authority(),
828 MeerkatMachineFieldlessRuntimeInternalAuthority::UserInterruptDispatch
829 )
830 }
831
832 pub(crate) const fn dsl_input_variant(self) -> dsl::MeerkatMachineInputVariant {
833 match self {
834 $($(Self::$variant => dsl::MeerkatMachineInputVariant::$variant,)+)+
835 }
836 }
837
838 pub(crate) fn dsl_input(self) -> dsl::MeerkatMachineInput {
839 match self {
840 $($(Self::$variant => dsl::MeerkatMachineInput::$variant,)+)+
841 }
842 }
843
844 pub(crate) fn from_dsl_input_variant(
845 variant: dsl::MeerkatMachineInputVariant,
846 ) -> Option<Self> {
847 Self::ALL
848 .iter()
849 .copied()
850 .find(|input| input.dsl_input_variant() == variant)
851 }
852
853 pub(crate) fn reject_raw_dsl_input(
854 input: &dsl::MeerkatMachineInput,
855 ) -> Result<(), String> {
856 if let Some(fieldless) = Self::from_dsl_input_variant(input.variant())
857 && fieldless.requires_typed_runtime_internal_stager()
858 {
859 let variant = fieldless.input_variant();
860 return Err(format!(
861 "fieldless runtime-internal input {variant:?} must use typed runtime-internal staging authority"
862 ));
863 }
864 Ok(())
865 }
866 }
867 };
868}
869
870meerkat_machine_fieldless_runtime_internal_inputs!(
871 RuntimeOwner => [
872 RuntimeExecutorExited,
873 PrimitiveApplied,
874 LlmReturnedTerminal,
875 ToolCallsResolved,
876 BoundaryContinue,
877 BoundaryComplete,
878 ExtractionStart,
879 ExtractionValidationPassed,
880 CancelNow,
881 RequestCancelAfterBoundary,
882 CancellationObserved,
883 TurnLimitReached,
884 BudgetExhausted,
885 TimeBudgetExceeded,
886 ForceCancelNoRun,
887 CancelWaitAll,
888 StopDrain,
889 DrainExitedClean,
890 DrainExitedRespawnable,
891 SurfaceShutdown,
892 DetachIngress,
893 ClearLocalEndpoint,
894 ],
895 UserInterruptDispatch => [
896 InterruptCurrentRun,
897 ],
898);
899
900#[derive(Debug, Clone, Copy, PartialEq, Eq)]
901pub enum MeerkatMachineFieldlessRuntimeInternalAuthority {
902 RuntimeOwner,
903 UserInterruptDispatch,
904}
905
906#[doc(hidden)]
907#[must_use]
908pub fn canonical_meerkat_machine_runtime_internal_classifications()
909-> Vec<MeerkatMachineRuntimeInternalClassificationRecord> {
910 MeerkatMachineRuntimeInternalInput::CLASSIFICATIONS.to_vec()
911}
912
913#[derive(Debug, Clone, Copy, PartialEq, Eq)]
914pub enum MeerkatMachineCommandClassification {
915 CatalogInput(MeerkatMachineCatalogInput),
916 CatalogInputs(&'static [MeerkatMachineCatalogInput]),
917 ShellMechanic(MeerkatMachineShellMechanicReason),
918}
919
920impl MeerkatMachineCommandClassification {
921 #[must_use]
922 pub fn catalog_inputs(self) -> Vec<MeerkatMachineCatalogInput> {
923 match self {
924 Self::CatalogInput(input) => vec![input],
925 Self::CatalogInputs(inputs) => inputs.to_vec(),
926 Self::ShellMechanic(_) => Vec::new(),
927 }
928 }
929
930 #[must_use]
931 pub fn catalog_input_variants(self) -> Vec<MeerkatMachineInputVariant> {
932 self.catalog_inputs()
933 .into_iter()
934 .map(MeerkatMachineCatalogInput::input_variant)
935 .collect()
936 }
937}
938
939#[derive(Debug, Clone, Copy, PartialEq, Eq)]
940pub enum MeerkatMachineCatalogInput {
941 RegisterSession,
942 UnregisterSession,
943 EnsureSessionWithExecutor,
944 SetSilentIntents,
945 CancelAfterBoundary,
946 StopRuntimeExecutor,
947 ServiceTurnCommitted,
948 ContainsSession,
949 SessionHasExecutor,
950 SessionHasComms,
951 OpsLifecycleRegistry,
952 PrepareBindings,
953 InputState,
954 ListActiveInputs,
955 ReconfigureSessionLlmIdentity,
956 StagePersistentFilter,
957 RequestDeferredTools,
958 PublishCommittedVisibleSet,
959 SetPeerIngressContext,
960 NotifyDrainExited,
961 AbortAll,
962 Abort,
963 Wait,
964 Ingest,
965 PublishEvent,
966 Retire,
967 Recycle,
968 Reset,
969 Recover,
970 Destroy,
971 RuntimeState,
972 ModelRoutingStatus,
973 SetModelRoutingBaseline,
974 RequestFiniteSwitchTurn,
975 RequestUntilChangedSwitchTurn,
976 AdmitModelRoutingAssistantTurn,
977 BeginImageOperation,
978 ActivateImageOperationOverride,
979 CompleteImageOperation,
980 RestoreImageOperationOverride,
981 LoadBoundaryReceipt,
982 AcceptWithCompletion,
983 AcceptWithoutWake,
984 Prepare,
985 Commit,
986 Fail,
987}
988
989impl MeerkatMachineCatalogInput {
990 pub const ALL: &'static [Self] = &[
991 Self::RegisterSession,
992 Self::UnregisterSession,
993 Self::EnsureSessionWithExecutor,
994 Self::SetSilentIntents,
995 Self::CancelAfterBoundary,
996 Self::StopRuntimeExecutor,
997 Self::ServiceTurnCommitted,
998 Self::ContainsSession,
999 Self::SessionHasExecutor,
1000 Self::SessionHasComms,
1001 Self::OpsLifecycleRegistry,
1002 Self::PrepareBindings,
1003 Self::InputState,
1004 Self::ListActiveInputs,
1005 Self::ReconfigureSessionLlmIdentity,
1006 Self::StagePersistentFilter,
1007 Self::RequestDeferredTools,
1008 Self::PublishCommittedVisibleSet,
1009 Self::SetPeerIngressContext,
1010 Self::NotifyDrainExited,
1011 Self::AbortAll,
1012 Self::Abort,
1013 Self::Wait,
1014 Self::Ingest,
1015 Self::PublishEvent,
1016 Self::Retire,
1017 Self::Recycle,
1018 Self::Reset,
1019 Self::Recover,
1020 Self::Destroy,
1021 Self::RuntimeState,
1022 Self::ModelRoutingStatus,
1023 Self::SetModelRoutingBaseline,
1024 Self::RequestFiniteSwitchTurn,
1025 Self::RequestUntilChangedSwitchTurn,
1026 Self::AdmitModelRoutingAssistantTurn,
1027 Self::BeginImageOperation,
1028 Self::ActivateImageOperationOverride,
1029 Self::CompleteImageOperation,
1030 Self::RestoreImageOperationOverride,
1031 Self::LoadBoundaryReceipt,
1032 Self::AcceptWithCompletion,
1033 Self::AcceptWithoutWake,
1034 Self::Prepare,
1035 Self::Commit,
1036 Self::Fail,
1037 ];
1038
1039 #[must_use]
1040 pub const fn input_variant(self) -> MeerkatMachineInputVariant {
1041 match self {
1042 Self::RegisterSession => MeerkatMachineInputVariant::RegisterSession,
1043 Self::UnregisterSession => MeerkatMachineInputVariant::UnregisterSession,
1044 Self::EnsureSessionWithExecutor => {
1045 MeerkatMachineInputVariant::EnsureSessionWithExecutor
1046 }
1047 Self::SetSilentIntents => MeerkatMachineInputVariant::SetSilentIntents,
1048 Self::CancelAfterBoundary => MeerkatMachineInputVariant::CancelAfterBoundary,
1049 Self::StopRuntimeExecutor => MeerkatMachineInputVariant::StopRuntimeExecutor,
1050 Self::ServiceTurnCommitted => MeerkatMachineInputVariant::ServiceTurnCommitted,
1051 Self::ContainsSession => MeerkatMachineInputVariant::ContainsSession,
1052 Self::SessionHasExecutor => MeerkatMachineInputVariant::SessionHasExecutor,
1053 Self::SessionHasComms => MeerkatMachineInputVariant::SessionHasComms,
1054 Self::OpsLifecycleRegistry => MeerkatMachineInputVariant::OpsLifecycleRegistry,
1055 Self::PrepareBindings => MeerkatMachineInputVariant::PrepareBindings,
1056 Self::InputState => MeerkatMachineInputVariant::InputState,
1057 Self::ListActiveInputs => MeerkatMachineInputVariant::ListActiveInputs,
1058 Self::ReconfigureSessionLlmIdentity => {
1059 MeerkatMachineInputVariant::ReconfigureSessionLlmIdentity
1060 }
1061 Self::StagePersistentFilter => MeerkatMachineInputVariant::StagePersistentFilter,
1062 Self::RequestDeferredTools => MeerkatMachineInputVariant::RequestDeferredTools,
1063 Self::PublishCommittedVisibleSet => {
1064 MeerkatMachineInputVariant::PublishCommittedVisibleSet
1065 }
1066 Self::SetPeerIngressContext => MeerkatMachineInputVariant::SetPeerIngressContext,
1067 Self::NotifyDrainExited => MeerkatMachineInputVariant::NotifyDrainExited,
1068 Self::AbortAll => MeerkatMachineInputVariant::AbortAll,
1069 Self::Abort => MeerkatMachineInputVariant::Abort,
1070 Self::Wait => MeerkatMachineInputVariant::Wait,
1071 Self::Ingest => MeerkatMachineInputVariant::Ingest,
1072 Self::PublishEvent => MeerkatMachineInputVariant::PublishEvent,
1073 Self::Retire => MeerkatMachineInputVariant::Retire,
1074 Self::Recycle => MeerkatMachineInputVariant::Recycle,
1075 Self::Reset => MeerkatMachineInputVariant::Reset,
1076 Self::Recover => MeerkatMachineInputVariant::Recover,
1077 Self::Destroy => MeerkatMachineInputVariant::Destroy,
1078 Self::RuntimeState => MeerkatMachineInputVariant::RuntimeState,
1079 Self::ModelRoutingStatus => MeerkatMachineInputVariant::ModelRoutingStatus,
1080 Self::SetModelRoutingBaseline => MeerkatMachineInputVariant::SetModelRoutingBaseline,
1081 Self::RequestFiniteSwitchTurn => MeerkatMachineInputVariant::RequestFiniteSwitchTurn,
1082 Self::RequestUntilChangedSwitchTurn => {
1083 MeerkatMachineInputVariant::RequestUntilChangedSwitchTurn
1084 }
1085 Self::AdmitModelRoutingAssistantTurn => {
1086 MeerkatMachineInputVariant::AdmitModelRoutingAssistantTurn
1087 }
1088 Self::BeginImageOperation => MeerkatMachineInputVariant::BeginImageOperation,
1089 Self::ActivateImageOperationOverride => {
1090 MeerkatMachineInputVariant::ActivateImageOperationOverride
1091 }
1092 Self::CompleteImageOperation => MeerkatMachineInputVariant::CompleteImageOperation,
1093 Self::RestoreImageOperationOverride => {
1094 MeerkatMachineInputVariant::RestoreImageOperationOverride
1095 }
1096 Self::LoadBoundaryReceipt => MeerkatMachineInputVariant::LoadBoundaryReceipt,
1097 Self::AcceptWithCompletion => MeerkatMachineInputVariant::AcceptWithCompletion,
1098 Self::AcceptWithoutWake => MeerkatMachineInputVariant::AcceptWithoutWake,
1099 Self::Prepare => MeerkatMachineInputVariant::Prepare,
1100 Self::Commit => MeerkatMachineInputVariant::Commit,
1101 Self::Fail => MeerkatMachineInputVariant::Fail,
1102 }
1103 }
1104
1105 #[must_use]
1106 pub const fn as_str(self) -> &'static str {
1107 match self {
1108 Self::RegisterSession => "RegisterSession",
1109 Self::UnregisterSession => "UnregisterSession",
1110 Self::EnsureSessionWithExecutor => "EnsureSessionWithExecutor",
1111 Self::SetSilentIntents => "SetSilentIntents",
1112 Self::CancelAfterBoundary => "CancelAfterBoundary",
1113 Self::StopRuntimeExecutor => "StopRuntimeExecutor",
1114 Self::ServiceTurnCommitted => "ServiceTurnCommitted",
1115 Self::ContainsSession => "ContainsSession",
1116 Self::SessionHasExecutor => "SessionHasExecutor",
1117 Self::SessionHasComms => "SessionHasComms",
1118 Self::OpsLifecycleRegistry => "OpsLifecycleRegistry",
1119 Self::PrepareBindings => "PrepareBindings",
1120 Self::InputState => "InputState",
1121 Self::ListActiveInputs => "ListActiveInputs",
1122 Self::ReconfigureSessionLlmIdentity => "ReconfigureSessionLlmIdentity",
1123 Self::StagePersistentFilter => "StagePersistentFilter",
1124 Self::RequestDeferredTools => "RequestDeferredTools",
1125 Self::PublishCommittedVisibleSet => "PublishCommittedVisibleSet",
1126 Self::SetPeerIngressContext => "SetPeerIngressContext",
1127 Self::NotifyDrainExited => "NotifyDrainExited",
1128 Self::AbortAll => "AbortAll",
1129 Self::Abort => "Abort",
1130 Self::Wait => "Wait",
1131 Self::Ingest => "Ingest",
1132 Self::PublishEvent => "PublishEvent",
1133 Self::Retire => "Retire",
1134 Self::Recycle => "Recycle",
1135 Self::Reset => "Reset",
1136 Self::Recover => "Recover",
1137 Self::Destroy => "Destroy",
1138 Self::RuntimeState => "RuntimeState",
1139 Self::ModelRoutingStatus => "ModelRoutingStatus",
1140 Self::SetModelRoutingBaseline => "SetModelRoutingBaseline",
1141 Self::RequestFiniteSwitchTurn => "RequestFiniteSwitchTurn",
1142 Self::RequestUntilChangedSwitchTurn => "RequestUntilChangedSwitchTurn",
1143 Self::AdmitModelRoutingAssistantTurn => "AdmitModelRoutingAssistantTurn",
1144 Self::BeginImageOperation => "BeginImageOperation",
1145 Self::ActivateImageOperationOverride => "ActivateImageOperationOverride",
1146 Self::CompleteImageOperation => "CompleteImageOperation",
1147 Self::RestoreImageOperationOverride => "RestoreImageOperationOverride",
1148 Self::LoadBoundaryReceipt => "LoadBoundaryReceipt",
1149 Self::AcceptWithCompletion => "AcceptWithCompletion",
1150 Self::AcceptWithoutWake => "AcceptWithoutWake",
1151 Self::Prepare => "Prepare",
1152 Self::Commit => "Commit",
1153 Self::Fail => "Fail",
1154 }
1155 }
1156}
1157
1158impl MeerkatMachineCommandVariant {
1159 #[must_use]
1160 pub const fn catalog_input(self) -> Option<MeerkatMachineCatalogInput> {
1161 match self {
1162 Self::ConfigureModelRoutingBaseline
1163 | Self::RequestSwitchTurn
1164 | Self::ResolvedSessionLlmCapabilities
1165 | Self::SessionModelRoutingStatus
1166 | Self::PrepareLocalSessionBindings => None,
1167 Self::RegisterSession => Some(MeerkatMachineCatalogInput::RegisterSession),
1168 Self::UnregisterSession => Some(MeerkatMachineCatalogInput::UnregisterSession),
1169 Self::EnsureSessionWithExecutor => {
1170 Some(MeerkatMachineCatalogInput::EnsureSessionWithExecutor)
1171 }
1172 Self::SetSilentIntents => Some(MeerkatMachineCatalogInput::SetSilentIntents),
1173 Self::CancelAfterBoundary => Some(MeerkatMachineCatalogInput::CancelAfterBoundary),
1174 Self::StopRuntimeExecutor => Some(MeerkatMachineCatalogInput::StopRuntimeExecutor),
1175 Self::CommitServiceTurnTerminalReceipt => {
1176 Some(MeerkatMachineCatalogInput::ServiceTurnCommitted)
1177 }
1178 Self::ContainsSession => Some(MeerkatMachineCatalogInput::ContainsSession),
1179 Self::SessionHasExecutor => Some(MeerkatMachineCatalogInput::SessionHasExecutor),
1180 Self::SessionHasComms => Some(MeerkatMachineCatalogInput::SessionHasComms),
1181 Self::OpsLifecycleRegistry => Some(MeerkatMachineCatalogInput::OpsLifecycleRegistry),
1182 Self::PrepareBindings => Some(MeerkatMachineCatalogInput::PrepareBindings),
1183 Self::InputState => Some(MeerkatMachineCatalogInput::InputState),
1184 Self::ListActiveInputs => Some(MeerkatMachineCatalogInput::ListActiveInputs),
1185 Self::ReconfigureSessionLlmIdentity => {
1186 Some(MeerkatMachineCatalogInput::ReconfigureSessionLlmIdentity)
1187 }
1188 Self::StagePersistentFilter => Some(MeerkatMachineCatalogInput::StagePersistentFilter),
1189 Self::RequestDeferredTools => Some(MeerkatMachineCatalogInput::RequestDeferredTools),
1190 Self::PublishCommittedVisibleSet => {
1191 Some(MeerkatMachineCatalogInput::PublishCommittedVisibleSet)
1192 }
1193 Self::SetPeerIngressContext => Some(MeerkatMachineCatalogInput::SetPeerIngressContext),
1194 Self::NotifyDrainExited => Some(MeerkatMachineCatalogInput::NotifyDrainExited),
1195 Self::AbortAll => Some(MeerkatMachineCatalogInput::AbortAll),
1196 Self::Abort => Some(MeerkatMachineCatalogInput::Abort),
1197 Self::Wait => Some(MeerkatMachineCatalogInput::Wait),
1198 Self::Ingest => Some(MeerkatMachineCatalogInput::Ingest),
1199 Self::PublishEvent => Some(MeerkatMachineCatalogInput::PublishEvent),
1200 Self::Retire => Some(MeerkatMachineCatalogInput::Retire),
1201 Self::Recycle => Some(MeerkatMachineCatalogInput::Recycle),
1202 Self::Reset => Some(MeerkatMachineCatalogInput::Reset),
1203 Self::Recover => Some(MeerkatMachineCatalogInput::Recover),
1204 Self::Destroy => Some(MeerkatMachineCatalogInput::Destroy),
1205 Self::RuntimeState => Some(MeerkatMachineCatalogInput::RuntimeState),
1206 Self::AdmitModelRoutingAssistantTurn => {
1207 Some(MeerkatMachineCatalogInput::AdmitModelRoutingAssistantTurn)
1208 }
1209 Self::BeginImageOperation => Some(MeerkatMachineCatalogInput::BeginImageOperation),
1210 Self::ActivateImageOperationOverride => {
1211 Some(MeerkatMachineCatalogInput::ActivateImageOperationOverride)
1212 }
1213 Self::CompleteImageOperation => {
1214 Some(MeerkatMachineCatalogInput::CompleteImageOperation)
1215 }
1216 Self::RestoreImageOperationOverride => {
1217 Some(MeerkatMachineCatalogInput::RestoreImageOperationOverride)
1218 }
1219 Self::LoadBoundaryReceipt => Some(MeerkatMachineCatalogInput::LoadBoundaryReceipt),
1220 Self::AcceptWithCompletion => Some(MeerkatMachineCatalogInput::AcceptWithCompletion),
1221 Self::AcceptWithoutWake => Some(MeerkatMachineCatalogInput::AcceptWithoutWake),
1222 Self::Prepare => Some(MeerkatMachineCatalogInput::Prepare),
1223 Self::Commit => Some(MeerkatMachineCatalogInput::Commit),
1224 Self::Fail => Some(MeerkatMachineCatalogInput::Fail),
1225 }
1226 }
1227}
1228
1229#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1230pub enum MeerkatMachineShellMechanicReason {
1231 ModelRoutingShellConfiguration,
1232 TurnControlOverlayRequest,
1233 RealtimeTransportObservation,
1234 SessionModelRoutingObservation,
1235 LocalSessionBindingBootstrap,
1236}
1237
1238#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1239pub struct MeerkatMachineCommandClassificationRecord {
1240 pub command: MeerkatMachineCommandVariant,
1241 pub classification: MeerkatMachineCommandClassification,
1242}
1243
1244#[doc(hidden)]
1245#[must_use]
1246pub fn canonical_meerkat_machine_command_classifications()
1247-> Vec<MeerkatMachineCommandClassificationRecord> {
1248 MeerkatMachineCommand::command_variant_manifest()
1249 .iter()
1250 .copied()
1251 .map(|variant| MeerkatMachineCommandClassificationRecord {
1252 command: variant,
1253 classification: meerkat_machine_command_classification(variant),
1254 })
1255 .collect()
1256}
1257
1258const fn meerkat_machine_command_classification(
1259 variant: MeerkatMachineCommandVariant,
1260) -> MeerkatMachineCommandClassification {
1261 match variant {
1262 MeerkatMachineCommandVariant::ConfigureModelRoutingBaseline => {
1263 MeerkatMachineCommandClassification::CatalogInput(
1264 MeerkatMachineCatalogInput::SetModelRoutingBaseline,
1265 )
1266 }
1267 MeerkatMachineCommandVariant::RequestSwitchTurn => {
1268 MeerkatMachineCommandClassification::CatalogInputs(&[
1269 MeerkatMachineCatalogInput::RequestFiniteSwitchTurn,
1270 MeerkatMachineCatalogInput::RequestUntilChangedSwitchTurn,
1271 ])
1272 }
1273 MeerkatMachineCommandVariant::ResolvedSessionLlmCapabilities => {
1274 MeerkatMachineCommandClassification::ShellMechanic(
1275 MeerkatMachineShellMechanicReason::SessionModelRoutingObservation,
1276 )
1277 }
1278 MeerkatMachineCommandVariant::SessionModelRoutingStatus => {
1279 MeerkatMachineCommandClassification::CatalogInput(
1280 MeerkatMachineCatalogInput::ModelRoutingStatus,
1281 )
1282 }
1283 MeerkatMachineCommandVariant::PrepareLocalSessionBindings => {
1284 MeerkatMachineCommandClassification::ShellMechanic(
1285 MeerkatMachineShellMechanicReason::LocalSessionBindingBootstrap,
1286 )
1287 }
1288 MeerkatMachineCommandVariant::RegisterSession => {
1289 MeerkatMachineCommandClassification::CatalogInput(
1290 MeerkatMachineCatalogInput::RegisterSession,
1291 )
1292 }
1293 MeerkatMachineCommandVariant::UnregisterSession => {
1294 MeerkatMachineCommandClassification::CatalogInput(
1295 MeerkatMachineCatalogInput::UnregisterSession,
1296 )
1297 }
1298 MeerkatMachineCommandVariant::EnsureSessionWithExecutor => {
1299 MeerkatMachineCommandClassification::CatalogInput(
1300 MeerkatMachineCatalogInput::EnsureSessionWithExecutor,
1301 )
1302 }
1303 MeerkatMachineCommandVariant::SetSilentIntents => {
1304 MeerkatMachineCommandClassification::CatalogInput(
1305 MeerkatMachineCatalogInput::SetSilentIntents,
1306 )
1307 }
1308 MeerkatMachineCommandVariant::CancelAfterBoundary => {
1309 MeerkatMachineCommandClassification::CatalogInput(
1310 MeerkatMachineCatalogInput::CancelAfterBoundary,
1311 )
1312 }
1313 MeerkatMachineCommandVariant::StopRuntimeExecutor => {
1314 MeerkatMachineCommandClassification::CatalogInput(
1315 MeerkatMachineCatalogInput::StopRuntimeExecutor,
1316 )
1317 }
1318 MeerkatMachineCommandVariant::CommitServiceTurnTerminalReceipt => {
1319 MeerkatMachineCommandClassification::CatalogInput(
1320 MeerkatMachineCatalogInput::ServiceTurnCommitted,
1321 )
1322 }
1323 MeerkatMachineCommandVariant::ContainsSession => {
1324 MeerkatMachineCommandClassification::CatalogInput(
1325 MeerkatMachineCatalogInput::ContainsSession,
1326 )
1327 }
1328 MeerkatMachineCommandVariant::SessionHasExecutor => {
1329 MeerkatMachineCommandClassification::CatalogInput(
1330 MeerkatMachineCatalogInput::SessionHasExecutor,
1331 )
1332 }
1333 MeerkatMachineCommandVariant::SessionHasComms => {
1334 MeerkatMachineCommandClassification::CatalogInput(
1335 MeerkatMachineCatalogInput::SessionHasComms,
1336 )
1337 }
1338 MeerkatMachineCommandVariant::OpsLifecycleRegistry => {
1339 MeerkatMachineCommandClassification::CatalogInput(
1340 MeerkatMachineCatalogInput::OpsLifecycleRegistry,
1341 )
1342 }
1343 MeerkatMachineCommandVariant::PrepareBindings => {
1344 MeerkatMachineCommandClassification::CatalogInput(
1345 MeerkatMachineCatalogInput::PrepareBindings,
1346 )
1347 }
1348 MeerkatMachineCommandVariant::InputState => {
1349 MeerkatMachineCommandClassification::CatalogInput(
1350 MeerkatMachineCatalogInput::InputState,
1351 )
1352 }
1353 MeerkatMachineCommandVariant::ListActiveInputs => {
1354 MeerkatMachineCommandClassification::CatalogInput(
1355 MeerkatMachineCatalogInput::ListActiveInputs,
1356 )
1357 }
1358 MeerkatMachineCommandVariant::ReconfigureSessionLlmIdentity => {
1359 MeerkatMachineCommandClassification::CatalogInput(
1360 MeerkatMachineCatalogInput::ReconfigureSessionLlmIdentity,
1361 )
1362 }
1363 MeerkatMachineCommandVariant::StagePersistentFilter => {
1364 MeerkatMachineCommandClassification::CatalogInput(
1365 MeerkatMachineCatalogInput::StagePersistentFilter,
1366 )
1367 }
1368 MeerkatMachineCommandVariant::RequestDeferredTools => {
1369 MeerkatMachineCommandClassification::CatalogInput(
1370 MeerkatMachineCatalogInput::RequestDeferredTools,
1371 )
1372 }
1373 MeerkatMachineCommandVariant::PublishCommittedVisibleSet => {
1374 MeerkatMachineCommandClassification::CatalogInput(
1375 MeerkatMachineCatalogInput::PublishCommittedVisibleSet,
1376 )
1377 }
1378 MeerkatMachineCommandVariant::SetPeerIngressContext => {
1379 MeerkatMachineCommandClassification::CatalogInput(
1380 MeerkatMachineCatalogInput::SetPeerIngressContext,
1381 )
1382 }
1383 MeerkatMachineCommandVariant::NotifyDrainExited => {
1384 MeerkatMachineCommandClassification::CatalogInput(
1385 MeerkatMachineCatalogInput::NotifyDrainExited,
1386 )
1387 }
1388 MeerkatMachineCommandVariant::AbortAll => {
1389 MeerkatMachineCommandClassification::CatalogInput(MeerkatMachineCatalogInput::AbortAll)
1390 }
1391 MeerkatMachineCommandVariant::Abort => {
1392 MeerkatMachineCommandClassification::CatalogInput(MeerkatMachineCatalogInput::Abort)
1393 }
1394 MeerkatMachineCommandVariant::Wait => {
1395 MeerkatMachineCommandClassification::CatalogInput(MeerkatMachineCatalogInput::Wait)
1396 }
1397 MeerkatMachineCommandVariant::Ingest => {
1398 MeerkatMachineCommandClassification::CatalogInput(MeerkatMachineCatalogInput::Ingest)
1399 }
1400 MeerkatMachineCommandVariant::PublishEvent => {
1401 MeerkatMachineCommandClassification::CatalogInput(
1402 MeerkatMachineCatalogInput::PublishEvent,
1403 )
1404 }
1405 MeerkatMachineCommandVariant::Retire => {
1406 MeerkatMachineCommandClassification::CatalogInput(MeerkatMachineCatalogInput::Retire)
1407 }
1408 MeerkatMachineCommandVariant::Recycle => {
1409 MeerkatMachineCommandClassification::CatalogInput(MeerkatMachineCatalogInput::Recycle)
1410 }
1411 MeerkatMachineCommandVariant::Reset => {
1412 MeerkatMachineCommandClassification::CatalogInput(MeerkatMachineCatalogInput::Reset)
1413 }
1414 MeerkatMachineCommandVariant::Recover => {
1415 MeerkatMachineCommandClassification::CatalogInput(MeerkatMachineCatalogInput::Recover)
1416 }
1417 MeerkatMachineCommandVariant::Destroy => {
1418 MeerkatMachineCommandClassification::CatalogInput(MeerkatMachineCatalogInput::Destroy)
1419 }
1420 MeerkatMachineCommandVariant::RuntimeState => {
1421 MeerkatMachineCommandClassification::CatalogInput(
1422 MeerkatMachineCatalogInput::RuntimeState,
1423 )
1424 }
1425 MeerkatMachineCommandVariant::AdmitModelRoutingAssistantTurn => {
1426 MeerkatMachineCommandClassification::CatalogInput(
1427 MeerkatMachineCatalogInput::AdmitModelRoutingAssistantTurn,
1428 )
1429 }
1430 MeerkatMachineCommandVariant::BeginImageOperation => {
1431 MeerkatMachineCommandClassification::CatalogInput(
1432 MeerkatMachineCatalogInput::BeginImageOperation,
1433 )
1434 }
1435 MeerkatMachineCommandVariant::ActivateImageOperationOverride => {
1436 MeerkatMachineCommandClassification::CatalogInput(
1437 MeerkatMachineCatalogInput::ActivateImageOperationOverride,
1438 )
1439 }
1440 MeerkatMachineCommandVariant::CompleteImageOperation => {
1441 MeerkatMachineCommandClassification::CatalogInput(
1442 MeerkatMachineCatalogInput::CompleteImageOperation,
1443 )
1444 }
1445 MeerkatMachineCommandVariant::RestoreImageOperationOverride => {
1446 MeerkatMachineCommandClassification::CatalogInput(
1447 MeerkatMachineCatalogInput::RestoreImageOperationOverride,
1448 )
1449 }
1450 MeerkatMachineCommandVariant::LoadBoundaryReceipt => {
1451 MeerkatMachineCommandClassification::CatalogInput(
1452 MeerkatMachineCatalogInput::LoadBoundaryReceipt,
1453 )
1454 }
1455 MeerkatMachineCommandVariant::AcceptWithCompletion => {
1456 MeerkatMachineCommandClassification::CatalogInput(
1457 MeerkatMachineCatalogInput::AcceptWithCompletion,
1458 )
1459 }
1460 MeerkatMachineCommandVariant::AcceptWithoutWake => {
1461 MeerkatMachineCommandClassification::CatalogInput(
1462 MeerkatMachineCatalogInput::AcceptWithoutWake,
1463 )
1464 }
1465 MeerkatMachineCommandVariant::Prepare => {
1466 MeerkatMachineCommandClassification::CatalogInput(MeerkatMachineCatalogInput::Prepare)
1467 }
1468 MeerkatMachineCommandVariant::Commit => {
1469 MeerkatMachineCommandClassification::CatalogInput(MeerkatMachineCatalogInput::Commit)
1470 }
1471 MeerkatMachineCommandVariant::Fail => {
1472 MeerkatMachineCommandClassification::CatalogInput(MeerkatMachineCatalogInput::Fail)
1473 }
1474 }
1475}
1476
1477#[derive(Debug, Clone, PartialEq, Eq)]
1481pub struct MeerkatCompletionWaiterSnapshot {
1482 pub input_id: InputId,
1483 pub waiter_count: usize,
1484}
1485
1486#[derive(Debug, Clone, PartialEq, Eq)]
1491pub struct MeerkatCompletionWaitersSnapshot {
1492 pub input_count: usize,
1493 pub waiter_count: usize,
1494 pub waiting_inputs: Vec<MeerkatCompletionWaiterSnapshot>,
1495}
1496
1497#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1499pub enum MeerkatDriverKind {
1500 Ephemeral,
1501 Persistent,
1502}
1503
1504#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1506pub struct MeerkatCursorSnapshot {
1507 pub agent_applied_cursor: u64,
1508 pub runtime_observed_seq: u64,
1509 pub runtime_last_injected_seq: u64,
1510}
1511
1512#[derive(Debug, Clone)]
1514pub struct MeerkatBindingSnapshot {
1515 pub session_id: SessionId,
1516 pub runtime_id: LogicalRuntimeId,
1517 pub driver_kind: MeerkatDriverKind,
1518 pub driver_present: bool,
1519 pub completions_present: bool,
1520 pub ops_registry_present: bool,
1521 pub attachment_live: bool,
1522 pub epoch_id: RuntimeEpochId,
1523 pub cursor_state: MeerkatCursorSnapshot,
1524}
1525
1526#[derive(Debug, Clone)]
1528pub struct MeerkatControlSnapshot {
1529 pub phase: RuntimeState,
1530 pub current_run_id: Option<RunId>,
1531 pub pre_run_phase: Option<RuntimeState>,
1532}
1533
1534#[derive(Debug, Clone)]
1536pub struct MeerkatAdmittedInputSnapshot {
1537 pub input_id: InputId,
1538 pub content_shape: Option<ContentShape>,
1539 pub request_id: Option<RequestId>,
1540 pub reservation_key: Option<ReservationKey>,
1541 pub handling_mode: Option<HandlingMode>,
1542 pub lifecycle: Option<InputLifecycleState>,
1543 pub terminal_outcome: Option<InputTerminalOutcome>,
1544 pub last_run_id: Option<RunId>,
1545 pub last_boundary_sequence: Option<u64>,
1546 pub is_prompt: bool,
1547}
1548
1549#[derive(Debug, Clone)]
1551pub struct MeerkatInputsSnapshot {
1552 pub admission_order: Vec<MeerkatAdmittedInputSnapshot>,
1553 pub queue: Vec<InputId>,
1554 pub steer_queue: Vec<InputId>,
1555 pub current_run_id: Option<RunId>,
1556 pub current_run_contributors: Vec<InputId>,
1557 pub post_admission_signal: String,
1558 pub silent_intent_overrides: Vec<String>,
1559}
1560
1561#[derive(Debug, Clone)]
1567pub struct MeerkatLedgerSnapshot {
1568 pub input_count: usize,
1569 pub non_terminal_count: usize,
1570 pub accepted_count: usize,
1571 pub queued_count: usize,
1572 pub staged_count: usize,
1573 pub applied_count: usize,
1574 pub applied_pending_consumption_count: usize,
1575 pub consumed_count: usize,
1576 pub superseded_count: usize,
1577 pub coalesced_count: usize,
1578 pub abandoned_count: usize,
1579}
1580
1581#[derive(Debug, Clone)]
1583pub struct MeerkatOpsSnapshot {
1584 pub operation_count: usize,
1585 pub active_count: usize,
1586 pub wait_request_id: Option<WaitRequestId>,
1587 pub pending_wait_present: bool,
1588 pub pending_wait_request_id: Option<WaitRequestId>,
1589 pub wait_operation_ids: Vec<OperationId>,
1590 pub operations: Vec<OperationLifecycleSnapshot>,
1591}
1592
1593#[derive(Debug, Clone)]
1595pub struct MeerkatDrainSnapshot {
1596 pub slot_present: bool,
1597 pub phase: Option<CommsDrainPhase>,
1598 pub mode: Option<CommsDrainMode>,
1599 pub handle_present: bool,
1600}
1601
1602#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
1609pub struct MeerkatFormalStateProjection {
1610 pub available_fields: BTreeMap<String, String>,
1612 pub unavailable_fields: Vec<String>,
1614}
1615
1616#[derive(Debug, Clone)]
1621pub struct MeerkatMachineSpineSnapshot {
1622 pub binding: MeerkatBindingSnapshot,
1623 pub control: MeerkatControlSnapshot,
1624 pub inputs: MeerkatInputsSnapshot,
1625 pub ledger: MeerkatLedgerSnapshot,
1626 pub completion_waiters: MeerkatCompletionWaitersSnapshot,
1627 pub ops: MeerkatOpsSnapshot,
1628 pub drain: MeerkatDrainSnapshot,
1629 pub formal_state: MeerkatFormalStateProjection,
1630}
1631
1632impl MeerkatMachineSpineSnapshot {
1633 pub fn validate_spine_invariants(&self) -> Result<(), Vec<String>> {
1639 let mut violations = Vec::new();
1640
1641 if self.control.phase == RuntimeState::Running && self.control.current_run_id.is_none() {
1645 violations
1646 .push("RunningHasActiveRunInvariant: phase is Running but no active run_id".into());
1647 }
1648
1649 if self.control.current_run_id.is_some()
1651 && !matches!(
1652 self.control.phase,
1653 RuntimeState::Running | RuntimeState::Retired
1654 )
1655 {
1656 violations.push(format!(
1657 "ActiveRunPhaseInvariant: active run_id present but phase is {:?}",
1658 self.control.phase
1659 ));
1660 }
1661
1662 if self.control.phase == RuntimeState::Destroyed {
1664 if !self.inputs.queue.is_empty() {
1665 violations.push("DestroyedShapeInvariant: Destroyed but queue is non-empty".into());
1666 }
1667 if !self.inputs.steer_queue.is_empty() {
1668 violations
1669 .push("DestroyedShapeInvariant: Destroyed but steer_queue is non-empty".into());
1670 }
1671 if self.completion_waiters.input_count > 0 {
1672 violations.push(
1673 "DestroyedShapeInvariant: Destroyed but completion waiters remain".into(),
1674 );
1675 }
1676 }
1677
1678 let queue_set: std::collections::HashSet<_> = self.inputs.queue.iter().collect();
1682 let steer_set: std::collections::HashSet<_> = self.inputs.steer_queue.iter().collect();
1683 if !queue_set.is_disjoint(&steer_set) {
1684 violations
1685 .push("QueueSteerDisjointInvariant: queue and steer_queue share entries".into());
1686 }
1687
1688 for qid in &self.inputs.queue {
1690 if let Some(snap) = self
1691 .inputs
1692 .admission_order
1693 .iter()
1694 .find(|a| &a.input_id == qid)
1695 {
1696 if snap.handling_mode != Some(HandlingMode::Queue) {
1697 violations.push(format!(
1698 "QueueHandlingInvariant: queue entry {qid} has handling_mode {:?}",
1699 snap.handling_mode
1700 ));
1701 }
1702 if snap.lifecycle != Some(InputLifecycleState::Queued) {
1703 violations.push(format!(
1704 "QueueHandlingInvariant: queue entry {qid} has lifecycle {:?}",
1705 snap.lifecycle
1706 ));
1707 }
1708 }
1709 }
1710
1711 for sid in &self.inputs.steer_queue {
1713 if let Some(snap) = self
1714 .inputs
1715 .admission_order
1716 .iter()
1717 .find(|a| &a.input_id == sid)
1718 {
1719 if snap.handling_mode != Some(HandlingMode::Steer) {
1720 violations.push(format!(
1721 "SteerHandlingInvariant: steer_queue entry {sid} has handling_mode {:?}",
1722 snap.handling_mode
1723 ));
1724 }
1725 if snap.lifecycle != Some(InputLifecycleState::Queued) {
1726 violations.push(format!(
1727 "SteerHandlingInvariant: steer_queue entry {sid} has lifecycle {:?}",
1728 snap.lifecycle
1729 ));
1730 }
1731 }
1732 }
1733
1734 for cid in &self.inputs.current_run_contributors {
1737 if let Some(snap) = self
1738 .inputs
1739 .admission_order
1740 .iter()
1741 .find(|a| &a.input_id == cid)
1742 && !matches!(
1743 snap.lifecycle,
1744 Some(
1745 InputLifecycleState::Staged
1746 | InputLifecycleState::Applied
1747 | InputLifecycleState::AppliedPendingConsumption
1748 )
1749 )
1750 {
1751 violations.push(format!(
1752 "ContributorLifecycleInvariant: contributor {cid} has lifecycle {:?}",
1753 snap.lifecycle
1754 ));
1755 }
1756 }
1757
1758 for snap in &self.inputs.admission_order {
1760 if snap.terminal_outcome.is_some() {
1761 if queue_set.contains(&snap.input_id) {
1762 violations.push(format!(
1763 "TerminalInputsNotQueuedInvariant: terminal input {} in queue",
1764 snap.input_id
1765 ));
1766 }
1767 if steer_set.contains(&snap.input_id) {
1768 violations.push(format!(
1769 "TerminalInputsNotQueuedInvariant: terminal input {} in steer_queue",
1770 snap.input_id
1771 ));
1772 }
1773 }
1774 }
1775
1776 if self.control.current_run_id.is_some() && self.inputs.current_run_contributors.is_empty()
1778 {
1779 violations
1780 .push("CurrentRunContributorsInvariant: active run but no contributors".into());
1781 }
1782
1783 if let Some(control_run_id) = &self.control.current_run_id {
1787 for cid in &self.inputs.current_run_contributors {
1788 if let Some(snap) = self
1789 .inputs
1790 .admission_order
1791 .iter()
1792 .find(|a| &a.input_id == cid)
1793 && snap.last_run_id.as_ref() != Some(control_run_id)
1794 {
1795 violations.push(format!(
1796 "ContributorRunIdentityInvariant: contributor {cid} has last_run_id {:?}, expected {:?}",
1797 snap.last_run_id, control_run_id
1798 ));
1799 }
1800 }
1801 }
1802
1803 let wait_active = self.ops.wait_request_id.is_some();
1807 if wait_active && self.ops.wait_operation_ids.is_empty() {
1808 violations
1809 .push("WaitAllAlignmentInvariant: wait_active but no wait_operation_ids".into());
1810 }
1811 if !wait_active && !self.ops.wait_operation_ids.is_empty() {
1812 violations.push(
1813 "WaitAllAlignmentInvariant: wait_operation_ids present but no wait_request_id"
1814 .into(),
1815 );
1816 }
1817
1818 if let Some(phase) = self.drain.phase {
1822 if phase != CommsDrainPhase::Inactive && !self.binding.attachment_live {
1823 }
1827 let _ = phase; }
1829
1830 if let Some(phase) = self.drain.phase
1832 && phase != CommsDrainPhase::Inactive
1833 && self.drain.mode.is_none()
1834 {
1835 violations.push("DrainModeInvariant: drain.phase is active but mode is None".into());
1836 }
1837
1838 if violations.is_empty() {
1839 Ok(())
1840 } else {
1841 Err(violations)
1842 }
1843 }
1844}