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