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