Skip to main content

behavior/actor/
creation.rs

1//! Staged fresh-actor creation capabilities.
2
3use core::future::Future;
4use core::marker::PhantomData;
5use core::num::NonZeroU64;
6
7use super::addressing::{Address, EndpointAddress, EstablishedActor, EstablishedRecipient};
8use crate::next::Never;
9use crate::{
10    ActionItem, Actions, Behavior, BehaviorAddr, BehaviorBase, ItemSettlement, Protocol,
11    SettledItem,
12};
13
14/// Correlation for one staged creation within a static child occurrence.
15///
16/// This value is neither an actor address nor a runtime route. Its constructor
17/// is private so only a [`CreationSequence`] can issue it.
18#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
19pub struct CreationId(NonZeroU64);
20
21impl CreationId {
22    /// Return the occurrence-local numeric value for protocols that derive
23    /// another correlation from this creation.
24    ///
25    /// This number is neither an actor identity nor evidence that the runtime
26    /// established a fresh child. Only a committed creation settlement proves
27    /// establishment.
28    #[must_use]
29    pub const fn get(self) -> u64 {
30        self.0.get()
31    }
32}
33
34/// Checked source of IDs that are not reused within one child occurrence.
35#[derive(Debug, PartialEq, Eq)]
36pub struct CreationSequence {
37    next: Option<NonZeroU64>,
38}
39
40impl CreationSequence {
41    /// Begin a fresh sequence for one child occurrence.
42    #[must_use]
43    pub const fn new() -> Self {
44        Self {
45            next: Some(NonZeroU64::MIN),
46        }
47    }
48
49    /// Issue the next ID, or return absence after the finite sequence is
50    /// exhausted. Exhaustion leaves the sequence unchanged.
51    pub fn issue(&mut self) -> Option<CreationId> {
52        let value = self.next?;
53        self.next = value.checked_add(1);
54        Some(CreationId(value))
55    }
56}
57
58impl Default for CreationSequence {
59    fn default() -> Self {
60        Self::new()
61    }
62}
63
64/// Behavior-owned provenance for a staged fresh actor creation request.
65#[derive(Debug, Clone, Copy, PartialEq, Eq)]
66pub enum CreationKind {
67    /// An initial or ordinary later birth.
68    Birth,
69    /// A fresh successor requested by a replacement protocol.
70    Replacement {
71        /// Creator-local ID of the exact child this request supersedes.
72        previous: CreationId,
73    },
74}
75
76impl CreationKind {
77    #[must_use]
78    pub const fn replacement(previous: CreationId) -> Self {
79        Self::Replacement { previous }
80    }
81}
82
83/// A staged request to establish one fresh child.
84///
85/// The ID is correlation within the request's static child occurrence, not an
86/// address, route, actor identity, or proof of freshness. The kind is
87/// Behavior-owned intent. Replacement at an existing address is deliberately
88/// absent; stable identity is derived with a proxy actor.
89///
90/// ```compile_fail
91/// let mut creations = behavior::CreationSequence::new();
92/// let id = creations.issue().expect("the first child ID exists");
93/// let _ = behavior::CreateChild::<behavior::MailAddr, ()>::new(
94///     id,
95///     (),
96///     behavior::CreationKind::Birth,
97/// );
98/// ```
99#[derive(Debug, Clone, PartialEq, Eq)]
100pub struct CreateChild<A: Address, New> {
101    id: CreationId,
102    child: New,
103    kind: CreationKind,
104    address: PhantomData<fn() -> A>,
105}
106
107impl<A: Address, New> CreateChild<A, New> {
108    #[must_use]
109    pub(crate) const fn from_parts(id: CreationId, child: New, kind: CreationKind) -> Self {
110        Self {
111            id,
112            child,
113            kind,
114            address: PhantomData,
115        }
116    }
117
118    #[must_use]
119    pub const fn birth(id: CreationId, child: New) -> Self {
120        Self::from_parts(id, child, CreationKind::Birth)
121    }
122
123    #[must_use]
124    pub const fn replacement(id: CreationId, previous: CreationId, child: New) -> Self {
125        Self::from_parts(id, child, CreationKind::replacement(previous))
126    }
127
128    #[must_use]
129    pub const fn id(&self) -> CreationId {
130        self.id
131    }
132
133    #[must_use]
134    pub const fn kind(&self) -> CreationKind {
135        self.kind
136    }
137
138    #[must_use]
139    pub const fn child(&self) -> &New {
140        &self.child
141    }
142
143    /// Consume the staged request, returning its exact correlation, child,
144    /// and creation provenance to the interpreter.
145    ///
146    /// Taking these parts does not establish a child actor. The interpreter
147    /// remains responsible for fresh creation and for returning owned work on
148    /// rejection.
149    #[must_use]
150    pub fn into_parts(self) -> (CreationId, New, CreationKind) {
151        (self.id, self.child, self.kind)
152    }
153}
154
155/// One ordered creation batch.
156///
157/// The batch is the all-or-none unit for runtime route preparation. After
158/// routing succeeds, each child still settles independently in this declared
159/// order.
160#[derive(Debug, Clone, PartialEq, Eq)]
161pub struct Creations<Item> {
162    items: Vec<Item>,
163}
164
165impl<Item> Creations<Item> {
166    /// Construct an empty creation batch.
167    #[must_use]
168    pub const fn empty() -> Self {
169        Self { items: Vec::new() }
170    }
171
172    #[must_use]
173    pub fn one(item: Item) -> Self {
174        Self { items: vec![item] }
175    }
176
177    /// Consume a batch containing exactly one item.
178    ///
179    /// # Errors
180    /// Returns the complete ordered batch when it is empty or contains more
181    /// than one item.
182    pub fn into_one(self) -> Result<Item, Self> {
183        let one: Result<[Item; 1], Vec<Item>> = self.items.try_into();
184        match one {
185            Ok([item]) => Ok(item),
186            Err(items) => Err(Self { items }),
187        }
188    }
189
190    #[must_use]
191    pub fn and(mut self, item: Item) -> Self {
192        self.items.push(item);
193        self
194    }
195
196    /// Transform every item while preserving declared order and cardinality.
197    #[must_use]
198    pub fn map<Mapped>(self, mut map: impl FnMut(Item) -> Mapped) -> Creations<Mapped> {
199        Creations::from_items(self.items.into_iter().map(&mut map).collect())
200    }
201
202    #[must_use]
203    pub fn len(&self) -> usize {
204        self.items.len()
205    }
206
207    #[must_use]
208    pub fn is_empty(&self) -> bool {
209        self.items.is_empty()
210    }
211
212    pub(crate) fn from_items(items: Vec<Item>) -> Self {
213        Self { items }
214    }
215
216    pub fn iter(&self) -> core::slice::Iter<'_, Item> {
217        self.items.iter()
218    }
219}
220
221impl<Item> Default for Creations<Item> {
222    fn default() -> Self {
223        Self::empty()
224    }
225}
226
227impl<Item> Extend<Item> for Creations<Item> {
228    fn extend<Items: IntoIterator<Item = Item>>(&mut self, items: Items) {
229        self.items.extend(items);
230    }
231}
232
233impl<Item> FromIterator<Item> for Creations<Item> {
234    fn from_iter<Items: IntoIterator<Item = Item>>(items: Items) -> Self {
235        Self::from_items(items.into_iter().collect())
236    }
237}
238
239impl<'a, Item> IntoIterator for &'a Creations<Item> {
240    type Item = &'a Item;
241    type IntoIter = core::slice::Iter<'a, Item>;
242
243    fn into_iter(self) -> Self::IntoIter {
244        self.iter()
245    }
246}
247
248impl<Item> IntoIterator for Creations<Item> {
249    type Item = Item;
250    type IntoIter = std::vec::IntoIter<Item>;
251
252    fn into_iter(self) -> Self::IntoIter {
253        self.items.into_iter()
254    }
255}
256
257/// Static proof that `Role` names one exact direct child of `Parent`.
258///
259/// Behavior authoring owns this relationship. A runtime may use the proof to
260/// build application topology, but the role itself allocates nothing and is
261/// not evidence that the child was created or installed.
262pub trait ChildRole<Parent: Behavior> {
263    /// The only child behavior accepted at this role.
264    type Child: Behavior;
265
266    /// Structural position of this role in `Parent`'s closed child sum.
267    type Position: ChildPosition<<Parent::Birth as BirthMode>::Child, Self::Child>;
268}
269
270/// Declares how one effect occurrence is resolved from an authored parent.
271///
272/// This is topology metadata, not actor identity or a runtime capability.
273/// Generated nominal roles implement it with their declared parent, child,
274/// and structural position. [`ChildHead`] and [`ChildTail`] implement it as
275/// raw structural positions. Consumers normally use
276/// [`ResolveChildOccurrence`] rather than inspecting `Resolution`.
277///
278/// Manually authored roles may implement this trait as the power-user path by
279/// selecting [`DeclaredChildOccurrence`] with the same relationship expressed
280/// by their [`ChildRole`] implementation. The actual resolution contract is
281/// sealed, so downstream code cannot redefine wrapper transparency or replace
282/// structural resolution with a runtime lookup.
283pub trait ChildOccurrence<Parent: Behavior>: Sized {
284    /// Sealed descriptor interpreted by [`ResolveChildOccurrence`].
285    type Resolution: ChildOccurrenceResolution<Parent, Self>;
286}
287
288/// Sealed descriptor for one nominal child occurrence declared by `Parent`.
289///
290/// This type exists so generated and manually authored roles can carry their
291/// static declaration into the sealed resolver. It has no values or runtime
292/// behavior.
293pub struct DeclaredChildOccurrence;
294
295/// Sealed descriptor for a raw structural child position.
296///
297/// This type has no values or runtime behavior.
298#[doc(hidden)]
299pub struct StructuralChildOccurrence<Position>(PhantomData<fn() -> Position>);
300
301/// Resolve an effect's nominal or structural occurrence against the concrete
302/// behavior currently being interpreted.
303///
304/// This is a sealed, type-level derived construction. It performs no lookup,
305/// allocates no actor, and introduces no second identity: the resolved child's
306/// [`Behavior::Protocol`] remains canonical identity, while `Position` is only
307/// navigation evidence into the emitter's direct birth algebra.
308///
309/// A nominal role follows [`BehaviorBase`] through a wrapper only when the
310/// wrapper preserves the exact protocol and the role's declared child at its
311/// exact structural position. A wrapper may append births after that position,
312/// but it cannot replace, reorder, or insert births before it. Raw
313/// [`ChildHead`] and [`ChildTail`] positions instead resolve directly against
314/// the running emitter's own birth algebra.
315///
316/// A wrapper that replaces its base role's child cannot silently reuse that
317/// role:
318///
319/// ```compile_fail
320///
321/// struct ActorProtocol;
322/// impl behavior::Protocol for ActorProtocol {
323///     type Addr = behavior::MailAddr;
324///     type Msg = behavior::Never;
325/// }
326///
327/// macro_rules! inert {
328///     ($actor:ident, $birth:ty) => {
329///         struct $actor;
330///         impl behavior::Behavior for $actor {
331///             type Protocol = ActorProtocol;
332///             type Event = behavior::Never;
333///             type Sends = behavior::NoSends;
334///             type Ph = behavior::Never;
335///             type Error = behavior::Never;
336///             type Birth = $birth;
337///             fn transition(
338///                 &mut self,
339///                 _: behavior::ActiveTurn,
340///                 event: behavior::Never,
341///             ) -> behavior::BehaviorActed<Self> {
342///                 match event {}
343///             }
344///         }
345///     };
346/// }
347/// inert!(Child, behavior::NoBirths);
348/// inert!(Proxy, behavior::NoBirths);
349/// inert!(Parent, behavior::Births<Child>);
350/// inert!(ChangedTopology, behavior::Births<Proxy>);
351///
352/// impl behavior::BehaviorBase for Parent {
353///     type Base = Self;
354///     fn base(&self) -> &Self { self }
355/// }
356/// impl behavior::BehaviorBase for ChangedTopology {
357///     type Base = Parent;
358///     fn base(&self) -> &Parent { unreachable!() }
359/// }
360///
361/// struct WorkerRole;
362/// impl behavior::ChildRole<Parent> for WorkerRole {
363///     type Child = Child;
364///     type Position = behavior::ChildHead;
365/// }
366/// impl behavior::ChildOccurrence<Parent> for WorkerRole {
367///     type Resolution = behavior::DeclaredChildOccurrence;
368/// }
369///
370/// fn require<T: behavior::ResolveChildOccurrence<WorkerRole>>() {}
371/// require::<ChangedTopology>();
372/// ```
373pub trait ResolveChildOccurrence<Occurrence>:
374    Behavior + sealed::ResolveChildOccurrence<Occurrence>
375{
376    /// Exact concrete child behavior at this occurrence.
377    type Child: Behavior;
378
379    /// Exact structural position in this emitter's direct birth algebra.
380    type Position: ChildPosition<<Self::Birth as BirthMode>::Child, Self::Child>;
381}
382
383impl<Emitter, Occurrence> ResolveChildOccurrence<Occurrence> for Emitter
384where
385    Emitter: Behavior + BehaviorBase + sealed::ResolveChildOccurrence<Occurrence>,
386    Emitter::Base: Behavior,
387    Occurrence: ChildOccurrence<Emitter::Base>,
388    Occurrence::Resolution: ResolveChildOccurrenceDescriptor<Emitter, Occurrence>,
389{
390    type Child =
391        <Occurrence::Resolution as ResolveChildOccurrenceDescriptor<Emitter, Occurrence>>::Child;
392    type Position =
393        <Occurrence::Resolution as ResolveChildOccurrenceDescriptor<Emitter, Occurrence>>::Position;
394}
395
396/// Child behavior resolved from `Occurrence` for the running `Emitter`.
397pub type ResolvedChild<Emitter, Occurrence> =
398    <Emitter as ResolveChildOccurrence<Occurrence>>::Child;
399
400/// Structural birth position resolved from `Occurrence` for the running
401/// `Emitter`.
402pub type ResolvedChildPosition<Emitter, Occurrence> =
403    <Emitter as ResolveChildOccurrence<Occurrence>>::Position;
404
405/// Child behavior selected by one named role.
406pub type RoleChild<Parent, Role> = <Role as ChildRole<Parent>>::Child;
407
408/// Canonical protocol selected by one named role.
409pub type RoleProtocol<Parent, Role> = <RoleChild<Parent, Role> as Behavior>::Protocol;
410
411/// One complete creation paired with a route selected by the interpreter.
412///
413/// Behavior never constructs or stores this value. It exists only between the
414/// generic batch-routing step and the concrete child host, and it returns
415/// complete on rejection or corruption.
416#[derive(Debug, Clone, PartialEq, Eq)]
417pub struct RoutedCreation<A: Address, New> {
418    creation: CreateChild<A, New>,
419    route: A::Nonce,
420}
421
422impl<A: Address, New> RoutedCreation<A, New> {
423    /// Pair one creation with the route selected by the current runtime.
424    #[must_use]
425    pub const fn new(creation: CreateChild<A, New>, route: A::Nonce) -> Self {
426        Self { creation, route }
427    }
428
429    #[must_use]
430    pub const fn id(&self) -> CreationId {
431        self.creation.id()
432    }
433
434    #[must_use]
435    pub const fn kind(&self) -> CreationKind {
436        self.creation.kind()
437    }
438
439    #[must_use]
440    pub const fn route(&self) -> A::Nonce {
441        self.route
442    }
443
444    /// Borrow the staged child for its pure initialization fold while the
445    /// complete routed request remains owned for a possible rejection.
446    #[must_use]
447    pub fn child_mut(&mut self) -> &mut New {
448        &mut self.creation.child
449    }
450
451    #[must_use]
452    pub fn into_parts(self) -> (CreateChild<A, New>, A::Nonce) {
453        (self.creation, self.route)
454    }
455}
456
457/// Failure to claim an address fresh with respect to the current actor
458/// configuration.
459#[derive(Debug, Clone, Copy, PartialEq, Eq, thiserror::Error)]
460pub enum AllocationRejection {
461    /// The allocator has no address it can presently claim.
462    #[error("fresh actor-address allocation is exhausted")]
463    Exhausted,
464    /// The proposed address was already claimed; accepting it would violate
465    /// actor-name freshness.
466    #[error("the proposed actor address is already claimed")]
467    AddressAlreadyClaimed,
468}
469
470/// Complete semantic rejection of one staged fresh creation.
471#[derive(Debug, Clone, Copy, PartialEq, Eq, thiserror::Error)]
472pub enum CreationRejection {
473    /// Fresh address allocation failed.
474    #[error("fresh allocation failed: {0}")]
475    Allocation(AllocationRejection),
476    /// The child's initialization fold did not complete successfully.
477    #[error("child initialization failed")]
478    InitializationFailed,
479    /// Installation or commit failed after allocation.
480    #[error("the interpreter could not install and commit the child")]
481    EnvironmentFailed,
482}
483
484/// The creator namespace cannot route an entire declared creation batch.
485#[derive(Debug, Clone, Copy, PartialEq, Eq, thiserror::Error)]
486#[error("the creator child namespace is exhausted")]
487pub struct ChildNamespaceExhausted;
488
489impl<A, New> ActionItem for Creations<CreateChild<A, New>>
490where
491    A: Address,
492    A::Nonce: Send,
493    New: Send,
494{
495    type Accepted = Creations<RoutedCreation<A, New>>;
496    type Rejection = ChildNamespaceExhausted;
497    type Prerequisite = Never;
498}
499
500/// One committed fresh child with its creator-local provenance and exact
501/// installed actor. The occurrence distinguishes equal child behaviors in
502/// distinct static positions; it is not an actor identity or runtime route.
503pub struct CommittedChild<C, Occurrence>
504where
505    C: Behavior,
506    BehaviorAddr<C>: EndpointAddress,
507{
508    id: CreationId,
509    kind: CreationKind,
510    actor: EstablishedActor<C>,
511    occurrence: PhantomData<fn() -> Occurrence>,
512}
513
514impl<C, Occurrence> CommittedChild<C, Occurrence>
515where
516    C: Behavior,
517    BehaviorAddr<C>: EndpointAddress,
518{
519    /// Record an already committed fresh installation. This does not install
520    /// an actor; only a successful interpreter installation may issue its
521    /// runtime-owned actor value.
522    #[must_use]
523    pub const fn new(id: CreationId, kind: CreationKind, actor: EstablishedActor<C>) -> Self {
524        Self {
525            id,
526            kind,
527            actor,
528            occurrence: PhantomData,
529        }
530    }
531
532    #[must_use]
533    pub const fn id(&self) -> CreationId {
534        self.id
535    }
536
537    #[must_use]
538    pub const fn kind(&self) -> CreationKind {
539        self.kind
540    }
541
542    #[must_use]
543    pub fn actor(&self) -> EstablishedActor<C> {
544        self.actor.clone()
545    }
546
547    #[must_use]
548    pub fn into_parts(self) -> (CreationId, CreationKind, EstablishedActor<C>) {
549        (self.id, self.kind, self.actor)
550    }
551}
552
553/// Committed or rejected result for one exact concrete child occurrence.
554///
555/// `Installed` is constructed only after fresh allocation, successful
556/// initialization, endpoint establishment, and creator-local binding. It returns the
557/// exact installed actor. `Rejected` carries no capability, so a
558/// failed request cannot be used as an established destination. Both variants
559/// preserve Behavior-authored creation provenance.
560///
561/// `Occurrence` is topology navigation evidence authored by the parent. It
562/// distinguishes duplicate occurrences without becoming another protocol
563/// identity or runtime key. A consumer that only sends messages may project
564/// the protocol recipient without retaining the installed actor.
565///
566/// A rejected named report has no actor capability to extract:
567///
568/// ```compile_fail,E0026
569/// fn rejected_actor<C, Occurrence>(report: behavior::EstablishedCreation<C, Occurrence>)
570/// where
571///     C: behavior::Behavior,
572///     behavior::BehaviorAddr<C>: behavior::EndpointAddress,
573/// {
574///     let behavior::EstablishedCreation::Rejected { actor, .. } = report else { return; };
575///     let _: behavior::EstablishedActor<C> = actor;
576/// }
577/// ```
578///
579/// Duplicate occurrences remain incompatible even when their protocols and
580/// endpoint representations match:
581///
582/// ```compile_fail,E0308
583/// fn wrong_occurrence<C, Primary, Backup>(backup: behavior::EstablishedCreation<C, Backup>)
584/// where
585///     C: behavior::Behavior,
586///     behavior::BehaviorAddr<C>: behavior::EndpointAddress,
587/// {
588///     let _: behavior::EstablishedCreation<C, Primary> = backup;
589/// }
590/// ```
591pub enum EstablishedCreation<C, Occurrence>
592where
593    C: Behavior,
594    BehaviorAddr<C>: EndpointAddress,
595{
596    Installed(CommittedChild<C, Occurrence>),
597    Rejected {
598        id: CreationId,
599        kind: CreationKind,
600        reason: CreationRejection,
601        occurrence: PhantomData<fn() -> Occurrence>,
602    },
603}
604
605impl<C, Occurrence> EstablishedCreation<C, Occurrence>
606where
607    C: Behavior,
608    BehaviorAddr<C>: EndpointAddress,
609{
610    #[must_use]
611    pub const fn installed(child: CommittedChild<C, Occurrence>) -> Self {
612        Self::Installed(child)
613    }
614
615    #[must_use]
616    pub const fn rejected(id: CreationId, kind: CreationKind, reason: CreationRejection) -> Self {
617        Self::Rejected {
618            id,
619            kind,
620            reason,
621            occurrence: PhantomData,
622        }
623    }
624
625    #[must_use]
626    pub const fn id(&self) -> CreationId {
627        match self {
628            Self::Installed(child) => child.id(),
629            Self::Rejected { id, .. } => *id,
630        }
631    }
632
633    #[must_use]
634    pub const fn kind(&self) -> CreationKind {
635        match self {
636            Self::Installed(child) => child.kind(),
637            Self::Rejected { kind, .. } => *kind,
638        }
639    }
640
641    /// Consume the report and return its exact endpoint capability.
642    ///
643    /// # Errors
644    /// Returns the original [`CreationRejection`] when child creation did not
645    /// commit.
646    pub fn into_recipient(self) -> Result<EstablishedRecipient<C::Protocol>, CreationRejection> {
647        match self {
648            Self::Installed(child) => Ok(child.into_parts().2.into_recipient()),
649            Self::Rejected { reason, .. } => Err(reason),
650        }
651    }
652
653    /// Transfer the concrete committed child without recreating authority
654    /// from a protocol recipient.
655    ///
656    /// # Errors
657    /// Returns the original [`CreationRejection`] when child creation did not
658    /// commit.
659    pub fn into_committed(self) -> Result<CommittedChild<C, Occurrence>, CreationRejection> {
660        match self {
661            Self::Installed(child) => Ok(child),
662            Self::Rejected { reason, .. } => Err(reason),
663        }
664    }
665}
666
667/// Complete result after a runtime accepts one child definition.
668///
669/// A created child leaves only its exact established capability. Rejection
670/// during the pure initialization transition returns the current child and its
671/// exact error. A caught panic returns the extant current child without
672/// claiming an error or successful actions. Rejection while establishing the
673/// host returns the current child and the still-uninterpreted initialization
674/// actions. No variant reconstructs a pre-initialization value or silently
675/// discards an affine action.
676///
677/// A failed child installation returns current work and no installed actor:
678///
679/// ```compile_fail,E0026
680/// fn rejected_actor<C, Occurrence>(outcome: behavior::ChildCreationOutcome<C, Occurrence>)
681/// where
682///     C: behavior::Behavior,
683///     behavior::BehaviorAddr<C>: behavior::EndpointAddress,
684/// {
685///     if let behavior::ChildCreationOutcome::HostRejected { actor, .. } = outcome {
686///         let _: behavior::EstablishedActor<C> = actor;
687///     }
688/// }
689/// ```
690pub enum ChildCreationOutcome<C, Occurrence>
691where
692    C: Behavior,
693    BehaviorAddr<C>: EndpointAddress,
694{
695    /// Fresh child creation committed successfully.
696    Established(CommittedChild<C, Occurrence>),
697    /// The child's pure initialization transition rejected before host commit.
698    InitializationRejected {
699        /// Current child value with its creator correlation and private route.
700        creation: RoutedCreation<BehaviorAddr<C>, C>,
701        /// Exact error returned by the child's initialization transition.
702        error: C::Error,
703    },
704    /// The child's pure initialization panicked before any host commitment.
705    ///
706    /// Only the outer routed child that survived Rust unwinding is returned;
707    /// this does not promise recovery of values destroyed inside user code.
708    InitializationPanicked {
709        /// Current child value with its creator correlation and private route.
710        creation: RoutedCreation<BehaviorAddr<C>, C>,
711    },
712    /// Host establishment rejected after initialization produced actions.
713    HostRejected {
714        /// Current child value with its creator correlation and private route.
715        creation: RoutedCreation<BehaviorAddr<C>, C>,
716        /// Complete initialization actions that were never interpreted.
717        initialization: Actions<BehaviorAddr<C>, C::Ph, C::Sends, C::Birth>,
718        /// Exact reason the host could not commit this child.
719        reason: CreationRejection,
720    },
721}
722
723impl<C, Occurrence> ChildCreationOutcome<C, Occurrence>
724where
725    C: Behavior,
726    BehaviorAddr<C>: EndpointAddress,
727{
728    /// Consume a committed child result into its exact concrete actor
729    /// capability.
730    ///
731    /// The committed variant directly owns the actor, ID, kind, and
732    /// occurrence; no nested rejection can appear under success.
733    ///
734    /// # Errors
735    ///
736    /// Returns the complete original result when creation did not commit.
737    pub fn into_committed(self) -> Result<CommittedChild<C, Occurrence>, Self> {
738        match self {
739            Self::Established(child) => Ok(child),
740            other => Err(other),
741        }
742    }
743
744    /// Consume a committed child into its exact actor.
745    ///
746    /// # Errors
747    /// Returns the complete original result when creation did not commit.
748    pub fn into_actor(self) -> Result<EstablishedActor<C>, Self> {
749        self.into_committed().map(|child| child.into_parts().2)
750    }
751}
752
753/// One complete child-creation settlement returned to its creator.
754///
755/// This product moves the existing settlement without reclassifying it. In
756/// particular, initialization and host rejection retain the current child and
757/// exact initialization value. A runtime that cannot admit this value to the
758/// live creator must recover it from the returned event and keep it in host
759/// custody.
760#[must_use = "a child-creation settlement must be admitted or retained"]
761pub struct ChildCreationSettled<C, Occurrence>
762where
763    C: Behavior,
764    BehaviorAddr<C>: EndpointAddress,
765{
766    settlement: SettledItem<
767        RoutedCreation<BehaviorAddr<C>, C>,
768        ItemSettlement<
769            RoutedCreation<BehaviorAddr<C>, C>,
770            ChildCreationOutcome<C, Occurrence>,
771            CreationRejection,
772            Never,
773        >,
774    >,
775}
776
777impl<C, Occurrence> ChildCreationSettled<C, Occurrence>
778where
779    C: Behavior,
780    BehaviorAddr<C>: EndpointAddress,
781{
782    #[must_use]
783    pub const fn new(
784        settlement: SettledItem<
785            RoutedCreation<BehaviorAddr<C>, C>,
786            ItemSettlement<
787                RoutedCreation<BehaviorAddr<C>, C>,
788                ChildCreationOutcome<C, Occurrence>,
789                CreationRejection,
790                Never,
791            >,
792        >,
793    ) -> Self {
794        Self { settlement }
795    }
796
797    /// Recover the exact generic settlement without cloning any owned value.
798    #[must_use]
799    pub fn into_settlement(
800        self,
801    ) -> SettledItem<
802        RoutedCreation<BehaviorAddr<C>, C>,
803        ItemSettlement<
804            RoutedCreation<BehaviorAddr<C>, C>,
805            ChildCreationOutcome<C, Occurrence>,
806            CreationRejection,
807            Never,
808        >,
809    > {
810        self.settlement
811    }
812}
813
814impl<C, Occurrence> core::fmt::Debug for ChildCreationSettled<C, Occurrence>
815where
816    C: Behavior,
817    BehaviorAddr<C>: EndpointAddress,
818{
819    fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
820        formatter
821            .debug_struct("ChildCreationSettled")
822            .finish_non_exhaustive()
823    }
824}
825
826/// Non-authoritative correlation to one creation result in the current action.
827///
828/// `P` and `Occurrence` select the exact creator-local entry statically. The
829/// value carries no recipient, actor identity, or child-hosting authority; the
830/// corresponding creation settlement remains its sole authoritative owner.
831///
832/// Equal ID representations at different occurrences cannot be
833/// substituted:
834///
835/// ```compile_fail,E0308
836/// struct Worker;
837/// impl behavior::Protocol for Worker {
838///     type Addr = behavior::MailAddr;
839///     type Msg = ();
840/// }
841/// struct Primary;
842/// struct Backup;
843/// let mut sequence = behavior::CreationSequence::new();
844/// let id = sequence.issue().expect("fixture creation ID");
845/// let backup = behavior::CreationCorrelation::<Worker, Backup>::new(id);
846/// let _: behavior::CreationCorrelation<Worker, Primary> = backup;
847/// ```
848pub struct CreationCorrelation<P, Occurrence>
849where
850    P: Protocol,
851{
852    id: CreationId,
853    occurrence: PhantomData<fn() -> (P, Occurrence)>,
854}
855
856impl<P, Occurrence> CreationCorrelation<P, Occurrence>
857where
858    P: Protocol,
859{
860    #[must_use]
861    pub const fn new(id: CreationId) -> Self {
862        Self {
863            id,
864            occurrence: PhantomData,
865        }
866    }
867
868    #[must_use]
869    pub const fn id(self) -> CreationId {
870        self.id
871    }
872}
873
874impl<P, Occurrence> Copy for CreationCorrelation<P, Occurrence> where P: Protocol {}
875
876impl<P, Occurrence> Clone for CreationCorrelation<P, Occurrence>
877where
878    P: Protocol,
879{
880    fn clone(&self) -> Self {
881        *self
882    }
883}
884
885impl<P, Occurrence> core::fmt::Debug for CreationCorrelation<P, Occurrence>
886where
887    P: Protocol,
888{
889    fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
890        formatter
891            .debug_tuple("CreationCorrelation")
892            .field(&self.id)
893            .finish()
894    }
895}
896
897impl<P, Occurrence> PartialEq for CreationCorrelation<P, Occurrence>
898where
899    P: Protocol,
900{
901    fn eq(&self, other: &Self) -> bool {
902        self.id == other.id
903    }
904}
905
906impl<P, Occurrence> Eq for CreationCorrelation<P, Occurrence> where P: Protocol {}
907
908/// Same-action communication to one declared creator-local role.
909///
910/// The interpreter resolves this route only after all creations in the same
911/// [`crate::Actions`] have committed. A rejected or absent binding must produce
912/// a typed interpreter outcome; it can never be converted into a logical
913/// address by nonce arithmetic.
914pub struct ChildDelivery<P, Occurrence>
915where
916    P: Protocol,
917{
918    pub creation: CreationId,
919    pub message: P::Msg,
920    occurrence: PhantomData<fn() -> Occurrence>,
921}
922
923/// Private typed communication to one declared creator-local child role.
924///
925/// `ChildDelivery` addresses the child's public protocol. `ChildInput`
926/// instead selects one owner-defined member of the concrete child's event
927/// algebra through `Source`. This is the static boundary used for lifecycle
928/// coordination between an owner and a composed child: it retains the exact
929/// child behavior, occurrence, input, and ingress owner without exposing the
930/// input through the child's public protocol or performing a runtime lookup.
931///
932/// This is a derived Bombay communication form. Like `ChildDelivery`, its
933/// creator-local route is interpreted only after same-action creations have
934/// committed; constructing it performs no delivery.
935pub struct ChildInput<Child, Source, Input, Occurrence>
936where
937    Child: Behavior,
938{
939    /// Creator-local creation ID of the concrete child receiving the input.
940    pub creation: CreationId,
941    /// Complete private input transferred to the child.
942    pub input: Input,
943    marker: PhantomData<fn() -> (Child, Source, Occurrence)>,
944}
945
946/// Exact reason one public child delivery was not accepted.
947#[derive(Clone, Copy, Debug, Eq, PartialEq)]
948pub enum ChildDeliveryReason {
949    MissingBinding,
950    ClosedRecipient,
951}
952
953/// Exact reason one private child input was not accepted.
954#[derive(Clone, Copy, Debug, Eq, PartialEq)]
955pub enum ChildInputReason {
956    MissingBinding,
957    ClosedControlLane,
958}
959
960/// One report emitted through an established creator/child relationship.
961///
962/// The interpreter attaches `child` from its exact local binding; the
963/// emitting behavior supplies only `report`. `EventIngress` separately keeps
964/// the concrete child behavior and occurrence in the parent's event type, so
965/// equal nonce representations cannot confuse different child roles.
966#[derive(Debug, Clone, Copy, PartialEq, Eq)]
967pub struct ChildReport<R> {
968    /// Creator-local ID of the child that emitted the report.
969    pub child: CreationId,
970    /// Complete report value transferred by that child.
971    pub report: R,
972}
973
974impl<R> ChildReport<R> {
975    /// Attach an established creator-local creation ID to one report.
976    #[must_use]
977    pub const fn new(child: CreationId, report: R) -> Self {
978        Self { child, report }
979    }
980}
981
982impl<R> From<(CreationId, crate::ReportToParent<R>)> for ChildReport<R> {
983    fn from((child, request): (CreationId, crate::ReportToParent<R>)) -> Self {
984        Self::new(child, request.into_inner())
985    }
986}
987
988impl<Child, Source, Input, Occurrence> ChildInput<Child, Source, Input, Occurrence>
989where
990    Child: Behavior,
991    Child::Event: crate::ChildInputIngress<Source, Input>,
992{
993    /// Construct a private input for one exact creator-local child creation.
994    #[must_use]
995    pub const fn after(creation: CreationId, input: Input) -> Self {
996        Self {
997            creation,
998            input,
999            marker: PhantomData,
1000        }
1001    }
1002}
1003
1004impl<Child, Source, Input, Occurrence> Clone for ChildInput<Child, Source, Input, Occurrence>
1005where
1006    Child: Behavior,
1007    Input: Clone,
1008{
1009    fn clone(&self) -> Self {
1010        Self {
1011            creation: self.creation,
1012            input: self.input.clone(),
1013            marker: PhantomData,
1014        }
1015    }
1016}
1017
1018impl<P, Occurrence> ChildDelivery<P, Occurrence>
1019where
1020    P: Protocol,
1021{
1022    #[must_use]
1023    pub const fn after(creation: CreationId, message: P::Msg) -> Self {
1024        Self {
1025            creation,
1026            message,
1027            occurrence: PhantomData,
1028        }
1029    }
1030}
1031
1032impl<P, Occurrence> Clone for ChildDelivery<P, Occurrence>
1033where
1034    P: Protocol,
1035    P::Msg: Clone,
1036{
1037    fn clone(&self) -> Self {
1038        Self {
1039            creation: self.creation,
1040            message: self.message.clone(),
1041            occurrence: PhantomData,
1042        }
1043    }
1044}
1045
1046impl<P, Occurrence> ActionItem for ChildDelivery<P, Occurrence>
1047where
1048    P: Protocol,
1049    P::Msg: Send,
1050{
1051    type Accepted = ();
1052    type Rejection = ChildDeliveryReason;
1053    type Prerequisite = CreationCorrelation<P, Occurrence>;
1054}
1055
1056impl<Child, Source, Input, Occurrence> ActionItem for ChildInput<Child, Source, Input, Occurrence>
1057where
1058    Child: Behavior,
1059    Input: Send,
1060{
1061    type Accepted = ();
1062    type Rejection = ChildInputReason;
1063    type Prerequisite = CreationCorrelation<Child::Protocol, Occurrence>;
1064}
1065
1066/// Runtime ownership port for establishing one concrete child behavior.
1067///
1068/// The result vocabulary belongs to the creation request, never the runtime.
1069/// Accepting ownership consumes the child definition and returns its one
1070/// authoritative created-or-rejected result. Refusal before ownership transfer
1071/// returns the complete request. Child creation has no prerequisite, while
1072/// interpreter corruption uses the shared [`crate::InterpreterFault`] sum.
1073///
1074/// A runtime cannot substitute a private receipt or rejection type:
1075///
1076/// ```compile_fail,E0271
1077/// #[derive(Clone, Copy, Eq, PartialEq)]
1078/// struct RuntimeAddr;
1079/// impl behavior::Address for RuntimeAddr { type Nonce = u8; }
1080/// #[derive(Clone)]
1081/// struct Endpoint;
1082/// struct Installed<B: behavior::Behavior>(Endpoint, std::sync::mpsc::Sender<B::Event>);
1083/// impl<B: behavior::Behavior> Clone for Installed<B> {
1084///     fn clone(&self) -> Self { Self(self.0.clone(), self.1.clone()) }
1085/// }
1086/// impl behavior::EndpointAddress for RuntimeAddr {
1087///     type Established<P> = Endpoint where P: behavior::Protocol<Addr = Self>;
1088///     type Installed<B> = Installed<B>
1089///         where B: behavior::Behavior<Protocol: behavior::Protocol<Addr = Self>>;
1090///     fn recipient<B>(installed: &Self::Installed<B>) -> Endpoint
1091///     where B: behavior::Behavior<Protocol: behavior::Protocol<Addr = Self>> {
1092///         installed.0.clone()
1093///     }
1094/// }
1095/// struct Child;
1096/// impl behavior::Protocol for Child {
1097///     type Addr = RuntimeAddr;
1098///     type Msg = behavior::Never;
1099/// }
1100/// impl behavior::Behavior for Child {
1101///     type Protocol = Self;
1102///     type Event = behavior::User<RuntimeAddr, behavior::Never>;
1103///     type Sends = behavior::NoSends;
1104///     type Ph = behavior::Never;
1105///     type Error = behavior::Never;
1106///     type Birth = behavior::NoBirths;
1107///     fn transition(
1108///         &mut self,
1109///         _: behavior::ActiveTurn,
1110///         event: Self::Event,
1111///     ) -> behavior::BehaviorActed<Self> {
1112///         match event.message {}
1113///     }
1114/// }
1115/// struct Runtime;
1116///
1117/// impl behavior::EstablishChild<behavior::ChildHead, Child> for Runtime {
1118///     fn establish_child(
1119///         &mut self,
1120///         creation: behavior::RoutedCreation<behavior::BehaviorAddr<Child>, Child>,
1121///     ) -> impl core::future::Future<Output = behavior::ItemSettlement<
1122///         behavior::RoutedCreation<behavior::BehaviorAddr<Child>, Child>,
1123///         (),
1124///         &'static str,
1125///         behavior::Never,
1126///     >> + Send {
1127///         async move { behavior::ItemSettlement::Rejected { item: creation, reason: "no" } }
1128///     }
1129/// }
1130/// ```
1131pub trait EstablishChild<Occurrence, C>
1132where
1133    C: Behavior,
1134    BehaviorAddr<C>: EndpointAddress,
1135{
1136    /// Establish exactly the supplied child or return its complete settlement.
1137    fn establish_child(
1138        &mut self,
1139        creation: RoutedCreation<BehaviorAddr<C>, C>,
1140    ) -> impl Future<
1141        Output = ItemSettlement<
1142            RoutedCreation<BehaviorAddr<C>, C>,
1143            ChildCreationOutcome<C, Occurrence>,
1144            CreationRejection,
1145            Never,
1146        >,
1147    > + Send;
1148}
1149
1150/// Authoritative result shape for one closed child choice.
1151///
1152/// This type-level product depends only on the declared child protocols and
1153/// their occurrences. It contains no runtime-selected type.
1154#[doc(hidden)]
1155pub trait ChildCreationProduct<A: Address, Occurrence>: Sized {
1156    type Result;
1157}
1158
1159/// Exhaustive static dispatch of one creation-only child sum.
1160///
1161/// This is an interpreter-facing derived construction, not another actor-model
1162/// operation. Implementations must preserve the ID, route, and creation kind and
1163/// call exactly one concrete [`EstablishChild`] implementation. [`ChildChoice`]
1164/// provides the closed recursive heterogeneous sum. Dispatch futures are
1165/// sendable; heterogeneous sums therefore require sendable alternatives,
1166/// runtime routes, and child hosts.
1167pub trait DispatchBirth<A: Address, Host>: ChildCreationProduct<A, ChildHead> + Sized {
1168    /// Select exactly one concrete child host while preserving creation data
1169    /// in every non-accepted settlement.
1170    fn dispatch_birth(
1171        self,
1172        id: CreationId,
1173        route: A::Nonce,
1174        kind: CreationKind,
1175        host: &mut Host,
1176    ) -> impl Future<
1177        Output = ItemSettlement<
1178            RoutedCreation<A, Self>,
1179            <Self as ChildCreationProduct<A, ChildHead>>::Result,
1180            CreationRejection,
1181            Never,
1182        >,
1183    > + Send;
1184}
1185
1186trait CreateSelectedChild<A: Address, Occurrence, Host>:
1187    ChildCreationProduct<A, Occurrence> + Sized
1188{
1189    fn dispatch_birth_at(
1190        self,
1191        id: CreationId,
1192        route: A::Nonce,
1193        kind: CreationKind,
1194        host: &mut Host,
1195    ) -> impl Future<
1196        Output = ItemSettlement<
1197            RoutedCreation<A, Self>,
1198            <Self as ChildCreationProduct<A, Occurrence>>::Result,
1199            CreationRejection,
1200            Never,
1201        >,
1202    > + Send;
1203}
1204
1205impl<A, Child, Host> DispatchBirth<A, Host> for Child
1206where
1207    A: Address,
1208    Child: CreateSelectedChild<A, ChildHead, Host>,
1209{
1210    fn dispatch_birth(
1211        self,
1212        id: CreationId,
1213        route: A::Nonce,
1214        kind: CreationKind,
1215        host: &mut Host,
1216    ) -> impl Future<
1217        Output = ItemSettlement<
1218            RoutedCreation<A, Self>,
1219            <Self as ChildCreationProduct<A, ChildHead>>::Result,
1220            CreationRejection,
1221            Never,
1222        >,
1223    > + Send {
1224        self.dispatch_birth_at(id, route, kind, host)
1225    }
1226}
1227
1228/// One alternative in a closed, recursively composed child-creation sum.
1229///
1230/// `Head` is one concrete child behavior and `Tail` is the remaining closed
1231/// sum. This is a creation choice only: it is not a behavior, message
1232/// envelope, registry, or runtime dispatch mechanism.
1233///
1234/// Every alternative requires a concrete child host; incomplete interpreter
1235/// support is rejected statically:
1236///
1237/// ```compile_fail,E0277
1238/// #[derive(Clone, Copy, Eq, PartialEq)]
1239/// struct RuntimeAddr;
1240/// impl behavior::Address for RuntimeAddr { type Nonce = u8; }
1241/// #[derive(Clone)]
1242/// struct Endpoint;
1243/// struct Installed<B: behavior::Behavior>(Endpoint, std::sync::mpsc::Sender<B::Event>);
1244/// impl<B: behavior::Behavior> Clone for Installed<B> {
1245///     fn clone(&self) -> Self { Self(self.0.clone(), self.1.clone()) }
1246/// }
1247/// impl behavior::EndpointAddress for RuntimeAddr {
1248///     type Established<P> = Endpoint where P: behavior::Protocol<Addr = Self>;
1249///     type Installed<B> = Installed<B>
1250///         where B: behavior::Behavior<Protocol: behavior::Protocol<Addr = Self>>;
1251///     fn recipient<B>(installed: &Self::Installed<B>) -> Endpoint
1252///     where B: behavior::Behavior<Protocol: behavior::Protocol<Addr = Self>> {
1253///         installed.0.clone()
1254///     }
1255/// }
1256/// struct CacheWorker;
1257/// struct QueueWorker;
1258///
1259/// macro_rules! inert {
1260///     ($child:ty) => {
1261///         impl behavior::Protocol for $child {
1262///             type Addr = RuntimeAddr;
1263///             type Msg = behavior::Never;
1264///         }
1265///         impl behavior::Behavior for $child {
1266///             type Protocol = Self;
1267///             type Event = behavior::User<RuntimeAddr, behavior::Never>;
1268///             type Sends = behavior::NoSends;
1269///             type Ph = behavior::Never;
1270///             type Error = behavior::Never;
1271///             type Birth = behavior::NoBirths;
1272///
1273///             fn transition(
1274///                 &mut self,
1275///                 _: behavior::ActiveTurn,
1276///                 event: Self::Event,
1277///             ) -> behavior::BehaviorActed<Self> {
1278///                 match event.message {}
1279///             }
1280///         }
1281///     };
1282/// }
1283/// inert!(CacheWorker);
1284/// inert!(QueueWorker);
1285///
1286/// struct Incomplete;
1287/// impl behavior::EstablishChild<behavior::ChildHead, CacheWorker> for Incomplete {
1288///     fn establish_child(
1289///         &mut self,
1290///         creation: behavior::RoutedCreation<RuntimeAddr, CacheWorker>,
1291///     ) -> impl core::future::Future<Output = behavior::ItemSettlement<
1292///         behavior::RoutedCreation<RuntimeAddr, CacheWorker>,
1293///         behavior::ChildCreationOutcome<CacheWorker, behavior::ChildHead>,
1294///         behavior::CreationRejection,
1295///         behavior::Never,
1296///     >> + Send {
1297///         async move { behavior::ItemSettlement::Rejected {
1298///             item: creation,
1299///             reason: behavior::CreationRejection::EnvironmentFailed,
1300///         } }
1301///     }
1302/// }
1303///
1304/// type WorkerChoices = behavior::ChildChoice<
1305///     CacheWorker,
1306///     behavior::ChildChoice<QueueWorker, behavior::Never>,
1307/// >;
1308/// fn require_complete<T: behavior::DispatchBirth<RuntimeAddr, Incomplete>>() {}
1309/// require_complete::<WorkerChoices>();
1310/// ```
1311#[derive(Debug, Clone, PartialEq, Eq)]
1312pub enum ChildChoice<Head, Tail> {
1313    /// Select the concrete child at this position.
1314    Head(Head),
1315    /// Select one concrete child from the remaining alternatives.
1316    Tail(Tail),
1317}
1318
1319/// Position selecting the head of a closed [`ChildChoice`] sum.
1320#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
1321pub struct ChildHead;
1322
1323/// Position selecting inside the tail of a closed [`ChildChoice`] sum.
1324#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
1325pub struct ChildTail<Position>(PhantomData<fn() -> Position>);
1326
1327/// Static proof that `Child` occupies `Position` in a closed child sum.
1328///
1329/// This trait provides structural evidence only. It does not construct a
1330/// choice, perform creation, or select a child through runtime inspection.
1331/// A role cannot claim a position occupied by a different child:
1332///
1333/// ```compile_fail
1334/// struct CacheWorker;
1335/// struct QueueWorker;
1336/// struct Parent;
1337/// macro_rules! inert {
1338///     ($actor:ty) => {
1339///         impl behavior::Protocol for $actor {
1340///             type Addr = behavior::MailAddr;
1341///             type Msg = behavior::Never;
1342///         }
1343///         impl behavior::Behavior for $actor {
1344///             type Protocol = Self;
1345///             type Event = behavior::User<behavior::MailAddr, behavior::Never>;
1346///             type Sends = Vec<behavior::Never>;
1347///             type Ph = behavior::Never;
1348///             type Error = behavior::Never;
1349///             type Birth = behavior::NoBirths;
1350///             fn transition(&mut self, _: behavior::ActiveTurn, event: Self::Event) -> behavior::BehaviorActed<Self> {
1351///                 match event.message {}
1352///             }
1353///         }
1354///     };
1355/// }
1356/// inert!(CacheWorker);
1357/// inert!(QueueWorker);
1358/// impl behavior::Protocol for Parent {
1359///     type Addr = behavior::MailAddr;
1360///     type Msg = behavior::Never;
1361/// }
1362/// impl behavior::Behavior for Parent {
1363///     type Protocol = Self;
1364///     type Event = behavior::User<behavior::MailAddr, behavior::Never>;
1365///     type Sends = Vec<behavior::Never>;
1366///     type Ph = behavior::Never;
1367///     type Error = behavior::Never;
1368///     type Birth = behavior::Births<behavior::ChildChoice<QueueWorker, behavior::ChildChoice<CacheWorker, behavior::Never>>>;
1369///     fn transition(&mut self, _: behavior::ActiveTurn, event: Self::Event) -> behavior::BehaviorActed<Self> {
1370///         match event.message {}
1371///     }
1372/// }
1373/// struct ForgedCacheRole;
1374/// impl behavior::ChildRole<Parent> for ForgedCacheRole {
1375///     type Child = CacheWorker;
1376///     type Position = behavior::ChildHead;
1377/// }
1378/// ```
1379pub trait ChildPosition<Children, Child: Behavior>: sealed::ChildPosition {}
1380
1381impl sealed::ChildPosition for ChildHead {}
1382
1383impl<Child: Behavior> ChildPosition<Child, Child> for ChildHead {}
1384
1385impl<Head: Behavior, Tail> ChildPosition<ChildChoice<Head, Tail>, Head> for ChildHead {}
1386
1387impl<Position> sealed::ChildPosition for ChildTail<Position> {}
1388
1389impl<Head, Tail, Position, Child> ChildPosition<ChildChoice<Head, Tail>, Child>
1390    for ChildTail<Position>
1391where
1392    Child: Behavior,
1393    Position: ChildPosition<Tail, Child>,
1394{
1395}
1396
1397/// Append one closed direct-child algebra after another.
1398///
1399/// `Self` remains the structural prefix, so every child occurrence already
1400/// valid in that prefix retains both its child type and its position. `Tail`
1401/// begins only after the prefix's final position. The two injection functions
1402/// change only the closed sum containing a child; [`append_creations`](Self::append_creations)
1403/// additionally preserves every creation's ID, kind, and batch order while
1404/// placing all prefix creations before all appended creations.
1405///
1406/// This is a static composition of Bombay's existing staged-creation
1407/// capability, not another actor effect and not an allocation operation. The
1408/// interpreter remains solely responsible for establishing and binding the child.
1409///
1410/// A generic topology owner can therefore retain an inner behavior's exact
1411/// creation effects and append children whose concrete types were inferred
1412/// from value construction:
1413///
1414/// ```
1415/// type Combined = <behavior::Never as behavior::BirthNodeAppend<behavior::Never>>::Output;
1416/// let _: core::marker::PhantomData<Combined> = core::marker::PhantomData;
1417/// ```
1418pub trait BirthNodeAppend<Tail>: sealed::BirthNode + Sized
1419where
1420    Tail: sealed::BirthNode,
1421{
1422    /// Closed child algebra containing the complete prefix followed by the
1423    /// complete appended tail.
1424    type Output: sealed::BirthNode;
1425
1426    /// Inject one child from the existing prefix without changing its
1427    /// structural occurrence.
1428    fn append_prefix(self) -> Self::Output;
1429
1430    /// Inject one child from the appended tail after every prefix occurrence.
1431    fn append_tail(tail: Tail) -> Self::Output;
1432
1433    /// Preserve and concatenate two ordered creation batches.
1434    #[must_use]
1435    fn append_creations<A: Address>(
1436        prefix: Creations<CreateChild<A, Self>>,
1437        tail: Creations<CreateChild<A, Tail>>,
1438    ) -> Creations<CreateChild<A, Self::Output>> {
1439        let mut combined = Vec::with_capacity(prefix.len() + tail.len());
1440        combined.extend(prefix.into_iter().map(|creation| {
1441            let (id, child, kind) = creation.into_parts();
1442            CreateChild::from_parts(id, Self::append_prefix(child), kind)
1443        }));
1444        combined.extend(tail.into_iter().map(|creation| {
1445            let (id, child, kind) = creation.into_parts();
1446            CreateChild::from_parts(id, Self::append_tail(child), kind)
1447        }));
1448        Creations::from_items(combined)
1449    }
1450}
1451
1452impl<Tail> BirthNodeAppend<Tail> for Never
1453where
1454    Tail: sealed::BirthNode,
1455{
1456    type Output = Tail;
1457
1458    fn append_prefix(self) -> Self::Output {
1459        match self {}
1460    }
1461
1462    fn append_tail(tail: Tail) -> Self::Output {
1463        tail
1464    }
1465}
1466
1467impl<Node> BirthNodeAppend<Never> for Node
1468where
1469    Node: sealed::NonEmptyBirthNode,
1470{
1471    type Output = Node;
1472
1473    fn append_prefix(self) -> Self::Output {
1474        self
1475    }
1476
1477    fn append_tail(tail: Never) -> Self::Output {
1478        match tail {}
1479    }
1480}
1481
1482impl<Child, Tail> BirthNodeAppend<Tail> for Child
1483where
1484    Child: Behavior,
1485    Tail: sealed::NonEmptyBirthNode,
1486{
1487    type Output = ChildChoice<Child, Tail>;
1488
1489    fn append_prefix(self) -> Self::Output {
1490        ChildChoice::Head(self)
1491    }
1492
1493    fn append_tail(tail: Tail) -> Self::Output {
1494        ChildChoice::Tail(tail)
1495    }
1496}
1497
1498impl<Head, Rest, Tail> BirthNodeAppend<Tail> for ChildChoice<Head, Rest>
1499where
1500    Head: Behavior,
1501    Rest: sealed::BirthNode + BirthNodeAppend<Tail>,
1502    Tail: sealed::NonEmptyBirthNode,
1503    Rest::Output: sealed::BirthNode,
1504{
1505    type Output = ChildChoice<Head, Rest::Output>;
1506
1507    fn append_prefix(self) -> Self::Output {
1508        match self {
1509            ChildChoice::Head(head) => ChildChoice::Head(head),
1510            ChildChoice::Tail(rest) => ChildChoice::Tail(rest.append_prefix()),
1511        }
1512    }
1513
1514    fn append_tail(tail: Tail) -> Self::Output {
1515        ChildChoice::Tail(Rest::append_tail(tail))
1516    }
1517}
1518
1519impl<Parent: Behavior> ChildOccurrence<Parent> for ChildHead {
1520    type Resolution = StructuralChildOccurrence<Self>;
1521}
1522
1523impl<Parent: Behavior, Position> ChildOccurrence<Parent> for ChildTail<Position> {
1524    type Resolution = StructuralChildOccurrence<Self>;
1525}
1526
1527/// Sealed proof that an occurrence may select one resolver descriptor.
1528///
1529/// Nominal occurrences can select [`DeclaredChildOccurrence`] only when their
1530/// existing [`ChildRole`] implementation supplies the child and position. Raw
1531/// structural descriptors are available only to the identical
1532/// [`ChildHead`] or [`ChildTail`] occurrence.
1533#[doc(hidden)]
1534pub trait ChildOccurrenceResolution<Parent: Behavior, Occurrence>:
1535    sealed::ChildOccurrenceDescriptor + sealed::OccurrenceResolution<Parent, Occurrence>
1536{
1537}
1538
1539impl<Parent, Occurrence> ChildOccurrenceResolution<Parent, Occurrence> for DeclaredChildOccurrence
1540where
1541    Parent: Behavior,
1542    Occurrence: ChildRole<Parent>,
1543{
1544}
1545
1546impl<Parent: Behavior> ChildOccurrenceResolution<Parent, ChildHead>
1547    for StructuralChildOccurrence<ChildHead>
1548{
1549}
1550
1551impl<Parent: Behavior, Position> ChildOccurrenceResolution<Parent, ChildTail<Position>>
1552    for StructuralChildOccurrence<ChildTail<Position>>
1553{
1554}
1555
1556/// Sealed implementation detail for resolving occurrence descriptors.
1557#[doc(hidden)]
1558pub trait ResolveChildOccurrenceDescriptor<Emitter: Behavior, Occurrence>:
1559    sealed::ChildOccurrenceDescriptor + sealed::ResolveDescriptor<Emitter, Occurrence>
1560{
1561    type Child: Behavior;
1562    type Position: ChildPosition<<Emitter::Birth as BirthMode>::Child, Self::Child>;
1563}
1564
1565impl<Emitter, Occurrence, Position> ResolveChildOccurrenceDescriptor<Emitter, Occurrence>
1566    for StructuralChildOccurrence<Position>
1567where
1568    Emitter: Behavior,
1569    <Emitter::Birth as BirthMode>::Child: BirthNodeAt<Position>,
1570    Position: ChildPosition<
1571            <Emitter::Birth as BirthMode>::Child,
1572            <<Emitter::Birth as BirthMode>::Child as BirthNodeAt<Position>>::Child,
1573        >,
1574{
1575    type Child = <<Emitter::Birth as BirthMode>::Child as BirthNodeAt<Position>>::Child;
1576    type Position = Position;
1577}
1578
1579impl<Emitter, Occurrence> ResolveChildOccurrenceDescriptor<Emitter, Occurrence>
1580    for DeclaredChildOccurrence
1581where
1582    Emitter:
1583        Behavior<Protocol = <<Emitter as BehaviorBase>::Base as Behavior>::Protocol> + BehaviorBase,
1584    Emitter::Base: Behavior,
1585    Occurrence: ChildRole<Emitter::Base>,
1586    <Emitter::Birth as BirthMode>::Child:
1587        BirthNodeAt<Occurrence::Position, Child = Occurrence::Child>,
1588    Occurrence::Position: ChildPosition<<Emitter::Birth as BirthMode>::Child, Occurrence::Child>,
1589{
1590    type Child = Occurrence::Child;
1591    type Position = Occurrence::Position;
1592}
1593
1594/// Sealed inverse projection from one structural position to its child.
1595#[doc(hidden)]
1596pub trait BirthNodeAt<Position>: sealed::BirthNode {
1597    type Child: Behavior;
1598}
1599
1600impl<Child: Behavior> BirthNodeAt<ChildHead> for Child {
1601    type Child = Child;
1602}
1603
1604impl<Head: Behavior, Tail> BirthNodeAt<ChildHead> for ChildChoice<Head, Tail>
1605where
1606    Tail: sealed::BirthNode,
1607{
1608    type Child = Head;
1609}
1610
1611impl<Head, Tail, Position> BirthNodeAt<ChildTail<Position>> for ChildChoice<Head, Tail>
1612where
1613    Head: Behavior,
1614    Tail: BirthNodeAt<Position>,
1615{
1616    type Child = <Tail as BirthNodeAt<Position>>::Child;
1617}
1618
1619/// Downstream shape of one direct-child occurrence product.
1620///
1621/// Behavior owns the closed node algebra: a concrete [`Behavior`] leaf,
1622/// [`ChildChoice`], or [`Never`]. A runtime owns the representation associated
1623/// with each leaf. `Empty` supplies its terminal representation and `Member`
1624/// receives one concrete child, its structural occurrence, and the remaining
1625/// child product.
1626///
1627/// This is a type-level derived construction. It creates no value, allocates
1628/// no actor, interprets no effect, and introduces no protocol identity or
1629/// runtime key. A shape that builds a heterogeneous product should retain
1630/// `Tail`; the product includes every declared child exactly once.
1631///
1632/// ```
1633/// struct NoChildBindings;
1634/// struct ChildBinding<Position, Child, Tail>(core::marker::PhantomData<fn() -> (Position, Child, Tail)>);
1635/// struct RuntimeStorage;
1636///
1637/// impl behavior::ChildOccurrenceShape for RuntimeStorage {
1638///     type Empty = NoChildBindings;
1639///     type Member<Occurrence, Child: behavior::Behavior, Tail> =
1640///         ChildBinding<Occurrence, Child, Tail>;
1641/// }
1642///
1643/// type ChildBindings<Node> = behavior::ChildOccurrences<Node, RuntimeStorage>;
1644/// ```
1645pub trait ChildOccurrenceShape {
1646    /// Representation of the empty [`Never`] node.
1647    type Empty;
1648
1649    /// Representation of one concrete child followed by the remaining product.
1650    type Member<Occurrence, Child: Behavior, Tail>;
1651}
1652
1653/// Sealed occurrence product of a closed direct-child birth node.
1654///
1655/// The product starts at [`ChildHead`] and advances through
1656/// [`ChildTail<Position>`] in exactly the same way as [`DispatchBirth`] and
1657/// [`ChildPosition`]. A downstream runtime selects only the result shape
1658/// through [`ChildOccurrenceShape`]; it cannot reclassify a foreign type as a
1659/// birth node or replace the recursion.
1660///
1661/// This product is intentionally direct rather than transitive. Each installed
1662/// actor owns the bindings for its own `Behavior::Birth`; when a concrete child
1663/// is installed, the same product law applies to that child's birth algebra.
1664///
1665/// Foreign types cannot extend the closed node algebra:
1666///
1667/// ```compile_fail
1668/// struct RuntimeShape;
1669/// impl behavior::ChildOccurrenceShape for RuntimeShape {
1670///     type Empty = ();
1671///     type Member<Occurrence, Child: behavior::Behavior, Tail> = ();
1672/// }
1673///
1674/// struct ForeignNode;
1675/// impl behavior::ChildOccurrenceProduct<RuntimeShape> for ForeignNode {
1676///     type Product = ();
1677/// }
1678/// ```
1679pub trait ChildOccurrenceProduct<Shape>: sealed::BirthNode
1680where
1681    Shape: ChildOccurrenceShape,
1682{
1683    /// Complete shape-owned representation of this closed birth node.
1684    type Product;
1685}
1686
1687/// Occurrence-carrying recursion for [`ChildOccurrenceProduct`]. Consumers
1688/// should name [`ChildOccurrenceProduct`] or [`ChildOccurrences`] instead.
1689#[doc(hidden)]
1690pub trait ChildOccurrenceProductAt<Occurrence, Shape>: sealed::BirthNode
1691where
1692    Shape: ChildOccurrenceShape,
1693{
1694    type Product;
1695}
1696
1697impl<Node, Shape> ChildOccurrenceProduct<Shape> for Node
1698where
1699    Node: ChildOccurrenceProductAt<ChildHead, Shape>,
1700    Shape: ChildOccurrenceShape,
1701{
1702    type Product = <Node as ChildOccurrenceProductAt<ChildHead, Shape>>::Product;
1703}
1704
1705impl<Occurrence, Shape, Child> ChildOccurrenceProductAt<Occurrence, Shape> for Child
1706where
1707    Shape: ChildOccurrenceShape,
1708    Child: Behavior,
1709{
1710    type Product = Shape::Member<Occurrence, Child, Shape::Empty>;
1711}
1712
1713impl<Occurrence, Shape, Head, Tail> ChildOccurrenceProductAt<Occurrence, Shape>
1714    for ChildChoice<Head, Tail>
1715where
1716    Shape: ChildOccurrenceShape,
1717    Head: Behavior,
1718    Tail: ChildOccurrenceProductAt<ChildTail<Occurrence>, Shape>,
1719{
1720    type Product = Shape::Member<
1721        Occurrence,
1722        Head,
1723        <Tail as ChildOccurrenceProductAt<ChildTail<Occurrence>, Shape>>::Product,
1724    >;
1725}
1726
1727impl<Occurrence, Shape> ChildOccurrenceProductAt<Occurrence, Shape> for Never
1728where
1729    Shape: ChildOccurrenceShape,
1730{
1731    type Product = Shape::Empty;
1732}
1733
1734/// Occurrence-preserving representation selected by one downstream shape.
1735pub type ChildOccurrences<Node, Shape> = <Node as ChildOccurrenceProduct<Shape>>::Product;
1736
1737mod sealed {
1738    use super::{
1739        Behavior, BehaviorBase, BirthMode, BirthNodeAt, ChildChoice, ChildHead, ChildOccurrence,
1740        ChildRole, ChildTail, DeclaredChildOccurrence, Never, ResolveChildOccurrenceDescriptor,
1741        StructuralChildOccurrence,
1742    };
1743
1744    pub trait BirthNode {}
1745
1746    pub trait NonEmptyBirthNode: BirthNode {}
1747
1748    impl<Child: Behavior> BirthNode for Child {}
1749    impl<Child: Behavior> NonEmptyBirthNode for Child {}
1750
1751    impl<Head, Tail> BirthNode for ChildChoice<Head, Tail>
1752    where
1753        Head: Behavior,
1754        Tail: BirthNode,
1755    {
1756    }
1757
1758    impl<Head, Tail> NonEmptyBirthNode for ChildChoice<Head, Tail>
1759    where
1760        Head: Behavior,
1761        Tail: BirthNode,
1762    {
1763    }
1764
1765    impl BirthNode for Never {}
1766
1767    pub trait ChildPosition {}
1768    pub trait ChildProduct {}
1769
1770    pub trait ChildOccurrenceDescriptor {}
1771
1772    impl ChildOccurrenceDescriptor for DeclaredChildOccurrence {}
1773
1774    impl<Position> ChildOccurrenceDescriptor for StructuralChildOccurrence<Position> {}
1775
1776    pub trait OccurrenceResolution<Parent: Behavior, Occurrence> {}
1777
1778    impl<Parent, Occurrence> OccurrenceResolution<Parent, Occurrence> for DeclaredChildOccurrence
1779    where
1780        Parent: Behavior,
1781        Occurrence: ChildRole<Parent>,
1782    {
1783    }
1784
1785    impl<Parent: Behavior> OccurrenceResolution<Parent, ChildHead>
1786        for StructuralChildOccurrence<ChildHead>
1787    {
1788    }
1789
1790    impl<Parent: Behavior, Position> OccurrenceResolution<Parent, ChildTail<Position>>
1791        for StructuralChildOccurrence<ChildTail<Position>>
1792    {
1793    }
1794
1795    pub trait ResolveDescriptor<Emitter: Behavior, Occurrence> {}
1796
1797    impl<Emitter, Occurrence, Position> ResolveDescriptor<Emitter, Occurrence>
1798        for StructuralChildOccurrence<Position>
1799    where
1800        Emitter: Behavior,
1801        <Emitter::Birth as BirthMode>::Child: BirthNodeAt<Position>,
1802    {
1803    }
1804
1805    impl<Emitter, Occurrence> ResolveDescriptor<Emitter, Occurrence> for DeclaredChildOccurrence
1806    where
1807        Emitter: Behavior<Protocol = <<Emitter as BehaviorBase>::Base as Behavior>::Protocol>
1808            + BehaviorBase,
1809        Emitter::Base: Behavior,
1810        Occurrence: ChildRole<Emitter::Base>,
1811        <Emitter::Birth as BirthMode>::Child:
1812            BirthNodeAt<Occurrence::Position, Child = Occurrence::Child>,
1813        Occurrence::Position:
1814            super::ChildPosition<<Emitter::Birth as BirthMode>::Child, Occurrence::Child>,
1815    {
1816    }
1817
1818    pub trait ResolveChildOccurrence<Occurrence> {}
1819
1820    impl<Emitter, Occurrence> ResolveChildOccurrence<Occurrence> for Emitter
1821    where
1822        Emitter: Behavior + BehaviorBase,
1823        Emitter::Base: Behavior,
1824        Occurrence: ChildOccurrence<Emitter::Base>,
1825        Occurrence::Resolution: ResolveChildOccurrenceDescriptor<Emitter, Occurrence>,
1826    {
1827    }
1828}
1829
1830/// The empty heterogeneous creation product.
1831#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
1832pub struct NoChildren;
1833
1834impl sealed::ChildProduct for NoChildren {}
1835
1836/// One creation appended to an ordered heterogeneous child product.
1837pub struct ChildCons<A: Address, C, Earlier> {
1838    creation: CreateChild<A, C>,
1839    earlier: Earlier,
1840}
1841
1842impl<A: Address, C, Earlier> sealed::ChildProduct for ChildCons<A, C, Earlier> {}
1843
1844/// A pure, ordered heterogeneous product of staged direct-child creations.
1845///
1846/// This value owns no mailbox, address, runtime actor, or lifecycle. Every
1847/// product position is a distinct static child occurrence, so equal numeric IDs
1848/// in different positions remain distinct correlations.
1849pub struct Children<A: Address, Product = NoChildren> {
1850    product: Product,
1851    address: PhantomData<fn() -> A>,
1852}
1853
1854/// Closed recursive conversion implemented only by Bombay child products.
1855pub trait ChildProduct<A: Address>: sealed::ChildProduct + Sized {
1856    /// Closed sum containing exactly the concrete child behavior types.
1857    type Choice: BirthNodeAppend<Never>;
1858
1859    #[doc(hidden)]
1860    fn stage(self) -> Vec<CreateChild<A, Self::Choice>>;
1861}
1862
1863impl<A: Address> ChildProduct<A> for NoChildren {
1864    type Choice = Never;
1865
1866    fn stage(self) -> Vec<CreateChild<A, Self::Choice>> {
1867        Vec::new()
1868    }
1869}
1870
1871impl<A, C, Earlier> ChildProduct<A> for ChildCons<A, C, Earlier>
1872where
1873    A: Address,
1874    C: Behavior,
1875    C::Protocol: Protocol<Addr = A>,
1876    Earlier: ChildProduct<A>,
1877{
1878    type Choice = ChildChoice<C, Earlier::Choice>;
1879
1880    fn stage(self) -> Vec<CreateChild<A, Self::Choice>> {
1881        let earlier = self.earlier.stage();
1882        let mut creates = earlier
1883            .into_iter()
1884            .map(|creation| {
1885                let (id, child, kind) = creation.into_parts();
1886                CreateChild::from_parts(id, ChildChoice::Tail(child), kind)
1887            })
1888            .collect::<Vec<_>>();
1889        let (id, child, kind) = self.creation.into_parts();
1890        creates.push(CreateChild::from_parts(id, ChildChoice::Head(child), kind));
1891        creates
1892    }
1893}
1894
1895impl<A: Address> Children<A, NoChildren> {
1896    /// Start an empty heterogeneous creation product.
1897    #[must_use]
1898    pub const fn new() -> Self {
1899        Self {
1900            product: NoChildren,
1901            address: PhantomData,
1902        }
1903    }
1904}
1905
1906impl<A: Address> Default for Children<A, NoChildren> {
1907    fn default() -> Self {
1908        Self::new()
1909    }
1910}
1911
1912impl<A: Address, Product> Children<A, Product> {
1913    /// Append one complete staged creation, preserving its provenance.
1914    #[must_use]
1915    pub fn create<C>(self, creation: CreateChild<A, C>) -> Children<A, ChildCons<A, C, Product>>
1916    where
1917        C: Behavior,
1918        C::Protocol: Protocol<Addr = A>,
1919    {
1920        Children {
1921            product: ChildCons {
1922                creation,
1923                earlier: self.product,
1924            },
1925            address: PhantomData,
1926        }
1927    }
1928
1929    /// Append one ordinary fresh-birth request.
1930    #[must_use]
1931    pub fn child<C>(self, id: CreationId, child: C) -> Children<A, ChildCons<A, C, Product>>
1932    where
1933        C: Behavior,
1934        C::Protocol: Protocol<Addr = A>,
1935    {
1936        self.create(CreateChild::birth(id, child))
1937    }
1938}
1939
1940impl<A, Product> Children<A, Product>
1941where
1942    A: Address,
1943    Product: ChildProduct<A>,
1944{
1945    /// Produce one ordered creation batch.
1946    #[must_use]
1947    pub fn into_creates(self) -> Creations<CreateChild<A, Product::Choice>> {
1948        Creations::from_items(self.product.stage())
1949    }
1950}
1951
1952impl<A, Occurrence, Head, Tail> ChildCreationProduct<A, Occurrence> for ChildChoice<Head, Tail>
1953where
1954    A: EndpointAddress,
1955    Head: Behavior,
1956    Head::Protocol: Protocol<Addr = A>,
1957    Tail: ChildCreationProduct<A, ChildTail<Occurrence>>,
1958{
1959    type Result = ChildChoice<
1960        ChildCreationOutcome<Head, Occurrence>,
1961        <Tail as ChildCreationProduct<A, ChildTail<Occurrence>>>::Result,
1962    >;
1963}
1964
1965impl<A, Occurrence, Head, Tail, Host> CreateSelectedChild<A, Occurrence, Host>
1966    for ChildChoice<Head, Tail>
1967where
1968    A: EndpointAddress,
1969    A::Nonce: Send,
1970    Head: Behavior + Send,
1971    Head::Protocol: Protocol<Addr = A>,
1972    Tail: CreateSelectedChild<A, ChildTail<Occurrence>, Host> + Send,
1973    Host: EstablishChild<Occurrence, Head> + Send,
1974{
1975    async fn dispatch_birth_at(
1976        self,
1977        id: CreationId,
1978        route: A::Nonce,
1979        kind: CreationKind,
1980        host: &mut Host,
1981    ) -> ItemSettlement<
1982        RoutedCreation<A, Self>,
1983        <Self as ChildCreationProduct<A, Occurrence>>::Result,
1984        CreationRejection,
1985        Never,
1986    > {
1987        match self {
1988            Self::Head(child) => {
1989                let creation = RoutedCreation::new(CreateChild::from_parts(id, child, kind), route);
1990                match host.establish_child(creation).await {
1991                    ItemSettlement::Accepted(receipt) => {
1992                        ItemSettlement::Accepted(ChildChoice::Head(receipt))
1993                    }
1994                    ItemSettlement::Rejected { item, reason } => {
1995                        let (creation, route) = item.into_parts();
1996                        let (id, child, kind) = creation.into_parts();
1997                        ItemSettlement::Rejected {
1998                            item: RoutedCreation::new(
1999                                CreateChild::from_parts(id, Self::Head(child), kind),
2000                                route,
2001                            ),
2002                            reason,
2003                        }
2004                    }
2005                    ItemSettlement::Blocked { prerequisite, .. } => match prerequisite {},
2006                    ItemSettlement::Corrupt { item, fault } => {
2007                        let (creation, route) = item.into_parts();
2008                        let (id, child, kind) = creation.into_parts();
2009                        ItemSettlement::Corrupt {
2010                            item: RoutedCreation::new(
2011                                CreateChild::from_parts(id, Self::Head(child), kind),
2012                                route,
2013                            ),
2014                            fault,
2015                        }
2016                    }
2017                }
2018            }
2019            Self::Tail(tail) => match tail.dispatch_birth_at(id, route, kind, host).await {
2020                ItemSettlement::Accepted(receipt) => {
2021                    ItemSettlement::Accepted(ChildChoice::Tail(receipt))
2022                }
2023                ItemSettlement::Rejected { item, reason } => {
2024                    let (creation, route) = item.into_parts();
2025                    let (id, child, kind) = creation.into_parts();
2026                    ItemSettlement::Rejected {
2027                        item: RoutedCreation::new(
2028                            CreateChild::from_parts(id, Self::Tail(child), kind),
2029                            route,
2030                        ),
2031                        reason,
2032                    }
2033                }
2034                ItemSettlement::Blocked { prerequisite, .. } => match prerequisite {},
2035                ItemSettlement::Corrupt { item, fault } => {
2036                    let (creation, route) = item.into_parts();
2037                    let (id, child, kind) = creation.into_parts();
2038                    ItemSettlement::Corrupt {
2039                        item: RoutedCreation::new(
2040                            CreateChild::from_parts(id, Self::Tail(child), kind),
2041                            route,
2042                        ),
2043                        fault,
2044                    }
2045                }
2046            },
2047        }
2048    }
2049}
2050
2051impl<A, Occurrence> ChildCreationProduct<A, Occurrence> for Never
2052where
2053    A: Address,
2054{
2055    type Result = Never;
2056}
2057
2058impl<A, Occurrence, Host> CreateSelectedChild<A, Occurrence, Host> for Never
2059where
2060    A: Address,
2061{
2062    fn dispatch_birth_at(
2063        self,
2064        _id: CreationId,
2065        _route: A::Nonce,
2066        _kind: CreationKind,
2067        _host: &mut Host,
2068    ) -> impl Future<
2069        Output = ItemSettlement<
2070            RoutedCreation<A, Self>,
2071            <Self as ChildCreationProduct<A, Occurrence>>::Result,
2072            CreationRejection,
2073            Never,
2074        >,
2075    > + Send {
2076        async move { match self {} }
2077    }
2078}
2079
2080impl<A, Occurrence, C> ChildCreationProduct<A, Occurrence> for C
2081where
2082    A: EndpointAddress,
2083    C: Behavior,
2084    C::Protocol: Protocol<Addr = A>,
2085{
2086    type Result = ChildCreationOutcome<C, Occurrence>;
2087}
2088
2089impl<A, Occurrence, C, Host> CreateSelectedChild<A, Occurrence, Host> for C
2090where
2091    A: EndpointAddress,
2092    C: Behavior,
2093    C::Protocol: Protocol<Addr = A>,
2094    Host: EstablishChild<Occurrence, C>,
2095{
2096    fn dispatch_birth_at(
2097        self,
2098        id: CreationId,
2099        route: A::Nonce,
2100        kind: CreationKind,
2101        host: &mut Host,
2102    ) -> impl Future<
2103        Output = ItemSettlement<
2104            RoutedCreation<A, Self>,
2105            <Self as ChildCreationProduct<A, Occurrence>>::Result,
2106            CreationRejection,
2107            Never,
2108        >,
2109    > + Send {
2110        host.establish_child(RoutedCreation::new(
2111            CreateChild::from_parts(id, self, kind),
2112            route,
2113        ))
2114    }
2115}
2116
2117/// A type-level description of a behavior's creation capability.
2118pub trait BirthMode {
2119    type Child;
2120}
2121
2122/// Empty protocol projection of a closed behavior-birth algebra.
2123pub struct NoBirthProtocols;
2124
2125/// One behavior protocol followed by the remaining closed birth projection.
2126pub struct BirthProtocol<P: Protocol, Tail> {
2127    protocol: PhantomData<fn() -> P>,
2128    tail: PhantomData<fn() -> Tail>,
2129}
2130
2131/// Structural position selecting the current projected birth protocol.
2132pub struct BirthProtocolHead;
2133
2134/// Structural position selecting inside the remaining protocol projection.
2135pub struct BirthProtocolTail<Position>(PhantomData<fn() -> Position>);
2136
2137/// Static membership evidence for one occurrence in a birth-protocol product.
2138pub trait BirthProtocolAt<P: Protocol, Position> {}
2139
2140impl<P: Protocol, Tail> BirthProtocolAt<P, BirthProtocolHead> for BirthProtocol<P, Tail> {}
2141
2142impl<Head, Tail, P, Position> BirthProtocolAt<P, BirthProtocolTail<Position>>
2143    for BirthProtocol<Head, Tail>
2144where
2145    Head: Protocol,
2146    P: Protocol,
2147    Tail: BirthProtocolAt<P, Position>,
2148{
2149}
2150
2151/// Closed product operation used by the structural birth projection.
2152pub trait BirthProtocolProduct {
2153    type Append<Tail: BirthProtocolProduct>: BirthProtocolProduct;
2154}
2155
2156impl BirthProtocolProduct for NoBirthProtocols {
2157    type Append<Tail: BirthProtocolProduct> = Tail;
2158}
2159
2160impl<P, Rest> BirthProtocolProduct for BirthProtocol<P, Rest>
2161where
2162    P: Protocol,
2163    Rest: BirthProtocolProduct,
2164{
2165    type Append<Tail: BirthProtocolProduct> = BirthProtocol<P, Rest::Append<Tail>>;
2166}
2167
2168/// Closed static projection of a behavior's own protocol and every protocol
2169/// reachable through its transitive staged-birth algebra.
2170///
2171/// This is structural information derived from [`Behavior::Birth`]. It makes
2172/// no hosting or allocation decision and does not inspect send destinations.
2173pub trait BirthProtocols: Behavior {
2174    type Protocols: BirthProtocolProduct;
2175}
2176
2177impl<B> BirthProtocols for B
2178where
2179    B: Behavior,
2180    B::Birth: BirthModeProtocols,
2181{
2182    type Protocols = BirthProtocol<B::Protocol, <B::Birth as BirthModeProtocols>::Protocols>;
2183}
2184
2185#[doc(hidden)]
2186pub trait BirthModeProtocols {
2187    type Protocols: BirthProtocolProduct;
2188}
2189
2190impl<M> BirthModeProtocols for M
2191where
2192    M: BirthMode,
2193    M::Child: BirthNodeProtocols,
2194{
2195    type Protocols = <M::Child as BirthNodeProtocols>::Protocols;
2196}
2197
2198#[doc(hidden)]
2199pub trait BirthNodeProtocols {
2200    type Protocols: BirthProtocolProduct;
2201}
2202
2203impl<B> BirthNodeProtocols for B
2204where
2205    B: BirthProtocols,
2206{
2207    type Protocols = B::Protocols;
2208}
2209
2210impl<Head, Tail> BirthNodeProtocols for ChildChoice<Head, Tail>
2211where
2212    Head: BirthNodeProtocols,
2213    Tail: BirthNodeProtocols,
2214{
2215    type Protocols = <Head::Protocols as BirthProtocolProduct>::Append<Tail::Protocols>;
2216}
2217
2218impl BirthNodeProtocols for Never {
2219    type Protocols = NoBirthProtocols;
2220}
2221
2222/// Structural logical-destination projection for one closed birth node.
2223///
2224/// This implementation detail is public only because its associated product
2225/// participates in the blanket [`crate::LogicalHostRequirements`] interface.
2226#[doc(hidden)]
2227pub trait BirthNodeLogicalHosts {
2228    type LogicalHosts: BirthProtocolProduct;
2229}
2230
2231impl<B> BirthNodeLogicalHosts for B
2232where
2233    B: crate::LogicalHostRequirements,
2234{
2235    type LogicalHosts = B::LogicalHosts;
2236}
2237
2238impl<Head, Tail> BirthNodeLogicalHosts for ChildChoice<Head, Tail>
2239where
2240    Head: BirthNodeLogicalHosts,
2241    Tail: BirthNodeLogicalHosts,
2242{
2243    type LogicalHosts = <Head::LogicalHosts as BirthProtocolProduct>::Append<Tail::LogicalHosts>;
2244}
2245
2246impl BirthNodeLogicalHosts for Never {
2247    type LogicalHosts = NoBirthProtocols;
2248}
2249
2250/// This behavior cannot emit child births.
2251#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
2252pub struct NoBirths;
2253
2254impl BirthMode for NoBirths {
2255    type Child = Never;
2256}
2257
2258/// This behavior may emit births of `C`.
2259#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
2260pub struct Births<C>(PhantomData<fn() -> C>);
2261
2262impl<C> BirthMode for Births<C> {
2263    type Child = C;
2264}
2265
2266/// This behavior may emit births of `C` whose exact settlements remain in
2267/// runtime custody until actor retirement.
2268///
2269/// Unlike [`Births`], this mode does not return a creation settlement as a
2270/// later input to the live creator. It is the deliberate policy for actors
2271/// whose terminal owner, rather than another behavior transition, must retain
2272/// every authoritative creation result.
2273#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
2274pub struct RetirementBirths<C>(PhantomData<fn() -> C>);
2275
2276impl<C> BirthMode for RetirementBirths<C> {
2277    type Child = C;
2278}
2279
2280#[cfg(test)]
2281mod tests {
2282    use super::*;
2283    use crate::{Actions, BehaviorActed, NoBirths, User};
2284
2285    #[derive(Clone, Copy, Debug, Eq, PartialEq)]
2286    struct TestAddr(u64);
2287
2288    impl Address for TestAddr {
2289        type Nonce = u64;
2290    }
2291
2292    struct TestEndpoint<P>(PhantomData<fn() -> P>);
2293
2294    impl<P> Clone for TestEndpoint<P> {
2295        fn clone(&self) -> Self {
2296            *self
2297        }
2298    }
2299
2300    impl<P> Copy for TestEndpoint<P> {}
2301
2302    struct TestInstalled<B: Behavior> {
2303        endpoint: TestEndpoint<B::Protocol>,
2304        control: std::sync::mpsc::Sender<B::Event>,
2305    }
2306
2307    impl<B: Behavior> Clone for TestInstalled<B> {
2308        fn clone(&self) -> Self {
2309            Self {
2310                endpoint: self.endpoint,
2311                control: self.control.clone(),
2312            }
2313        }
2314    }
2315
2316    impl EndpointAddress for TestAddr {
2317        type Established<P>
2318            = TestEndpoint<P>
2319        where
2320            P: Protocol<Addr = Self>;
2321
2322        type Installed<B>
2323            = TestInstalled<B>
2324        where
2325            B: Behavior<Protocol: Protocol<Addr = Self>>;
2326
2327        fn recipient<B>(installed: &Self::Installed<B>) -> Self::Established<B::Protocol>
2328        where
2329            B: Behavior<Protocol: Protocol<Addr = Self>>,
2330        {
2331            installed.endpoint
2332        }
2333    }
2334
2335    #[derive(Debug, Clone, Copy, PartialEq, Eq)]
2336    struct Child;
2337
2338    struct SharedProtocol;
2339
2340    impl behavior::Protocol for SharedProtocol {
2341        type Addr = TestAddr;
2342        type Msg = u8;
2343    }
2344
2345    struct Primary;
2346    struct Fallback;
2347
2348    macro_rules! shared_protocol_behavior {
2349        ($behavior:ty, $birth:ty) => {
2350            impl Behavior for $behavior {
2351                type Protocol = SharedProtocol;
2352                type Event = User<TestAddr, u8>;
2353                type Sends = Vec<Never>;
2354                type Ph = Never;
2355                type Error = Never;
2356                type Birth = $birth;
2357
2358                fn transition(
2359                    &mut self,
2360                    _: crate::ActiveTurn,
2361                    _: Self::Event,
2362                ) -> BehaviorActed<Self> {
2363                    Ok(Actions::cont())
2364                }
2365            }
2366        };
2367    }
2368
2369    shared_protocol_behavior!(Primary, Births<Child>);
2370    shared_protocol_behavior!(Fallback, NoBirths);
2371
2372    impl behavior::Protocol for Child {
2373        type Addr = TestAddr;
2374        type Msg = u8;
2375    }
2376
2377    impl Behavior for Child {
2378        type Protocol = Self;
2379        type Event = User<TestAddr, u8>;
2380        type Sends = Vec<Never>;
2381        type Ph = Never;
2382        type Error = Never;
2383        type Birth = NoBirths;
2384
2385        fn transition(&mut self, _: crate::ActiveTurn, _: Self::Event) -> BehaviorActed<Self> {
2386            Ok(Actions::cont())
2387        }
2388    }
2389
2390    #[derive(Debug, Clone, Copy, PartialEq, Eq)]
2391    enum ChildPlan {
2392        CreateChild,
2393        RejectBeforeTransfer,
2394    }
2395
2396    struct RecordingHost {
2397        calls: usize,
2398        observed: Vec<(CreationId, u64, CreationKind)>,
2399        plan: ChildPlan,
2400        control_receivers: Vec<std::sync::mpsc::Receiver<User<TestAddr, u8>>>,
2401    }
2402
2403    #[derive(Debug, PartialEq, Eq)]
2404    enum SharedCreation {
2405        Primary(CreationId, u64),
2406        Fallback(CreationId, u64),
2407    }
2408
2409    #[derive(Default)]
2410    struct SharedProtocolHost(
2411        Vec<SharedCreation>,
2412        Vec<std::sync::mpsc::Receiver<User<TestAddr, u8>>>,
2413    );
2414
2415    impl EstablishChild<ChildHead, Primary> for SharedProtocolHost {
2416        async fn establish_child(
2417            &mut self,
2418            creation: RoutedCreation<TestAddr, Primary>,
2419        ) -> ItemSettlement<
2420            RoutedCreation<TestAddr, Primary>,
2421            ChildCreationOutcome<Primary, ChildHead>,
2422            CreationRejection,
2423            Never,
2424        > {
2425            let id = creation.id();
2426            let kind = creation.kind();
2427            let route = creation.route();
2428            let (creation, _) = creation.into_parts();
2429            let (_, _child, _) = creation.into_parts();
2430            self.0.push(SharedCreation::Primary(id, route));
2431            let (control, receiver) = std::sync::mpsc::channel();
2432            self.1.push(receiver);
2433            ItemSettlement::Accepted(ChildCreationOutcome::Established(CommittedChild::new(
2434                id,
2435                kind,
2436                EstablishedActor::issued(TestInstalled {
2437                    endpoint: TestEndpoint(PhantomData),
2438                    control,
2439                }),
2440            )))
2441        }
2442    }
2443
2444    impl EstablishChild<ChildTail<ChildHead>, Fallback> for SharedProtocolHost {
2445        async fn establish_child(
2446            &mut self,
2447            creation: RoutedCreation<TestAddr, Fallback>,
2448        ) -> ItemSettlement<
2449            RoutedCreation<TestAddr, Fallback>,
2450            ChildCreationOutcome<Fallback, ChildTail<ChildHead>>,
2451            CreationRejection,
2452            Never,
2453        > {
2454            let id = creation.id();
2455            let kind = creation.kind();
2456            let route = creation.route();
2457            let (creation, _) = creation.into_parts();
2458            let (_, _child, _) = creation.into_parts();
2459            self.0.push(SharedCreation::Fallback(id, route));
2460            let (control, receiver) = std::sync::mpsc::channel();
2461            self.1.push(receiver);
2462            ItemSettlement::Accepted(ChildCreationOutcome::Established(CommittedChild::new(
2463                id,
2464                kind,
2465                EstablishedActor::issued(TestInstalled {
2466                    endpoint: TestEndpoint(PhantomData),
2467                    control,
2468                }),
2469            )))
2470        }
2471    }
2472
2473    impl EstablishChild<ChildHead, Child> for RecordingHost {
2474        async fn establish_child(
2475            &mut self,
2476            creation: RoutedCreation<TestAddr, Child>,
2477        ) -> ItemSettlement<
2478            RoutedCreation<TestAddr, Child>,
2479            ChildCreationOutcome<Child, ChildHead>,
2480            CreationRejection,
2481            Never,
2482        > {
2483            self.calls += 1;
2484            self.observed
2485                .push((creation.id(), creation.route(), creation.kind()));
2486            match self.plan {
2487                ChildPlan::CreateChild => {
2488                    let id = creation.id();
2489                    let kind = creation.kind();
2490                    let (creation, _) = creation.into_parts();
2491                    let (_, _child, _) = creation.into_parts();
2492                    let (control, receiver) = std::sync::mpsc::channel();
2493                    self.control_receivers.push(receiver);
2494                    ItemSettlement::Accepted(ChildCreationOutcome::Established(
2495                        CommittedChild::new(
2496                            id,
2497                            kind,
2498                            EstablishedActor::issued(TestInstalled {
2499                                endpoint: TestEndpoint(PhantomData),
2500                                control,
2501                            }),
2502                        ),
2503                    ))
2504                }
2505                ChildPlan::RejectBeforeTransfer => ItemSettlement::Rejected {
2506                    item: creation,
2507                    reason: CreationRejection::EnvironmentFailed,
2508                },
2509            }
2510        }
2511    }
2512
2513    fn host(plan: ChildPlan) -> RecordingHost {
2514        RecordingHost {
2515            calls: 0,
2516            observed: Vec::new(),
2517            plan,
2518            control_receivers: Vec::new(),
2519        }
2520    }
2521
2522    fn assert_send<T: Send>(_: &T) {}
2523
2524    #[test]
2525    fn empty_child_product_stages_no_creations() {
2526        let creations = <NoChildren as ChildProduct<TestAddr>>::stage(NoChildren);
2527        assert!(creations.is_empty());
2528    }
2529
2530    #[test]
2531    fn creation_values_preserve_ids_order_and_debug_identity() {
2532        let mut sequence = CreationSequence::new();
2533        let first = sequence.issue().expect("the first creation ID exists");
2534        let second = sequence.issue().expect("the second creation ID exists");
2535        assert_eq!(first.get(), 1);
2536        assert_eq!(second.get(), 2);
2537
2538        let first_correlation = CreationCorrelation::<SharedProtocol, ChildHead>::new(first);
2539        let same_correlation = CreationCorrelation::<SharedProtocol, ChildHead>::new(first);
2540        let second_correlation = CreationCorrelation::<SharedProtocol, ChildHead>::new(second);
2541        assert_eq!(first_correlation, same_correlation);
2542        assert_ne!(first_correlation, second_correlation);
2543        assert_eq!(
2544            format!("{first_correlation:?}"),
2545            "CreationCorrelation(CreationId(1))"
2546        );
2547
2548        let mut creations = Creations::one(1_u8);
2549        creations.extend([2, 3]);
2550        assert_eq!(creations.len(), 3);
2551        assert!(!creations.is_empty());
2552        assert_eq!(creations.iter().copied().collect::<Vec<_>>(), [1, 2, 3]);
2553        let borrowed = (&creations).into_iter().copied().collect::<Vec<_>>();
2554        assert_eq!(borrowed, [1, 2, 3]);
2555
2556        let collected: Creations<_> = [4_u8, 5].into_iter().collect();
2557        assert_eq!(collected.len(), 2);
2558        let collected_values = collected.into_iter().collect::<Vec<_>>();
2559        assert_eq!(collected_values, [4, 5]);
2560
2561        let returned = ChildCreationSettled::<Child, ChildHead>::new(SettledItem::Unattempted(
2562            RoutedCreation::new(CreateChild::birth(first, Child), 17),
2563        ));
2564        assert_eq!(format!("{returned:?}"), "ChildCreationSettled { .. }");
2565    }
2566
2567    #[tokio::test]
2568    async fn concrete_child_dispatches_once_with_exact_creation_and_route() {
2569        let mut sequence = CreationSequence::new();
2570        let previous = sequence.issue().expect("the previous ID exists");
2571        let id = sequence.issue().expect("the replacement ID exists");
2572        let mut host = host(ChildPlan::CreateChild);
2573        let kind = CreationKind::replacement(previous);
2574        let future = Child.dispatch_birth(id, 17, kind, &mut host);
2575        assert_send(&future);
2576        let result = future.await;
2577
2578        let ItemSettlement::Accepted(ChildCreationOutcome::Established(established)) = result
2579        else {
2580            panic!("expected the child to be created");
2581        };
2582        assert_eq!(established.id(), id);
2583        assert_eq!(host.calls, 1);
2584        assert_eq!(host.observed, [(id, 17, kind)]);
2585    }
2586
2587    #[tokio::test]
2588    async fn concrete_child_returns_the_exact_rejected_creation_without_retry() {
2589        let mut sequence = CreationSequence::new();
2590        let previous = sequence.issue().expect("the previous ID exists");
2591        let id = sequence.issue().expect("the replacement ID exists");
2592        let mut host = host(ChildPlan::RejectBeforeTransfer);
2593        let kind = CreationKind::replacement(previous);
2594        let future = Child.dispatch_birth(id, 23, kind, &mut host);
2595        assert_send(&future);
2596        let result = future.await;
2597
2598        let ItemSettlement::Rejected { item, reason } = result else {
2599            panic!("expected refusal before child ownership transfer");
2600        };
2601        assert_eq!(
2602            item,
2603            RoutedCreation::new(CreateChild::replacement(id, previous, Child), 23)
2604        );
2605        assert_eq!(reason, CreationRejection::EnvironmentFailed);
2606        assert_eq!(host.calls, 1);
2607        assert_eq!(host.observed, [(id, 23, kind)]);
2608    }
2609
2610    #[tokio::test]
2611    async fn distinct_child_alternatives_preserve_one_canonical_protocol_identity() {
2612        type Alternatives = ChildChoice<Primary, ChildChoice<Fallback, Never>>;
2613
2614        fn requires_shared_protocol<C: Behavior<Protocol = SharedProtocol>>() {}
2615        requires_shared_protocol::<Primary>();
2616        requires_shared_protocol::<Fallback>();
2617
2618        let mut sequence = CreationSequence::new();
2619        let primary_id = sequence.issue().expect("the primary ID exists");
2620        let fallback_id = sequence.issue().expect("the fallback ID exists");
2621        let mut host = SharedProtocolHost::default();
2622        let primary = Alternatives::Head(Primary)
2623            .dispatch_birth(primary_id, 11, CreationKind::Birth, &mut host)
2624            .await;
2625        let fallback = Alternatives::Tail(ChildChoice::Head(Fallback))
2626            .dispatch_birth(fallback_id, 17, CreationKind::Birth, &mut host)
2627            .await;
2628
2629        let ItemSettlement::Accepted(ChildChoice::Head(ChildCreationOutcome::Established(primary))) =
2630            primary
2631        else {
2632            panic!("expected the primary child result");
2633        };
2634        assert_eq!(primary.id(), primary_id);
2635        let ItemSettlement::Accepted(ChildChoice::Tail(ChildChoice::Head(
2636            ChildCreationOutcome::Established(fallback),
2637        ))) = fallback
2638        else {
2639            panic!("expected the fallback child result");
2640        };
2641        assert_eq!(fallback.id(), fallback_id);
2642
2643        assert_eq!(
2644            host.0,
2645            [
2646                SharedCreation::Primary(primary_id, 11),
2647                SharedCreation::Fallback(fallback_id, 17),
2648            ]
2649        );
2650    }
2651
2652    #[test]
2653    fn birth_protocol_projection_recurses_without_inspecting_send_lanes() {
2654        type Protocols = <Primary as BirthProtocols>::Protocols;
2655        type Expected = BirthProtocol<SharedProtocol, BirthProtocol<Child, NoBirthProtocols>>;
2656
2657        trait Same<T> {}
2658        impl<T> Same<T> for T {}
2659        fn exact<T: Same<Expected>>() {}
2660        exact::<Protocols>();
2661    }
2662}