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 PrepareTerminalSupervisorCleanupBindings,
815 RecoverRevokedSupervisorReceipt,
816 RecoverSupervisorBinding,
817 RecoverSupervisorRevocationPending,
818 RecoverSupervisorRotationOperation,
819 RecoverSupervisorRotationTerminalReceipt,
820 RefreshSupervisorBindingRoute,
821 RequestSupervisorTrustPublish,
822 ResolveSupervisorCleanupCommandAdmission,
823 ResumeSupervisorRotation,
824 RevokeSupervisor,
825 SubmitSupervisorRotation,
826 SupervisorRotationNextPublished,
827 SupervisorRotationPreviousRevoked,
828 SupervisorTrustEdgePublishFailed,
829 SupervisorTrustEdgePublished,
830 SupervisorTrustEdgeRevokeFailed,
831 SupervisorTrustEdgeRevoked,
832 ObserveSupervisorRotation,
833 ],
834 MobOperatorAuthorityLifecycle => [
835 GrantMobOperatorManageMob,
836 ResolveMobOperatorCreateAuthority,
837 RestoreMobOperatorAuthority,
838 SetMobOperatorCreateAuthority,
839 SetMobOperatorProfileMutation,
840 SetMobOperatorSpawnProfilesInMob,
841 ],
842 PeerRequestLifecycle => [
843 PeerRequestReceived,
844 PeerRequestSendFailed,
845 PeerRequestSent,
846 PeerRequestTimedOut,
847 PeerResponseProgressArrived,
848 PeerResponseReplied,
849 PeerResponseTerminalArrived,
850 ],
851 VisibilityAuthorityLifecycle => [
852 CommitDeferredNames,
853 CommitVisibilityFilter,
854 ClearTurnToolOverlay,
855 ReplaceDeferredToolAuthorityCatalog,
856 ReplaceFilterToolAuthorityCatalog,
857 SetTurnToolOverlay,
858 StageDeferredNames,
859 StageVisibilityFilter,
860 SurfaceSetRemovalTimeout,
861 ReplaceVisibilityState,
862 ],
863 DeferredSessionLifecycle => [
864 AbandonDeferredSessionPromotion,
865 AuthorizeDeferredSessionMachineArchivedResume,
866 AuthorizeDeferredSessionSystemContextAppend,
867 BeginDeferredSessionArchive,
868 BeginDeferredSessionPromotion,
869 DropDeferredSession,
870 FinishDeferredSessionArchive,
871 FinishDeferredSessionPromotion,
872 RestoreDeferredSessionArchive,
873 StageDeferredSession,
874 UpdateDeferredSessionKeepAlive,
875 UpdateDeferredSessionLlmIdentity,
876 ],
877 ExtractionLifecycle => [
878 EnterExtraction,
879 ExtractionFailed,
880 ExtractionStart,
881 ExtractionValidationFailed,
882 ExtractionValidationPassed,
883 ],
884 McpServerLifecycle => [
885 McpServerConnectPending,
886 McpServerConnected,
887 McpServerDisconnected,
888 McpServerFailed,
889 McpServerReload,
890 ],
891 ModelRoutingLifecycle => [
892 CommitStickyModelFallback,
893 ModelRoutingStatus,
894 RequestFiniteSwitchTurn,
895 RequestUntilChangedSwitchTurn,
896 SetModelRoutingBaseline,
897 ],
898 ExternalSurfaceLifecycle => [
899 AdmitSurfaceRequest,
900 CancelSurfaceRequest,
901 ClassifySurfaceRequestTerminal,
902 FinishSurfaceRequestUnpublished,
903 PublishOrCancelSurfaceRequest,
904 PublishSurfaceRequest,
905 RecordLiveWebrtcAnswerAccepted,
906 RecordLiveWebrtcTokenIssued,
907 RecordLiveWebsocketTokenIssued,
908 ResolveLiveWebrtcAnswerAdmission,
909 ResolveLiveWebsocketTokenAdmission,
910 SurfaceApplyBoundary,
911 SurfaceCallFinished,
912 SurfaceCallStarted,
913 SurfaceFinalizeRemovalClean,
914 SurfaceFinalizeRemovalForced,
915 SurfaceMarkPendingFailed,
916 SurfaceMarkPendingSucceeded,
917 SurfaceRegister,
918 SurfaceShutdown,
919 SurfaceSnapshotAligned,
920 SurfaceStageAdd,
921 SurfaceStageReload,
922 SurfaceStageRemove,
923 ],
924 FailureRecoveryLifecycle => [
925 ClassifyLlmFailureRecovery,
926 ClassifyRuntimeLifecycleDurability,
927 ClassifyRuntimeLifecycleState,
928 FatalFailure,
929 RecoverableFailure,
930 RecoverRuntimeAuthority,
931 ResolveVisibleRuntimePhase,
932 ],
933 UserInterruptDispatch => [
934 InterruptCurrentRun,
935 ResolveUserInterruptPublicResult,
936 ],
937 SessionUnregisterDrainLifecycle => [
938 BeginUnregisterSession,
939 CommsDrainExitedForUnregister,
940 CompletionWaitersResolvedForUnregister,
941 RuntimeLoopStoppedForUnregister,
942 ],
943);
944
945macro_rules! meerkat_machine_fieldless_runtime_internal_inputs {
946 ($($authority:ident => [$($variant:ident),+ $(,)?]),+ $(,)?) => {
947 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
948 pub enum MeerkatMachineFieldlessRuntimeInternalInput {
949 $($($variant),+),+
950 }
951
952 impl MeerkatMachineFieldlessRuntimeInternalInput {
953 pub const ALL: &'static [Self] = &[
954 $($(Self::$variant),+),+
955 ];
956
957 #[must_use]
958 pub const fn runtime_internal_input(self) -> MeerkatMachineRuntimeInternalInput {
959 match self {
960 $($(Self::$variant => MeerkatMachineRuntimeInternalInput::$variant,)+)+
961 }
962 }
963
964 #[must_use]
965 pub const fn input_variant(self) -> MeerkatMachineInputVariant {
966 self.runtime_internal_input().input_variant()
967 }
968
969 #[must_use]
970 pub const fn authority(self) -> MeerkatMachineFieldlessRuntimeInternalAuthority {
971 match self {
972 $(
973 $(Self::$variant)|+ => MeerkatMachineFieldlessRuntimeInternalAuthority::$authority,
974 )+
975 }
976 }
977
978 #[must_use]
979 pub const fn requires_typed_runtime_internal_stager(self) -> bool {
980 matches!(
981 self.authority(),
982 MeerkatMachineFieldlessRuntimeInternalAuthority::UserInterruptDispatch
983 )
984 }
985
986 pub(crate) const fn dsl_input_variant(self) -> dsl::MeerkatMachineInputVariant {
987 match self {
988 $($(Self::$variant => dsl::MeerkatMachineInputVariant::$variant,)+)+
989 }
990 }
991
992 pub(crate) fn dsl_input(self) -> dsl::MeerkatMachineInput {
993 match self {
994 $($(Self::$variant => dsl::MeerkatMachineInput::$variant,)+)+
995 }
996 }
997
998 pub(crate) fn from_dsl_input_variant(
999 variant: dsl::MeerkatMachineInputVariant,
1000 ) -> Option<Self> {
1001 Self::ALL
1002 .iter()
1003 .copied()
1004 .find(|input| input.dsl_input_variant() == variant)
1005 }
1006
1007 pub(crate) fn reject_raw_dsl_input(
1008 input: &dsl::MeerkatMachineInput,
1009 ) -> Result<(), String> {
1010 if let Some(fieldless) = Self::from_dsl_input_variant(input.variant())
1011 && fieldless.requires_typed_runtime_internal_stager()
1012 {
1013 let variant = fieldless.input_variant();
1014 return Err(format!(
1015 "fieldless runtime-internal input {variant:?} must use typed runtime-internal staging authority"
1016 ));
1017 }
1018 Ok(())
1019 }
1020 }
1021 };
1022}
1023
1024meerkat_machine_fieldless_runtime_internal_inputs!(
1025 RuntimeOwner => [
1026 RuntimeExecutorExited,
1027 ForceCancelNoRun,
1028 CancelWaitAll,
1029 StopDrain,
1030 SurfaceShutdown,
1031 DetachIngress,
1032 ClearLocalEndpoint,
1033 ],
1034 UserInterruptDispatch => [
1035 InterruptCurrentRun,
1036 ],
1037);
1038
1039#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1040pub enum MeerkatMachineFieldlessRuntimeInternalAuthority {
1041 RuntimeOwner,
1042 UserInterruptDispatch,
1043}
1044
1045#[doc(hidden)]
1046#[must_use]
1047pub fn canonical_meerkat_machine_runtime_internal_classifications()
1048-> Vec<MeerkatMachineRuntimeInternalClassificationRecord> {
1049 MeerkatMachineRuntimeInternalInput::CLASSIFICATIONS.to_vec()
1050}
1051
1052#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1053pub enum MeerkatMachineCommandClassification {
1054 CatalogInput(MeerkatMachineCatalogInput),
1055 CatalogInputs(&'static [MeerkatMachineCatalogInput]),
1056 ShellMechanic(MeerkatMachineShellMechanicReason),
1057}
1058
1059impl MeerkatMachineCommandClassification {
1060 #[must_use]
1061 pub fn catalog_inputs(self) -> Vec<MeerkatMachineCatalogInput> {
1062 match self {
1063 Self::CatalogInput(input) => vec![input],
1064 Self::CatalogInputs(inputs) => inputs.to_vec(),
1065 Self::ShellMechanic(_) => Vec::new(),
1066 }
1067 }
1068
1069 #[must_use]
1070 pub fn catalog_input_variants(self) -> Vec<MeerkatMachineInputVariant> {
1071 self.catalog_inputs()
1072 .into_iter()
1073 .map(MeerkatMachineCatalogInput::input_variant)
1074 .collect()
1075 }
1076}
1077
1078#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1079pub enum MeerkatMachineCatalogInput {
1080 RegisterSession,
1081 UnregisterSession,
1082 EnsureSessionWithExecutor,
1083 SetSilentIntents,
1084 CancelAfterBoundary,
1085 StopRuntimeExecutor,
1086 ServiceTurnCommitted,
1087 ContainsSession,
1088 SessionHasExecutor,
1089 SessionHasComms,
1090 OpsLifecycleRegistry,
1091 PrepareBindings,
1092 InputState,
1093 ListActiveInputs,
1094 ReconfigureSessionLlmIdentity,
1095 StagePersistentFilter,
1096 RequestDeferredTools,
1097 PublishCommittedVisibleSet,
1098 SetPeerIngressContext,
1099 NotifyDrainExited,
1100 AbortAll,
1101 Abort,
1102 Wait,
1103 Ingest,
1104 PublishEvent,
1105 Retire,
1106 Recycle,
1107 Reset,
1108 Recover,
1109 Destroy,
1110 RuntimeState,
1111 ModelRoutingStatus,
1112 SetModelRoutingBaseline,
1113 RequestFiniteSwitchTurn,
1114 RequestUntilChangedSwitchTurn,
1115 AdmitModelRoutingAssistantTurn,
1116 BeginImageOperation,
1117 DenyImageOperationPlan,
1118 ActivateImageOperationOverride,
1119 ClassifyImageOperationTerminal,
1120 CompleteImageOperation,
1121 RestoreImageOperationOverride,
1122 LoadBoundaryReceipt,
1123 AcceptWithCompletion,
1124 AcceptWithoutWake,
1125}
1126
1127impl MeerkatMachineCatalogInput {
1128 pub const ALL: &'static [Self] = &[
1129 Self::RegisterSession,
1130 Self::UnregisterSession,
1131 Self::EnsureSessionWithExecutor,
1132 Self::SetSilentIntents,
1133 Self::CancelAfterBoundary,
1134 Self::StopRuntimeExecutor,
1135 Self::ServiceTurnCommitted,
1136 Self::ContainsSession,
1137 Self::SessionHasExecutor,
1138 Self::SessionHasComms,
1139 Self::OpsLifecycleRegistry,
1140 Self::PrepareBindings,
1141 Self::InputState,
1142 Self::ListActiveInputs,
1143 Self::ReconfigureSessionLlmIdentity,
1144 Self::StagePersistentFilter,
1145 Self::RequestDeferredTools,
1146 Self::PublishCommittedVisibleSet,
1147 Self::SetPeerIngressContext,
1148 Self::NotifyDrainExited,
1149 Self::AbortAll,
1150 Self::Abort,
1151 Self::Wait,
1152 Self::Ingest,
1153 Self::PublishEvent,
1154 Self::Retire,
1155 Self::Recycle,
1156 Self::Reset,
1157 Self::Recover,
1158 Self::Destroy,
1159 Self::RuntimeState,
1160 Self::ModelRoutingStatus,
1161 Self::SetModelRoutingBaseline,
1162 Self::RequestFiniteSwitchTurn,
1163 Self::RequestUntilChangedSwitchTurn,
1164 Self::AdmitModelRoutingAssistantTurn,
1165 Self::BeginImageOperation,
1166 Self::DenyImageOperationPlan,
1167 Self::ActivateImageOperationOverride,
1168 Self::ClassifyImageOperationTerminal,
1169 Self::CompleteImageOperation,
1170 Self::RestoreImageOperationOverride,
1171 Self::LoadBoundaryReceipt,
1172 Self::AcceptWithCompletion,
1173 Self::AcceptWithoutWake,
1174 ];
1175
1176 #[must_use]
1177 pub const fn input_variant(self) -> MeerkatMachineInputVariant {
1178 match self {
1179 Self::RegisterSession => MeerkatMachineInputVariant::RegisterSession,
1180 Self::UnregisterSession => MeerkatMachineInputVariant::UnregisterSession,
1181 Self::EnsureSessionWithExecutor => {
1182 MeerkatMachineInputVariant::EnsureSessionWithExecutor
1183 }
1184 Self::SetSilentIntents => MeerkatMachineInputVariant::SetSilentIntents,
1185 Self::CancelAfterBoundary => MeerkatMachineInputVariant::CancelAfterBoundary,
1186 Self::StopRuntimeExecutor => MeerkatMachineInputVariant::StopRuntimeExecutor,
1187 Self::ServiceTurnCommitted => MeerkatMachineInputVariant::ServiceTurnCommitted,
1188 Self::ContainsSession => MeerkatMachineInputVariant::ContainsSession,
1189 Self::SessionHasExecutor => MeerkatMachineInputVariant::SessionHasExecutor,
1190 Self::SessionHasComms => MeerkatMachineInputVariant::SessionHasComms,
1191 Self::OpsLifecycleRegistry => MeerkatMachineInputVariant::OpsLifecycleRegistry,
1192 Self::PrepareBindings => MeerkatMachineInputVariant::PrepareBindings,
1193 Self::InputState => MeerkatMachineInputVariant::InputState,
1194 Self::ListActiveInputs => MeerkatMachineInputVariant::ListActiveInputs,
1195 Self::ReconfigureSessionLlmIdentity => {
1196 MeerkatMachineInputVariant::ReconfigureSessionLlmIdentity
1197 }
1198 Self::StagePersistentFilter => MeerkatMachineInputVariant::StagePersistentFilter,
1199 Self::RequestDeferredTools => MeerkatMachineInputVariant::RequestDeferredTools,
1200 Self::PublishCommittedVisibleSet => {
1201 MeerkatMachineInputVariant::PublishCommittedVisibleSet
1202 }
1203 Self::SetPeerIngressContext => MeerkatMachineInputVariant::SetPeerIngressContext,
1204 Self::NotifyDrainExited => MeerkatMachineInputVariant::NotifyDrainExited,
1205 Self::AbortAll => MeerkatMachineInputVariant::AbortAll,
1206 Self::Abort => MeerkatMachineInputVariant::Abort,
1207 Self::Wait => MeerkatMachineInputVariant::Wait,
1208 Self::Ingest => MeerkatMachineInputVariant::Ingest,
1209 Self::PublishEvent => MeerkatMachineInputVariant::PublishEvent,
1210 Self::Retire => MeerkatMachineInputVariant::Retire,
1211 Self::Recycle => MeerkatMachineInputVariant::Recycle,
1212 Self::Reset => MeerkatMachineInputVariant::Reset,
1213 Self::Recover => MeerkatMachineInputVariant::Recover,
1214 Self::Destroy => MeerkatMachineInputVariant::Destroy,
1215 Self::RuntimeState => MeerkatMachineInputVariant::RuntimeState,
1216 Self::ModelRoutingStatus => MeerkatMachineInputVariant::ModelRoutingStatus,
1217 Self::SetModelRoutingBaseline => MeerkatMachineInputVariant::SetModelRoutingBaseline,
1218 Self::RequestFiniteSwitchTurn => MeerkatMachineInputVariant::RequestFiniteSwitchTurn,
1219 Self::RequestUntilChangedSwitchTurn => {
1220 MeerkatMachineInputVariant::RequestUntilChangedSwitchTurn
1221 }
1222 Self::AdmitModelRoutingAssistantTurn => {
1223 MeerkatMachineInputVariant::AdmitModelRoutingAssistantTurn
1224 }
1225 Self::BeginImageOperation => MeerkatMachineInputVariant::BeginImageOperation,
1226 Self::DenyImageOperationPlan => MeerkatMachineInputVariant::DenyImageOperationPlan,
1227 Self::ActivateImageOperationOverride => {
1228 MeerkatMachineInputVariant::ActivateImageOperationOverride
1229 }
1230 Self::ClassifyImageOperationTerminal => {
1231 MeerkatMachineInputVariant::ClassifyImageOperationTerminal
1232 }
1233 Self::CompleteImageOperation => MeerkatMachineInputVariant::CompleteImageOperation,
1234 Self::RestoreImageOperationOverride => {
1235 MeerkatMachineInputVariant::RestoreImageOperationOverride
1236 }
1237 Self::LoadBoundaryReceipt => MeerkatMachineInputVariant::LoadBoundaryReceipt,
1238 Self::AcceptWithCompletion => MeerkatMachineInputVariant::AcceptWithCompletion,
1239 Self::AcceptWithoutWake => MeerkatMachineInputVariant::AcceptWithoutWake,
1240 }
1241 }
1242
1243 #[must_use]
1244 pub const fn as_str(self) -> &'static str {
1245 match self {
1246 Self::RegisterSession => "RegisterSession",
1247 Self::UnregisterSession => "UnregisterSession",
1248 Self::EnsureSessionWithExecutor => "EnsureSessionWithExecutor",
1249 Self::SetSilentIntents => "SetSilentIntents",
1250 Self::CancelAfterBoundary => "CancelAfterBoundary",
1251 Self::StopRuntimeExecutor => "StopRuntimeExecutor",
1252 Self::ServiceTurnCommitted => "ServiceTurnCommitted",
1253 Self::ContainsSession => "ContainsSession",
1254 Self::SessionHasExecutor => "SessionHasExecutor",
1255 Self::SessionHasComms => "SessionHasComms",
1256 Self::OpsLifecycleRegistry => "OpsLifecycleRegistry",
1257 Self::PrepareBindings => "PrepareBindings",
1258 Self::InputState => "InputState",
1259 Self::ListActiveInputs => "ListActiveInputs",
1260 Self::ReconfigureSessionLlmIdentity => "ReconfigureSessionLlmIdentity",
1261 Self::StagePersistentFilter => "StagePersistentFilter",
1262 Self::RequestDeferredTools => "RequestDeferredTools",
1263 Self::PublishCommittedVisibleSet => "PublishCommittedVisibleSet",
1264 Self::SetPeerIngressContext => "SetPeerIngressContext",
1265 Self::NotifyDrainExited => "NotifyDrainExited",
1266 Self::AbortAll => "AbortAll",
1267 Self::Abort => "Abort",
1268 Self::Wait => "Wait",
1269 Self::Ingest => "Ingest",
1270 Self::PublishEvent => "PublishEvent",
1271 Self::Retire => "Retire",
1272 Self::Recycle => "Recycle",
1273 Self::Reset => "Reset",
1274 Self::Recover => "Recover",
1275 Self::Destroy => "Destroy",
1276 Self::RuntimeState => "RuntimeState",
1277 Self::ModelRoutingStatus => "ModelRoutingStatus",
1278 Self::SetModelRoutingBaseline => "SetModelRoutingBaseline",
1279 Self::RequestFiniteSwitchTurn => "RequestFiniteSwitchTurn",
1280 Self::RequestUntilChangedSwitchTurn => "RequestUntilChangedSwitchTurn",
1281 Self::AdmitModelRoutingAssistantTurn => "AdmitModelRoutingAssistantTurn",
1282 Self::BeginImageOperation => "BeginImageOperation",
1283 Self::DenyImageOperationPlan => "DenyImageOperationPlan",
1284 Self::ActivateImageOperationOverride => "ActivateImageOperationOverride",
1285 Self::ClassifyImageOperationTerminal => "ClassifyImageOperationTerminal",
1286 Self::CompleteImageOperation => "CompleteImageOperation",
1287 Self::RestoreImageOperationOverride => "RestoreImageOperationOverride",
1288 Self::LoadBoundaryReceipt => "LoadBoundaryReceipt",
1289 Self::AcceptWithCompletion => "AcceptWithCompletion",
1290 Self::AcceptWithoutWake => "AcceptWithoutWake",
1291 }
1292 }
1293}
1294
1295impl MeerkatMachineCommandVariant {
1296 #[must_use]
1297 pub const fn catalog_input(self) -> Option<MeerkatMachineCatalogInput> {
1298 match self {
1299 Self::ConfigureModelRoutingBaseline
1300 | Self::RequestSwitchTurn
1301 | Self::ResolvedSessionLlmCapabilities
1302 | Self::SessionModelRoutingStatus
1303 | Self::PrepareLocalSessionBindings => None,
1304 Self::RegisterSession => Some(MeerkatMachineCatalogInput::RegisterSession),
1305 Self::UnregisterSession => Some(MeerkatMachineCatalogInput::UnregisterSession),
1306 Self::EnsureSessionWithExecutor => {
1307 Some(MeerkatMachineCatalogInput::EnsureSessionWithExecutor)
1308 }
1309 Self::SetSilentIntents => Some(MeerkatMachineCatalogInput::SetSilentIntents),
1310 Self::CancelAfterBoundary => Some(MeerkatMachineCatalogInput::CancelAfterBoundary),
1311 Self::StopRuntimeExecutor => Some(MeerkatMachineCatalogInput::StopRuntimeExecutor),
1312 Self::CommitServiceTurnTerminalReceipt => {
1313 Some(MeerkatMachineCatalogInput::ServiceTurnCommitted)
1314 }
1315 Self::ContainsSession => Some(MeerkatMachineCatalogInput::ContainsSession),
1316 Self::SessionHasExecutor => Some(MeerkatMachineCatalogInput::SessionHasExecutor),
1317 Self::SessionHasComms => Some(MeerkatMachineCatalogInput::SessionHasComms),
1318 Self::OpsLifecycleRegistry => Some(MeerkatMachineCatalogInput::OpsLifecycleRegistry),
1319 Self::PrepareBindings => Some(MeerkatMachineCatalogInput::PrepareBindings),
1320 Self::InputState => Some(MeerkatMachineCatalogInput::InputState),
1321 Self::InputStateByIdempotencyKey => Some(MeerkatMachineCatalogInput::InputState),
1324 Self::InteractionTerminalStatus => Some(MeerkatMachineCatalogInput::InputState),
1328 Self::RunTerminalStatus => Some(MeerkatMachineCatalogInput::InputState),
1329 Self::ListActiveInputs => Some(MeerkatMachineCatalogInput::ListActiveInputs),
1330 Self::ReconfigureSessionLlmIdentity => {
1331 Some(MeerkatMachineCatalogInput::ReconfigureSessionLlmIdentity)
1332 }
1333 Self::StagePersistentFilter => Some(MeerkatMachineCatalogInput::StagePersistentFilter),
1334 Self::RequestDeferredTools => Some(MeerkatMachineCatalogInput::RequestDeferredTools),
1335 Self::PublishCommittedVisibleSet => {
1336 Some(MeerkatMachineCatalogInput::PublishCommittedVisibleSet)
1337 }
1338 Self::SetPeerIngressContext => Some(MeerkatMachineCatalogInput::SetPeerIngressContext),
1339 Self::NotifyDrainExited => Some(MeerkatMachineCatalogInput::NotifyDrainExited),
1340 Self::AbortAll => Some(MeerkatMachineCatalogInput::AbortAll),
1341 Self::Abort => Some(MeerkatMachineCatalogInput::Abort),
1342 Self::Wait => Some(MeerkatMachineCatalogInput::Wait),
1343 Self::Ingest => Some(MeerkatMachineCatalogInput::Ingest),
1344 Self::PublishEvent => Some(MeerkatMachineCatalogInput::PublishEvent),
1345 Self::Retire => Some(MeerkatMachineCatalogInput::Retire),
1346 Self::Recycle => Some(MeerkatMachineCatalogInput::Recycle),
1347 Self::Reset => Some(MeerkatMachineCatalogInput::Reset),
1348 Self::Recover => Some(MeerkatMachineCatalogInput::Recover),
1349 Self::Destroy => Some(MeerkatMachineCatalogInput::Destroy),
1350 Self::RuntimeState => Some(MeerkatMachineCatalogInput::RuntimeState),
1351 Self::AdmitModelRoutingAssistantTurn => {
1352 Some(MeerkatMachineCatalogInput::AdmitModelRoutingAssistantTurn)
1353 }
1354 Self::BeginImageOperation => Some(MeerkatMachineCatalogInput::BeginImageOperation),
1355 Self::DenyImageOperationPlan => {
1356 Some(MeerkatMachineCatalogInput::DenyImageOperationPlan)
1357 }
1358 Self::ActivateImageOperationOverride => {
1359 Some(MeerkatMachineCatalogInput::ActivateImageOperationOverride)
1360 }
1361 Self::ClassifyImageOperationTerminal => {
1362 Some(MeerkatMachineCatalogInput::ClassifyImageOperationTerminal)
1363 }
1364 Self::CompleteImageOperation => {
1365 Some(MeerkatMachineCatalogInput::CompleteImageOperation)
1366 }
1367 Self::RestoreImageOperationOverride => {
1368 Some(MeerkatMachineCatalogInput::RestoreImageOperationOverride)
1369 }
1370 Self::LoadBoundaryReceipt => Some(MeerkatMachineCatalogInput::LoadBoundaryReceipt),
1371 Self::AcceptWithCompletion => Some(MeerkatMachineCatalogInput::AcceptWithCompletion),
1372 Self::AcceptWithoutWake => Some(MeerkatMachineCatalogInput::AcceptWithoutWake),
1373 }
1374 }
1375}
1376
1377#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1378pub enum MeerkatMachineShellMechanicReason {
1379 ModelRoutingShellConfiguration,
1380 TurnControlOverlayRequest,
1381 RealtimeTransportObservation,
1382 SessionModelRoutingObservation,
1383 LocalSessionBindingBootstrap,
1384}
1385
1386#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1387pub struct MeerkatMachineCommandClassificationRecord {
1388 pub command: MeerkatMachineCommandVariant,
1389 pub classification: MeerkatMachineCommandClassification,
1390}
1391
1392#[doc(hidden)]
1393#[must_use]
1394pub fn canonical_meerkat_machine_command_classifications()
1395-> Vec<MeerkatMachineCommandClassificationRecord> {
1396 MeerkatMachineCommand::command_variant_manifest()
1397 .iter()
1398 .copied()
1399 .map(|variant| MeerkatMachineCommandClassificationRecord {
1400 command: variant,
1401 classification: meerkat_machine_command_classification(variant),
1402 })
1403 .collect()
1404}
1405
1406const fn meerkat_machine_command_classification(
1407 variant: MeerkatMachineCommandVariant,
1408) -> MeerkatMachineCommandClassification {
1409 match variant {
1410 MeerkatMachineCommandVariant::ConfigureModelRoutingBaseline => {
1411 MeerkatMachineCommandClassification::CatalogInput(
1412 MeerkatMachineCatalogInput::SetModelRoutingBaseline,
1413 )
1414 }
1415 MeerkatMachineCommandVariant::RequestSwitchTurn => {
1416 MeerkatMachineCommandClassification::CatalogInputs(&[
1417 MeerkatMachineCatalogInput::RequestFiniteSwitchTurn,
1418 MeerkatMachineCatalogInput::RequestUntilChangedSwitchTurn,
1419 ])
1420 }
1421 MeerkatMachineCommandVariant::ResolvedSessionLlmCapabilities => {
1422 MeerkatMachineCommandClassification::ShellMechanic(
1423 MeerkatMachineShellMechanicReason::SessionModelRoutingObservation,
1424 )
1425 }
1426 MeerkatMachineCommandVariant::SessionModelRoutingStatus => {
1427 MeerkatMachineCommandClassification::CatalogInput(
1428 MeerkatMachineCatalogInput::ModelRoutingStatus,
1429 )
1430 }
1431 MeerkatMachineCommandVariant::PrepareLocalSessionBindings => {
1432 MeerkatMachineCommandClassification::ShellMechanic(
1433 MeerkatMachineShellMechanicReason::LocalSessionBindingBootstrap,
1434 )
1435 }
1436 MeerkatMachineCommandVariant::RegisterSession => {
1437 MeerkatMachineCommandClassification::CatalogInput(
1438 MeerkatMachineCatalogInput::RegisterSession,
1439 )
1440 }
1441 MeerkatMachineCommandVariant::UnregisterSession => {
1442 MeerkatMachineCommandClassification::CatalogInput(
1443 MeerkatMachineCatalogInput::UnregisterSession,
1444 )
1445 }
1446 MeerkatMachineCommandVariant::EnsureSessionWithExecutor => {
1447 MeerkatMachineCommandClassification::CatalogInput(
1448 MeerkatMachineCatalogInput::EnsureSessionWithExecutor,
1449 )
1450 }
1451 MeerkatMachineCommandVariant::SetSilentIntents => {
1452 MeerkatMachineCommandClassification::CatalogInput(
1453 MeerkatMachineCatalogInput::SetSilentIntents,
1454 )
1455 }
1456 MeerkatMachineCommandVariant::CancelAfterBoundary => {
1457 MeerkatMachineCommandClassification::CatalogInput(
1458 MeerkatMachineCatalogInput::CancelAfterBoundary,
1459 )
1460 }
1461 MeerkatMachineCommandVariant::StopRuntimeExecutor => {
1462 MeerkatMachineCommandClassification::CatalogInput(
1463 MeerkatMachineCatalogInput::StopRuntimeExecutor,
1464 )
1465 }
1466 MeerkatMachineCommandVariant::CommitServiceTurnTerminalReceipt => {
1467 MeerkatMachineCommandClassification::CatalogInput(
1468 MeerkatMachineCatalogInput::ServiceTurnCommitted,
1469 )
1470 }
1471 MeerkatMachineCommandVariant::ContainsSession => {
1472 MeerkatMachineCommandClassification::CatalogInput(
1473 MeerkatMachineCatalogInput::ContainsSession,
1474 )
1475 }
1476 MeerkatMachineCommandVariant::SessionHasExecutor => {
1477 MeerkatMachineCommandClassification::CatalogInput(
1478 MeerkatMachineCatalogInput::SessionHasExecutor,
1479 )
1480 }
1481 MeerkatMachineCommandVariant::SessionHasComms => {
1482 MeerkatMachineCommandClassification::CatalogInput(
1483 MeerkatMachineCatalogInput::SessionHasComms,
1484 )
1485 }
1486 MeerkatMachineCommandVariant::OpsLifecycleRegistry => {
1487 MeerkatMachineCommandClassification::CatalogInput(
1488 MeerkatMachineCatalogInput::OpsLifecycleRegistry,
1489 )
1490 }
1491 MeerkatMachineCommandVariant::PrepareBindings => {
1492 MeerkatMachineCommandClassification::CatalogInput(
1493 MeerkatMachineCatalogInput::PrepareBindings,
1494 )
1495 }
1496 MeerkatMachineCommandVariant::InputState => {
1497 MeerkatMachineCommandClassification::CatalogInput(
1498 MeerkatMachineCatalogInput::InputState,
1499 )
1500 }
1501 MeerkatMachineCommandVariant::InputStateByIdempotencyKey => {
1505 MeerkatMachineCommandClassification::CatalogInput(
1506 MeerkatMachineCatalogInput::InputState,
1507 )
1508 }
1509 MeerkatMachineCommandVariant::InteractionTerminalStatus
1513 | MeerkatMachineCommandVariant::RunTerminalStatus => {
1514 MeerkatMachineCommandClassification::CatalogInput(
1515 MeerkatMachineCatalogInput::InputState,
1516 )
1517 }
1518 MeerkatMachineCommandVariant::ListActiveInputs => {
1519 MeerkatMachineCommandClassification::CatalogInput(
1520 MeerkatMachineCatalogInput::ListActiveInputs,
1521 )
1522 }
1523 MeerkatMachineCommandVariant::ReconfigureSessionLlmIdentity => {
1524 MeerkatMachineCommandClassification::CatalogInput(
1525 MeerkatMachineCatalogInput::ReconfigureSessionLlmIdentity,
1526 )
1527 }
1528 MeerkatMachineCommandVariant::StagePersistentFilter => {
1529 MeerkatMachineCommandClassification::CatalogInput(
1530 MeerkatMachineCatalogInput::StagePersistentFilter,
1531 )
1532 }
1533 MeerkatMachineCommandVariant::RequestDeferredTools => {
1534 MeerkatMachineCommandClassification::CatalogInput(
1535 MeerkatMachineCatalogInput::RequestDeferredTools,
1536 )
1537 }
1538 MeerkatMachineCommandVariant::PublishCommittedVisibleSet => {
1539 MeerkatMachineCommandClassification::CatalogInput(
1540 MeerkatMachineCatalogInput::PublishCommittedVisibleSet,
1541 )
1542 }
1543 MeerkatMachineCommandVariant::SetPeerIngressContext => {
1544 MeerkatMachineCommandClassification::CatalogInput(
1545 MeerkatMachineCatalogInput::SetPeerIngressContext,
1546 )
1547 }
1548 MeerkatMachineCommandVariant::NotifyDrainExited => {
1549 MeerkatMachineCommandClassification::CatalogInput(
1550 MeerkatMachineCatalogInput::NotifyDrainExited,
1551 )
1552 }
1553 MeerkatMachineCommandVariant::AbortAll => {
1554 MeerkatMachineCommandClassification::CatalogInput(MeerkatMachineCatalogInput::AbortAll)
1555 }
1556 MeerkatMachineCommandVariant::Abort => {
1557 MeerkatMachineCommandClassification::CatalogInput(MeerkatMachineCatalogInput::Abort)
1558 }
1559 MeerkatMachineCommandVariant::Wait => {
1560 MeerkatMachineCommandClassification::CatalogInput(MeerkatMachineCatalogInput::Wait)
1561 }
1562 MeerkatMachineCommandVariant::Ingest => {
1563 MeerkatMachineCommandClassification::CatalogInput(MeerkatMachineCatalogInput::Ingest)
1564 }
1565 MeerkatMachineCommandVariant::PublishEvent => {
1566 MeerkatMachineCommandClassification::CatalogInput(
1567 MeerkatMachineCatalogInput::PublishEvent,
1568 )
1569 }
1570 MeerkatMachineCommandVariant::Retire => {
1571 MeerkatMachineCommandClassification::CatalogInput(MeerkatMachineCatalogInput::Retire)
1572 }
1573 MeerkatMachineCommandVariant::Recycle => {
1574 MeerkatMachineCommandClassification::CatalogInput(MeerkatMachineCatalogInput::Recycle)
1575 }
1576 MeerkatMachineCommandVariant::Reset => {
1577 MeerkatMachineCommandClassification::CatalogInput(MeerkatMachineCatalogInput::Reset)
1578 }
1579 MeerkatMachineCommandVariant::Recover => {
1580 MeerkatMachineCommandClassification::CatalogInput(MeerkatMachineCatalogInput::Recover)
1581 }
1582 MeerkatMachineCommandVariant::Destroy => {
1583 MeerkatMachineCommandClassification::CatalogInput(MeerkatMachineCatalogInput::Destroy)
1584 }
1585 MeerkatMachineCommandVariant::RuntimeState => {
1586 MeerkatMachineCommandClassification::CatalogInput(
1587 MeerkatMachineCatalogInput::RuntimeState,
1588 )
1589 }
1590 MeerkatMachineCommandVariant::AdmitModelRoutingAssistantTurn => {
1591 MeerkatMachineCommandClassification::CatalogInput(
1592 MeerkatMachineCatalogInput::AdmitModelRoutingAssistantTurn,
1593 )
1594 }
1595 MeerkatMachineCommandVariant::BeginImageOperation => {
1596 MeerkatMachineCommandClassification::CatalogInput(
1597 MeerkatMachineCatalogInput::BeginImageOperation,
1598 )
1599 }
1600 MeerkatMachineCommandVariant::DenyImageOperationPlan => {
1601 MeerkatMachineCommandClassification::CatalogInput(
1602 MeerkatMachineCatalogInput::DenyImageOperationPlan,
1603 )
1604 }
1605 MeerkatMachineCommandVariant::ActivateImageOperationOverride => {
1606 MeerkatMachineCommandClassification::CatalogInput(
1607 MeerkatMachineCatalogInput::ActivateImageOperationOverride,
1608 )
1609 }
1610 MeerkatMachineCommandVariant::ClassifyImageOperationTerminal => {
1611 MeerkatMachineCommandClassification::CatalogInput(
1612 MeerkatMachineCatalogInput::ClassifyImageOperationTerminal,
1613 )
1614 }
1615 MeerkatMachineCommandVariant::CompleteImageOperation => {
1616 MeerkatMachineCommandClassification::CatalogInput(
1617 MeerkatMachineCatalogInput::CompleteImageOperation,
1618 )
1619 }
1620 MeerkatMachineCommandVariant::RestoreImageOperationOverride => {
1621 MeerkatMachineCommandClassification::CatalogInput(
1622 MeerkatMachineCatalogInput::RestoreImageOperationOverride,
1623 )
1624 }
1625 MeerkatMachineCommandVariant::LoadBoundaryReceipt => {
1626 MeerkatMachineCommandClassification::CatalogInput(
1627 MeerkatMachineCatalogInput::LoadBoundaryReceipt,
1628 )
1629 }
1630 MeerkatMachineCommandVariant::AcceptWithCompletion => {
1631 MeerkatMachineCommandClassification::CatalogInput(
1632 MeerkatMachineCatalogInput::AcceptWithCompletion,
1633 )
1634 }
1635 MeerkatMachineCommandVariant::AcceptWithoutWake => {
1636 MeerkatMachineCommandClassification::CatalogInput(
1637 MeerkatMachineCatalogInput::AcceptWithoutWake,
1638 )
1639 }
1640 }
1641}
1642
1643#[derive(Debug, Clone, PartialEq, Eq)]
1647pub struct MeerkatCompletionWaiterSnapshot {
1648 pub input_id: InputId,
1649 pub waiter_count: usize,
1650}
1651
1652#[derive(Debug, Clone, PartialEq, Eq)]
1657pub struct MeerkatCompletionWaitersSnapshot {
1658 pub input_count: usize,
1659 pub waiter_count: usize,
1660 pub waiting_inputs: Vec<MeerkatCompletionWaiterSnapshot>,
1661}
1662
1663#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1665pub enum MeerkatDriverKind {
1666 Ephemeral,
1667 Persistent,
1668}
1669
1670#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1672pub struct MeerkatCursorSnapshot {
1673 pub agent_applied_cursor: u64,
1674 pub runtime_observed_seq: u64,
1675 pub runtime_last_injected_seq: u64,
1676}
1677
1678#[derive(Debug, Clone)]
1680pub struct MeerkatBindingSnapshot {
1681 pub session_id: SessionId,
1682 pub runtime_id: LogicalRuntimeId,
1683 pub driver_kind: MeerkatDriverKind,
1684 pub driver_present: bool,
1685 pub completions_present: bool,
1686 pub ops_registry_present: bool,
1687 pub epoch_id: RuntimeEpochId,
1688 pub cursor_state: MeerkatCursorSnapshot,
1689}
1690
1691#[derive(Debug, Clone)]
1693pub struct MeerkatControlSnapshot {
1694 pub phase: RuntimeState,
1695 pub current_run_id: Option<RunId>,
1696 pub pre_run_phase: Option<RuntimeState>,
1697}
1698
1699#[derive(Debug, Clone)]
1701pub struct MeerkatAdmittedInputSnapshot {
1702 pub input_id: InputId,
1703 pub content_shape: Option<ContentShape>,
1704 pub request_id: Option<RequestId>,
1705 pub reservation_key: Option<ReservationKey>,
1706 pub handling_mode: Option<HandlingMode>,
1707 pub live_interrupt_required: bool,
1711 pub lifecycle: Option<InputLifecycleState>,
1712 pub terminal_outcome: Option<InputTerminalOutcome>,
1713 pub last_run_id: Option<RunId>,
1714 pub last_boundary_sequence: Option<u64>,
1715 pub is_prompt: bool,
1716}
1717
1718#[derive(Debug, Clone)]
1720pub struct MeerkatInputsSnapshot {
1721 pub admission_order: Vec<MeerkatAdmittedInputSnapshot>,
1722 pub queue: Vec<InputId>,
1723 pub steer_queue: Vec<InputId>,
1724 pub current_run_id: Option<RunId>,
1725 pub current_run_contributors: Vec<InputId>,
1726 pub post_admission_signal: String,
1727 pub silent_intent_overrides: Vec<String>,
1728}
1729
1730#[derive(Debug, Clone)]
1736pub struct MeerkatArchiveSnapshot {
1737 pub control: MeerkatControlSnapshot,
1738 pub queue: Vec<InputId>,
1739 pub steer_queue: Vec<InputId>,
1740 pub completion_waiters: MeerkatCompletionWaitersSnapshot,
1741}
1742
1743#[derive(Debug, Clone)]
1749pub struct MeerkatLedgerSnapshot {
1750 pub input_count: usize,
1751 pub non_terminal_count: usize,
1752 pub accepted_count: usize,
1753 pub queued_count: usize,
1754 pub staged_count: usize,
1755 pub applied_count: usize,
1756 pub applied_pending_consumption_count: usize,
1757 pub consumed_count: usize,
1758 pub superseded_count: usize,
1759 pub coalesced_count: usize,
1760 pub abandoned_count: usize,
1761}
1762
1763#[derive(Debug, Clone)]
1765pub struct MeerkatOpsSnapshot {
1766 pub operation_count: usize,
1767 pub active_count: usize,
1768 pub wait_request_id: Option<WaitRequestId>,
1769 pub pending_wait_present: bool,
1770 pub pending_wait_request_id: Option<WaitRequestId>,
1771 pub wait_operation_ids: Vec<OperationId>,
1772 pub operations: Vec<OperationLifecycleSnapshot>,
1773}
1774
1775#[derive(Debug, Clone)]
1780pub struct MeerkatDrainSnapshot {
1781 pub slot_present: bool,
1782 pub phase: Option<CommsDrainPhase>,
1783 pub mode: Option<CommsDrainMode>,
1784 pub handle_present: bool,
1785}
1786
1787#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
1794pub struct MeerkatFormalStateProjection {
1795 pub available_fields: BTreeMap<String, String>,
1797 pub unavailable_fields: Vec<String>,
1799}
1800
1801#[derive(Debug, Clone)]
1806pub struct MeerkatMachineSpineSnapshot {
1807 pub binding: MeerkatBindingSnapshot,
1808 pub control: MeerkatControlSnapshot,
1809 pub inputs: MeerkatInputsSnapshot,
1810 pub ledger: MeerkatLedgerSnapshot,
1811 pub completion_waiters: MeerkatCompletionWaitersSnapshot,
1812 pub ops: MeerkatOpsSnapshot,
1813 pub drain: MeerkatDrainSnapshot,
1814 pub formal_state: MeerkatFormalStateProjection,
1815}
1816
1817impl MeerkatMachineSpineSnapshot {
1818 pub fn validate_spine_invariants(&self) -> Result<(), Vec<String>> {
1824 let mut violations = Vec::new();
1825
1826 if self.control.phase == RuntimeState::Running && self.control.current_run_id.is_none() {
1830 violations
1831 .push("RunningHasActiveRunInvariant: phase is Running but no active run_id".into());
1832 }
1833
1834 if self.control.current_run_id.is_some()
1836 && !matches!(
1837 self.control.phase,
1838 RuntimeState::Running | RuntimeState::Retired
1839 )
1840 {
1841 violations.push(format!(
1842 "ActiveRunPhaseInvariant: active run_id present but phase is {:?}",
1843 self.control.phase
1844 ));
1845 }
1846
1847 if self.control.phase == RuntimeState::Destroyed {
1849 if !self.inputs.queue.is_empty() {
1850 violations.push("DestroyedShapeInvariant: Destroyed but queue is non-empty".into());
1851 }
1852 if !self.inputs.steer_queue.is_empty() {
1853 violations
1854 .push("DestroyedShapeInvariant: Destroyed but steer_queue is non-empty".into());
1855 }
1856 if self.completion_waiters.input_count > 0 {
1857 violations.push(
1858 "DestroyedShapeInvariant: Destroyed but completion waiters remain".into(),
1859 );
1860 }
1861 }
1862
1863 let queue_set: std::collections::HashSet<_> = self.inputs.queue.iter().collect();
1867 let steer_set: std::collections::HashSet<_> = self.inputs.steer_queue.iter().collect();
1868 if !queue_set.is_disjoint(&steer_set) {
1869 violations
1870 .push("QueueSteerDisjointInvariant: queue and steer_queue share entries".into());
1871 }
1872
1873 for qid in &self.inputs.queue {
1875 if let Some(snap) = self
1876 .inputs
1877 .admission_order
1878 .iter()
1879 .find(|a| &a.input_id == qid)
1880 {
1881 if snap.handling_mode != Some(HandlingMode::Queue) {
1882 violations.push(format!(
1883 "QueueHandlingInvariant: queue entry {qid} has handling_mode {:?}",
1884 snap.handling_mode
1885 ));
1886 }
1887 if snap.lifecycle != Some(InputLifecycleState::Queued) {
1888 violations.push(format!(
1889 "QueueHandlingInvariant: queue entry {qid} has lifecycle {:?}",
1890 snap.lifecycle
1891 ));
1892 }
1893 }
1894 }
1895
1896 for sid in &self.inputs.steer_queue {
1898 if let Some(snap) = self
1899 .inputs
1900 .admission_order
1901 .iter()
1902 .find(|a| &a.input_id == sid)
1903 {
1904 if snap.handling_mode != Some(HandlingMode::Steer) {
1905 violations.push(format!(
1906 "SteerHandlingInvariant: steer_queue entry {sid} has handling_mode {:?}",
1907 snap.handling_mode
1908 ));
1909 }
1910 if snap.lifecycle != Some(InputLifecycleState::Queued) {
1911 violations.push(format!(
1912 "SteerHandlingInvariant: steer_queue entry {sid} has lifecycle {:?}",
1913 snap.lifecycle
1914 ));
1915 }
1916 }
1917 }
1918
1919 for cid in &self.inputs.current_run_contributors {
1922 if let Some(snap) = self
1923 .inputs
1924 .admission_order
1925 .iter()
1926 .find(|a| &a.input_id == cid)
1927 && !matches!(
1928 snap.lifecycle,
1929 Some(
1930 InputLifecycleState::Staged
1931 | InputLifecycleState::Applied
1932 | InputLifecycleState::AppliedPendingConsumption
1933 )
1934 )
1935 {
1936 violations.push(format!(
1937 "ContributorLifecycleInvariant: contributor {cid} has lifecycle {:?}",
1938 snap.lifecycle
1939 ));
1940 }
1941 }
1942
1943 for snap in &self.inputs.admission_order {
1945 if snap.terminal_outcome.is_some() {
1946 if queue_set.contains(&snap.input_id) {
1947 violations.push(format!(
1948 "TerminalInputsNotQueuedInvariant: terminal input {} in queue",
1949 snap.input_id
1950 ));
1951 }
1952 if steer_set.contains(&snap.input_id) {
1953 violations.push(format!(
1954 "TerminalInputsNotQueuedInvariant: terminal input {} in steer_queue",
1955 snap.input_id
1956 ));
1957 }
1958 }
1959 }
1960
1961 if self.control.current_run_id.is_some() && self.inputs.current_run_contributors.is_empty()
1963 {
1964 violations
1965 .push("CurrentRunContributorsInvariant: active run but no contributors".into());
1966 }
1967
1968 if let Some(control_run_id) = &self.control.current_run_id {
1972 for cid in &self.inputs.current_run_contributors {
1973 if let Some(snap) = self
1974 .inputs
1975 .admission_order
1976 .iter()
1977 .find(|a| &a.input_id == cid)
1978 && snap.last_run_id.as_ref() != Some(control_run_id)
1979 {
1980 violations.push(format!(
1981 "ContributorRunIdentityInvariant: contributor {cid} has last_run_id {:?}, expected {:?}",
1982 snap.last_run_id, control_run_id
1983 ));
1984 }
1985 }
1986 }
1987
1988 let wait_active = self.ops.wait_request_id.is_some();
1992 if wait_active && self.ops.wait_operation_ids.is_empty() {
1993 violations
1994 .push("WaitAllAlignmentInvariant: wait_active but no wait_operation_ids".into());
1995 }
1996 if !wait_active && !self.ops.wait_operation_ids.is_empty() {
1997 violations.push(
1998 "WaitAllAlignmentInvariant: wait_operation_ids present but no wait_request_id"
1999 .into(),
2000 );
2001 }
2002
2003 if let Some(phase) = self.drain.phase
2007 && phase != CommsDrainPhase::Inactive
2008 && self.drain.mode.is_none()
2009 {
2010 violations.push("DrainModeInvariant: drain.phase is active but mode is None".into());
2011 }
2012
2013 if violations.is_empty() {
2014 Ok(())
2015 } else {
2016 Err(violations)
2017 }
2018 }
2019}