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