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