Skip to main content

meerkat_runtime/meerkat_machine/
dsl.rs

1//! MeerkatMachine DSL definition with real bridging types.
2#![allow(clippy::too_many_arguments)]
3
4use meerkat_machine_dsl::machine;
5use meerkat_machine_schema::catalog::dsl::OptionValueExt;
6
7// ---------------------------------------------------------------------------
8// Bridging types
9// ---------------------------------------------------------------------------
10
11#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
12pub struct SessionId(pub String);
13
14impl<T: Into<String>> From<T> for SessionId {
15    fn from(s: T) -> Self {
16        Self(s.into())
17    }
18}
19
20impl SessionId {
21    pub fn from_domain(id: &meerkat_core::types::SessionId) -> Self {
22        Self(id.to_string())
23    }
24}
25
26#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
27pub struct AgentRuntimeId(pub String);
28
29impl<T: Into<String>> From<T> for AgentRuntimeId {
30    fn from(s: T) -> Self {
31        Self(s.into())
32    }
33}
34
35impl AgentRuntimeId {
36    pub fn from_domain(id: &crate::identifiers::LogicalRuntimeId) -> Self {
37        Self(id.to_string())
38    }
39}
40
41#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
42pub struct FenceToken(pub u64);
43
44impl From<u64> for FenceToken {
45    fn from(v: u64) -> Self {
46        Self(v)
47    }
48}
49
50impl FenceToken {
51    pub fn from_domain(value: u64) -> Self {
52        Self(value)
53    }
54}
55
56#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
57pub struct Generation(pub u64);
58
59impl From<u64> for Generation {
60    fn from(v: u64) -> Self {
61        Self(v)
62    }
63}
64
65impl Generation {
66    pub fn from_domain(value: u64) -> Self {
67        Self(value)
68    }
69}
70
71#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
72pub struct RuntimeEpochId(pub String);
73
74impl<T: Into<String>> From<T> for RuntimeEpochId {
75    fn from(s: T) -> Self {
76        Self(s.into())
77    }
78}
79
80impl RuntimeEpochId {
81    pub fn from_domain(id: &meerkat_core::runtime_epoch::RuntimeEpochId) -> Self {
82        Self(id.to_string())
83    }
84}
85
86#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
87pub struct RunId(pub String);
88
89impl<T: Into<String>> From<T> for RunId {
90    fn from(s: T) -> Self {
91        Self(s.into())
92    }
93}
94
95impl RunId {
96    pub fn from_domain(id: &meerkat_core::lifecycle::RunId) -> Self {
97        Self(id.to_string())
98    }
99}
100
101#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
102pub struct InputId(pub String);
103
104impl<T: Into<String>> From<T> for InputId {
105    fn from(s: T) -> Self {
106        Self(s.into())
107    }
108}
109
110impl InputId {
111    pub fn from_domain(id: &meerkat_core::lifecycle::InputId) -> Self {
112        Self(id.to_string())
113    }
114}
115
116#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
117pub struct WorkId(pub String);
118
119impl<T: Into<String>> From<T> for WorkId {
120    fn from(s: T) -> Self {
121        Self(s.into())
122    }
123}
124
125impl WorkId {
126    pub fn from_domain(id: &meerkat_core::lifecycle::InputId) -> Self {
127        Self(id.to_string())
128    }
129}
130
131#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
132pub struct OperationId(pub String);
133
134impl<T: Into<String>> From<T> for OperationId {
135    fn from(s: T) -> Self {
136        Self(s.into())
137    }
138}
139
140impl OperationId {
141    pub fn from_domain(id: &meerkat_core::ops::OperationId) -> Self {
142        Self::from(serde_json::to_string(id).unwrap_or_else(|_| "\"unknown\"".to_string()))
143    }
144}
145
146#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
147pub struct WaitRequestId(pub String);
148
149impl<T: Into<String>> From<T> for WaitRequestId {
150    fn from(s: T) -> Self {
151        Self(s.into())
152    }
153}
154
155impl WaitRequestId {
156    pub fn from_domain(id: &meerkat_core::lifecycle::WaitRequestId) -> Self {
157        Self(id.to_string())
158    }
159}
160
161/// Typed async-operation kind. Closed mirror of
162/// [`meerkat_core::ops_lifecycle::OperationKind`] — replaces the former
163/// newtype wrapper around an opaque JSON-encoded string. The DSL writes this
164/// variant directly on `RegisterOp` so guards on `PeerReadyOp`
165/// (`kind_is_mob_member_child`) can reason about the closed set without
166/// string parsing. `BackgroundToolCapacitySlot` is a generated shell admission
167/// reservation, not a background job, so completion-feed publication can
168/// distinguish it from `BackgroundToolOp`.
169#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
170pub enum OperationKind {
171    #[default]
172    MobMemberChild,
173    BackgroundToolOp,
174    BackgroundToolCapacitySlot,
175}
176
177#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
178pub enum OperationSourceKind {
179    #[default]
180    SessionChild,
181    BackendPeer,
182}
183
184/// Typed source identity for an async operation. The lifecycle machine stores
185/// this on `RegisterOp` so peer-only operation identity is not reconstructed
186/// from display strings or shell-side labels.
187#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
188pub struct OperationSource {
189    pub kind: OperationSourceKind,
190    pub session_id: Option<SessionId>,
191    pub peer_id: Option<PeerId>,
192    pub address: Option<PeerAddress>,
193}
194
195impl OperationSource {
196    pub fn from_domain(source: &meerkat_core::ops_lifecycle::OperationSource) -> Self {
197        match source {
198            meerkat_core::ops_lifecycle::OperationSource::SessionChild { session_id } => Self {
199                kind: OperationSourceKind::SessionChild,
200                session_id: Some(SessionId::from_domain(session_id)),
201                peer_id: None,
202                address: None,
203            },
204            meerkat_core::ops_lifecycle::OperationSource::BackendPeer { peer_id, address } => {
205                Self {
206                    kind: OperationSourceKind::BackendPeer,
207                    session_id: None,
208                    peer_id: Some(PeerId(peer_id.to_string())),
209                    address: Some(PeerAddress(address.to_string())),
210                }
211            }
212        }
213    }
214
215    pub fn to_domain(&self) -> Result<meerkat_core::ops_lifecycle::OperationSource, String> {
216        match self.kind {
217            OperationSourceKind::SessionChild => {
218                let session_id = self
219                    .session_id
220                    .as_ref()
221                    .ok_or_else(|| "session operation source missing session_id".to_string())?;
222                let session_id = meerkat_core::types::SessionId::parse(&session_id.0)
223                    .map_err(|error| format!("invalid session operation source id: {error}"))?;
224                Ok(meerkat_core::ops_lifecycle::OperationSource::session_child(
225                    session_id,
226                ))
227            }
228            OperationSourceKind::BackendPeer => {
229                let peer_id = self
230                    .peer_id
231                    .as_ref()
232                    .ok_or_else(|| "backend peer operation source missing peer_id".to_string())?;
233                let address = self
234                    .address
235                    .as_ref()
236                    .ok_or_else(|| "backend peer operation source missing address".to_string())?;
237                let peer_id = meerkat_core::comms::PeerId::parse(&peer_id.0).map_err(|error| {
238                    format!("invalid backend peer operation source id: {error}")
239                })?;
240                let address =
241                    meerkat_core::comms::PeerAddress::parse(&address.0).map_err(|error| {
242                        format!("invalid backend peer operation source address: {error}")
243                    })?;
244                Ok(meerkat_core::ops_lifecycle::OperationSource::backend_peer(
245                    peer_id, address,
246                ))
247            }
248        }
249    }
250}
251
252impl From<meerkat_core::ops_lifecycle::OperationKind> for OperationKind {
253    fn from(kind: meerkat_core::ops_lifecycle::OperationKind) -> Self {
254        match kind {
255            meerkat_core::ops_lifecycle::OperationKind::MobMemberChild => Self::MobMemberChild,
256            meerkat_core::ops_lifecycle::OperationKind::BackgroundToolOp => Self::BackgroundToolOp,
257            meerkat_core::ops_lifecycle::OperationKind::BackgroundToolCapacitySlot => {
258                Self::BackgroundToolCapacitySlot
259            }
260        }
261    }
262}
263
264impl From<OperationKind> for meerkat_core::ops_lifecycle::OperationKind {
265    fn from(kind: OperationKind) -> Self {
266        match kind {
267            OperationKind::MobMemberChild => Self::MobMemberChild,
268            OperationKind::BackgroundToolOp => Self::BackgroundToolOp,
269            OperationKind::BackgroundToolCapacitySlot => Self::BackgroundToolCapacitySlot,
270        }
271    }
272}
273
274impl OperationKind {
275    pub fn from_domain(kind: &meerkat_core::ops_lifecycle::OperationKind) -> Self {
276        Self::from(*kind)
277    }
278}
279
280/// Typed mirror of [`meerkat_core::Provider`] for use inside DSL bridging
281/// types. Closed 5-variant enum; the seam carries the discriminant directly
282/// rather than a JSON-encoded string.
283#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
284pub enum Provider {
285    #[default]
286    Anthropic,
287    OpenAI,
288    Gemini,
289    SelfHosted,
290    Other,
291}
292
293impl From<meerkat_core::provider::Provider> for Provider {
294    fn from(p: meerkat_core::provider::Provider) -> Self {
295        match p {
296            meerkat_core::provider::Provider::Anthropic => Self::Anthropic,
297            meerkat_core::provider::Provider::OpenAI => Self::OpenAI,
298            meerkat_core::provider::Provider::Gemini => Self::Gemini,
299            meerkat_core::provider::Provider::SelfHosted => Self::SelfHosted,
300            meerkat_core::provider::Provider::Other => Self::Other,
301        }
302    }
303}
304
305impl From<Provider> for meerkat_core::provider::Provider {
306    fn from(p: Provider) -> Self {
307        match p {
308            Provider::Anthropic => Self::Anthropic,
309            Provider::OpenAI => Self::OpenAI,
310            Provider::Gemini => Self::Gemini,
311            Provider::SelfHosted => Self::SelfHosted,
312            Provider::Other => Self::Other,
313        }
314    }
315}
316
317/// Typed mirror of [`meerkat_core::AuthBindingRef`] — structural string
318/// projection carrying the flat forms of `realm` / `binding` / `profile`
319/// with bidirectional `From`.
320///
321/// The DSL layer keeps string fields because this mirror is the
322/// DSL-layer identity carrier (used inside runtime-owned guards /
323/// transitions where slug validation has already happened at the
324/// boundary). Domain-side `AuthBindingRef` carries the typed atoms
325/// (`RealmId` / `BindingId` / `ProfileId`).
326#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
327pub struct AuthBindingRef {
328    pub realm_id: String,
329    pub binding_id: String,
330    pub profile_id: Option<String>,
331}
332
333impl From<&meerkat_core::AuthBindingRef> for AuthBindingRef {
334    fn from(r: &meerkat_core::AuthBindingRef) -> Self {
335        Self {
336            realm_id: r.realm.as_str().to_owned(),
337            binding_id: r.binding.as_str().to_owned(),
338            profile_id: r.profile.as_ref().map(|p| p.as_str().to_owned()),
339        }
340    }
341}
342
343/// Fallible conversion — DSL-layer flat strings may be slug-invalid
344/// (the DSL mirror intentionally accepts opaque strings to survive
345/// deserialization drift across schema versions), so lifting back to
346/// the typed-atom domain form may reject.
347impl TryFrom<AuthBindingRef> for meerkat_core::AuthBindingRef {
348    type Error = meerkat_core::IdentityError;
349
350    fn try_from(r: AuthBindingRef) -> Result<Self, Self::Error> {
351        Ok(Self {
352            realm: meerkat_core::RealmId::parse(&r.realm_id)?,
353            binding: meerkat_core::BindingId::parse(&r.binding_id)?,
354            profile: r
355                .profile_id
356                .as_deref()
357                .map(meerkat_core::ProfileId::parse)
358                .transpose()?,
359            origin: meerkat_core::connection::BindingOrigin::Configured,
360        })
361    }
362}
363
364/// Typed mirror of [`meerkat_core::SessionLlmIdentity`] — structural field
365/// projection with typed `Provider` and `AuthBindingRef` mirrors. The
366/// `provider_params` payload is a legitimately open-set `serde_json::Value`
367/// at the persistence boundary (arbitrary provider-specific options), so it
368/// rides on a stable JSON-serialization field inside the DSL — never parsed
369/// back as a discriminant inside any guard or transition.
370#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
371pub struct SessionLlmIdentity {
372    pub model: String,
373    pub provider: Provider,
374    pub self_hosted_server_id: Option<String>,
375    /// Stable JSON serialization of the open-set `provider_params` payload.
376    /// Carried as an opaque identity token; DSL guards never inspect its
377    /// content. Boundary-legitimate per the dogma round-4 brief's
378    /// "variable JSON payload" carve-out applied at field granularity.
379    pub provider_params_repr: Option<String>,
380    pub auth_binding: Option<AuthBindingRef>,
381}
382
383impl SessionLlmIdentity {
384    pub fn from_domain(id: &meerkat_core::SessionLlmIdentity) -> Self {
385        Self {
386            model: id.model.clone(),
387            provider: Provider::from(id.provider),
388            self_hosted_server_id: id.self_hosted_server_id.clone(),
389            provider_params_repr: id
390                .provider_params
391                .as_ref()
392                .map(|v| serde_json::to_string(v).unwrap_or_default()),
393            auth_binding: id.auth_binding.as_ref().map(AuthBindingRef::from),
394        }
395    }
396}
397
398impl TryFrom<SessionLlmIdentity> for meerkat_core::SessionLlmIdentity {
399    type Error = String;
400
401    fn try_from(id: SessionLlmIdentity) -> Result<Self, Self::Error> {
402        Ok(Self {
403            model: id.model,
404            provider: id.provider.into(),
405            self_hosted_server_id: id.self_hosted_server_id,
406            provider_params: id
407                .provider_params_repr
408                .as_deref()
409                .map(serde_json::from_str)
410                .transpose()
411                .map_err(|err| format!("invalid generated provider_params identity: {err}"))?,
412            auth_binding: id
413                .auth_binding
414                .map(meerkat_core::AuthBindingRef::try_from)
415                .transpose()
416                .map_err(|err| format!("invalid generated auth binding identity: {err}"))?,
417        })
418    }
419}
420
421/// Typed mirror of [`meerkat_core::SessionToolVisibilityState`] —
422/// structural projection using typed `ToolFilter` / `ToolVisibilityWitness`
423/// mirrors plus ordered name sets for deterministic Ord/Hash.
424#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
425pub struct SessionToolVisibilityState {
426    pub capability_base_filter: ToolFilter,
427    pub inherited_base_filter: ToolFilter,
428    pub active_filter: ToolFilter,
429    pub staged_filter: ToolFilter,
430    pub active_requested_deferred_names: std::collections::BTreeSet<ToolName>,
431    pub staged_requested_deferred_names: std::collections::BTreeSet<ToolName>,
432    pub active_revision: u64,
433    pub staged_revision: u64,
434    pub requested_witnesses: std::collections::BTreeMap<ToolName, ToolVisibilityWitness>,
435    pub filter_witnesses: std::collections::BTreeMap<ToolName, ToolVisibilityWitness>,
436}
437
438impl SessionToolVisibilityState {
439    pub fn from_domain(id: &meerkat_core::SessionToolVisibilityState) -> Self {
440        Self {
441            capability_base_filter: ToolFilter::from(&id.capability_base_filter),
442            inherited_base_filter: ToolFilter::from(&id.inherited_base_filter),
443            active_filter: ToolFilter::from(&id.active_filter),
444            staged_filter: ToolFilter::from(&id.staged_filter),
445            active_requested_deferred_names: id.active_requested_deferred_names.clone(),
446            staged_requested_deferred_names: id.staged_requested_deferred_names.clone(),
447            active_revision: id.active_revision,
448            staged_revision: id.staged_revision,
449            requested_witnesses: id
450                .requested_witnesses
451                .iter()
452                .map(|(k, w)| (k.clone(), ToolVisibilityWitness::from(w)))
453                .collect(),
454            filter_witnesses: id
455                .filter_witnesses
456                .iter()
457                .map(|(k, w)| (k.clone(), ToolVisibilityWitness::from(w)))
458                .collect(),
459        }
460    }
461}
462
463/// Typed mirror of
464/// [`crate::meerkat_machine_types::SessionLlmCapabilitySurface`] — structural
465/// projection of the boolean capability matrix plus optional call timeout.
466#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
467pub struct SessionLlmCapabilitySurface {
468    pub supports_temperature: bool,
469    pub supports_thinking: bool,
470    pub supports_reasoning: bool,
471    pub inline_video: bool,
472    pub vision: bool,
473    pub image_input: bool,
474    pub image_tool_results: bool,
475    pub supports_web_search: bool,
476    pub image_generation: bool,
477    pub realtime: bool,
478    pub call_timeout_secs: Option<u64>,
479}
480
481impl From<&crate::meerkat_machine_types::SessionLlmCapabilitySurface>
482    for SessionLlmCapabilitySurface
483{
484    fn from(s: &crate::meerkat_machine_types::SessionLlmCapabilitySurface) -> Self {
485        Self {
486            supports_temperature: s.supports_temperature,
487            supports_thinking: s.supports_thinking,
488            supports_reasoning: s.supports_reasoning,
489            inline_video: s.inline_video,
490            vision: s.vision,
491            image_input: s.image_input,
492            image_tool_results: s.image_tool_results,
493            supports_web_search: s.supports_web_search,
494            image_generation: s.image_generation,
495            realtime: s.realtime,
496            call_timeout_secs: s.call_timeout_secs,
497        }
498    }
499}
500
501impl From<SessionLlmCapabilitySurface>
502    for crate::meerkat_machine_types::SessionLlmCapabilitySurface
503{
504    fn from(s: SessionLlmCapabilitySurface) -> Self {
505        Self {
506            supports_temperature: s.supports_temperature,
507            supports_thinking: s.supports_thinking,
508            supports_reasoning: s.supports_reasoning,
509            inline_video: s.inline_video,
510            vision: s.vision,
511            image_input: s.image_input,
512            image_tool_results: s.image_tool_results,
513            supports_web_search: s.supports_web_search,
514            image_generation: s.image_generation,
515            realtime: s.realtime,
516            call_timeout_secs: s.call_timeout_secs,
517        }
518    }
519}
520
521impl SessionLlmCapabilitySurface {
522    pub fn from_domain(id: &crate::meerkat_machine_types::SessionLlmCapabilitySurface) -> Self {
523        Self::from(id)
524    }
525}
526
527/// Typed capability-surface resolution status. Closed mirror of
528/// [`crate::meerkat_machine_types::SessionLlmCapabilitySurfaceStatus`] —
529/// replaces the former JSON-stringified wrapper the DSL used to carry the
530/// two-state discriminant across the seam.
531///
532/// The DSL stores the variant directly on `ReconfigureSessionLlmIdentity`
533/// flow state; the shell maps to/from the domain enum via the `From` impls
534/// below — no `serde_json::to_string`, no string compares.
535#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
536pub enum SessionLlmCapabilitySurfaceStatus {
537    Resolved,
538    #[default]
539    Unresolved,
540}
541
542impl From<crate::meerkat_machine_types::SessionLlmCapabilitySurfaceStatus>
543    for SessionLlmCapabilitySurfaceStatus
544{
545    fn from(status: crate::meerkat_machine_types::SessionLlmCapabilitySurfaceStatus) -> Self {
546        match status {
547            crate::meerkat_machine_types::SessionLlmCapabilitySurfaceStatus::Resolved => {
548                Self::Resolved
549            }
550            crate::meerkat_machine_types::SessionLlmCapabilitySurfaceStatus::Unresolved => {
551                Self::Unresolved
552            }
553        }
554    }
555}
556
557impl From<SessionLlmCapabilitySurfaceStatus>
558    for crate::meerkat_machine_types::SessionLlmCapabilitySurfaceStatus
559{
560    fn from(status: SessionLlmCapabilitySurfaceStatus) -> Self {
561        match status {
562            SessionLlmCapabilitySurfaceStatus::Resolved => Self::Resolved,
563            SessionLlmCapabilitySurfaceStatus::Unresolved => Self::Unresolved,
564        }
565    }
566}
567
568impl SessionLlmCapabilitySurfaceStatus {
569    pub fn from_domain(
570        id: &crate::meerkat_machine_types::SessionLlmCapabilitySurfaceStatus,
571    ) -> Self {
572        Self::from(*id)
573    }
574}
575
576/// Typed mirror of
577/// [`crate::meerkat_machine_types::SessionToolVisibilityDelta`] — structural
578/// projection using typed `ToolFilter` mirrors plus the two boolean change
579/// flags. Replaces the former `format!("{id:?}")` Debug-stringified wrapper.
580#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
581pub struct SessionToolVisibilityDelta {
582    pub previous_capability_base_filter: ToolFilter,
583    pub current_capability_base_filter: ToolFilter,
584    pub committed_visible_set_changed: bool,
585    pub revision_bumped: bool,
586}
587
588impl SessionToolVisibilityDelta {
589    pub fn from_domain(id: &crate::meerkat_machine_types::SessionToolVisibilityDelta) -> Self {
590        Self {
591            previous_capability_base_filter: ToolFilter::from(&id.previous_capability_base_filter),
592            current_capability_base_filter: ToolFilter::from(&id.current_capability_base_filter),
593            committed_visible_set_changed: id.committed_visible_set_changed,
594            revision_bumped: id.revision_bumped,
595        }
596    }
597}
598
599/// Canonical typed tool identity. This IS the domain type —
600/// [`meerkat_core::types::ToolName`] — carried directly through the machine
601/// (K8a fold: the tool-visibility name domain is `ToolName`-keyed end to end;
602/// no stringly bridge inside the machine).
603pub type ToolName = meerkat_core::types::ToolName;
604
605/// Typed mirror of [`meerkat_core::ToolFilter`] — closed 3-variant
606/// discriminant with a `BTreeSet<ToolName>` name payload for
607/// `Allow`/`Deny` so the value is `Ord + Hash` and deterministic across
608/// iteration, matching the R3 `InputAbandonReason::MaxAttemptsExhausted {
609/// attempts }` pattern of carrying the discriminant's companion data in a
610/// field with stable ordering.
611#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
612pub enum ToolFilter {
613    #[default]
614    All,
615    Allow(std::collections::BTreeSet<ToolName>),
616    Deny(std::collections::BTreeSet<ToolName>),
617}
618
619impl From<&meerkat_core::ToolFilter> for ToolFilter {
620    fn from(f: &meerkat_core::ToolFilter) -> Self {
621        match f {
622            meerkat_core::ToolFilter::All => Self::All,
623            meerkat_core::ToolFilter::Allow(names) => Self::Allow(names.iter().cloned().collect()),
624            meerkat_core::ToolFilter::Deny(names) => Self::Deny(names.iter().cloned().collect()),
625        }
626    }
627}
628
629impl From<ToolFilter> for meerkat_core::ToolFilter {
630    fn from(f: ToolFilter) -> Self {
631        match f {
632            ToolFilter::All => Self::All,
633            ToolFilter::Allow(names) => Self::Allow(names.into_iter().collect()),
634            ToolFilter::Deny(names) => Self::Deny(names.into_iter().collect()),
635        }
636    }
637}
638
639impl ToolFilter {
640    pub fn from_domain(id: &meerkat_core::ToolFilter) -> Self {
641        Self::from(id)
642    }
643}
644
645/// Typed mirror of [`meerkat_core::types::ToolSourceKind`] — closed
646/// Closed discriminant for tool provenance classification.
647#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
648pub enum ToolSourceKind {
649    #[default]
650    Builtin,
651    Shell,
652    Comms,
653    Memory,
654    Schedule,
655    WorkGraph,
656    Mob,
657    Callback,
658    Mcp,
659    RustBundle,
660}
661
662impl From<&meerkat_core::types::ToolSourceKind> for ToolSourceKind {
663    fn from(k: &meerkat_core::types::ToolSourceKind) -> Self {
664        match k {
665            meerkat_core::types::ToolSourceKind::Builtin => Self::Builtin,
666            meerkat_core::types::ToolSourceKind::Shell => Self::Shell,
667            meerkat_core::types::ToolSourceKind::Comms => Self::Comms,
668            meerkat_core::types::ToolSourceKind::Memory => Self::Memory,
669            meerkat_core::types::ToolSourceKind::Schedule => Self::Schedule,
670            meerkat_core::types::ToolSourceKind::WorkGraph => Self::WorkGraph,
671            meerkat_core::types::ToolSourceKind::Mob => Self::Mob,
672            meerkat_core::types::ToolSourceKind::Callback => Self::Callback,
673            meerkat_core::types::ToolSourceKind::Mcp => Self::Mcp,
674            meerkat_core::types::ToolSourceKind::RustBundle => Self::RustBundle,
675        }
676    }
677}
678
679/// Typed mirror of [`meerkat_core::types::ToolProvenance`] — structural
680/// projection carried inside [`ToolVisibilityWitness`], using the typed
681/// `ToolSourceKind` discriminant mirror.
682#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
683pub struct ToolProvenance {
684    pub kind: ToolSourceKind,
685    pub source_id: String,
686}
687
688impl From<&meerkat_core::types::ToolProvenance> for ToolProvenance {
689    fn from(p: &meerkat_core::types::ToolProvenance) -> Self {
690        Self {
691            kind: ToolSourceKind::from(&p.kind),
692            source_id: p.source_id.to_string(),
693        }
694    }
695}
696
697/// Typed mirror of [`meerkat_core::ToolVisibilityWitness`] — structural
698/// projection of the two optional witness fields.
699#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
700pub struct ToolVisibilityWitness {
701    pub last_seen_provenance: Option<ToolProvenance>,
702}
703
704impl From<&meerkat_core::ToolVisibilityWitness> for ToolVisibilityWitness {
705    fn from(w: &meerkat_core::ToolVisibilityWitness) -> Self {
706        Self {
707            last_seen_provenance: w.last_seen_provenance.as_ref().map(ToolProvenance::from),
708        }
709    }
710}
711
712impl ToolVisibilityWitness {
713    pub fn from_domain(id: &meerkat_core::ToolVisibilityWitness) -> Self {
714        Self::from(id)
715    }
716
717    fn len(&self) -> u64 {
718        u64::from(self.last_seen_provenance.is_some())
719    }
720}
721
722/// Bridging type for an MCP server identifier, matching the catalog type.
723/// Used as the key in `mcp_server_states` and carried on MCP lifecycle
724/// inputs and effects.
725#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
726pub struct McpServerId(pub String);
727
728impl<T: Into<String>> From<T> for McpServerId {
729    fn from(s: T) -> Self {
730        Self(s.into())
731    }
732}
733
734/// Bridging wrapper mapping [`meerkat_core::PeerCorrelationId`] into the DSL
735/// macro's type system. Keyed map values for `pending_peer_requests` and
736/// `inbound_peer_requests`; carried on every W1-A peer-lifecycle input and
737/// effect.
738#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
739pub struct PeerCorrelationId(pub String);
740
741impl From<meerkat_core::PeerCorrelationId> for PeerCorrelationId {
742    fn from(id: meerkat_core::PeerCorrelationId) -> Self {
743        Self(id.0.to_string())
744    }
745}
746
747impl From<uuid::Uuid> for PeerCorrelationId {
748    fn from(id: uuid::Uuid) -> Self {
749        Self(id.to_string())
750    }
751}
752
753impl From<String> for PeerCorrelationId {
754    fn from(s: String) -> Self {
755        Self(s)
756    }
757}
758
759impl From<&str> for PeerCorrelationId {
760    fn from(s: &str) -> Self {
761        Self(s.to_string())
762    }
763}
764
765/// Typed outbound peer-request state, mirroring
766/// [`meerkat_core::OutboundPeerRequestState`]. Unit variants only; failure
767/// reason travels on the `PeerResponseTerminalArrived` input's companion
768/// fields, not in the enum.
769#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
770pub enum OutboundPeerRequestState {
771    #[default]
772    Sent,
773    AcceptedProgress,
774    Completed,
775    Failed,
776    TimedOut,
777}
778
779impl From<meerkat_core::OutboundPeerRequestState> for OutboundPeerRequestState {
780    #[allow(clippy::panic)]
781    fn from(s: meerkat_core::OutboundPeerRequestState) -> Self {
782        match s {
783            meerkat_core::OutboundPeerRequestState::Sent => Self::Sent,
784            meerkat_core::OutboundPeerRequestState::AcceptedProgress => Self::AcceptedProgress,
785            meerkat_core::OutboundPeerRequestState::Completed => Self::Completed,
786            meerkat_core::OutboundPeerRequestState::Failed => Self::Failed,
787            meerkat_core::OutboundPeerRequestState::TimedOut => Self::TimedOut,
788            _ => panic!(
789                "unsupported OutboundPeerRequestState variant; update generated MeerkatMachine mirror"
790            ),
791        }
792    }
793}
794
795impl From<OutboundPeerRequestState> for meerkat_core::OutboundPeerRequestState {
796    fn from(s: OutboundPeerRequestState) -> Self {
797        match s {
798            OutboundPeerRequestState::Sent => Self::Sent,
799            OutboundPeerRequestState::AcceptedProgress => Self::AcceptedProgress,
800            OutboundPeerRequestState::Completed => Self::Completed,
801            OutboundPeerRequestState::Failed => Self::Failed,
802            OutboundPeerRequestState::TimedOut => Self::TimedOut,
803        }
804    }
805}
806
807/// Typed inbound peer-request state, mirroring
808/// [`meerkat_core::InboundPeerRequestState`].
809#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
810pub enum InboundPeerRequestState {
811    #[default]
812    Received,
813    Replied,
814}
815
816impl From<meerkat_core::InboundPeerRequestState> for InboundPeerRequestState {
817    #[allow(clippy::panic)]
818    fn from(s: meerkat_core::InboundPeerRequestState) -> Self {
819        match s {
820            meerkat_core::InboundPeerRequestState::Received => Self::Received,
821            meerkat_core::InboundPeerRequestState::Replied => Self::Replied,
822            _ => panic!(
823                "unsupported InboundPeerRequestState variant; update generated MeerkatMachine mirror"
824            ),
825        }
826    }
827}
828
829impl From<InboundPeerRequestState> for meerkat_core::InboundPeerRequestState {
830    fn from(s: InboundPeerRequestState) -> Self {
831        match s {
832            InboundPeerRequestState::Received => Self::Received,
833            InboundPeerRequestState::Replied => Self::Replied,
834        }
835    }
836}
837
838/// Typed terminal disposition carried on `PeerResponseTerminalArrived`.
839/// Mirror of [`meerkat_core::handles::PeerTerminalDisposition`].
840#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
841pub enum PeerTerminalDisposition {
842    #[default]
843    Completed,
844    Failed,
845}
846
847impl From<meerkat_core::handles::PeerTerminalDisposition> for PeerTerminalDisposition {
848    #[allow(clippy::panic)]
849    fn from(d: meerkat_core::handles::PeerTerminalDisposition) -> Self {
850        match d {
851            meerkat_core::handles::PeerTerminalDisposition::Completed => Self::Completed,
852            meerkat_core::handles::PeerTerminalDisposition::Failed => Self::Failed,
853            _ => panic!(
854                "unsupported PeerTerminalDisposition variant; update generated MeerkatMachine mirror"
855            ),
856        }
857    }
858}
859
860/// Typed lifecycle state of an interaction stream reservation (U6 / dogma #5).
861///
862/// Owns whether a reserved subscriber/stream channel is still claimable
863/// (`Reserved`), live with an attached consumer (`Attached`), or terminal
864/// (`Completed` after a terminal event won, `Expired` after the TTL elapsed
865/// without an attach, `ClosedEarly` after the consumer dropped the stream
866/// before terminal). Mirror of [`meerkat_core::InteractionStreamState`].
867#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
868pub enum InteractionStreamState {
869    #[default]
870    Reserved,
871    Attached,
872    Completed,
873    Expired,
874    ClosedEarly,
875}
876
877impl From<meerkat_core::InteractionStreamState> for InteractionStreamState {
878    #[allow(clippy::panic)]
879    fn from(s: meerkat_core::InteractionStreamState) -> Self {
880        match s {
881            meerkat_core::InteractionStreamState::Reserved => Self::Reserved,
882            meerkat_core::InteractionStreamState::Attached => Self::Attached,
883            meerkat_core::InteractionStreamState::Completed => Self::Completed,
884            meerkat_core::InteractionStreamState::Expired => Self::Expired,
885            meerkat_core::InteractionStreamState::ClosedEarly => Self::ClosedEarly,
886            _ => panic!(
887                "unsupported InteractionStreamState variant; update generated MeerkatMachine mirror"
888            ),
889        }
890    }
891}
892
893impl From<InteractionStreamState> for meerkat_core::InteractionStreamState {
894    fn from(s: InteractionStreamState) -> Self {
895        match s {
896            InteractionStreamState::Reserved => Self::Reserved,
897            InteractionStreamState::Attached => Self::Attached,
898            InteractionStreamState::Completed => Self::Completed,
899            InteractionStreamState::Expired => Self::Expired,
900            InteractionStreamState::ClosedEarly => Self::ClosedEarly,
901        }
902    }
903}
904
905/// Per-server MCP connection lifecycle state. Matches the catalog copy;
906/// unit variants only so the DSL can reason about state via map inserts.
907/// Failure detail travels on the `McpServerFailed` input and
908/// `McpServerStateChanged` effect's companion fields, not on the enum.
909#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
910pub enum McpServerState {
911    #[default]
912    PendingConnect,
913    Connected,
914    Failed,
915    Disconnected,
916}
917
918/// Stable identity of a comms runtime instance (W2-G / issue #264).
919///
920/// The runtime derives this string from the `Arc<dyn CommsRuntime>` pointer
921/// address via `CommsRuntimeId::from_runtime()`. The DSL treats it as an
922/// opaque newtype; two distinct `Arc`s produce distinct ids so the owner
923/// invariant can catch silent transport swaps.
924#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
925pub struct CommsRuntimeId(pub String);
926
927impl<T: Into<String>> From<T> for CommsRuntimeId {
928    fn from(s: T) -> Self {
929        Self(s.into())
930    }
931}
932
933impl CommsRuntimeId {
934    /// Derive a stable id from an `Arc<dyn CommsRuntime>`'s pointer address.
935    ///
936    /// Two `Arc` instances with the same pointee produce the same id; two
937    /// distinct `Arc` instances produce distinct ids even if their contents
938    /// are equivalent. This is sufficient for detecting silent transport
939    /// swaps at the DSL boundary.
940    pub fn from_runtime(runtime: &std::sync::Arc<dyn meerkat_core::agent::CommsRuntime>) -> Self {
941        let ptr = std::sync::Arc::as_ptr(runtime).cast::<()>() as usize;
942        Self(format!("comms-runtime-0x{ptr:x}"))
943    }
944}
945
946/// Mob instance identifier for peer-ingress ownership (W2-G / issue #264).
947///
948/// Bridging newtype mirroring `meerkat_mob::ids::MobId`. The DSL layer keeps
949/// this opaque because `meerkat-runtime` does not depend on `meerkat-mob`;
950/// the shell stringifies the real `MobId` before firing `AttachMobIngress`.
951#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
952pub struct MobId(pub String);
953
954impl<T: Into<String>> From<T> for MobId {
955    fn from(s: T) -> Self {
956        Self(s.into())
957    }
958}
959
960/// Parsed transport envelope class for peer ingress.
961///
962/// This is the mechanical shape comms may derive from a wire envelope before
963/// semantic admission. The DSL consumes it to own the peer-input class,
964/// auth-exemption, lifecycle, silent-routing, and response-terminal facts.
965#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
966pub enum PeerIngressEnvelopeClass {
967    #[default]
968    Message,
969    Request,
970    Lifecycle,
971    Response,
972    Ack,
973}
974
975/// DSL-owned admitted ingress kind.
976#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
977pub enum PeerIngressAdmittedKind {
978    #[default]
979    Message,
980    Request,
981    Response,
982    Ack,
983    PlainEvent,
984}
985
986/// DSL-owned peer input class.
987#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
988pub enum PeerIngressInputClass {
989    #[default]
990    ActionableMessage,
991    ActionableRequest,
992    ResponseProgress,
993    ResponseTerminal,
994    PeerLifecycleAdded,
995    PeerLifecycleRetired,
996    PeerLifecycleUnwired,
997    SilentRequest,
998    Ack,
999    PlainEvent,
1000}
1001
1002/// DSL-owned peer lifecycle classifier.
1003#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
1004pub enum PeerIngressLifecycleClass {
1005    #[default]
1006    PeerAdded,
1007    PeerRetired,
1008    PeerUnwired,
1009}
1010
1011/// DSL-owned peer ingress auth classifier.
1012#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
1013pub enum PeerIngressAuthClass {
1014    #[default]
1015    Required,
1016    SupervisorBridgeExempt,
1017}
1018
1019/// Parsed response status for peer ingress.
1020#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
1021pub enum PeerIngressResponseStatus {
1022    #[default]
1023    Accepted,
1024    Completed,
1025    Failed,
1026}
1027
1028/// Closed classifier for peer-ingress request intents that drive fixed
1029/// lifecycle routing (mob peer add/retire/unwire) plus the supervisor-bridge
1030/// channel. The machine guards on this typed class; arbitrary user-configured
1031/// silent intents remain an open set matched against the raw `request_intent`
1032/// string via `silent_intent_overrides`, so `Other` covers everything outside
1033/// the closed routing set.
1034#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
1035pub enum PeerIngressRequestClass {
1036    #[default]
1037    Other,
1038    MobPeerAdded,
1039    MobPeerRetired,
1040    MobPeerUnwired,
1041    SupervisorBridge,
1042}
1043
1044/// DSL-owned response progress/terminal classifier.
1045#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
1046pub enum PeerIngressResponseTerminality {
1047    #[default]
1048    Progress,
1049    TerminalCompleted,
1050    TerminalFailed,
1051}
1052
1053/// DSL-owned public peer-ingress authority phase.
1054#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
1055pub enum PeerIngressAuthorityPhaseClass {
1056    #[default]
1057    Absent,
1058    Received,
1059    Dropped,
1060    Delivered,
1061}
1062
1063impl From<PeerIngressAuthorityPhaseClass> for meerkat_core::PeerIngressAuthorityPhase {
1064    fn from(phase: PeerIngressAuthorityPhaseClass) -> Self {
1065        match phase {
1066            PeerIngressAuthorityPhaseClass::Absent => Self::Absent,
1067            PeerIngressAuthorityPhaseClass::Received => Self::Received,
1068            PeerIngressAuthorityPhaseClass::Dropped => Self::Dropped,
1069            PeerIngressAuthorityPhaseClass::Delivered => Self::Delivered,
1070        }
1071    }
1072}
1073
1074/// DSL-owned receive/admission result for classified peer ingress.
1075#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
1076pub enum PeerIngressReceiveOutcomeClass {
1077    #[default]
1078    Admitted,
1079    DroppedUntrustedSender,
1080    DroppedSessionClosed,
1081    DroppedInboxFull,
1082}
1083
1084impl From<PeerIngressReceiveOutcomeClass> for meerkat_core::PeerIngressReceiveOutcome {
1085    fn from(outcome: PeerIngressReceiveOutcomeClass) -> Self {
1086        match outcome {
1087            PeerIngressReceiveOutcomeClass::Admitted => Self::Admitted,
1088            PeerIngressReceiveOutcomeClass::DroppedUntrustedSender => Self::DroppedUntrustedSender,
1089            PeerIngressReceiveOutcomeClass::DroppedSessionClosed => Self::DroppedSessionClosed,
1090            PeerIngressReceiveOutcomeClass::DroppedInboxFull => Self::DroppedInboxFull,
1091        }
1092    }
1093}
1094
1095/// DSL-owned admission diagnostic copy emitted with receive authority.
1096#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
1097pub enum PeerIngressAdmissionDiagnosticClass {
1098    #[default]
1099    TrustedAtAdmission,
1100    UntrustedAtAdmission,
1101}
1102
1103impl From<PeerIngressAdmissionDiagnosticClass> for meerkat_core::PeerIngressAdmissionDiagnostic {
1104    fn from(diagnostic: PeerIngressAdmissionDiagnosticClass) -> Self {
1105        match diagnostic {
1106            PeerIngressAdmissionDiagnosticClass::TrustedAtAdmission => Self::TrustedAtAdmission,
1107            PeerIngressAdmissionDiagnosticClass::UntrustedAtAdmission => Self::UntrustedAtAdmission,
1108        }
1109    }
1110}
1111
1112/// Peer-ingress transport capability ownership kind (W2-G / issue #264).
1113///
1114/// Paired with `peer_ingress_comms_runtime_id` and `peer_ingress_mob_id` in
1115/// DSL state; `peer_ingress_owner_consistency` enforces pairing. Silent
1116/// downgrade `MobOwned` → `SessionOwned` is structurally impossible:
1117/// `AttachSessionIngress` requires `Unattached`; `AttachMobIngress` permits
1118/// `Unattached` or `SessionOwned` but never `MobOwned` → `SessionOwned`.
1119#[derive(
1120    Debug,
1121    Clone,
1122    Copy,
1123    PartialEq,
1124    Eq,
1125    PartialOrd,
1126    Ord,
1127    Hash,
1128    Default,
1129    serde::Serialize,
1130    serde::Deserialize,
1131)]
1132pub enum PeerIngressOwnerKind {
1133    #[default]
1134    Unattached,
1135    SessionOwned,
1136    MobOwned,
1137}
1138
1139/// Supervisor-bridge authorization kind (Wave 3 D Row 21).
1140///
1141/// Paired with `supervisor_bound_{name, peer_id, address, epoch}` in DSL
1142/// state; `supervisor_binding_consistency` enforces pairing. Rotation is
1143/// structural: `BindSupervisor` requires `Unbound`; `AuthorizeSupervisor`
1144/// requires `Bound`; `RevokeSupervisor` requires `Bound` and returns to
1145/// `Unbound`. Before Wave 3 D this fact lived as an `Option<AuthorizedSupervisorState>`
1146/// on the comms drain task's stack — the identity and epoch of the
1147/// authorized supervisor were helper-local while the corresponding trust
1148/// edge was router-owned. Moving the authorization discriminant + epoch
1149/// into DSL state collapses that split ownership.
1150#[derive(
1151    Debug,
1152    Clone,
1153    Copy,
1154    PartialEq,
1155    Eq,
1156    PartialOrd,
1157    Ord,
1158    Hash,
1159    Default,
1160    serde::Serialize,
1161    serde::Deserialize,
1162)]
1163pub enum SupervisorBindingKind {
1164    #[default]
1165    Unbound,
1166    Bound,
1167}
1168
1169/// Typed turn-execution phase, mirrored 1:1 by the closed set of literals the
1170/// DSL transitions assign to `turn_phase`. Replaces the prior stringly-typed
1171/// encoding so the ephemeral driver and runtime handles consume an exhaustive
1172/// enum instead of parsing folklore.
1173#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
1174pub enum TurnPhase {
1175    #[default]
1176    Ready,
1177    ApplyingPrimitive,
1178    CallingLlm,
1179    WaitingForOps,
1180    DrainingBoundary,
1181    Extracting,
1182    ErrorRecovery,
1183    Cancelling,
1184    Completed,
1185    Failed,
1186    Cancelled,
1187}
1188
1189impl TurnPhase {
1190    pub const fn as_str(self) -> &'static str {
1191        match self {
1192            Self::Ready => "Ready",
1193            Self::ApplyingPrimitive => "ApplyingPrimitive",
1194            Self::CallingLlm => "CallingLlm",
1195            Self::WaitingForOps => "WaitingForOps",
1196            Self::DrainingBoundary => "DrainingBoundary",
1197            Self::Extracting => "Extracting",
1198            Self::ErrorRecovery => "ErrorRecovery",
1199            Self::Cancelling => "Cancelling",
1200            Self::Completed => "Completed",
1201            Self::Failed => "Failed",
1202            Self::Cancelled => "Cancelled",
1203        }
1204    }
1205}
1206
1207/// Typed registration substate. Closed set of literals previously assigned to
1208/// `registration_phase`.
1209#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
1210pub enum RegistrationPhase {
1211    #[default]
1212    Queuing,
1213    Active,
1214    Draining,
1215}
1216
1217impl RegistrationPhase {
1218    pub const fn as_str(self) -> &'static str {
1219        match self {
1220            Self::Queuing => "Queuing",
1221            Self::Active => "Active",
1222            Self::Draining => "Draining",
1223        }
1224    }
1225}
1226
1227/// Typed comms drain substate. Mirrors the closed set of literals the DSL
1228/// transitions assign to `drain_phase`.
1229#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
1230pub enum DrainPhase {
1231    #[default]
1232    Inactive,
1233    Running,
1234    Stopped,
1235    ExitedRespawnable,
1236}
1237
1238impl DrainPhase {
1239    pub const fn as_str(self) -> &'static str {
1240        match self {
1241            Self::Inactive => "Inactive",
1242            Self::Running => "Running",
1243            Self::Stopped => "Stopped",
1244            Self::ExitedRespawnable => "ExitedRespawnable",
1245        }
1246    }
1247}
1248
1249/// Typed comms drain mode. Mirrors `crate::meerkat_machine::CommsDrainMode`
1250/// (which is the shell-side enum) so the DSL can hold a closed set of typed
1251/// variants instead of a `Debug`-formatted string.
1252#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
1253pub enum DrainMode {
1254    #[default]
1255    Timed,
1256    AttachedSession,
1257    PersistentHost,
1258}
1259
1260impl DrainMode {
1261    pub const fn as_str(self) -> &'static str {
1262        match self {
1263            Self::Timed => "Timed",
1264            Self::AttachedSession => "AttachedSession",
1265            Self::PersistentHost => "PersistentHost",
1266        }
1267    }
1268}
1269
1270impl From<crate::meerkat_machine::CommsDrainMode> for DrainMode {
1271    fn from(mode: crate::meerkat_machine::CommsDrainMode) -> Self {
1272        match mode {
1273            crate::meerkat_machine::CommsDrainMode::Timed => Self::Timed,
1274            crate::meerkat_machine::CommsDrainMode::AttachedSession => Self::AttachedSession,
1275            crate::meerkat_machine::CommsDrainMode::PersistentHost => Self::PersistentHost,
1276        }
1277    }
1278}
1279
1280/// Typed external-tool surface global phase. Closed set of literals previously
1281/// assigned to `surface_phase`.
1282#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
1283pub enum SurfacePhase {
1284    #[default]
1285    Operating,
1286    Shutdown,
1287}
1288
1289impl SurfacePhase {
1290    pub const fn as_str(self) -> &'static str {
1291        match self {
1292            Self::Operating => "Operating",
1293            Self::Shutdown => "Shutdown",
1294        }
1295    }
1296}
1297
1298/// Typed input-lifecycle phase, mirroring the closed set of literals the DSL
1299/// transitions assign to `input_phases`. The shell projects from this onto the
1300/// richer `crate::input_state::InputLifecycleState` (which keeps an `Accepted`
1301/// pre-DSL-admission variant the DSL itself never writes).
1302#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
1303pub enum InputPhase {
1304    #[default]
1305    Queued,
1306    Staged,
1307    Applied,
1308    AppliedPendingConsumption,
1309    Consumed,
1310    Superseded,
1311    Coalesced,
1312    Abandoned,
1313}
1314
1315impl InputPhase {
1316    pub const fn as_str(self) -> &'static str {
1317        match self {
1318            Self::Queued => "Queued",
1319            Self::Staged => "Staged",
1320            Self::Applied => "Applied",
1321            Self::AppliedPendingConsumption => "AppliedPendingConsumption",
1322            Self::Consumed => "Consumed",
1323            Self::Superseded => "Superseded",
1324            Self::Coalesced => "Coalesced",
1325            Self::Abandoned => "Abandoned",
1326        }
1327    }
1328}
1329
1330#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
1331pub enum RecoveredInputObservedPhase {
1332    Accepted,
1333    #[default]
1334    Queued,
1335    Staged,
1336    Applied,
1337    AppliedPendingConsumption,
1338    Consumed,
1339    Superseded,
1340    Coalesced,
1341    Abandoned,
1342}
1343
1344/// Typed input terminal kind, mirroring the closed set of literals the DSL
1345/// transitions assign to `input_terminal_kind`. The companion fields
1346/// (`input_superseded_by`, `input_aggregate_id`, `input_abandon_reason`,
1347/// `input_abandon_attempt_count`) carry payload metadata for variants that
1348/// need it.
1349#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
1350pub enum InputTerminalKind {
1351    #[default]
1352    Consumed,
1353    Superseded,
1354    Coalesced,
1355    Abandoned,
1356}
1357
1358impl InputTerminalKind {
1359    pub const fn as_str(self) -> &'static str {
1360        match self {
1361            Self::Consumed => "Consumed",
1362            Self::Superseded => "Superseded",
1363            Self::Coalesced => "Coalesced",
1364            Self::Abandoned => "Abandoned",
1365        }
1366    }
1367}
1368
1369/// Public lifecycle class emitted by generated authority before runtime
1370/// surfaces project input state onto their transport enums.
1371#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
1372pub enum InputPublicLifecycleState {
1373    #[default]
1374    Accepted,
1375    Queued,
1376    Staged,
1377    Applied,
1378    AppliedPendingConsumption,
1379    Consumed,
1380    Superseded,
1381    Coalesced,
1382    Abandoned,
1383}
1384
1385impl InputPublicLifecycleState {
1386    pub const fn as_str(self) -> &'static str {
1387        match self {
1388            Self::Accepted => "Accepted",
1389            Self::Queued => "Queued",
1390            Self::Staged => "Staged",
1391            Self::Applied => "Applied",
1392            Self::AppliedPendingConsumption => "AppliedPendingConsumption",
1393            Self::Consumed => "Consumed",
1394            Self::Superseded => "Superseded",
1395            Self::Coalesced => "Coalesced",
1396            Self::Abandoned => "Abandoned",
1397        }
1398    }
1399}
1400
1401/// Public terminal result class emitted by generated authority before runtime
1402/// surfaces project input state onto their transport enums.
1403#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
1404pub enum InputPublicTerminalOutcome {
1405    #[default]
1406    Completed,
1407    Abandoned,
1408    Superseded,
1409    Coalesced,
1410    Cancelled,
1411}
1412
1413impl InputPublicTerminalOutcome {
1414    pub const fn as_str(self) -> &'static str {
1415        match self {
1416            Self::Completed => "Completed",
1417            Self::Abandoned => "Abandoned",
1418            Self::Superseded => "Superseded",
1419            Self::Coalesced => "Coalesced",
1420            Self::Cancelled => "Cancelled",
1421        }
1422    }
1423}
1424
1425/// Typed pending external-surface op. Closed set of literals previously
1426/// assigned to `surface_pending_op`.
1427#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
1428pub enum SurfacePendingOp {
1429    #[default]
1430    None,
1431    Add,
1432    Reload,
1433}
1434
1435impl SurfacePendingOp {
1436    pub const fn as_str(self) -> &'static str {
1437        match self {
1438            Self::None => "None",
1439            Self::Add => "Add",
1440            Self::Reload => "Reload",
1441        }
1442    }
1443}
1444
1445/// Typed staged external-surface op. Closed set of literals previously
1446/// assigned to `surface_staged_op`.
1447#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
1448pub enum SurfaceStagedOp {
1449    #[default]
1450    None,
1451    Add,
1452    Remove,
1453    Reload,
1454}
1455
1456impl SurfaceStagedOp {
1457    pub const fn as_str(self) -> &'static str {
1458        match self {
1459            Self::None => "None",
1460            Self::Add => "Add",
1461            Self::Remove => "Remove",
1462            Self::Reload => "Reload",
1463        }
1464    }
1465}
1466
1467/// Typed turn primitive kind. Closed mirror of
1468/// [`meerkat_core::turn_execution_authority::TurnPrimitiveKind`] — replaces the
1469/// former literal-string `primitive_kind` field and `StartConversationRun`
1470/// input field.
1471#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
1472pub enum TurnPrimitiveKind {
1473    #[default]
1474    None,
1475    ConversationTurn,
1476    ImmediateAppend,
1477    ImmediateContextAppend,
1478}
1479
1480impl From<meerkat_core::turn_execution_authority::TurnPrimitiveKind> for TurnPrimitiveKind {
1481    fn from(kind: meerkat_core::turn_execution_authority::TurnPrimitiveKind) -> Self {
1482        match kind {
1483            meerkat_core::turn_execution_authority::TurnPrimitiveKind::None => Self::None,
1484            meerkat_core::turn_execution_authority::TurnPrimitiveKind::ConversationTurn => {
1485                Self::ConversationTurn
1486            }
1487            meerkat_core::turn_execution_authority::TurnPrimitiveKind::ImmediateAppend => {
1488                Self::ImmediateAppend
1489            }
1490            meerkat_core::turn_execution_authority::TurnPrimitiveKind::ImmediateContextAppend => {
1491                Self::ImmediateContextAppend
1492            }
1493        }
1494    }
1495}
1496
1497impl From<TurnPrimitiveKind> for meerkat_core::turn_execution_authority::TurnPrimitiveKind {
1498    fn from(kind: TurnPrimitiveKind) -> Self {
1499        match kind {
1500            TurnPrimitiveKind::None => Self::None,
1501            TurnPrimitiveKind::ConversationTurn => Self::ConversationTurn,
1502            TurnPrimitiveKind::ImmediateAppend => Self::ImmediateAppend,
1503            TurnPrimitiveKind::ImmediateContextAppend => Self::ImmediateContextAppend,
1504        }
1505    }
1506}
1507
1508/// Typed turn primitive content shape. Closed mirror of
1509/// [`meerkat_core::turn_execution_authority::ContentShape`] so the runtime DSL
1510/// carries the same contract instead of local string labels.
1511#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
1512pub enum ContentShape {
1513    #[default]
1514    Conversation,
1515    ConversationAndContext,
1516    Context,
1517    Empty,
1518    ImmediateAppend,
1519    ImmediateContext,
1520}
1521
1522impl ContentShape {
1523    pub const fn as_str(self) -> &'static str {
1524        match self {
1525            Self::Conversation => {
1526                meerkat_core::turn_execution_authority::ContentShape::Conversation.as_str()
1527            }
1528            Self::ConversationAndContext => {
1529                meerkat_core::turn_execution_authority::ContentShape::ConversationAndContext
1530                    .as_str()
1531            }
1532            Self::Context => meerkat_core::turn_execution_authority::ContentShape::Context.as_str(),
1533            Self::Empty => meerkat_core::turn_execution_authority::ContentShape::Empty.as_str(),
1534            Self::ImmediateAppend => {
1535                meerkat_core::turn_execution_authority::ContentShape::ImmediateAppend.as_str()
1536            }
1537            Self::ImmediateContext => {
1538                meerkat_core::turn_execution_authority::ContentShape::ImmediateContext.as_str()
1539            }
1540        }
1541    }
1542}
1543
1544impl std::fmt::Display for ContentShape {
1545    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1546        f.write_str(self.as_str())
1547    }
1548}
1549
1550impl From<meerkat_core::turn_execution_authority::ContentShape> for ContentShape {
1551    fn from(shape: meerkat_core::turn_execution_authority::ContentShape) -> Self {
1552        match shape {
1553            meerkat_core::turn_execution_authority::ContentShape::Conversation => {
1554                Self::Conversation
1555            }
1556            meerkat_core::turn_execution_authority::ContentShape::ConversationAndContext => {
1557                Self::ConversationAndContext
1558            }
1559            meerkat_core::turn_execution_authority::ContentShape::Context => Self::Context,
1560            meerkat_core::turn_execution_authority::ContentShape::Empty => Self::Empty,
1561            meerkat_core::turn_execution_authority::ContentShape::ImmediateAppend => {
1562                Self::ImmediateAppend
1563            }
1564            meerkat_core::turn_execution_authority::ContentShape::ImmediateContext => {
1565                Self::ImmediateContext
1566            }
1567        }
1568    }
1569}
1570
1571impl From<ContentShape> for meerkat_core::turn_execution_authority::ContentShape {
1572    fn from(shape: ContentShape) -> Self {
1573        match shape {
1574            ContentShape::Conversation => Self::Conversation,
1575            ContentShape::ConversationAndContext => Self::ConversationAndContext,
1576            ContentShape::Context => Self::Context,
1577            ContentShape::Empty => Self::Empty,
1578            ContentShape::ImmediateAppend => Self::ImmediateAppend,
1579            ContentShape::ImmediateContext => Self::ImmediateContext,
1580        }
1581    }
1582}
1583
1584/// Typed turn terminal outcome. Closed mirror of
1585/// [`meerkat_core::turn_execution_authority::TurnTerminalOutcome`] — replaces
1586/// the former literal-string `terminal_outcome` field.
1587#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
1588pub enum TurnTerminalOutcome {
1589    #[default]
1590    None,
1591    Completed,
1592    Failed,
1593    Cancelled,
1594    BudgetExhausted,
1595    TimeBudgetExceeded,
1596    StructuredOutputValidationFailed,
1597}
1598
1599impl From<meerkat_core::turn_execution_authority::TurnTerminalOutcome> for TurnTerminalOutcome {
1600    fn from(outcome: meerkat_core::turn_execution_authority::TurnTerminalOutcome) -> Self {
1601        match outcome {
1602            meerkat_core::turn_execution_authority::TurnTerminalOutcome::None => Self::None,
1603            meerkat_core::turn_execution_authority::TurnTerminalOutcome::Completed => {
1604                Self::Completed
1605            }
1606            meerkat_core::turn_execution_authority::TurnTerminalOutcome::Failed => Self::Failed,
1607            meerkat_core::turn_execution_authority::TurnTerminalOutcome::Cancelled => {
1608                Self::Cancelled
1609            }
1610            meerkat_core::turn_execution_authority::TurnTerminalOutcome::BudgetExhausted => {
1611                Self::BudgetExhausted
1612            }
1613            meerkat_core::turn_execution_authority::TurnTerminalOutcome::TimeBudgetExceeded => {
1614                Self::TimeBudgetExceeded
1615            }
1616            meerkat_core::turn_execution_authority::TurnTerminalOutcome::StructuredOutputValidationFailed => {
1617                Self::StructuredOutputValidationFailed
1618            }
1619        }
1620    }
1621}
1622
1623impl From<TurnTerminalOutcome> for meerkat_core::turn_execution_authority::TurnTerminalOutcome {
1624    fn from(outcome: TurnTerminalOutcome) -> Self {
1625        match outcome {
1626            TurnTerminalOutcome::None => Self::None,
1627            TurnTerminalOutcome::Completed => Self::Completed,
1628            TurnTerminalOutcome::Failed => Self::Failed,
1629            TurnTerminalOutcome::Cancelled => Self::Cancelled,
1630            TurnTerminalOutcome::BudgetExhausted => Self::BudgetExhausted,
1631            TurnTerminalOutcome::TimeBudgetExceeded => Self::TimeBudgetExceeded,
1632            TurnTerminalOutcome::StructuredOutputValidationFailed => {
1633                Self::StructuredOutputValidationFailed
1634            }
1635        }
1636    }
1637}
1638
1639/// Typed turn terminal cause. Closed mirror of
1640/// [`meerkat_core::turn_execution_authority::TurnTerminalCauseKind`] carried by
1641/// MeerkatMachine terminal failure inputs/effects so display messages cannot
1642/// classify terminal failures.
1643#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
1644pub enum TurnTerminalCauseKind {
1645    #[default]
1646    Unknown,
1647    HookDenied,
1648    HookFailure,
1649    LlmFailure,
1650    ToolFailure,
1651    StructuredOutputValidationFailed,
1652    BudgetExhausted,
1653    TimeBudgetExceeded,
1654    RetryExhausted,
1655    TurnLimitReached,
1656    RuntimeApplyFailure,
1657    FatalFailure,
1658}
1659
1660impl From<meerkat_core::turn_execution_authority::TurnTerminalCauseKind> for TurnTerminalCauseKind {
1661    fn from(kind: meerkat_core::turn_execution_authority::TurnTerminalCauseKind) -> Self {
1662        match kind {
1663            meerkat_core::turn_execution_authority::TurnTerminalCauseKind::Unknown => {
1664                Self::Unknown
1665            }
1666            meerkat_core::turn_execution_authority::TurnTerminalCauseKind::HookDenied => {
1667                Self::HookDenied
1668            }
1669            meerkat_core::turn_execution_authority::TurnTerminalCauseKind::HookFailure => {
1670                Self::HookFailure
1671            }
1672            meerkat_core::turn_execution_authority::TurnTerminalCauseKind::LlmFailure => {
1673                Self::LlmFailure
1674            }
1675            meerkat_core::turn_execution_authority::TurnTerminalCauseKind::ToolFailure => {
1676                Self::ToolFailure
1677            }
1678            meerkat_core::turn_execution_authority::TurnTerminalCauseKind::StructuredOutputValidationFailed => {
1679                Self::StructuredOutputValidationFailed
1680            }
1681            meerkat_core::turn_execution_authority::TurnTerminalCauseKind::BudgetExhausted => {
1682                Self::BudgetExhausted
1683            }
1684            meerkat_core::turn_execution_authority::TurnTerminalCauseKind::TimeBudgetExceeded => {
1685                Self::TimeBudgetExceeded
1686            }
1687            meerkat_core::turn_execution_authority::TurnTerminalCauseKind::RetryExhausted => {
1688                Self::RetryExhausted
1689            }
1690            meerkat_core::turn_execution_authority::TurnTerminalCauseKind::TurnLimitReached => {
1691                Self::TurnLimitReached
1692            }
1693            meerkat_core::turn_execution_authority::TurnTerminalCauseKind::RuntimeApplyFailure => {
1694                Self::RuntimeApplyFailure
1695            }
1696            meerkat_core::turn_execution_authority::TurnTerminalCauseKind::FatalFailure => {
1697                Self::FatalFailure
1698            }
1699        }
1700    }
1701}
1702
1703impl From<TurnTerminalCauseKind> for meerkat_core::turn_execution_authority::TurnTerminalCauseKind {
1704    fn from(kind: TurnTerminalCauseKind) -> Self {
1705        match kind {
1706            TurnTerminalCauseKind::Unknown => Self::Unknown,
1707            TurnTerminalCauseKind::HookDenied => Self::HookDenied,
1708            TurnTerminalCauseKind::HookFailure => Self::HookFailure,
1709            TurnTerminalCauseKind::LlmFailure => Self::LlmFailure,
1710            TurnTerminalCauseKind::ToolFailure => Self::ToolFailure,
1711            TurnTerminalCauseKind::StructuredOutputValidationFailed => {
1712                Self::StructuredOutputValidationFailed
1713            }
1714            TurnTerminalCauseKind::BudgetExhausted => Self::BudgetExhausted,
1715            TurnTerminalCauseKind::TimeBudgetExceeded => Self::TimeBudgetExceeded,
1716            TurnTerminalCauseKind::RetryExhausted => Self::RetryExhausted,
1717            TurnTerminalCauseKind::TurnLimitReached => Self::TurnLimitReached,
1718            TurnTerminalCauseKind::RuntimeApplyFailure => Self::RuntimeApplyFailure,
1719            TurnTerminalCauseKind::FatalFailure => Self::FatalFailure,
1720        }
1721    }
1722}
1723
1724/// Normalized terminal-cause class for surface-result classification. The DSL
1725/// owns the typed mirror so the `ClassifyTurnTerminalCauseClass` /
1726/// `ResolveTurnSurfaceResult` transitions can carry it; the
1727/// `terminal_surface_mapping` codegen derives the classification table from
1728/// those transitions.
1729#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
1730pub enum TerminalCauseClass {
1731    #[default]
1732    Missing,
1733    Unknown,
1734    BudgetExhausted,
1735    TimeBudgetExceeded,
1736    RetryExhausted,
1737    StructuredOutputValidationFailed,
1738    OtherFailure,
1739}
1740
1741/// Surface result classification emitted by `ResolveTurnSurfaceResult`.
1742#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
1743pub enum SurfaceResultClass {
1744    #[default]
1745    Success,
1746    HardFailure,
1747    Cancelled,
1748    MissingTerminal,
1749}
1750
1751/// P0 Dogma Invariant 1: machine-owned LLM-failure recovery verdict emitted by
1752/// `ClassifyLlmFailureRecovery`. The DSL owns this typed mirror so the
1753/// classifier transitions can carry it; the agent loop mirrors the verdict
1754/// instead of unilaterally deciding fatal/exhaustion.
1755#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
1756pub enum LlmFailureRecoveryKind {
1757    #[default]
1758    Fatal,
1759    Recover,
1760    Exhausted,
1761}
1762
1763/// #323: pre-selected call-timeout source carried into the machine's
1764/// `ClassifyCallTimeout` classifier. Source selection is shell-side; the
1765/// machine owns the retryable-vs-terminal verdict.
1766#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
1767pub enum CallTimeoutSource {
1768    #[default]
1769    CallBudget,
1770    TurnBudget,
1771}
1772
1773/// #323: machine-owned call-timeout verdict emitted by `ClassifyCallTimeout`.
1774/// The agent loop mirrors this into the existing retry / budget-terminal paths.
1775#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
1776pub enum CallTimeoutVerdict {
1777    #[default]
1778    RetryableCallTimeout,
1779    TerminalTurnBudget,
1780}
1781
1782/// Raw failure source fact carried by runtime run-failure handoff.
1783/// MeerkatMachine maps this to terminal outcome/cause before public
1784/// projection.
1785#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
1786pub enum RunFailureSourceKind {
1787    #[default]
1788    Unknown,
1789    Llm,
1790    StoreError,
1791    ToolError,
1792    McpError,
1793    SessionNotFound,
1794    TokenBudgetExceeded,
1795    TimeBudgetExceeded,
1796    ToolCallBudgetExceeded,
1797    MaxTokensReached,
1798    ContentFiltered,
1799    MaxTurnsReached,
1800    Cancelled,
1801    InvalidStateTransition,
1802    OperationNotFound,
1803    DepthLimitExceeded,
1804    ConcurrencyLimitExceeded,
1805    ConfigError,
1806    InvalidToolAccess,
1807    SkillResolutionFailed,
1808    InternalError,
1809    BuildError,
1810    AuthReauthRequired,
1811    CallbackPending,
1812    StructuredOutputValidationFailed,
1813    InvalidOutputSchema,
1814    HookDenied,
1815    HookTimeout,
1816    HookExecutionFailed,
1817    HookConfigInvalid,
1818    TerminalFailure,
1819    NoPendingBoundary,
1820    LlmRetryExhausted,
1821}
1822
1823impl From<meerkat_core::turn_execution_authority::TurnFailureSourceKind> for RunFailureSourceKind {
1824    fn from(kind: meerkat_core::turn_execution_authority::TurnFailureSourceKind) -> Self {
1825        match kind {
1826            meerkat_core::turn_execution_authority::TurnFailureSourceKind::Unknown => {
1827                Self::Unknown
1828            }
1829            meerkat_core::turn_execution_authority::TurnFailureSourceKind::Llm => Self::Llm,
1830            meerkat_core::turn_execution_authority::TurnFailureSourceKind::StoreError => {
1831                Self::StoreError
1832            }
1833            meerkat_core::turn_execution_authority::TurnFailureSourceKind::ToolError => {
1834                Self::ToolError
1835            }
1836            meerkat_core::turn_execution_authority::TurnFailureSourceKind::McpError => {
1837                Self::McpError
1838            }
1839            meerkat_core::turn_execution_authority::TurnFailureSourceKind::SessionNotFound => {
1840                Self::SessionNotFound
1841            }
1842            meerkat_core::turn_execution_authority::TurnFailureSourceKind::TokenBudgetExceeded => {
1843                Self::TokenBudgetExceeded
1844            }
1845            meerkat_core::turn_execution_authority::TurnFailureSourceKind::TimeBudgetExceeded => {
1846                Self::TimeBudgetExceeded
1847            }
1848            meerkat_core::turn_execution_authority::TurnFailureSourceKind::ToolCallBudgetExceeded => {
1849                Self::ToolCallBudgetExceeded
1850            }
1851            meerkat_core::turn_execution_authority::TurnFailureSourceKind::MaxTokensReached => {
1852                Self::MaxTokensReached
1853            }
1854            meerkat_core::turn_execution_authority::TurnFailureSourceKind::ContentFiltered => {
1855                Self::ContentFiltered
1856            }
1857            meerkat_core::turn_execution_authority::TurnFailureSourceKind::MaxTurnsReached => {
1858                Self::MaxTurnsReached
1859            }
1860            meerkat_core::turn_execution_authority::TurnFailureSourceKind::Cancelled => {
1861                Self::Cancelled
1862            }
1863            meerkat_core::turn_execution_authority::TurnFailureSourceKind::InvalidStateTransition => {
1864                Self::InvalidStateTransition
1865            }
1866            meerkat_core::turn_execution_authority::TurnFailureSourceKind::OperationNotFound => {
1867                Self::OperationNotFound
1868            }
1869            meerkat_core::turn_execution_authority::TurnFailureSourceKind::DepthLimitExceeded => {
1870                Self::DepthLimitExceeded
1871            }
1872            meerkat_core::turn_execution_authority::TurnFailureSourceKind::ConcurrencyLimitExceeded => {
1873                Self::ConcurrencyLimitExceeded
1874            }
1875            meerkat_core::turn_execution_authority::TurnFailureSourceKind::ConfigError => {
1876                Self::ConfigError
1877            }
1878            meerkat_core::turn_execution_authority::TurnFailureSourceKind::InvalidToolAccess => {
1879                Self::InvalidToolAccess
1880            }
1881            meerkat_core::turn_execution_authority::TurnFailureSourceKind::SkillResolutionFailed => {
1882                Self::SkillResolutionFailed
1883            }
1884            meerkat_core::turn_execution_authority::TurnFailureSourceKind::InternalError => {
1885                Self::InternalError
1886            }
1887            meerkat_core::turn_execution_authority::TurnFailureSourceKind::BuildError => {
1888                Self::BuildError
1889            }
1890            meerkat_core::turn_execution_authority::TurnFailureSourceKind::AuthReauthRequired => {
1891                Self::AuthReauthRequired
1892            }
1893            meerkat_core::turn_execution_authority::TurnFailureSourceKind::CallbackPending => {
1894                Self::CallbackPending
1895            }
1896            meerkat_core::turn_execution_authority::TurnFailureSourceKind::StructuredOutputValidationFailed => {
1897                Self::StructuredOutputValidationFailed
1898            }
1899            meerkat_core::turn_execution_authority::TurnFailureSourceKind::InvalidOutputSchema => {
1900                Self::InvalidOutputSchema
1901            }
1902            meerkat_core::turn_execution_authority::TurnFailureSourceKind::HookDenied => {
1903                Self::HookDenied
1904            }
1905            meerkat_core::turn_execution_authority::TurnFailureSourceKind::HookTimeout => {
1906                Self::HookTimeout
1907            }
1908            meerkat_core::turn_execution_authority::TurnFailureSourceKind::HookExecutionFailed => {
1909                Self::HookExecutionFailed
1910            }
1911            meerkat_core::turn_execution_authority::TurnFailureSourceKind::HookConfigInvalid => {
1912                Self::HookConfigInvalid
1913            }
1914            meerkat_core::turn_execution_authority::TurnFailureSourceKind::TerminalFailure => {
1915                Self::TerminalFailure
1916            }
1917            meerkat_core::turn_execution_authority::TurnFailureSourceKind::NoPendingBoundary => {
1918                Self::NoPendingBoundary
1919            }
1920            meerkat_core::turn_execution_authority::TurnFailureSourceKind::LlmRetryExhausted => {
1921                Self::LlmRetryExhausted
1922            }
1923        }
1924    }
1925}
1926
1927/// Typed classifier for failures surfaced by the runtime apply loop when a
1928/// `CoreExecutor::apply` call fails and terminalizes the runtime turn.
1929/// The companion `last_runtime_apply_failure_message` state field carries the
1930/// human-readable projection.
1931#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
1932pub enum RuntimeApplyFailureCause {
1933    #[default]
1934    Unknown,
1935    PrimitiveRejected,
1936    RuntimeContextApply,
1937    RuntimeTurn,
1938    HookDenied,
1939    HookRuntimeFailure,
1940    ExecutorStopped,
1941    ExecutorControlFailed,
1942    ExecutorInternal,
1943}
1944
1945impl From<meerkat_core::lifecycle::CoreApplyFailureCauseKind> for RuntimeApplyFailureCause {
1946    #[allow(clippy::panic)]
1947    fn from(kind: meerkat_core::lifecycle::CoreApplyFailureCauseKind) -> Self {
1948        match kind {
1949            meerkat_core::lifecycle::CoreApplyFailureCauseKind::PrimitiveRejected => {
1950                Self::PrimitiveRejected
1951            }
1952            meerkat_core::lifecycle::CoreApplyFailureCauseKind::RuntimeContextApply => {
1953                Self::RuntimeContextApply
1954            }
1955            meerkat_core::lifecycle::CoreApplyFailureCauseKind::RuntimeTurn => Self::RuntimeTurn,
1956            meerkat_core::lifecycle::CoreApplyFailureCauseKind::HookDenied => Self::HookDenied,
1957            meerkat_core::lifecycle::CoreApplyFailureCauseKind::HookRuntimeFailure => {
1958                Self::HookRuntimeFailure
1959            }
1960            meerkat_core::lifecycle::CoreApplyFailureCauseKind::ExecutorStopped => {
1961                Self::ExecutorStopped
1962            }
1963            meerkat_core::lifecycle::CoreApplyFailureCauseKind::ExecutorControlFailed => {
1964                Self::ExecutorControlFailed
1965            }
1966            meerkat_core::lifecycle::CoreApplyFailureCauseKind::ExecutorInternal => {
1967                Self::ExecutorInternal
1968            }
1969            meerkat_core::lifecycle::CoreApplyFailureCauseKind::Unknown => Self::Unknown,
1970            _ => panic!(
1971                "unsupported CoreApplyFailureCauseKind variant; update generated MeerkatMachine mirror"
1972            ),
1973        }
1974    }
1975}
1976
1977impl From<&meerkat_core::lifecycle::CoreApplyFailureCause> for RuntimeApplyFailureCause {
1978    fn from(cause: &meerkat_core::lifecycle::CoreApplyFailureCause) -> Self {
1979        Self::from(cause.kind)
1980    }
1981}
1982
1983/// Typed pre-run phase marker. Closed set: `idle`, `attached`, `retired`.
1984/// Replaces the former literal-string `pre_run_phase` field.
1985#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
1986pub enum PreRunPhase {
1987    #[default]
1988    Idle,
1989    Attached,
1990    Retired,
1991}
1992
1993/// Generated authority for deferred session materialization.
1994///
1995/// The shell keeps bulky build payloads in a registry, but phase/admission
1996/// meaning for the staged lifecycle is owned here.
1997#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
1998pub enum StagedSessionPhase {
1999    #[default]
2000    NotStaged,
2001    Staged,
2002    Promoting,
2003    Closing,
2004}
2005
2006/// Explicit host/profile request class for mob operator access.
2007#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
2008pub enum MobOperatorAccessRequestKind {
2009    #[default]
2010    Inherit,
2011    Enable,
2012    Disable,
2013}
2014
2015/// Typed runtime notice classifier for the `RuntimeNotice` effect. Closed set
2016/// of per-transition runtime lifecycle markers (drain exited, runtime reset,
2017/// executor stopped/exited, runtime recovered) emitted by the runtime-control
2018/// plane. Replaces the former literal-string `kind` field on `RuntimeNotice`
2019/// so the shell dispatcher matches exhaustively on a typed discriminant
2020/// instead of comparing string literals. `detail` stays `String` — it's a
2021/// free-form diagnostic message that accompanies the kind.
2022#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
2023pub enum RuntimeNoticeKind {
2024    #[default]
2025    Drain,
2026    Reset,
2027    Stop,
2028    Exit,
2029    Recover,
2030}
2031
2032/// Closed top-level classifier for a published `RuntimeEvent`, mirroring the
2033/// five `RuntimeEvent` discriminants in `meerkat-runtime` (`InputLifecycle`,
2034/// `RunLifecycle`, `RuntimeStateChange`, `Topology`, `Projection`). Replaces the
2035/// former Debug-derived discriminant *string* on `PublishEvent.kind` so the DSL
2036/// carries a typed discriminant the shell maps exhaustively.
2037#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
2038pub enum RuntimeEventKind {
2039    #[default]
2040    InputLifecycle,
2041    RunLifecycle,
2042    RuntimeStateChange,
2043    Topology,
2044    Projection,
2045}
2046
2047/// Closed classifier for runtime-loop executor effects emitted as neutral DSL
2048/// facts before the runtime shell converts them to sealed executable effects.
2049#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
2050pub enum RuntimeEffectKind {
2051    #[default]
2052    CancelAfterBoundary,
2053    StopRuntimeExecutor,
2054}
2055
2056/// Typed runtime completion observation supplied by completion waiter plumbing.
2057/// Generated `ResolveRuntimeCompletionCleanup` authority owns whether that
2058/// observation permits runtime cleanup; surfaces must not match this enum to
2059/// decide cleanup locally.
2060#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
2061pub enum RuntimeCompletionObservedOutcome {
2062    #[default]
2063    Completed,
2064    CompletedWithoutResult,
2065    CallbackPending,
2066    Cancelled,
2067    Abandoned,
2068    RuntimeApplyFailed,
2069    FinalizationFailed,
2070    RuntimeTerminated,
2071}
2072
2073/// Typed observation of the terminal payload shape produced by runtime-loop
2074/// execution. This is input evidence only; the generated
2075/// `ResolveRuntimeCompletionResult` transition owns the public waiter class.
2076#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
2077pub enum RuntimeCompletionTerminalObservation {
2078    #[default]
2079    RunResult,
2080    NoResult,
2081    CallbackPending,
2082    MachineTerminal,
2083    RuntimeTerminated,
2084}
2085
2086/// Typed observation of whether runtime finalization completed after the
2087/// executor produced terminal evidence.
2088#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
2089pub enum RuntimeCompletionFinalizationObservation {
2090    #[default]
2091    Succeeded,
2092    Failed,
2093}
2094
2095/// Typed observation supplied by public session-interrupt surfaces. The
2096/// generated `ResolveUserInterruptPublicResult` transition owns the app-facing
2097/// result class; REST/RPC/CLI may only map its typed effect to transport shape.
2098#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
2099pub enum UserInterruptObservationKind {
2100    #[default]
2101    Accepted,
2102    IdleNoop,
2103    AttachedNoop,
2104    StagedNoop,
2105    Destroyed,
2106    NotInterruptible,
2107}
2108
2109/// Generated public result class for user interrupt requests.
2110#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
2111pub enum UserInterruptPublicResultKind {
2112    #[default]
2113    Interrupted,
2114    /// #348: a staged (not-yet-promoted) session interrupt is a typed no-op
2115    /// terminal — distinct from `Interrupted` (a live run was cancelled).
2116    StagedNoop,
2117    NotFound,
2118    SessionBusy,
2119    Conflict,
2120}
2121
2122/// Generated public completion result class for runtime-loop waiters. Payloads
2123/// remain runtime data, but this closed classifier is the authority for which
2124/// public `CompletionOutcome` variant may be emitted.
2125#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
2126pub enum RuntimeCompletionResultClass {
2127    #[default]
2128    Completed,
2129    CompletedWithoutResult,
2130    CallbackPending,
2131    Cancelled,
2132    AbandonedWithError,
2133    CompletedWithFinalizationFailure,
2134    RuntimeTerminated,
2135}
2136
2137/// Typed observation of the live-session projection available to generated
2138/// runtime-completion cleanup authority.
2139#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
2140pub enum RuntimeCompletionLiveSessionObservation {
2141    #[default]
2142    NotObserved,
2143    Present,
2144    Absent,
2145}
2146
2147/// Generated cleanup action for runtime completion side effects.
2148#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
2149pub enum RuntimeCompletionCleanupAction {
2150    #[default]
2151    RetainRuntime,
2152    CleanupRuntime,
2153}
2154
2155/// Generated authority for whether completion cleanup may release a surface
2156/// pre-admission guard.
2157#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
2158pub enum RuntimeCompletionPreAdmissionAction {
2159    #[default]
2160    RetainPreAdmission,
2161    ReleasePreAdmission,
2162}
2163
2164/// Typed mechanical failure observed by completion waiter plumbing.
2165#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
2166pub enum RuntimeCompletionWaitFailureObservation {
2167    #[default]
2168    ChannelClosed,
2169    AuthorityUnavailable,
2170}
2171
2172/// Generated public error class for mechanical runtime completion waiter
2173/// failures.
2174#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
2175pub enum RuntimeCompletionWaitFailurePublicErrorClass {
2176    #[default]
2177    InternalError,
2178}
2179
2180/// Generated public reason classifier for mechanical runtime completion waiter
2181/// failures.
2182#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
2183pub enum RuntimeCompletionWaitFailurePublicReason {
2184    #[default]
2185    CompletionChannelClosed,
2186    CompletionAuthorityUnavailable,
2187}
2188
2189/// Generated durability action for runtime-owned ops lifecycle snapshots.
2190#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
2191pub enum RuntimeOpsLifecycleDurabilityAction {
2192    #[default]
2193    RetainSnapshot,
2194    DeleteSnapshot,
2195}
2196
2197/// Typed public rejection class for `live/open` admission.
2198#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
2199pub enum LiveOpenAdmissionRejection {
2200    #[default]
2201    AlreadyBound,
2202    ChannelAlreadyBound,
2203}
2204
2205/// Typed public result class for `live/refresh` after the adapter command
2206/// queue accepts a refresh handoff. The RPC surface may only project this
2207/// value from a generated `LiveRefreshResultResolved` effect.
2208#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
2209pub enum LiveRefreshPublicStatus {
2210    #[default]
2211    Queued,
2212}
2213
2214/// Typed public result class for `live/close` after the live host accepts a
2215/// close handoff. The RPC surface may only project this value from a generated
2216/// `LiveCloseResultResolved` effect.
2217#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
2218pub enum LiveClosePublicStatus {
2219    #[default]
2220    Closed,
2221}
2222
2223/// Closed classifier for live adapter commands whose queue acceptance backs a
2224/// public RPC result.
2225#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
2226pub enum LiveCommandPublicKind {
2227    #[default]
2228    SendInput,
2229    CommitInput,
2230    Interrupt,
2231    TruncateAssistantOutput,
2232}
2233
2234/// Closed classifier for live command rejection observations. The live host
2235/// can observe why an adapter command handoff failed, but public error-class
2236/// truth is generated from this typed fact.
2237#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
2238pub enum LiveCommandRejectionReason {
2239    #[default]
2240    ChannelNotFound,
2241    NoAdapter,
2242    ChannelNotReady,
2243    UnsupportedCommand,
2244    AdapterError,
2245    InternalHostError,
2246}
2247
2248/// Typed public error class for live command rejections. RPC surfaces may only
2249/// project their JSON-RPC error code from a generated
2250/// `LiveCommandRejectionResolved` effect.
2251#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
2252pub enum LiveCommandRejectionPublicErrorClass {
2253    #[default]
2254    InvalidParams,
2255    InternalError,
2256}
2257
2258/// Closed classifier for live channel control requests whose rejection backs a
2259/// public RPC error result.
2260#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
2261pub enum LiveChannelRequestPublicKind {
2262    #[default]
2263    Status,
2264    Close,
2265    Refresh,
2266    WebrtcAnswer,
2267}
2268
2269/// Closed classifier for live channel control request rejection observations.
2270/// The live host can observe missing transport/cache pieces, but public
2271/// error-class truth is generated from this typed fact.
2272#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
2273pub enum LiveChannelRequestRejectionReason {
2274    #[default]
2275    ChannelNotFound,
2276    NoAdapter,
2277    InvalidToken,
2278    InvalidPayload,
2279    WebrtcAnswerError,
2280    InternalHostError,
2281}
2282
2283/// Typed public error class for live channel control request rejections. RPC
2284/// surfaces may only project their JSON-RPC error code from a generated
2285/// `LiveChannelRequestRejectionResolved` effect.
2286#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
2287pub enum LiveChannelRequestRejectionPublicErrorClass {
2288    #[default]
2289    InvalidParams,
2290    InternalError,
2291}
2292
2293/// Closed classifier for generated WebRTC answer admission rejections. The
2294/// transport can provide bearer material, but token existence, expiry,
2295/// channel binding, and single-use admission are decided by MeerkatMachine.
2296#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
2297pub enum LiveWebrtcAnswerAdmissionRejection {
2298    #[default]
2299    TokenNotFound,
2300    TokenExpired,
2301    TokenChannelMismatch,
2302    TokenAlreadyConsumed,
2303    ChannelNotBound,
2304}
2305
2306/// Closed classifier for generated WebSocket token admission rejections. The
2307/// WebSocket transport can present bearer material, but token existence,
2308/// expiry, channel binding, and single-use admission are decided by
2309/// MeerkatMachine.
2310#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
2311pub enum LiveWebsocketTokenAdmissionRejection {
2312    #[default]
2313    TokenNotFound,
2314    TokenExpired,
2315    TokenChannelMismatch,
2316    TokenAlreadyConsumed,
2317    ChannelNotBound,
2318}
2319
2320/// Typed public error class for live WebSocket token admission. The transport
2321/// projects its close/error code only from the generated admission effect.
2322#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
2323pub enum LiveWebsocketTokenAdmissionPublicErrorClass {
2324    #[default]
2325    InvalidToken,
2326}
2327
2328/// Typed public success class for `live/webrtc/answer`. The WebRTC stack
2329/// produces SDP material, but the public success result is projected only
2330/// after a generated `LiveWebrtcAnswerResultResolved` effect.
2331#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
2332pub enum LiveWebrtcAnswerPublicStatus {
2333    #[default]
2334    Answered,
2335}
2336
2337/// Typed terminal reason for RPC event streams. The router observes transport
2338/// end conditions, then submits the closed set here before projecting the
2339/// public `*/stream_end` notification.
2340#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
2341pub enum RpcEventStreamTerminalReason {
2342    #[default]
2343    RemoteEnd,
2344    TerminalError,
2345    ExplicitClose,
2346}
2347
2348/// Typed transport observation for RPC event-stream termination. The router
2349/// submits this non-public observation; generated authority derives the public
2350/// terminal reason and error code.
2351#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
2352pub enum RpcEventStreamTerminalObservationKind {
2353    #[default]
2354    TransportEnded,
2355    NotificationQueueOverflow,
2356    NotificationReceiverGone,
2357}
2358
2359/// Typed public error code for RPC event-stream terminal notifications. The
2360/// RPC surface may only project this value from a generated
2361/// `*EventStreamTerminalResolved` effect.
2362#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
2363pub enum RpcEventStreamTerminalErrorCode {
2364    #[default]
2365    StreamQueueOverflow,
2366    StreamReceiverGone,
2367}
2368
2369/// Typed public status class for `live/status` after the live host has
2370/// observed the adapter transport state. RPC/SDK surfaces may only project
2371/// these values from generated `LiveChannelStatusResolved` effects.
2372#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
2373pub enum LiveChannelPublicStatus {
2374    #[default]
2375    Idle,
2376    Opening,
2377    Ready,
2378    Degraded,
2379    Closing,
2380    Closed,
2381}
2382
2383/// Typed public degradation reason for `live/status`.
2384#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
2385pub enum LiveChannelDegradationReason {
2386    #[default]
2387    Unknown,
2388    RateLimited,
2389    ProviderThrottled,
2390    NetworkUnstable,
2391    Other,
2392}
2393
2394/// #51: provider-neutral role for a staged realtime transcript item, carried on
2395/// the `RealtimeTranscriptAppended` staging effect. Mirror of
2396/// `meerkat_core::realtime_transcript::RealtimeTranscriptRole`.
2397#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
2398pub enum RealtimeTranscriptRoleKind {
2399    #[default]
2400    User,
2401    Assistant,
2402}
2403
2404/// #51: output lane for a staged realtime transcript item (display text vs
2405/// spoken transcript). Mirror of `meerkat_core::realtime_transcript::TranscriptLane`.
2406#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
2407pub enum RealtimeTranscriptLaneKind {
2408    #[default]
2409    Display,
2410    Spoken,
2411}
2412
2413/// Typed mirror of the public runtime lifecycle projection. The shell passes
2414/// only the observed variant; generated transitions own the semantic facts
2415/// derived from it.
2416#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
2417pub enum RuntimeLifecycleObservedState {
2418    #[default]
2419    Initializing,
2420    Idle,
2421    Attached,
2422    Running,
2423    Retired,
2424    Stopped,
2425    Destroyed,
2426}
2427
2428#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
2429pub enum RuntimeLifecycleTerminality {
2430    #[default]
2431    NonTerminal,
2432    Terminal,
2433}
2434
2435#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
2436pub enum RuntimeInputAdmission {
2437    #[default]
2438    RejectsInput,
2439    AcceptsInput,
2440}
2441
2442#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
2443pub enum RuntimeQueueAdmission {
2444    #[default]
2445    BlocksQueue,
2446    ProcessesQueue,
2447}
2448
2449#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
2450pub enum RuntimePrepareAdmission {
2451    #[default]
2452    NotReady,
2453    Ready,
2454    Destroyed,
2455}
2456
2457#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
2458pub enum RuntimeIngressAdmission {
2459    #[default]
2460    Open,
2461    NotReady,
2462    Destroyed,
2463}
2464
2465#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
2466pub enum RuntimeLoopRunBinding {
2467    #[default]
2468    Blocked,
2469    AllocateNew,
2470    UsePrebound,
2471}
2472
2473/// Typed reason classifier for the `TurnRunCancelled` effect. Closed set of
2474/// cancellation-observation origins emitted when a turn's cancellation
2475/// request lands at an observable boundary. Replaces the former literal-
2476/// string `reason` field on `TurnRunCancelled`. Only one origin is emitted
2477/// today (`Observed`, fired by the `CancellationObserved` transition), but
2478/// this remains a closed classifier not a free-form message — future
2479/// cancellation origins extend the enum rather than reintroducing strings.
2480#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
2481pub enum TurnCancellationReason {
2482    #[default]
2483    Observed,
2484}
2485
2486/// Typed recoverable LLM retry failure classifier. Closed mirror of
2487/// [`meerkat_core::retry::LlmRetryFailureKind`] so retry authority records the
2488/// retry cause as data, not as a parsed diagnostic string.
2489#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
2490pub enum LlmRetryFailureKind {
2491    #[default]
2492    RateLimited,
2493    NetworkTimeout,
2494    CallTimeout,
2495    RetryableProviderError,
2496}
2497
2498impl From<meerkat_core::retry::LlmRetryFailureKind> for LlmRetryFailureKind {
2499    fn from(kind: meerkat_core::retry::LlmRetryFailureKind) -> Self {
2500        match kind {
2501            meerkat_core::retry::LlmRetryFailureKind::RateLimited => Self::RateLimited,
2502            meerkat_core::retry::LlmRetryFailureKind::NetworkTimeout => Self::NetworkTimeout,
2503            meerkat_core::retry::LlmRetryFailureKind::CallTimeout => Self::CallTimeout,
2504            meerkat_core::retry::LlmRetryFailureKind::RetryableProviderError => {
2505                Self::RetryableProviderError
2506            }
2507        }
2508    }
2509}
2510
2511/// Typed admission-signal classifier for the `PostAdmissionSignal` effect.
2512/// Closed set of post-admission wake/interrupt intents emitted by the
2513/// ingress authority so the shell dispatcher matches exhaustively on a
2514/// typed discriminant instead of comparing string literals. Mirrors the
2515/// shell-side `driver::ephemeral::PostAdmissionSignal` strength ordering
2516/// (WakeLoop < InterruptYielding < RequestImmediateProcessing); the
2517/// shell enum additionally carries a `None` bottom that the DSL never
2518/// emits, so only the three emitted variants appear here.
2519#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
2520pub enum PostAdmissionSignalKind {
2521    #[default]
2522    WakeLoop,
2523    InterruptYielding,
2524    RequestImmediateProcessing,
2525}
2526
2527/// Typed base lifecycle state for an external tool surface. Closed mirror of
2528/// [`meerkat_core::tool_scope::ExternalToolSurfaceBaseState`] — replaces the
2529/// former literal-string values in `surface_base_state`.
2530#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
2531pub enum ExternalToolSurfaceBaseState {
2532    #[default]
2533    Absent,
2534    Active,
2535    Removing,
2536    Removed,
2537}
2538
2539impl From<meerkat_core::tool_scope::ExternalToolSurfaceBaseState> for ExternalToolSurfaceBaseState {
2540    fn from(state: meerkat_core::tool_scope::ExternalToolSurfaceBaseState) -> Self {
2541        match state {
2542            meerkat_core::tool_scope::ExternalToolSurfaceBaseState::Absent => Self::Absent,
2543            meerkat_core::tool_scope::ExternalToolSurfaceBaseState::Active => Self::Active,
2544            meerkat_core::tool_scope::ExternalToolSurfaceBaseState::Removing => Self::Removing,
2545            meerkat_core::tool_scope::ExternalToolSurfaceBaseState::Removed => Self::Removed,
2546        }
2547    }
2548}
2549
2550impl From<ExternalToolSurfaceBaseState> for meerkat_core::tool_scope::ExternalToolSurfaceBaseState {
2551    fn from(state: ExternalToolSurfaceBaseState) -> Self {
2552        match state {
2553            ExternalToolSurfaceBaseState::Absent => Self::Absent,
2554            ExternalToolSurfaceBaseState::Active => Self::Active,
2555            ExternalToolSurfaceBaseState::Removing => Self::Removing,
2556            ExternalToolSurfaceBaseState::Removed => Self::Removed,
2557        }
2558    }
2559}
2560
2561/// Typed last-delta operation for an external tool surface. Closed mirror of
2562/// [`meerkat_core::tool_scope::ExternalToolSurfaceDeltaOperation`] — replaces
2563/// the former literal-string values in `surface_last_delta_operation`.
2564#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
2565pub enum ExternalToolSurfaceDeltaOperation {
2566    #[default]
2567    None,
2568    Add,
2569    Remove,
2570    Reload,
2571}
2572
2573impl From<meerkat_core::tool_scope::ExternalToolSurfaceDeltaOperation>
2574    for ExternalToolSurfaceDeltaOperation
2575{
2576    fn from(op: meerkat_core::tool_scope::ExternalToolSurfaceDeltaOperation) -> Self {
2577        match op {
2578            meerkat_core::tool_scope::ExternalToolSurfaceDeltaOperation::None => Self::None,
2579            meerkat_core::tool_scope::ExternalToolSurfaceDeltaOperation::Add => Self::Add,
2580            meerkat_core::tool_scope::ExternalToolSurfaceDeltaOperation::Remove => Self::Remove,
2581            meerkat_core::tool_scope::ExternalToolSurfaceDeltaOperation::Reload => Self::Reload,
2582        }
2583    }
2584}
2585
2586impl From<ExternalToolSurfaceDeltaOperation>
2587    for meerkat_core::tool_scope::ExternalToolSurfaceDeltaOperation
2588{
2589    fn from(op: ExternalToolSurfaceDeltaOperation) -> Self {
2590        match op {
2591            ExternalToolSurfaceDeltaOperation::None => Self::None,
2592            ExternalToolSurfaceDeltaOperation::Add => Self::Add,
2593            ExternalToolSurfaceDeltaOperation::Remove => Self::Remove,
2594            ExternalToolSurfaceDeltaOperation::Reload => Self::Reload,
2595        }
2596    }
2597}
2598
2599/// Typed last-delta phase for an external tool surface. Closed mirror of
2600/// [`meerkat_core::tool_scope::ExternalToolSurfaceDeltaPhase`] — replaces the
2601/// former literal-string values in `surface_last_delta_phase`.
2602#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
2603pub enum ExternalToolSurfaceDeltaPhase {
2604    #[default]
2605    None,
2606    Pending,
2607    Applied,
2608    Draining,
2609    Failed,
2610    Forced,
2611}
2612
2613impl From<meerkat_core::tool_scope::ExternalToolSurfaceDeltaPhase>
2614    for ExternalToolSurfaceDeltaPhase
2615{
2616    fn from(phase: meerkat_core::tool_scope::ExternalToolSurfaceDeltaPhase) -> Self {
2617        match phase {
2618            meerkat_core::tool_scope::ExternalToolSurfaceDeltaPhase::None => Self::None,
2619            meerkat_core::tool_scope::ExternalToolSurfaceDeltaPhase::Pending => Self::Pending,
2620            meerkat_core::tool_scope::ExternalToolSurfaceDeltaPhase::Applied => Self::Applied,
2621            meerkat_core::tool_scope::ExternalToolSurfaceDeltaPhase::Draining => Self::Draining,
2622            meerkat_core::tool_scope::ExternalToolSurfaceDeltaPhase::Failed => Self::Failed,
2623            meerkat_core::tool_scope::ExternalToolSurfaceDeltaPhase::Forced => Self::Forced,
2624        }
2625    }
2626}
2627
2628impl From<ExternalToolSurfaceDeltaPhase>
2629    for meerkat_core::tool_scope::ExternalToolSurfaceDeltaPhase
2630{
2631    fn from(phase: ExternalToolSurfaceDeltaPhase) -> Self {
2632        match phase {
2633            ExternalToolSurfaceDeltaPhase::None => Self::None,
2634            ExternalToolSurfaceDeltaPhase::Pending => Self::Pending,
2635            ExternalToolSurfaceDeltaPhase::Applied => Self::Applied,
2636            ExternalToolSurfaceDeltaPhase::Draining => Self::Draining,
2637            ExternalToolSurfaceDeltaPhase::Failed => Self::Failed,
2638            ExternalToolSurfaceDeltaPhase::Forced => Self::Forced,
2639        }
2640    }
2641}
2642
2643/// Typed failure cause for an external tool surface. Closed mirror of
2644/// [`meerkat_core::tool_scope::ExternalToolSurfaceFailureCause`] so pending
2645/// failure and call-rejection causes cross the DSL as data, not string codes.
2646#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
2647pub enum ExternalToolSurfaceFailureCause {
2648    #[default]
2649    PendingFailed,
2650    SurfaceDraining,
2651    SurfaceUnavailable,
2652}
2653
2654impl From<meerkat_core::tool_scope::ExternalToolSurfaceFailureCause>
2655    for ExternalToolSurfaceFailureCause
2656{
2657    fn from(cause: meerkat_core::tool_scope::ExternalToolSurfaceFailureCause) -> Self {
2658        match cause {
2659            meerkat_core::tool_scope::ExternalToolSurfaceFailureCause::PendingFailed => {
2660                Self::PendingFailed
2661            }
2662            meerkat_core::tool_scope::ExternalToolSurfaceFailureCause::SurfaceDraining => {
2663                Self::SurfaceDraining
2664            }
2665            meerkat_core::tool_scope::ExternalToolSurfaceFailureCause::SurfaceUnavailable => {
2666                Self::SurfaceUnavailable
2667            }
2668        }
2669    }
2670}
2671
2672impl From<ExternalToolSurfaceFailureCause>
2673    for meerkat_core::tool_scope::ExternalToolSurfaceFailureCause
2674{
2675    fn from(cause: ExternalToolSurfaceFailureCause) -> Self {
2676        match cause {
2677            ExternalToolSurfaceFailureCause::PendingFailed => Self::PendingFailed,
2678            ExternalToolSurfaceFailureCause::SurfaceDraining => Self::SurfaceDraining,
2679            ExternalToolSurfaceFailureCause::SurfaceUnavailable => Self::SurfaceUnavailable,
2680        }
2681    }
2682}
2683
2684/// Typed drain-exit reason. Closed mirror of
2685/// [`meerkat_core::handles::DrainExitReason`] — replaces the former
2686/// literal-string `reason` field on `NotifyDrainExited`.
2687#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
2688pub enum DrainExitReason {
2689    #[default]
2690    IdleTimeout,
2691    Dismissed,
2692    Failed,
2693    Aborted,
2694    SessionShutdown,
2695}
2696
2697impl From<meerkat_core::handles::DrainExitReason> for DrainExitReason {
2698    fn from(reason: meerkat_core::handles::DrainExitReason) -> Self {
2699        match reason {
2700            meerkat_core::handles::DrainExitReason::IdleTimeout => Self::IdleTimeout,
2701            meerkat_core::handles::DrainExitReason::Dismissed => Self::Dismissed,
2702            meerkat_core::handles::DrainExitReason::Failed => Self::Failed,
2703            meerkat_core::handles::DrainExitReason::Aborted => Self::Aborted,
2704            meerkat_core::handles::DrainExitReason::SessionShutdown => Self::SessionShutdown,
2705        }
2706    }
2707}
2708
2709impl From<DrainExitReason> for meerkat_core::handles::DrainExitReason {
2710    fn from(reason: DrainExitReason) -> Self {
2711        match reason {
2712            DrainExitReason::IdleTimeout => Self::IdleTimeout,
2713            DrainExitReason::Dismissed => Self::Dismissed,
2714            DrainExitReason::Failed => Self::Failed,
2715            DrainExitReason::Aborted => Self::Aborted,
2716            DrainExitReason::SessionShutdown => Self::SessionShutdown,
2717        }
2718    }
2719}
2720
2721/// Generated surface-request lifecycle phase. Surface transports may project
2722/// this value for diagnostics; mutation authority lives in MeerkatMachine
2723/// transitions.
2724#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
2725pub enum SurfaceRequestPhase {
2726    #[default]
2727    Pending,
2728    Published,
2729    Cancelled,
2730    Completed,
2731}
2732
2733/// Generated terminal-publication policy recorded when a surface request is
2734/// admitted.
2735#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
2736pub enum SurfaceRequestTerminalPolicy {
2737    #[default]
2738    RespondWithoutPublish,
2739    PublishOnSuccess,
2740}
2741
2742/// Typed work-lane origin for [`MeerkatMachineInput::Ingest`]. Closed set of
2743/// the work-lane labels the DSL observes on the admission seam — replaces
2744/// the former literal-string `origin` field. Structurally mirrors the
2745/// `MobMachine.RequestRuntimeIngress.origin` seam so the cross-machine
2746/// composition binds on a single typed enum instead of parallel
2747/// string-typed slots. Transport sources ([`meerkat_core::comms::InputSource`])
2748/// arriving from the shell side collapse to `External`; the
2749/// runtime-control-plane `Ingest` dispatch uses the dedicated `Ingest`
2750/// variant; mob-bridged ingress carries `External`/`Internal` matching
2751/// `meerkat-mob::ids::WorkOrigin`.
2752#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
2753pub enum WorkOrigin {
2754    #[default]
2755    External,
2756    Internal,
2757    /// Canonical admission entrypoint fired by the runtime control plane
2758    /// with no surface-level transport or work-lane label.
2759    Ingest,
2760}
2761
2762impl From<meerkat_core::comms::InputSource> for WorkOrigin {
2763    fn from(src: meerkat_core::comms::InputSource) -> Self {
2764        match src {
2765            // Transport-originated inputs are `External` work-lane: they
2766            // entered the runtime via a non-mob transport (TCP/UDS/stdin/
2767            // webhook/RPC). Mob-originated work fires the DSL directly
2768            // with `External`/`Internal` instead of going through the
2769            // session-admission handle.
2770            meerkat_core::comms::InputSource::Tcp
2771            | meerkat_core::comms::InputSource::Uds
2772            | meerkat_core::comms::InputSource::Stdin
2773            | meerkat_core::comms::InputSource::Webhook
2774            | meerkat_core::comms::InputSource::Rpc => Self::External,
2775        }
2776    }
2777}
2778
2779/// Typed async-operation lifecycle status. Closed mirror of
2780/// [`meerkat_core::ops_lifecycle::OperationStatus`] — replaces the former
2781/// literal-string values in the DSL's `op_statuses` map.
2782///
2783/// The DSL writes these variants directly on each ops lifecycle transition
2784/// (`RegisterOp`, `StartOp`, `CompleteOp`, `FailOp`, `CancelOp`, `AbortOp`,
2785/// `RetireRequestedOp`, `RetireCompletedOp`, `TerminateOp`). The shell's
2786/// `ShellState::status()` reads the typed value directly and maps to the
2787/// domain enum via the `From` impl below — no string compares, no string
2788/// parsing.
2789#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
2790pub enum OperationStatus {
2791    #[default]
2792    Absent,
2793    Provisioning,
2794    Running,
2795    Retiring,
2796    Completed,
2797    Failed,
2798    Aborted,
2799    Cancelled,
2800    Retired,
2801    Terminated,
2802}
2803
2804impl From<meerkat_core::ops_lifecycle::OperationStatus> for OperationStatus {
2805    fn from(status: meerkat_core::ops_lifecycle::OperationStatus) -> Self {
2806        match status {
2807            meerkat_core::ops_lifecycle::OperationStatus::Absent => Self::Absent,
2808            meerkat_core::ops_lifecycle::OperationStatus::Provisioning => Self::Provisioning,
2809            meerkat_core::ops_lifecycle::OperationStatus::Running => Self::Running,
2810            meerkat_core::ops_lifecycle::OperationStatus::Retiring => Self::Retiring,
2811            meerkat_core::ops_lifecycle::OperationStatus::Completed => Self::Completed,
2812            meerkat_core::ops_lifecycle::OperationStatus::Failed => Self::Failed,
2813            meerkat_core::ops_lifecycle::OperationStatus::Aborted => Self::Aborted,
2814            meerkat_core::ops_lifecycle::OperationStatus::Cancelled => Self::Cancelled,
2815            meerkat_core::ops_lifecycle::OperationStatus::Retired => Self::Retired,
2816            meerkat_core::ops_lifecycle::OperationStatus::Terminated => Self::Terminated,
2817        }
2818    }
2819}
2820
2821impl From<OperationStatus> for meerkat_core::ops_lifecycle::OperationStatus {
2822    fn from(status: OperationStatus) -> Self {
2823        match status {
2824            OperationStatus::Absent => Self::Absent,
2825            OperationStatus::Provisioning => Self::Provisioning,
2826            OperationStatus::Running => Self::Running,
2827            OperationStatus::Retiring => Self::Retiring,
2828            OperationStatus::Completed => Self::Completed,
2829            OperationStatus::Failed => Self::Failed,
2830            OperationStatus::Aborted => Self::Aborted,
2831            OperationStatus::Cancelled => Self::Cancelled,
2832            OperationStatus::Retired => Self::Retired,
2833            OperationStatus::Terminated => Self::Terminated,
2834        }
2835    }
2836}
2837
2838/// Typed discriminant mirror of
2839/// [`meerkat_core::ops_lifecycle::OperationTerminalOutcome`]. Unit variants
2840/// only; the full typed payload (completion result, failure error,
2841/// cancellation reason, terminated reason) is carried by the companion
2842/// `op_terminal_payload: Map<String, OpTerminalPayload>` field, keyed by the
2843/// same operation id. The machine guards that the payload variant matches
2844/// the discriminant on every terminal transition.
2845///
2846/// The DSL writes these variants directly on each terminal transition
2847/// (`CompleteOp`, `FailOp`, `CancelOp`, `AbortOp`, `RetireCompletedOp`,
2848/// `TerminateOp`); the shell reads the typed payload map directly — no JSON
2849/// codec, no string compares.
2850#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
2851pub enum OperationTerminalOutcomeKind {
2852    #[default]
2853    Completed,
2854    Failed,
2855    Aborted,
2856    Cancelled,
2857    Retired,
2858    Terminated,
2859}
2860
2861/// Typed terminal payload carried by the ops-lifecycle authority. This IS the
2862/// domain type — the machine state stores
2863/// [`meerkat_core::ops_lifecycle::OperationTerminalOutcome`] directly, so the
2864/// shell needs no codec in either direction (K8b fold: the former
2865/// `Map<String, String>` opaque-JSON payload carrier is deleted).
2866pub type OpTerminalPayload = meerkat_core::ops_lifecycle::OperationTerminalOutcome;
2867
2868/// Result payload for completed operations, referenced by the
2869/// `OpTerminalPayload::Completed` structural variant binding.
2870pub type OperationResult = meerkat_core::ops::OperationResult;
2871
2872impl From<&OpTerminalPayload> for OperationTerminalOutcomeKind {
2873    fn from(payload: &OpTerminalPayload) -> Self {
2874        match payload {
2875            OpTerminalPayload::Completed(_) => Self::Completed,
2876            OpTerminalPayload::Failed { .. } => Self::Failed,
2877            OpTerminalPayload::Aborted { .. } => Self::Aborted,
2878            OpTerminalPayload::Cancelled { .. } => Self::Cancelled,
2879            OpTerminalPayload::Retired => Self::Retired,
2880            OpTerminalPayload::Terminated { .. } => Self::Terminated,
2881        }
2882    }
2883}
2884
2885/// Typed public result class for operation lifecycle projections. Shell/tool
2886/// surfaces may format these classes, but the lifecycle machine owns the
2887/// status-to-public-result classification.
2888#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
2889pub enum OperationPublicResultClass {
2890    #[default]
2891    MissingAuthority,
2892    Running,
2893    Completed,
2894    Failed,
2895    Cancelled,
2896}
2897
2898#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
2899pub enum OperationCompletionFeedClass {
2900    #[default]
2901    Emit,
2902    Suppress,
2903}
2904
2905#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
2906pub enum OperationCompletionWakeClass {
2907    #[default]
2908    Wake,
2909    Ignore,
2910}
2911
2912#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
2913pub enum OperationDurabilityClass {
2914    #[default]
2915    Retain,
2916    Discard,
2917}
2918
2919impl From<OperationPublicResultClass> for meerkat_core::ops_lifecycle::OperationPublicResultClass {
2920    fn from(value: OperationPublicResultClass) -> Self {
2921        match value {
2922            OperationPublicResultClass::MissingAuthority => Self::MissingAuthority,
2923            OperationPublicResultClass::Running => Self::Running,
2924            OperationPublicResultClass::Completed => Self::Completed,
2925            OperationPublicResultClass::Failed => Self::Failed,
2926            OperationPublicResultClass::Cancelled => Self::Cancelled,
2927        }
2928    }
2929}
2930
2931impl From<OperationCompletionWakeClass>
2932    for meerkat_core::ops_lifecycle::OperationCompletionWakeClass
2933{
2934    fn from(value: OperationCompletionWakeClass) -> Self {
2935        match value {
2936            OperationCompletionWakeClass::Wake => Self::Wake,
2937            OperationCompletionWakeClass::Ignore => Self::Ignore,
2938        }
2939    }
2940}
2941
2942#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
2943pub enum OpRegistrationAdmissionResultKind {
2944    #[default]
2945    Accept,
2946    Reject,
2947}
2948
2949#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
2950pub enum OpRegistrationRejectReasonKind {
2951    #[default]
2952    AlreadyRegistered,
2953    MaxConcurrentExceeded,
2954}
2955
2956#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
2957pub enum OpLifecycleActionKind {
2958    #[default]
2959    Start,
2960    Fail,
2961    PeerReady,
2962    ProgressReported,
2963    Complete,
2964    Abort,
2965    Cancel,
2966    RetireRequested,
2967    RetireCompleted,
2968    Terminate,
2969}
2970
2971impl From<meerkat_core::ops_lifecycle::OperationLifecycleAction> for OpLifecycleActionKind {
2972    fn from(action: meerkat_core::ops_lifecycle::OperationLifecycleAction) -> Self {
2973        match action {
2974            meerkat_core::ops_lifecycle::OperationLifecycleAction::Start => Self::Start,
2975            meerkat_core::ops_lifecycle::OperationLifecycleAction::Fail => Self::Fail,
2976            meerkat_core::ops_lifecycle::OperationLifecycleAction::PeerReady => Self::PeerReady,
2977            meerkat_core::ops_lifecycle::OperationLifecycleAction::ProgressReported => {
2978                Self::ProgressReported
2979            }
2980            meerkat_core::ops_lifecycle::OperationLifecycleAction::Complete => Self::Complete,
2981            meerkat_core::ops_lifecycle::OperationLifecycleAction::Abort => Self::Abort,
2982            meerkat_core::ops_lifecycle::OperationLifecycleAction::Cancel => Self::Cancel,
2983            meerkat_core::ops_lifecycle::OperationLifecycleAction::RetireRequested => {
2984                Self::RetireRequested
2985            }
2986            meerkat_core::ops_lifecycle::OperationLifecycleAction::RetireCompleted => {
2987                Self::RetireCompleted
2988            }
2989            meerkat_core::ops_lifecycle::OperationLifecycleAction::Terminate => Self::Terminate,
2990        }
2991    }
2992}
2993
2994#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
2995pub enum OpLifecycleRejectReasonKind {
2996    #[default]
2997    OperationNotFound,
2998    InvalidTransition,
2999    PeerNotExpected,
3000    AlreadyPeerReady,
3001}
3002
3003/// Typed input-abandonment reason. Closed mirror of the discriminant set of
3004/// [`crate::input_state::InputAbandonReason`] — replaces the former
3005/// `format!("{reason:?}")` Debug round-trip in the DSL's
3006/// `input_abandon_reason` map.
3007///
3008/// The `MaxAttemptsExhausted` variant's `attempts` payload rides on the
3009/// companion `input_abandon_attempt_count: Map<String, u64>` field of the
3010/// DSL state; this enum only carries the discriminant. The domain
3011/// `InputAbandonReason::MaxAttemptsExhausted { attempts }` is reconstructed
3012/// in the driver by pairing the typed discriminant with that companion map.
3013#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
3014pub enum InputAbandonReason {
3015    #[default]
3016    Retired,
3017    Reset,
3018    Stopped,
3019    Destroyed,
3020    Cancelled,
3021    MaxAttemptsExhausted,
3022}
3023
3024impl From<&crate::input_state::InputAbandonReason> for InputAbandonReason {
3025    fn from(reason: &crate::input_state::InputAbandonReason) -> Self {
3026        match reason {
3027            crate::input_state::InputAbandonReason::Retired => Self::Retired,
3028            crate::input_state::InputAbandonReason::Reset => Self::Reset,
3029            crate::input_state::InputAbandonReason::Stopped => Self::Stopped,
3030            crate::input_state::InputAbandonReason::Destroyed => Self::Destroyed,
3031            crate::input_state::InputAbandonReason::Cancelled => Self::Cancelled,
3032            crate::input_state::InputAbandonReason::MaxAttemptsExhausted { .. } => {
3033                Self::MaxAttemptsExhausted
3034            }
3035        }
3036    }
3037}
3038
3039impl InputAbandonReason {
3040    /// Stable lowercase label for event wire formats. Mirrors the
3041    /// snake-case serde representation of the domain enum for consistency
3042    /// with existing consumers.
3043    pub const fn as_str(self) -> &'static str {
3044        match self {
3045            Self::Retired => "retired",
3046            Self::Reset => "reset",
3047            Self::Stopped => "stopped",
3048            Self::Destroyed => "destroyed",
3049            Self::Cancelled => "cancelled",
3050            Self::MaxAttemptsExhausted => "max_attempts_exhausted",
3051        }
3052    }
3053}
3054
3055/// Typed work-lane assignment for admitted inputs. Replaces the former
3056/// parallel `queue_lane` / `steer_lane` sets with a single map
3057/// (`input_lane: Map<String, Enum<InputLane>>`) so mutual exclusion is
3058/// structural — an admitted input is in exactly one lane by construction.
3059///
3060/// DSL-side mirror of the shell's `meerkat_core::types::HandlingMode`; the
3061/// DSL owns the typed mirror so transitions can carry it without depending
3062/// on the shell's domain enum.
3063#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
3064pub enum InputLane {
3065    #[default]
3066    Queue,
3067    Steer,
3068}
3069
3070impl From<crate::HandlingMode> for InputLane {
3071    fn from(mode: crate::HandlingMode) -> Self {
3072        match mode {
3073            crate::HandlingMode::Queue => Self::Queue,
3074            crate::HandlingMode::Steer => Self::Steer,
3075        }
3076    }
3077}
3078
3079/// Typed live-admission input kind carried by `ResolveAdmissionPlan`.
3080#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
3081pub enum AdmissionInputKind {
3082    #[default]
3083    Prompt,
3084    PeerMessage,
3085    PeerRequest,
3086    PeerResponseProgress,
3087    PeerResponseTerminal,
3088    FlowStep,
3089    ExternalEvent,
3090    Continuation,
3091    Operation,
3092}
3093
3094/// Typed continuation discriminant carried by `ResolveAdmissionPlan`. The DSL
3095/// owns the typed mirror of the shell's `ContinuationKind` so the lane and
3096/// run-apply semantics for WorkGraph attention re-entry are machine-emitted.
3097#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
3098pub enum AdmissionContinuationKind {
3099    #[default]
3100    Ordinary,
3101    WorkgraphAttention,
3102}
3103
3104impl From<crate::input::ContinuationKind> for AdmissionContinuationKind {
3105    fn from(kind: crate::input::ContinuationKind) -> Self {
3106        match kind {
3107            crate::input::ContinuationKind::Ordinary => Self::Ordinary,
3108            crate::input::ContinuationKind::WorkgraphAttention => Self::WorkgraphAttention,
3109        }
3110    }
3111}
3112
3113/// Typed durability class observed on an input.
3114#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
3115pub enum InputDurabilityKind {
3116    #[default]
3117    Durable,
3118    Ephemeral,
3119    Derived,
3120    Missing,
3121}
3122
3123impl From<crate::input::InputDurability> for InputDurabilityKind {
3124    fn from(durability: crate::input::InputDurability) -> Self {
3125        match durability {
3126            crate::input::InputDurability::Durable => Self::Durable,
3127            crate::input::InputDurability::Ephemeral => Self::Ephemeral,
3128            crate::input::InputDurability::Derived => Self::Derived,
3129        }
3130    }
3131}
3132
3133impl From<Option<crate::input::InputDurability>> for InputDurabilityKind {
3134    fn from(durability: Option<crate::input::InputDurability>) -> Self {
3135        durability.map(Self::from).unwrap_or(Self::Missing)
3136    }
3137}
3138
3139/// Typed input-origin class observed at live admission.
3140#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
3141pub enum AdmissionInputOriginKind {
3142    #[default]
3143    Operator,
3144    Peer,
3145    Flow,
3146    System,
3147    External,
3148}
3149
3150impl From<&crate::input::InputOrigin> for AdmissionInputOriginKind {
3151    fn from(origin: &crate::input::InputOrigin) -> Self {
3152        match origin {
3153            crate::input::InputOrigin::Operator => Self::Operator,
3154            crate::input::InputOrigin::Peer { .. } => Self::Peer,
3155            crate::input::InputOrigin::Flow { .. } => Self::Flow,
3156            crate::input::InputOrigin::System => Self::System,
3157            crate::input::InputOrigin::External { .. } => Self::External,
3158        }
3159    }
3160}
3161
3162impl From<crate::identifiers::InputKind> for AdmissionInputKind {
3163    fn from(kind: crate::identifiers::InputKind) -> Self {
3164        match kind {
3165            crate::identifiers::InputKind::Prompt => Self::Prompt,
3166            crate::identifiers::InputKind::PeerMessage => Self::PeerMessage,
3167            crate::identifiers::InputKind::PeerRequest => Self::PeerRequest,
3168            crate::identifiers::InputKind::PeerResponseProgress => Self::PeerResponseProgress,
3169            crate::identifiers::InputKind::PeerResponseTerminal => Self::PeerResponseTerminal,
3170            crate::identifiers::InputKind::FlowStep => Self::FlowStep,
3171            crate::identifiers::InputKind::ExternalEvent => Self::ExternalEvent,
3172            crate::identifiers::InputKind::Continuation => Self::Continuation,
3173            crate::identifiers::InputKind::Operation => Self::Operation,
3174        }
3175    }
3176}
3177
3178#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
3179pub enum AdmissionPolicyApplyMode {
3180    #[default]
3181    StageRunStart,
3182    StageRunBoundary,
3183    InjectNow,
3184    Ignore,
3185}
3186
3187impl From<AdmissionPolicyApplyMode> for crate::policy::ApplyMode {
3188    fn from(mode: AdmissionPolicyApplyMode) -> Self {
3189        match mode {
3190            AdmissionPolicyApplyMode::StageRunStart => Self::StageRunStart,
3191            AdmissionPolicyApplyMode::StageRunBoundary => Self::StageRunBoundary,
3192            AdmissionPolicyApplyMode::InjectNow => Self::InjectNow,
3193            AdmissionPolicyApplyMode::Ignore => Self::Ignore,
3194        }
3195    }
3196}
3197
3198impl From<crate::policy::ApplyMode> for AdmissionPolicyApplyMode {
3199    fn from(mode: crate::policy::ApplyMode) -> Self {
3200        match mode {
3201            crate::policy::ApplyMode::StageRunStart => Self::StageRunStart,
3202            crate::policy::ApplyMode::StageRunBoundary => Self::StageRunBoundary,
3203            crate::policy::ApplyMode::InjectNow => Self::InjectNow,
3204            crate::policy::ApplyMode::Ignore => Self::Ignore,
3205        }
3206    }
3207}
3208
3209#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
3210pub enum AdmissionPolicyWakeMode {
3211    #[default]
3212    WakeIfIdle,
3213    InterruptYielding,
3214    None,
3215}
3216
3217impl From<AdmissionPolicyWakeMode> for crate::policy::WakeMode {
3218    fn from(mode: AdmissionPolicyWakeMode) -> Self {
3219        match mode {
3220            AdmissionPolicyWakeMode::WakeIfIdle => Self::WakeIfIdle,
3221            AdmissionPolicyWakeMode::InterruptYielding => Self::InterruptYielding,
3222            AdmissionPolicyWakeMode::None => Self::None,
3223        }
3224    }
3225}
3226
3227#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
3228pub enum AdmissionPolicyQueueMode {
3229    None,
3230    #[default]
3231    Fifo,
3232    Coalesce,
3233    Supersede,
3234    Priority,
3235}
3236
3237impl From<AdmissionPolicyQueueMode> for crate::policy::QueueMode {
3238    fn from(mode: AdmissionPolicyQueueMode) -> Self {
3239        match mode {
3240            AdmissionPolicyQueueMode::None => Self::None,
3241            AdmissionPolicyQueueMode::Fifo => Self::Fifo,
3242            AdmissionPolicyQueueMode::Coalesce => Self::Coalesce,
3243            AdmissionPolicyQueueMode::Supersede => Self::Supersede,
3244            AdmissionPolicyQueueMode::Priority => Self::Priority,
3245        }
3246    }
3247}
3248
3249#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
3250pub enum AdmissionPolicyConsumePoint {
3251    OnAccept,
3252    OnApply,
3253    OnRunStart,
3254    #[default]
3255    OnRunComplete,
3256    ExplicitAck,
3257}
3258
3259impl From<AdmissionPolicyConsumePoint> for crate::policy::ConsumePoint {
3260    fn from(point: AdmissionPolicyConsumePoint) -> Self {
3261        match point {
3262            AdmissionPolicyConsumePoint::OnAccept => Self::OnAccept,
3263            AdmissionPolicyConsumePoint::OnApply => Self::OnApply,
3264            AdmissionPolicyConsumePoint::OnRunStart => Self::OnRunStart,
3265            AdmissionPolicyConsumePoint::OnRunComplete => Self::OnRunComplete,
3266            AdmissionPolicyConsumePoint::ExplicitAck => Self::ExplicitAck,
3267        }
3268    }
3269}
3270
3271#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
3272pub enum AdmissionPolicyDrainPolicy {
3273    #[default]
3274    QueueNextTurn,
3275    SteerBatch,
3276    Immediate,
3277    Ignore,
3278}
3279
3280impl From<AdmissionPolicyDrainPolicy> for crate::policy::DrainPolicy {
3281    fn from(policy: AdmissionPolicyDrainPolicy) -> Self {
3282        match policy {
3283            AdmissionPolicyDrainPolicy::QueueNextTurn => Self::QueueNextTurn,
3284            AdmissionPolicyDrainPolicy::SteerBatch => Self::SteerBatch,
3285            AdmissionPolicyDrainPolicy::Immediate => Self::Immediate,
3286            AdmissionPolicyDrainPolicy::Ignore => Self::Ignore,
3287        }
3288    }
3289}
3290
3291#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
3292pub enum AdmissionRoutingDisposition {
3293    #[default]
3294    Queue,
3295    Steer,
3296    Immediate,
3297    Drop,
3298}
3299
3300impl From<AdmissionRoutingDisposition> for crate::policy::RoutingDisposition {
3301    fn from(disposition: AdmissionRoutingDisposition) -> Self {
3302        match disposition {
3303            AdmissionRoutingDisposition::Queue => Self::Queue,
3304            AdmissionRoutingDisposition::Steer => Self::Steer,
3305            AdmissionRoutingDisposition::Immediate => Self::Immediate,
3306            AdmissionRoutingDisposition::Drop => Self::Drop,
3307        }
3308    }
3309}
3310
3311#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
3312pub enum AdmissionRunApplyBoundary {
3313    #[default]
3314    RunStart,
3315    RunCheckpoint,
3316    Immediate,
3317}
3318
3319impl From<AdmissionRunApplyBoundary> for meerkat_core::lifecycle::run_primitive::RunApplyBoundary {
3320    fn from(boundary: AdmissionRunApplyBoundary) -> Self {
3321        match boundary {
3322            AdmissionRunApplyBoundary::RunStart => Self::RunStart,
3323            AdmissionRunApplyBoundary::RunCheckpoint => Self::RunCheckpoint,
3324            AdmissionRunApplyBoundary::Immediate => Self::Immediate,
3325        }
3326    }
3327}
3328
3329#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
3330pub enum AdmissionRuntimeExecutionKind {
3331    #[default]
3332    ContentTurn,
3333    ResumePending,
3334}
3335
3336impl From<AdmissionRuntimeExecutionKind> for meerkat_core::lifecycle::RuntimeExecutionKind {
3337    fn from(kind: AdmissionRuntimeExecutionKind) -> Self {
3338        match kind {
3339            AdmissionRuntimeExecutionKind::ContentTurn => Self::ContentTurn,
3340            AdmissionRuntimeExecutionKind::ResumePending => Self::ResumePending,
3341        }
3342    }
3343}
3344
3345#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
3346pub enum AdmissionPeerResponseTerminalApplyIntent {
3347    #[default]
3348    AppendContextAndRun,
3349}
3350
3351impl From<AdmissionPeerResponseTerminalApplyIntent>
3352    for meerkat_core::lifecycle::run_primitive::PeerResponseTerminalApplyIntent
3353{
3354    fn from(intent: AdmissionPeerResponseTerminalApplyIntent) -> Self {
3355        match intent {
3356            AdmissionPeerResponseTerminalApplyIntent::AppendContextAndRun => {
3357                Self::AppendContextAndRun
3358            }
3359        }
3360    }
3361}
3362
3363#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
3364pub enum AdmissionPlanKind {
3365    ConsumedOnAccept,
3366    #[default]
3367    Queued,
3368}
3369
3370#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
3371pub enum AdmissionIdempotencyResultKind {
3372    #[default]
3373    Accept,
3374    Deduplicated,
3375}
3376
3377#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
3378pub enum AdmissionValidationResultKind {
3379    #[default]
3380    Accept,
3381    Reject,
3382}
3383
3384#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
3385pub enum PeerResponseTerminalObservedStatus {
3386    #[default]
3387    NotPeerTerminal,
3388    Completed,
3389    Failed,
3390    Cancelled,
3391}
3392
3393/// Typed admission-validation rejection reason emitted on
3394/// `AdmissionValidationResolved`. The machine names which validation rule
3395/// fired; shells render display text from this fact instead of mirroring the
3396/// guard rules.
3397#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
3398pub enum AdmissionRejectReasonKind {
3399    #[default]
3400    DurabilityMissing,
3401    ExternalDerivedDurabilityForbidden,
3402    DerivedDurabilityForbiddenForInputKind,
3403    PeerHandlingModeInvalid,
3404    PeerResponseTerminalInvalid,
3405}
3406
3407#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
3408pub enum WaitAllAdmissionResultKind {
3409    #[default]
3410    Accept,
3411    Reject,
3412}
3413
3414#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
3415pub enum WaitAllRejectReasonKind {
3416    #[default]
3417    DuplicateOperation,
3418    WaitAlreadyActive,
3419    OperationNotFound,
3420}
3421
3422#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
3423pub enum RecoveredInputNormalizationReasonKind {
3424    #[default]
3425    QueueAccepted,
3426    RollbackStaged,
3427    BoundaryReceiptCommitted,
3428    MissingBoundaryReceipt,
3429}
3430
3431#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
3432pub enum AdmissionQueueActionKind {
3433    #[default]
3434    None,
3435    EnqueueTo,
3436    EnqueueFront,
3437}
3438
3439#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
3440pub enum AdmissionExistingQueuedActionKind {
3441    #[default]
3442    None,
3443    Coalesce,
3444    Supersede,
3445}
3446
3447/// Typed persisted input kind carried by recovered-admission witnesses.
3448#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
3449pub enum RecoveredInputKind {
3450    #[default]
3451    Prompt,
3452    PeerMessage,
3453    PeerRequest,
3454    PeerResponseProgress,
3455    PeerResponseTerminal,
3456    FlowStep,
3457    ExternalEvent,
3458    Continuation,
3459    Operation,
3460}
3461
3462/// Generated recovery disposition for a persisted input row.
3463#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
3464pub enum RecoveredInputRecoveryDisposition {
3465    #[default]
3466    Retain,
3467    Discard,
3468}
3469
3470impl From<crate::identifiers::InputKind> for RecoveredInputKind {
3471    fn from(kind: crate::identifiers::InputKind) -> Self {
3472        match kind {
3473            crate::identifiers::InputKind::Prompt => Self::Prompt,
3474            crate::identifiers::InputKind::PeerMessage => Self::PeerMessage,
3475            crate::identifiers::InputKind::PeerRequest => Self::PeerRequest,
3476            crate::identifiers::InputKind::PeerResponseProgress => Self::PeerResponseProgress,
3477            crate::identifiers::InputKind::PeerResponseTerminal => Self::PeerResponseTerminal,
3478            crate::identifiers::InputKind::FlowStep => Self::FlowStep,
3479            crate::identifiers::InputKind::ExternalEvent => Self::ExternalEvent,
3480            crate::identifiers::InputKind::Continuation => Self::Continuation,
3481            crate::identifiers::InputKind::Operation => Self::Operation,
3482        }
3483    }
3484}
3485
3486/// Typed persisted runtime apply boundary carried by recovered-admission
3487/// witnesses.
3488#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
3489pub enum RecoveredRunApplyBoundary {
3490    #[default]
3491    RunStart,
3492    RunCheckpoint,
3493    Immediate,
3494}
3495
3496impl TryFrom<meerkat_core::lifecycle::run_primitive::RunApplyBoundary>
3497    for RecoveredRunApplyBoundary
3498{
3499    type Error = &'static str;
3500
3501    fn try_from(
3502        boundary: meerkat_core::lifecycle::run_primitive::RunApplyBoundary,
3503    ) -> Result<Self, Self::Error> {
3504        match boundary {
3505            meerkat_core::lifecycle::run_primitive::RunApplyBoundary::RunStart => {
3506                Ok(Self::RunStart)
3507            }
3508            meerkat_core::lifecycle::run_primitive::RunApplyBoundary::RunCheckpoint => {
3509                Ok(Self::RunCheckpoint)
3510            }
3511            meerkat_core::lifecycle::run_primitive::RunApplyBoundary::Immediate => {
3512                Ok(Self::Immediate)
3513            }
3514            _ => Err("unknown recovered runtime boundary"),
3515        }
3516    }
3517}
3518
3519/// Typed persisted runtime execution class carried by recovered-admission
3520/// witnesses.
3521#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
3522pub enum RecoveredRuntimeExecutionKind {
3523    #[default]
3524    ContentTurn,
3525    ResumePending,
3526}
3527
3528impl From<meerkat_core::lifecycle::RuntimeExecutionKind> for RecoveredRuntimeExecutionKind {
3529    fn from(kind: meerkat_core::lifecycle::RuntimeExecutionKind) -> Self {
3530        match kind {
3531            meerkat_core::lifecycle::RuntimeExecutionKind::ContentTurn => Self::ContentTurn,
3532            meerkat_core::lifecycle::RuntimeExecutionKind::ResumePending => Self::ResumePending,
3533        }
3534    }
3535}
3536
3537/// Typed recovered terminal peer-response apply intent.
3538#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
3539pub enum RecoveredPeerResponseTerminalApplyIntent {
3540    #[default]
3541    AppendContextAndRun,
3542}
3543
3544impl From<meerkat_core::lifecycle::run_primitive::PeerResponseTerminalApplyIntent>
3545    for RecoveredPeerResponseTerminalApplyIntent
3546{
3547    fn from(
3548        intent: meerkat_core::lifecycle::run_primitive::PeerResponseTerminalApplyIntent,
3549    ) -> Self {
3550        match intent {
3551            meerkat_core::lifecycle::run_primitive::PeerResponseTerminalApplyIntent::AppendContextAndRun => {
3552                Self::AppendContextAndRun
3553            }
3554        }
3555    }
3556}
3557
3558#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
3559pub enum RoutingSwitchTurnPhase {
3560    #[default]
3561    Requested,
3562    PendingForBoundary,
3563    ActiveFiniteOverride,
3564    ApplyingPersistentReconfigure,
3565    Terminal,
3566}
3567
3568#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
3569pub enum RoutingSwitchTurnTerminal {
3570    #[default]
3571    Denied,
3572    ConsumedAndRestored,
3573    PersistentReconfigureApplied,
3574}
3575
3576#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
3577pub enum RoutingDenialReason {
3578    #[default]
3579    CapabilityPolicy,
3580    ApprovalRequiredButUnavailable,
3581    DeniedDuringApproval,
3582    ScopedOverrideConflict,
3583    RealtimeTransportConflict,
3584}
3585
3586#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
3587pub enum RoutingSwitchApprovalReason {
3588    #[default]
3589    CrossProvider,
3590    CostExceedsThreshold,
3591    SafetyHold,
3592    UntilChangedFromModelOrigin,
3593    RealtimeDetachRequired,
3594}
3595
3596#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
3597pub enum RoutingImageApprovalReason {
3598    #[default]
3599    CrossProvider,
3600    CostExceedsThreshold,
3601    SafetyHold,
3602    RealtimeDetachRequired,
3603}
3604
3605#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
3606pub enum RoutingImagePlanDenialReason {
3607    #[default]
3608    UnsupportedTarget,
3609    UnsupportedCount,
3610    CapabilityPolicy,
3611    CostPolicy,
3612    SafetyPolicy,
3613    ApprovalRequiredButUnavailable,
3614    DeniedDuringApproval,
3615    ScopedOverrideConflict,
3616    RealtimeTransportConflict,
3617    ProjectionUnsupported,
3618}
3619
3620#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
3621pub enum RoutingApprovalPhase {
3622    #[default]
3623    Pending,
3624    PresentedToUser,
3625    Approved,
3626    Denied,
3627    SurfaceDetached,
3628}
3629
3630#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
3631pub enum RoutingApprovalParentKind {
3632    #[default]
3633    SwitchTurn,
3634    ImageOperation,
3635}
3636
3637#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
3638pub enum RoutingImageOperationPhase {
3639    #[default]
3640    Requested,
3641    PlanResolved,
3642    ScopedOverrideActive,
3643    ProviderCallInFlight,
3644    ResultCommitted,
3645    RestoringScopedOverride,
3646    Terminal,
3647}
3648
3649#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
3650pub enum RoutingImageTerminal {
3651    #[default]
3652    Generated,
3653    Denied,
3654    EmptyResult,
3655    RefusedByProvider,
3656    SafetyFiltered,
3657    Failed,
3658    Cancelled,
3659    Timeout,
3660    ScopedRestoreFailed,
3661}
3662
3663#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
3664pub enum RoutingImageTerminalObservation {
3665    #[default]
3666    Generated,
3667    EmptyResult,
3668    ProviderHttpError,
3669    ProviderNativeError,
3670    ExecutionFailed,
3671    BlobCommitFailed,
3672}
3673
3674#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
3675pub enum RoutingImageProviderErrorCode {
3676    #[default]
3677    Unknown,
3678    OpenAiContentFilter,
3679    OpenAiModelRefusal,
3680    GeminiSafety,
3681    GeminiModelRefusal,
3682    GeminiDeadlineExceeded,
3683}
3684
3685#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
3686pub enum RoutingProviderTextDisposition {
3687    #[default]
3688    NotEmitted,
3689    Captured,
3690    EmittedButNotStored,
3691}
3692
3693/// Typed bridge command class for supervisor-authorized mob peer overlay
3694/// observations. The runtime submits this as part of the generated
3695/// MeerkatMachine overlay authorization input so the bridge surface does not
3696/// decide whether the command peer should be present or absent.
3697#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
3698pub enum MobPeerOverlayCommandKind {
3699    #[default]
3700    Wire,
3701    Unwire,
3702}
3703
3704/// Generated admission result for supervisor bridge commands that require an
3705/// already-bound supervisor. The bridge shell may project this result to the
3706/// wire response, but it must not classify binding/epoch/sender admission from
3707/// snapshots on its own.
3708#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
3709pub enum SupervisorBridgeCommandAdmissionResultKind {
3710    #[default]
3711    Accept,
3712    Reject,
3713}
3714
3715/// Generated public rejection class for supervisor bridge command admission.
3716#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
3717pub enum SupervisorBridgeCommandRejectionKind {
3718    #[default]
3719    NotBound,
3720    StaleSupervisor,
3721    SenderMismatch,
3722}
3723
3724/// Generated admission result for `BindMember`, before bootstrap transport
3725/// checks or supervisor binding mutation.
3726#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
3727pub enum SupervisorBindAdmissionResultKind {
3728    #[default]
3729    Bootstrap,
3730    IdempotentAck,
3731    Reject,
3732}
3733
3734/// Generated public rejection class for `BindMember` admission.
3735#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
3736pub enum SupervisorBindRejectionKind {
3737    #[default]
3738    AlreadyBound,
3739    SenderMismatch,
3740}
3741
3742/// Generated material-admission verdict for `BindMember`. Owns the
3743/// transport/identity equality checks the shell previously decided inline:
3744/// advertised-address match, raw supervisor-peer sender match, expected
3745/// runtime peer-id match, and bootstrap-token match. The shell extracts the
3746/// four pure boolean observations and mirrors this verdict in the precedence
3747/// order address → sender → peer-id → token, else accept.
3748#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
3749pub enum SupervisorBindMaterialAdmissionKind {
3750    #[default]
3751    Accept,
3752    AddressMismatch,
3753    SenderMismatch,
3754    InvalidPeerSpec,
3755    InvalidBootstrapToken,
3756}
3757
3758/// Generated session-liveness verdict for an attempted transcript edit (fork /
3759/// rewrite / restore). Owns the `SESSION_BUSY` disjunction the shell previously
3760/// decided inline: a session is busy iff its runtime is running OR it holds any
3761/// active inputs. The shell extracts the two pure boolean observations
3762/// (`runtime_running`, `has_active_inputs`) and mirrors this verdict.
3763#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
3764pub enum TranscriptEditAdmissionKind {
3765    #[default]
3766    Admissible,
3767    DeniedBusy,
3768}
3769
3770/// Generated admission result for `AuthorizeSupervisor`.
3771#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
3772pub enum SupervisorAuthorizeAdmissionResultKind {
3773    #[default]
3774    Proceed,
3775    IdempotentAck,
3776    Reject,
3777}
3778
3779/// Generated public rejection class for `AuthorizeSupervisor` admission.
3780#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
3781pub enum SupervisorAuthorizeRejectionKind {
3782    #[default]
3783    NotBound,
3784    StaleSupervisor,
3785    SenderMismatch,
3786}
3787
3788// Track-B (R5): declarative peer endpoint descriptor for the runtime
3789// DSL. Shape mirrors `meerkat_core::comms::TrustedPeerDescriptor`.
3790// The catalog DSL holds an identical type; the two are structurally
3791// equivalent so the schema validator sees consistent opaque struct
3792// shapes.
3793#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
3794pub struct PeerEndpoint {
3795    pub name: PeerName,
3796    pub peer_id: PeerId,
3797    pub address: PeerAddress,
3798    pub signing_key: PeerSigningKey,
3799}
3800
3801impl PeerEndpoint {
3802    pub fn new(
3803        name: impl Into<PeerName>,
3804        peer_id: impl Into<PeerId>,
3805        address: impl Into<PeerAddress>,
3806        signing_key: impl Into<PeerSigningKey>,
3807    ) -> Self {
3808        Self {
3809            name: name.into(),
3810            peer_id: peer_id.into(),
3811            address: address.into(),
3812            signing_key: signing_key.into(),
3813        }
3814    }
3815}
3816
3817impl From<&meerkat_core::comms::TrustedPeerDescriptor> for PeerEndpoint {
3818    fn from(spec: &meerkat_core::comms::TrustedPeerDescriptor) -> Self {
3819        Self {
3820            name: PeerName(spec.name.as_str().to_owned()),
3821            peer_id: PeerId(spec.peer_id.to_string()),
3822            address: PeerAddress(spec.address.to_string()),
3823            signing_key: PeerSigningKey(spec.pubkey),
3824        }
3825    }
3826}
3827
3828/// DSL-local carrier for the Ed25519 public signing key associated with a
3829/// peer endpoint. The MeerkatMachine owns this projection alongside the
3830/// endpoint identity atoms so trust reconciliation can install the exact
3831/// key into the comms trust store without shell-side defaults.
3832#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
3833pub struct PeerSigningKey(pub [u8; 32]);
3834
3835impl From<[u8; 32]> for PeerSigningKey {
3836    fn from(key: [u8; 32]) -> Self {
3837        Self(key)
3838    }
3839}
3840
3841/// DSL-local newtype for a peer display name. Wraps the slug string
3842/// so the schema validator sees a stable opaque shape; mirrors
3843/// `meerkat_core::comms::PeerName` but avoids dragging the core
3844/// comms types into the DSL grammar.
3845#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
3846pub struct PeerName(pub String);
3847
3848impl<T: Into<String>> From<T> for PeerName {
3849    fn from(s: T) -> Self {
3850        Self(s.into())
3851    }
3852}
3853
3854impl PeerName {
3855    pub fn as_str(&self) -> &str {
3856        &self.0
3857    }
3858}
3859
3860/// DSL-local newtype for the canonical peer routing id.
3861#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
3862pub struct PeerId(pub String);
3863
3864impl<T: Into<String>> From<T> for PeerId {
3865    fn from(s: T) -> Self {
3866        Self(s.into())
3867    }
3868}
3869
3870impl PeerId {
3871    pub fn as_str(&self) -> &str {
3872        &self.0
3873    }
3874}
3875
3876/// DSL-local newtype for a peer transport endpoint URL.
3877#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
3878pub struct PeerAddress(pub String);
3879
3880impl<T: Into<String>> From<T> for PeerAddress {
3881    fn from(s: T) -> Self {
3882        Self(s.into())
3883    }
3884}
3885
3886impl PeerAddress {
3887    pub fn as_str(&self) -> &str {
3888        &self.0
3889    }
3890}
3891
3892// Ensure we keep the exact generated schema DSL body from the catalog source.
3893
3894// MeerkatMachine production body is catalog-owned. Keep bridge/runtime mechanics
3895// outside this macro invocation; canonical semantics live in the catalog DSL.
3896meerkat_machine_schema::meerkat_catalog_machine_dsl!("meerkat-runtime", "meerkat_machine::dsl");
3897
3898pub type MobToolCallerProvenance = meerkat_core::service::MobToolCallerProvenance;
3899pub type OpaquePrincipalToken = meerkat_core::service::OpaquePrincipalToken;
3900
3901// =====================================================================