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