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