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, InterpretationProgress,
11    ItemSettlement, Protocol, SettledItem, finish_item, prepare_item,
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 Custody = (Option<Self>, Option<Self::Reply>);
496    type Input<'a>
497        = &'a mut Option<Self>
498    where
499        Self: 'a;
500    type Reply = ItemSettlement<Self, Self::Accepted, Self::Rejection, Self::Prerequisite>;
501
502    fn prepare_interpretation(
503        progress: &mut Option<InterpretationProgress<Self, Self::Custody, Self::Reply>>,
504    ) {
505        prepare_item::<Self>(progress);
506    }
507    fn interpretation_input<'a>(
508        custody: &'a mut Self::Custody,
509    ) -> Option<(Self::Input<'a>, &'a mut Option<Self::Reply>)>
510    where
511        Self: 'a,
512    {
513        let (input, received) = custody;
514        if input.is_some() && received.is_none() {
515            Some((input, received))
516        } else {
517            None
518        }
519    }
520    fn finish_interpretation(
521        progress: &mut Option<InterpretationProgress<Self, Self::Custody, Self::Reply>>,
522    ) {
523        finish_item::<Self>(progress);
524    }
525
526    type Accepted = Creations<RoutedCreation<A, New>>;
527    type Rejection = ChildNamespaceExhausted;
528    type Prerequisite = Never;
529}
530
531/// One committed fresh child with its creator-local provenance and exact
532/// installed actor. The occurrence distinguishes equal child behaviors in
533/// distinct static positions; it is not an actor identity or runtime route.
534pub struct CommittedChild<C, Occurrence>
535where
536    C: Behavior,
537    BehaviorAddr<C>: EndpointAddress,
538{
539    id: CreationId,
540    kind: CreationKind,
541    actor: EstablishedActor<C>,
542    occurrence: PhantomData<fn() -> Occurrence>,
543}
544
545impl<C, Occurrence> CommittedChild<C, Occurrence>
546where
547    C: Behavior,
548    BehaviorAddr<C>: EndpointAddress,
549{
550    /// Record an already committed fresh installation. This does not install
551    /// an actor; only a successful interpreter installation may issue its
552    /// runtime-owned actor value.
553    #[must_use]
554    pub const fn new(id: CreationId, kind: CreationKind, actor: EstablishedActor<C>) -> Self {
555        Self {
556            id,
557            kind,
558            actor,
559            occurrence: PhantomData,
560        }
561    }
562
563    #[must_use]
564    pub const fn id(&self) -> CreationId {
565        self.id
566    }
567
568    #[must_use]
569    pub const fn kind(&self) -> CreationKind {
570        self.kind
571    }
572
573    #[must_use]
574    pub fn actor(&self) -> EstablishedActor<C> {
575        self.actor.clone()
576    }
577
578    #[must_use]
579    pub fn into_parts(self) -> (CreationId, CreationKind, EstablishedActor<C>) {
580        (self.id, self.kind, self.actor)
581    }
582}
583
584/// Committed or rejected result for one exact concrete child occurrence.
585///
586/// `Installed` is constructed only after fresh allocation, successful
587/// initialization, endpoint establishment, and creator-local binding. It returns the
588/// exact installed actor. `Rejected` carries no capability, so a
589/// failed request cannot be used as an established destination. Both variants
590/// preserve Behavior-authored creation provenance.
591///
592/// `Occurrence` is topology navigation evidence authored by the parent. It
593/// distinguishes duplicate occurrences without becoming another protocol
594/// identity or runtime key. A consumer that only sends messages may project
595/// the protocol recipient without retaining the installed actor.
596///
597/// A rejected named report has no actor capability to extract:
598///
599/// ```compile_fail,E0026
600/// fn rejected_actor<C, Occurrence>(report: behavior::EstablishedCreation<C, Occurrence>)
601/// where
602///     C: behavior::Behavior,
603///     behavior::BehaviorAddr<C>: behavior::EndpointAddress,
604/// {
605///     let behavior::EstablishedCreation::Rejected { actor, .. } = report else { return; };
606///     let _: behavior::EstablishedActor<C> = actor;
607/// }
608/// ```
609///
610/// Duplicate occurrences remain incompatible even when their protocols and
611/// endpoint representations match:
612///
613/// ```compile_fail,E0308
614/// fn wrong_occurrence<C, Primary, Backup>(backup: behavior::EstablishedCreation<C, Backup>)
615/// where
616///     C: behavior::Behavior,
617///     behavior::BehaviorAddr<C>: behavior::EndpointAddress,
618/// {
619///     let _: behavior::EstablishedCreation<C, Primary> = backup;
620/// }
621/// ```
622pub enum EstablishedCreation<C, Occurrence>
623where
624    C: Behavior,
625    BehaviorAddr<C>: EndpointAddress,
626{
627    Installed(CommittedChild<C, Occurrence>),
628    Rejected {
629        id: CreationId,
630        kind: CreationKind,
631        reason: CreationRejection,
632        occurrence: PhantomData<fn() -> Occurrence>,
633    },
634}
635
636impl<C, Occurrence> EstablishedCreation<C, Occurrence>
637where
638    C: Behavior,
639    BehaviorAddr<C>: EndpointAddress,
640{
641    #[must_use]
642    pub const fn installed(child: CommittedChild<C, Occurrence>) -> Self {
643        Self::Installed(child)
644    }
645
646    #[must_use]
647    pub const fn rejected(id: CreationId, kind: CreationKind, reason: CreationRejection) -> Self {
648        Self::Rejected {
649            id,
650            kind,
651            reason,
652            occurrence: PhantomData,
653        }
654    }
655
656    #[must_use]
657    pub const fn id(&self) -> CreationId {
658        match self {
659            Self::Installed(child) => child.id(),
660            Self::Rejected { id, .. } => *id,
661        }
662    }
663
664    #[must_use]
665    pub const fn kind(&self) -> CreationKind {
666        match self {
667            Self::Installed(child) => child.kind(),
668            Self::Rejected { kind, .. } => *kind,
669        }
670    }
671
672    /// Consume the report and return its exact endpoint capability.
673    ///
674    /// # Errors
675    /// Returns the original [`CreationRejection`] when child creation did not
676    /// commit.
677    pub fn into_recipient(self) -> Result<EstablishedRecipient<C::Protocol>, CreationRejection> {
678        match self {
679            Self::Installed(child) => Ok(child.into_parts().2.into_recipient()),
680            Self::Rejected { reason, .. } => Err(reason),
681        }
682    }
683
684    /// Transfer the concrete committed child without recreating authority
685    /// from a protocol recipient.
686    ///
687    /// # Errors
688    /// Returns the original [`CreationRejection`] when child creation did not
689    /// commit.
690    pub fn into_committed(self) -> Result<CommittedChild<C, Occurrence>, CreationRejection> {
691        match self {
692            Self::Installed(child) => Ok(child),
693            Self::Rejected { reason, .. } => Err(reason),
694        }
695    }
696}
697
698/// Complete result after a runtime accepts one child definition.
699///
700/// A created child leaves only its exact established capability. Rejection
701/// during the pure initialization transition returns the current child and its
702/// exact error. A caught panic returns the extant current child without
703/// claiming an error or successful actions. Rejection while establishing the
704/// host returns the current child and the still-uninterpreted initialization
705/// actions. No variant reconstructs a pre-initialization value or silently
706/// discards an affine action. If interpreter execution loses the definition,
707/// only its exact ID and explicit creation kind remain in an unavailable receipt;
708/// the interpreter retains its native cause without claiming an installed actor.
709///
710/// A failed child installation returns current work and no installed actor:
711///
712/// ```compile_fail,E0026
713/// fn rejected_actor<C, Occurrence>(outcome: behavior::ChildCreationOutcome<C, Occurrence>)
714/// where
715///     C: behavior::Behavior,
716///     behavior::BehaviorAddr<C>: behavior::EndpointAddress,
717/// {
718///     if let behavior::ChildCreationOutcome::HostRejected { actor, .. } = outcome {
719///         let _: behavior::EstablishedActor<C> = actor;
720///     }
721/// }
722/// ```
723pub enum ChildCreationOutcome<C, Occurrence>
724where
725    C: Behavior,
726    BehaviorAddr<C>: EndpointAddress,
727{
728    /// Fresh child creation committed successfully.
729    Established(CommittedChild<C, Occurrence>),
730    /// The interpreter consumed the request but cannot return the child definition.
731    /// No actor was committed; executor-specific failure remains in host custody.
732    Unavailable {
733        /// Exact creator-local correlation of the consumed request.
734        id: CreationId,
735        /// Explicit provenance of the consumed request.
736        kind: CreationKind,
737    },
738    /// The child's pure initialization transition rejected before host commit.
739    InitializationRejected {
740        /// Current child value with its creator correlation and private route.
741        creation: RoutedCreation<BehaviorAddr<C>, C>,
742        /// Exact error returned by the child's initialization transition.
743        error: C::Error,
744    },
745    /// The child's pure initialization panicked before any host commitment.
746    ///
747    /// Only the outer routed child that survived Rust unwinding is returned;
748    /// this does not promise recovery of values destroyed inside user code.
749    InitializationPanicked {
750        /// Current child value with its creator correlation and private route.
751        creation: RoutedCreation<BehaviorAddr<C>, C>,
752    },
753    /// Host establishment rejected after initialization produced actions.
754    HostRejected {
755        /// Current child value with its creator correlation and private route.
756        creation: RoutedCreation<BehaviorAddr<C>, C>,
757        /// Complete initialization actions that were never interpreted.
758        initialization: Actions<BehaviorAddr<C>, C::Ph, C::Sends, C::Birth>,
759        /// Exact reason the host could not commit this child.
760        reason: CreationRejection,
761    },
762}
763
764impl<C, Occurrence> ChildCreationOutcome<C, Occurrence>
765where
766    C: Behavior,
767    BehaviorAddr<C>: EndpointAddress,
768{
769    /// Consume a committed child result into its exact concrete actor
770    /// capability.
771    ///
772    /// The committed variant directly owns the actor, ID, kind, and
773    /// occurrence; no nested rejection can appear under success.
774    ///
775    /// # Errors
776    ///
777    /// Returns the complete original result when creation did not commit.
778    pub fn into_committed(self) -> Result<CommittedChild<C, Occurrence>, Self> {
779        match self {
780            Self::Established(child) => Ok(child),
781            other => Err(other),
782        }
783    }
784
785    /// Consume a committed child into its exact actor.
786    ///
787    /// # Errors
788    /// Returns the complete original result when creation did not commit.
789    pub fn into_actor(self) -> Result<EstablishedActor<C>, Self> {
790        self.into_committed().map(|child| child.into_parts().2)
791    }
792}
793
794/// One complete child-creation settlement returned to its creator.
795///
796/// This product moves the existing settlement without reclassifying it. In
797/// particular, initialization and host rejection retain the current child and
798/// exact initialization value. A runtime that cannot admit this value to the
799/// live creator must recover it from the returned event and keep it in host
800/// custody.
801#[must_use = "a child-creation settlement must be admitted or retained"]
802pub struct ChildCreationSettled<C, Occurrence>
803where
804    C: Behavior,
805    BehaviorAddr<C>: EndpointAddress,
806{
807    settlement: SettledItem<
808        RoutedCreation<BehaviorAddr<C>, C>,
809        ItemSettlement<
810            RoutedCreation<BehaviorAddr<C>, C>,
811            ChildCreationOutcome<C, Occurrence>,
812            CreationRejection,
813            Never,
814        >,
815    >,
816}
817
818impl<C, Occurrence> ChildCreationSettled<C, Occurrence>
819where
820    C: Behavior,
821    BehaviorAddr<C>: EndpointAddress,
822{
823    #[must_use]
824    pub const fn new(
825        settlement: SettledItem<
826            RoutedCreation<BehaviorAddr<C>, C>,
827            ItemSettlement<
828                RoutedCreation<BehaviorAddr<C>, C>,
829                ChildCreationOutcome<C, Occurrence>,
830                CreationRejection,
831                Never,
832            >,
833        >,
834    ) -> Self {
835        Self { settlement }
836    }
837
838    /// Recover the exact generic settlement without cloning any owned value.
839    #[must_use]
840    pub fn into_settlement(
841        self,
842    ) -> SettledItem<
843        RoutedCreation<BehaviorAddr<C>, C>,
844        ItemSettlement<
845            RoutedCreation<BehaviorAddr<C>, C>,
846            ChildCreationOutcome<C, Occurrence>,
847            CreationRejection,
848            Never,
849        >,
850    > {
851        self.settlement
852    }
853}
854
855impl<C, Occurrence> core::fmt::Debug for ChildCreationSettled<C, Occurrence>
856where
857    C: Behavior,
858    BehaviorAddr<C>: EndpointAddress,
859{
860    fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
861        formatter
862            .debug_struct("ChildCreationSettled")
863            .finish_non_exhaustive()
864    }
865}
866
867/// Non-authoritative correlation to one creation result in the current action.
868///
869/// `P` and `Occurrence` select the exact creator-local entry statically. The
870/// value carries no recipient, actor identity, or child-hosting authority; the
871/// corresponding creation settlement remains its sole authoritative owner.
872///
873/// Equal ID representations at different occurrences cannot be
874/// substituted:
875///
876/// ```compile_fail,E0308
877/// struct Worker;
878/// impl behavior::Protocol for Worker {
879///     type Addr = behavior::MailAddr;
880///     type Msg = ();
881/// }
882/// struct Primary;
883/// struct Backup;
884/// let mut sequence = behavior::CreationSequence::new();
885/// let id = sequence.issue().expect("fixture creation ID");
886/// let backup = behavior::CreationCorrelation::<Worker, Backup>::new(id);
887/// let _: behavior::CreationCorrelation<Worker, Primary> = backup;
888/// ```
889pub struct CreationCorrelation<P, Occurrence>
890where
891    P: Protocol,
892{
893    id: CreationId,
894    occurrence: PhantomData<fn() -> (P, Occurrence)>,
895}
896
897impl<P, Occurrence> CreationCorrelation<P, Occurrence>
898where
899    P: Protocol,
900{
901    #[must_use]
902    pub const fn new(id: CreationId) -> Self {
903        Self {
904            id,
905            occurrence: PhantomData,
906        }
907    }
908
909    #[must_use]
910    pub const fn id(self) -> CreationId {
911        self.id
912    }
913}
914
915impl<P, Occurrence> Copy for CreationCorrelation<P, Occurrence> where P: Protocol {}
916
917impl<P, Occurrence> Clone for CreationCorrelation<P, Occurrence>
918where
919    P: Protocol,
920{
921    fn clone(&self) -> Self {
922        *self
923    }
924}
925
926impl<P, Occurrence> core::fmt::Debug for CreationCorrelation<P, Occurrence>
927where
928    P: Protocol,
929{
930    fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
931        formatter
932            .debug_tuple("CreationCorrelation")
933            .field(&self.id)
934            .finish()
935    }
936}
937
938impl<P, Occurrence> PartialEq for CreationCorrelation<P, Occurrence>
939where
940    P: Protocol,
941{
942    fn eq(&self, other: &Self) -> bool {
943        self.id == other.id
944    }
945}
946
947impl<P, Occurrence> Eq for CreationCorrelation<P, Occurrence> where P: Protocol {}
948
949/// Same-action communication to one declared creator-local role.
950///
951/// The interpreter resolves this route only after all creations in the same
952/// [`crate::Actions`] have committed. A rejected or absent binding must produce
953/// a typed interpreter outcome; it can never be converted into a logical
954/// address by nonce arithmetic.
955pub struct ChildDelivery<P, Occurrence>
956where
957    P: Protocol,
958{
959    pub creation: CreationId,
960    pub message: P::Msg,
961    occurrence: PhantomData<fn() -> Occurrence>,
962}
963
964/// Private typed communication to one declared creator-local child role.
965///
966/// `ChildDelivery` addresses the child's public protocol. `ChildInput`
967/// instead selects one owner-defined member of the concrete child's event
968/// algebra through `Source`. This is the static boundary used for lifecycle
969/// coordination between an owner and a composed child: it retains the exact
970/// child behavior, occurrence, input, and ingress owner without exposing the
971/// input through the child's public protocol or performing a runtime lookup.
972///
973/// This is a derived Bombay communication form. Like `ChildDelivery`, its
974/// creator-local route is interpreted only after same-action creations have
975/// committed; constructing it performs no delivery.
976pub struct ChildInput<Child, Source, Input, Occurrence>
977where
978    Child: Behavior,
979{
980    /// Creator-local creation ID of the concrete child receiving the input.
981    pub creation: CreationId,
982    /// Complete private input transferred to the child.
983    pub input: Input,
984    marker: PhantomData<fn() -> (Child, Source, Occurrence)>,
985}
986
987/// Exact reason one public child delivery was not accepted.
988#[derive(Clone, Copy, Debug, Eq, PartialEq)]
989pub enum ChildDeliveryReason {
990    MissingBinding,
991    ClosedRecipient,
992}
993
994/// Exact reason one private child input was not accepted.
995#[derive(Clone, Copy, Debug, Eq, PartialEq)]
996pub enum ChildInputReason {
997    MissingBinding,
998    ClosedControlLane,
999}
1000
1001/// One report emitted through an established creator/child relationship.
1002///
1003/// The interpreter attaches `child` from its exact local binding; the
1004/// emitting behavior supplies only `report`. `EventIngress` separately keeps
1005/// the concrete child behavior and occurrence in the parent's event type, so
1006/// equal nonce representations cannot confuse different child roles.
1007#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1008pub struct ChildReport<R> {
1009    /// Creator-local ID of the child that emitted the report.
1010    pub child: CreationId,
1011    /// Complete report value transferred by that child.
1012    pub report: R,
1013}
1014
1015impl<R> ChildReport<R> {
1016    /// Attach an established creator-local creation ID to one report.
1017    #[must_use]
1018    pub const fn new(child: CreationId, report: R) -> Self {
1019        Self { child, report }
1020    }
1021}
1022
1023impl<R> From<(CreationId, crate::ReportToParent<R>)> for ChildReport<R> {
1024    fn from((child, request): (CreationId, crate::ReportToParent<R>)) -> Self {
1025        Self::new(child, request.into_inner())
1026    }
1027}
1028
1029impl<Child, Source, Input, Occurrence> ChildInput<Child, Source, Input, Occurrence>
1030where
1031    Child: Behavior,
1032    Child::Event: crate::ChildInputIngress<Source, Input>,
1033{
1034    /// Construct a private input for one exact creator-local child creation.
1035    #[must_use]
1036    pub const fn after(creation: CreationId, input: Input) -> Self {
1037        Self {
1038            creation,
1039            input,
1040            marker: PhantomData,
1041        }
1042    }
1043}
1044
1045impl<Child, Source, Input, Occurrence> Clone for ChildInput<Child, Source, Input, Occurrence>
1046where
1047    Child: Behavior,
1048    Input: Clone,
1049{
1050    fn clone(&self) -> Self {
1051        Self {
1052            creation: self.creation,
1053            input: self.input.clone(),
1054            marker: PhantomData,
1055        }
1056    }
1057}
1058
1059impl<P, Occurrence> ChildDelivery<P, Occurrence>
1060where
1061    P: Protocol,
1062{
1063    #[must_use]
1064    pub const fn after(creation: CreationId, message: P::Msg) -> Self {
1065        Self {
1066            creation,
1067            message,
1068            occurrence: PhantomData,
1069        }
1070    }
1071}
1072
1073impl<P, Occurrence> Clone for ChildDelivery<P, Occurrence>
1074where
1075    P: Protocol,
1076    P::Msg: Clone,
1077{
1078    fn clone(&self) -> Self {
1079        Self {
1080            creation: self.creation,
1081            message: self.message.clone(),
1082            occurrence: PhantomData,
1083        }
1084    }
1085}
1086
1087impl<P, Occurrence> ActionItem for ChildDelivery<P, Occurrence>
1088where
1089    P: Protocol,
1090    P::Msg: Send,
1091{
1092    type Custody = (Option<Self>, Option<Self::Reply>);
1093    type Input<'a>
1094        = &'a mut Option<Self>
1095    where
1096        Self: 'a;
1097    type Reply = ItemSettlement<Self, Self::Accepted, Self::Rejection, Self::Prerequisite>;
1098
1099    fn prepare_interpretation(
1100        progress: &mut Option<InterpretationProgress<Self, Self::Custody, Self::Reply>>,
1101    ) {
1102        prepare_item::<Self>(progress);
1103    }
1104    fn interpretation_input<'a>(
1105        custody: &'a mut Self::Custody,
1106    ) -> Option<(Self::Input<'a>, &'a mut Option<Self::Reply>)>
1107    where
1108        Self: 'a,
1109    {
1110        let (input, received) = custody;
1111        if input.is_some() && received.is_none() {
1112            Some((input, received))
1113        } else {
1114            None
1115        }
1116    }
1117    fn finish_interpretation(
1118        progress: &mut Option<InterpretationProgress<Self, Self::Custody, Self::Reply>>,
1119    ) {
1120        finish_item::<Self>(progress);
1121    }
1122
1123    type Accepted = ();
1124    type Rejection = ChildDeliveryReason;
1125    type Prerequisite = CreationCorrelation<P, Occurrence>;
1126}
1127
1128impl<Child, Source, Input, Occurrence> ActionItem for ChildInput<Child, Source, Input, Occurrence>
1129where
1130    Child: Behavior,
1131    Input: Send,
1132{
1133    type Custody = (Option<Self>, Option<Self::Reply>);
1134    type Input<'a>
1135        = &'a mut Option<Self>
1136    where
1137        Self: 'a;
1138    type Reply = ItemSettlement<Self, Self::Accepted, Self::Rejection, Self::Prerequisite>;
1139
1140    fn prepare_interpretation(
1141        progress: &mut Option<InterpretationProgress<Self, Self::Custody, Self::Reply>>,
1142    ) {
1143        prepare_item::<Self>(progress);
1144    }
1145    fn interpretation_input<'a>(
1146        custody: &'a mut Self::Custody,
1147    ) -> Option<(Self::Input<'a>, &'a mut Option<Self::Reply>)>
1148    where
1149        Self: 'a,
1150    {
1151        let (input, received) = custody;
1152        if input.is_some() && received.is_none() {
1153            Some((input, received))
1154        } else {
1155            None
1156        }
1157    }
1158    fn finish_interpretation(
1159        progress: &mut Option<InterpretationProgress<Self, Self::Custody, Self::Reply>>,
1160    ) {
1161        finish_item::<Self>(progress);
1162    }
1163
1164    type Accepted = ();
1165    type Rejection = ChildInputReason;
1166    type Prerequisite = CreationCorrelation<Child::Protocol, Occurrence>;
1167}
1168
1169/// Runtime ownership port for establishing one concrete child behavior.
1170///
1171/// The result vocabulary belongs to the creation request, never the runtime.
1172/// Accepting ownership consumes the child definition and returns its one
1173/// authoritative created-or-rejected result. Refusal before ownership transfer
1174/// returns the complete request. Child creation has no prerequisite, while
1175/// interpreter corruption uses the shared [`crate::InterpreterFault`] sum.
1176///
1177/// A runtime cannot substitute a private receipt or rejection type:
1178///
1179/// ```compile_fail,E0271
1180/// #[derive(Clone, Copy, Eq, PartialEq)]
1181/// struct RuntimeAddr;
1182/// impl behavior::Address for RuntimeAddr { type Nonce = u8; }
1183/// #[derive(Clone)]
1184/// struct Endpoint;
1185/// struct Installed<B: behavior::Behavior>(Endpoint, std::sync::mpsc::Sender<B::Event>);
1186/// impl<B: behavior::Behavior> Clone for Installed<B> {
1187///     fn clone(&self) -> Self { Self(self.0.clone(), self.1.clone()) }
1188/// }
1189/// impl behavior::EndpointAddress for RuntimeAddr {
1190///     type Established<P> = Endpoint where P: behavior::Protocol<Addr = Self>;
1191///     type Installed<B> = Installed<B>
1192///         where B: behavior::Behavior<Protocol: behavior::Protocol<Addr = Self>>;
1193///     fn recipient<B>(installed: &Self::Installed<B>) -> Endpoint
1194///     where B: behavior::Behavior<Protocol: behavior::Protocol<Addr = Self>> {
1195///         installed.0.clone()
1196///     }
1197/// }
1198/// struct Child;
1199/// impl behavior::Protocol for Child {
1200///     type Addr = RuntimeAddr;
1201///     type Msg = behavior::Never;
1202/// }
1203/// impl behavior::Behavior for Child {
1204///     type Protocol = Self;
1205///     type Event = behavior::User<RuntimeAddr, behavior::Never>;
1206///     type Sends = behavior::NoSends;
1207///     type Ph = behavior::Never;
1208///     type Error = behavior::Never;
1209///     type Birth = behavior::NoBirths;
1210///     fn transition(
1211///         &mut self,
1212///         _: behavior::ActiveTurn,
1213///         event: Self::Event,
1214///     ) -> behavior::BehaviorActed<Self> {
1215///         match event.message {}
1216///     }
1217/// }
1218/// struct Runtime;
1219///
1220/// impl behavior::EstablishChild<behavior::ChildHead, Child> for Runtime {
1221///     fn establish_child(
1222///         &mut self,
1223///         creation: behavior::RoutedCreation<behavior::BehaviorAddr<Child>, Child>,
1224///     ) -> impl core::future::Future<Output = behavior::ItemSettlement<
1225///         behavior::RoutedCreation<behavior::BehaviorAddr<Child>, Child>,
1226///         (),
1227///         &'static str,
1228///         behavior::Never,
1229///     >> + Send {
1230///         async move { behavior::ItemSettlement::Rejected { item: creation, reason: "no" } }
1231///     }
1232/// }
1233/// ```
1234pub trait EstablishChild<Occurrence, C>
1235where
1236    C: Behavior,
1237    BehaviorAddr<C>: EndpointAddress,
1238{
1239    /// Establish exactly the supplied child or return its complete settlement.
1240    fn establish_child(
1241        &mut self,
1242        creation: RoutedCreation<BehaviorAddr<C>, C>,
1243    ) -> impl Future<
1244        Output = ItemSettlement<
1245            RoutedCreation<BehaviorAddr<C>, C>,
1246            ChildCreationOutcome<C, Occurrence>,
1247            CreationRejection,
1248            Never,
1249        >,
1250    > + Send;
1251}
1252
1253/// Authoritative result shape for one closed child choice.
1254///
1255/// This type-level product depends only on the declared child protocols and
1256/// their occurrences. It contains no runtime-selected type.
1257#[doc(hidden)]
1258pub trait ChildCreationProduct<A: Address, Occurrence>: Sized {
1259    type Result;
1260}
1261
1262/// Exhaustive static dispatch of one creation-only child sum.
1263///
1264/// This is an interpreter-facing derived construction, not another actor-model
1265/// operation. Implementations must preserve the ID, route, and creation kind and
1266/// call exactly one concrete [`EstablishChild`] implementation. [`ChildChoice`]
1267/// provides the closed recursive heterogeneous sum. Dispatch futures are
1268/// sendable; heterogeneous sums therefore require sendable alternatives,
1269/// runtime routes, and child hosts.
1270pub trait DispatchBirth<A: Address, Host>: ChildCreationProduct<A, ChildHead> + Sized {
1271    /// Select exactly one concrete child host while preserving creation data
1272    /// in every non-accepted settlement.
1273    fn dispatch_birth(
1274        self,
1275        id: CreationId,
1276        route: A::Nonce,
1277        kind: CreationKind,
1278        host: &mut Host,
1279    ) -> impl Future<
1280        Output = ItemSettlement<
1281            RoutedCreation<A, Self>,
1282            <Self as ChildCreationProduct<A, ChildHead>>::Result,
1283            CreationRejection,
1284            Never,
1285        >,
1286    > + Send;
1287}
1288
1289trait CreateSelectedChild<A: Address, Occurrence, Host>:
1290    ChildCreationProduct<A, Occurrence> + Sized
1291{
1292    fn dispatch_birth_at(
1293        self,
1294        id: CreationId,
1295        route: A::Nonce,
1296        kind: CreationKind,
1297        host: &mut Host,
1298    ) -> impl Future<
1299        Output = ItemSettlement<
1300            RoutedCreation<A, Self>,
1301            <Self as ChildCreationProduct<A, Occurrence>>::Result,
1302            CreationRejection,
1303            Never,
1304        >,
1305    > + Send;
1306}
1307
1308impl<A, Child, Host> DispatchBirth<A, Host> for Child
1309where
1310    A: Address,
1311    Child: CreateSelectedChild<A, ChildHead, Host>,
1312{
1313    fn dispatch_birth(
1314        self,
1315        id: CreationId,
1316        route: A::Nonce,
1317        kind: CreationKind,
1318        host: &mut Host,
1319    ) -> impl Future<
1320        Output = ItemSettlement<
1321            RoutedCreation<A, Self>,
1322            <Self as ChildCreationProduct<A, ChildHead>>::Result,
1323            CreationRejection,
1324            Never,
1325        >,
1326    > + Send {
1327        self.dispatch_birth_at(id, route, kind, host)
1328    }
1329}
1330
1331/// One alternative in a closed, recursively composed child-creation sum.
1332///
1333/// `Head` is one concrete child behavior and `Tail` is the remaining closed
1334/// sum. This is a creation choice only: it is not a behavior, message
1335/// envelope, registry, or runtime dispatch mechanism.
1336///
1337/// Every alternative requires a concrete child host; incomplete interpreter
1338/// support is rejected statically:
1339///
1340/// ```compile_fail,E0277
1341/// #[derive(Clone, Copy, Eq, PartialEq)]
1342/// struct RuntimeAddr;
1343/// impl behavior::Address for RuntimeAddr { type Nonce = u8; }
1344/// #[derive(Clone)]
1345/// struct Endpoint;
1346/// struct Installed<B: behavior::Behavior>(Endpoint, std::sync::mpsc::Sender<B::Event>);
1347/// impl<B: behavior::Behavior> Clone for Installed<B> {
1348///     fn clone(&self) -> Self { Self(self.0.clone(), self.1.clone()) }
1349/// }
1350/// impl behavior::EndpointAddress for RuntimeAddr {
1351///     type Established<P> = Endpoint where P: behavior::Protocol<Addr = Self>;
1352///     type Installed<B> = Installed<B>
1353///         where B: behavior::Behavior<Protocol: behavior::Protocol<Addr = Self>>;
1354///     fn recipient<B>(installed: &Self::Installed<B>) -> Endpoint
1355///     where B: behavior::Behavior<Protocol: behavior::Protocol<Addr = Self>> {
1356///         installed.0.clone()
1357///     }
1358/// }
1359/// struct CacheWorker;
1360/// struct QueueWorker;
1361///
1362/// macro_rules! inert {
1363///     ($child:ty) => {
1364///         impl behavior::Protocol for $child {
1365///             type Addr = RuntimeAddr;
1366///             type Msg = behavior::Never;
1367///         }
1368///         impl behavior::Behavior for $child {
1369///             type Protocol = Self;
1370///             type Event = behavior::User<RuntimeAddr, behavior::Never>;
1371///             type Sends = behavior::NoSends;
1372///             type Ph = behavior::Never;
1373///             type Error = behavior::Never;
1374///             type Birth = behavior::NoBirths;
1375///
1376///             fn transition(
1377///                 &mut self,
1378///                 _: behavior::ActiveTurn,
1379///                 event: Self::Event,
1380///             ) -> behavior::BehaviorActed<Self> {
1381///                 match event.message {}
1382///             }
1383///         }
1384///     };
1385/// }
1386/// inert!(CacheWorker);
1387/// inert!(QueueWorker);
1388///
1389/// struct Incomplete;
1390/// impl behavior::EstablishChild<behavior::ChildHead, CacheWorker> for Incomplete {
1391///     fn establish_child(
1392///         &mut self,
1393///         creation: behavior::RoutedCreation<RuntimeAddr, CacheWorker>,
1394///     ) -> impl core::future::Future<Output = behavior::ItemSettlement<
1395///         behavior::RoutedCreation<RuntimeAddr, CacheWorker>,
1396///         behavior::ChildCreationOutcome<CacheWorker, behavior::ChildHead>,
1397///         behavior::CreationRejection,
1398///         behavior::Never,
1399///     >> + Send {
1400///         async move { behavior::ItemSettlement::Rejected {
1401///             item: creation,
1402///             reason: behavior::CreationRejection::EnvironmentFailed,
1403///         } }
1404///     }
1405/// }
1406///
1407/// type WorkerChoices = behavior::ChildChoice<
1408///     CacheWorker,
1409///     behavior::ChildChoice<QueueWorker, behavior::Never>,
1410/// >;
1411/// fn require_complete<T: behavior::DispatchBirth<RuntimeAddr, Incomplete>>() {}
1412/// require_complete::<WorkerChoices>();
1413/// ```
1414#[derive(Debug, Clone, PartialEq, Eq)]
1415pub enum ChildChoice<Head, Tail> {
1416    /// Select the concrete child at this position.
1417    Head(Head),
1418    /// Select one concrete child from the remaining alternatives.
1419    Tail(Tail),
1420}
1421
1422/// Position selecting the head of a closed [`ChildChoice`] sum.
1423#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
1424pub struct ChildHead;
1425
1426/// Position selecting inside the tail of a closed [`ChildChoice`] sum.
1427#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
1428pub struct ChildTail<Position>(PhantomData<fn() -> Position>);
1429
1430/// Static proof that `Child` occupies `Position` in a closed child sum.
1431///
1432/// This trait provides structural evidence only. It does not construct a
1433/// choice, perform creation, or select a child through runtime inspection.
1434/// A role cannot claim a position occupied by a different child:
1435///
1436/// ```compile_fail
1437/// struct CacheWorker;
1438/// struct QueueWorker;
1439/// struct Parent;
1440/// macro_rules! inert {
1441///     ($actor:ty) => {
1442///         impl behavior::Protocol for $actor {
1443///             type Addr = behavior::MailAddr;
1444///             type Msg = behavior::Never;
1445///         }
1446///         impl behavior::Behavior for $actor {
1447///             type Protocol = Self;
1448///             type Event = behavior::User<behavior::MailAddr, behavior::Never>;
1449///             type Sends = Vec<behavior::Never>;
1450///             type Ph = behavior::Never;
1451///             type Error = behavior::Never;
1452///             type Birth = behavior::NoBirths;
1453///             fn transition(&mut self, _: behavior::ActiveTurn, event: Self::Event) -> behavior::BehaviorActed<Self> {
1454///                 match event.message {}
1455///             }
1456///         }
1457///     };
1458/// }
1459/// inert!(CacheWorker);
1460/// inert!(QueueWorker);
1461/// impl behavior::Protocol for Parent {
1462///     type Addr = behavior::MailAddr;
1463///     type Msg = behavior::Never;
1464/// }
1465/// impl behavior::Behavior for Parent {
1466///     type Protocol = Self;
1467///     type Event = behavior::User<behavior::MailAddr, behavior::Never>;
1468///     type Sends = Vec<behavior::Never>;
1469///     type Ph = behavior::Never;
1470///     type Error = behavior::Never;
1471///     type Birth = behavior::Births<behavior::ChildChoice<QueueWorker, behavior::ChildChoice<CacheWorker, behavior::Never>>>;
1472///     fn transition(&mut self, _: behavior::ActiveTurn, event: Self::Event) -> behavior::BehaviorActed<Self> {
1473///         match event.message {}
1474///     }
1475/// }
1476/// struct ForgedCacheRole;
1477/// impl behavior::ChildRole<Parent> for ForgedCacheRole {
1478///     type Child = CacheWorker;
1479///     type Position = behavior::ChildHead;
1480/// }
1481/// ```
1482pub trait ChildPosition<Children, Child: Behavior>: sealed::ChildPosition {}
1483
1484impl sealed::ChildPosition for ChildHead {}
1485
1486impl<Child: Behavior> ChildPosition<Child, Child> for ChildHead {}
1487
1488impl<Head: Behavior, Tail> ChildPosition<ChildChoice<Head, Tail>, Head> for ChildHead {}
1489
1490impl<Position> sealed::ChildPosition for ChildTail<Position> {}
1491
1492impl<Head, Tail, Position, Child> ChildPosition<ChildChoice<Head, Tail>, Child>
1493    for ChildTail<Position>
1494where
1495    Child: Behavior,
1496    Position: ChildPosition<Tail, Child>,
1497{
1498}
1499
1500/// Append one closed direct-child algebra after another.
1501///
1502/// `Self` remains the structural prefix, so every child occurrence already
1503/// valid in that prefix retains both its child type and its position. `Tail`
1504/// begins only after the prefix's final position. The two injection functions
1505/// change only the closed sum containing a child; [`append_creations`](Self::append_creations)
1506/// additionally preserves every creation's ID, kind, and batch order while
1507/// placing all prefix creations before all appended creations.
1508///
1509/// This is a static composition of Bombay's existing staged-creation
1510/// capability, not another actor effect and not an allocation operation. The
1511/// interpreter remains solely responsible for establishing and binding the child.
1512///
1513/// A generic topology owner can therefore retain an inner behavior's exact
1514/// creation effects and append children whose concrete types were inferred
1515/// from value construction:
1516///
1517/// ```
1518/// type Combined = <behavior::Never as behavior::BirthNodeAppend<behavior::Never>>::Output;
1519/// let _: core::marker::PhantomData<Combined> = core::marker::PhantomData;
1520/// ```
1521pub trait BirthNodeAppend<Tail>: sealed::BirthNode + Sized
1522where
1523    Tail: sealed::BirthNode,
1524{
1525    /// Closed child algebra containing the complete prefix followed by the
1526    /// complete appended tail.
1527    type Output: sealed::BirthNode;
1528
1529    /// Inject one child from the existing prefix without changing its
1530    /// structural occurrence.
1531    fn append_prefix(self) -> Self::Output;
1532
1533    /// Inject one child from the appended tail after every prefix occurrence.
1534    fn append_tail(tail: Tail) -> Self::Output;
1535
1536    /// Preserve and concatenate two ordered creation batches.
1537    #[must_use]
1538    fn append_creations<A: Address>(
1539        prefix: Creations<CreateChild<A, Self>>,
1540        tail: Creations<CreateChild<A, Tail>>,
1541    ) -> Creations<CreateChild<A, Self::Output>> {
1542        let mut combined = Vec::with_capacity(prefix.len() + tail.len());
1543        combined.extend(prefix.into_iter().map(|creation| {
1544            let (id, child, kind) = creation.into_parts();
1545            CreateChild::from_parts(id, Self::append_prefix(child), kind)
1546        }));
1547        combined.extend(tail.into_iter().map(|creation| {
1548            let (id, child, kind) = creation.into_parts();
1549            CreateChild::from_parts(id, Self::append_tail(child), kind)
1550        }));
1551        Creations::from_items(combined)
1552    }
1553}
1554
1555impl<Tail> BirthNodeAppend<Tail> for Never
1556where
1557    Tail: sealed::BirthNode,
1558{
1559    type Output = Tail;
1560
1561    fn append_prefix(self) -> Self::Output {
1562        match self {}
1563    }
1564
1565    fn append_tail(tail: Tail) -> Self::Output {
1566        tail
1567    }
1568}
1569
1570impl<Node> BirthNodeAppend<Never> for Node
1571where
1572    Node: sealed::NonEmptyBirthNode,
1573{
1574    type Output = Node;
1575
1576    fn append_prefix(self) -> Self::Output {
1577        self
1578    }
1579
1580    fn append_tail(tail: Never) -> Self::Output {
1581        match tail {}
1582    }
1583}
1584
1585impl<Child, Tail> BirthNodeAppend<Tail> for Child
1586where
1587    Child: Behavior,
1588    Tail: sealed::NonEmptyBirthNode,
1589{
1590    type Output = ChildChoice<Child, Tail>;
1591
1592    fn append_prefix(self) -> Self::Output {
1593        ChildChoice::Head(self)
1594    }
1595
1596    fn append_tail(tail: Tail) -> Self::Output {
1597        ChildChoice::Tail(tail)
1598    }
1599}
1600
1601impl<Head, Rest, Tail> BirthNodeAppend<Tail> for ChildChoice<Head, Rest>
1602where
1603    Head: Behavior,
1604    Rest: sealed::BirthNode + BirthNodeAppend<Tail>,
1605    Tail: sealed::NonEmptyBirthNode,
1606    Rest::Output: sealed::BirthNode,
1607{
1608    type Output = ChildChoice<Head, Rest::Output>;
1609
1610    fn append_prefix(self) -> Self::Output {
1611        match self {
1612            ChildChoice::Head(head) => ChildChoice::Head(head),
1613            ChildChoice::Tail(rest) => ChildChoice::Tail(rest.append_prefix()),
1614        }
1615    }
1616
1617    fn append_tail(tail: Tail) -> Self::Output {
1618        ChildChoice::Tail(Rest::append_tail(tail))
1619    }
1620}
1621
1622impl<Parent: Behavior> ChildOccurrence<Parent> for ChildHead {
1623    type Resolution = StructuralChildOccurrence<Self>;
1624}
1625
1626impl<Parent: Behavior, Position> ChildOccurrence<Parent> for ChildTail<Position> {
1627    type Resolution = StructuralChildOccurrence<Self>;
1628}
1629
1630/// Sealed proof that an occurrence may select one resolver descriptor.
1631///
1632/// Nominal occurrences can select [`DeclaredChildOccurrence`] only when their
1633/// existing [`ChildRole`] implementation supplies the child and position. Raw
1634/// structural descriptors are available only to the identical
1635/// [`ChildHead`] or [`ChildTail`] occurrence.
1636#[doc(hidden)]
1637pub trait ChildOccurrenceResolution<Parent: Behavior, Occurrence>:
1638    sealed::ChildOccurrenceDescriptor + sealed::OccurrenceResolution<Parent, Occurrence>
1639{
1640}
1641
1642impl<Parent, Occurrence> ChildOccurrenceResolution<Parent, Occurrence> for DeclaredChildOccurrence
1643where
1644    Parent: Behavior,
1645    Occurrence: ChildRole<Parent>,
1646{
1647}
1648
1649impl<Parent: Behavior> ChildOccurrenceResolution<Parent, ChildHead>
1650    for StructuralChildOccurrence<ChildHead>
1651{
1652}
1653
1654impl<Parent: Behavior, Position> ChildOccurrenceResolution<Parent, ChildTail<Position>>
1655    for StructuralChildOccurrence<ChildTail<Position>>
1656{
1657}
1658
1659/// Sealed implementation detail for resolving occurrence descriptors.
1660#[doc(hidden)]
1661pub trait ResolveChildOccurrenceDescriptor<Emitter: Behavior, Occurrence>:
1662    sealed::ChildOccurrenceDescriptor + sealed::ResolveDescriptor<Emitter, Occurrence>
1663{
1664    type Child: Behavior;
1665    type Position: ChildPosition<<Emitter::Birth as BirthMode>::Child, Self::Child>;
1666}
1667
1668impl<Emitter, Occurrence, Position> ResolveChildOccurrenceDescriptor<Emitter, Occurrence>
1669    for StructuralChildOccurrence<Position>
1670where
1671    Emitter: Behavior,
1672    <Emitter::Birth as BirthMode>::Child: BirthNodeAt<Position>,
1673    Position: ChildPosition<
1674            <Emitter::Birth as BirthMode>::Child,
1675            <<Emitter::Birth as BirthMode>::Child as BirthNodeAt<Position>>::Child,
1676        >,
1677{
1678    type Child = <<Emitter::Birth as BirthMode>::Child as BirthNodeAt<Position>>::Child;
1679    type Position = Position;
1680}
1681
1682impl<Emitter, Occurrence> ResolveChildOccurrenceDescriptor<Emitter, Occurrence>
1683    for DeclaredChildOccurrence
1684where
1685    Emitter:
1686        Behavior<Protocol = <<Emitter as BehaviorBase>::Base as Behavior>::Protocol> + BehaviorBase,
1687    Emitter::Base: Behavior,
1688    Occurrence: ChildRole<Emitter::Base>,
1689    <Emitter::Birth as BirthMode>::Child:
1690        BirthNodeAt<Occurrence::Position, Child = Occurrence::Child>,
1691    Occurrence::Position: ChildPosition<<Emitter::Birth as BirthMode>::Child, Occurrence::Child>,
1692{
1693    type Child = Occurrence::Child;
1694    type Position = Occurrence::Position;
1695}
1696
1697/// Sealed inverse projection from one structural position to its child.
1698#[doc(hidden)]
1699pub trait BirthNodeAt<Position>: sealed::BirthNode {
1700    type Child: Behavior;
1701}
1702
1703impl<Child: Behavior> BirthNodeAt<ChildHead> for Child {
1704    type Child = Child;
1705}
1706
1707impl<Head: Behavior, Tail> BirthNodeAt<ChildHead> for ChildChoice<Head, Tail>
1708where
1709    Tail: sealed::BirthNode,
1710{
1711    type Child = Head;
1712}
1713
1714impl<Head, Tail, Position> BirthNodeAt<ChildTail<Position>> for ChildChoice<Head, Tail>
1715where
1716    Head: Behavior,
1717    Tail: BirthNodeAt<Position>,
1718{
1719    type Child = <Tail as BirthNodeAt<Position>>::Child;
1720}
1721
1722/// Downstream shape of one direct-child occurrence product.
1723///
1724/// Behavior owns the closed node algebra: a concrete [`Behavior`] leaf,
1725/// [`ChildChoice`], or [`Never`]. A runtime owns the representation associated
1726/// with each leaf. `Empty` supplies its terminal representation and `Member`
1727/// receives one concrete child, its structural occurrence, and the remaining
1728/// child product.
1729///
1730/// This is a type-level derived construction. It creates no value, allocates
1731/// no actor, interprets no effect, and introduces no protocol identity or
1732/// runtime key. A shape that builds a heterogeneous product should retain
1733/// `Tail`; the product includes every declared child exactly once.
1734///
1735/// ```
1736/// struct NoChildBindings;
1737/// struct ChildBinding<Position, Child, Tail>(core::marker::PhantomData<fn() -> (Position, Child, Tail)>);
1738/// struct RuntimeStorage;
1739///
1740/// impl behavior::ChildOccurrenceShape for RuntimeStorage {
1741///     type Empty = NoChildBindings;
1742/// }
1743/// impl<Occurrence, Child: behavior::Behavior, Tail>
1744///     behavior::ChildOccurrenceMember<Occurrence, Child, Tail> for RuntimeStorage
1745/// {
1746///     type Member = ChildBinding<Occurrence, Child, Tail>;
1747/// }
1748///
1749/// type ChildBindings<Node> = behavior::ChildOccurrences<Node, RuntimeStorage>;
1750/// ```
1751pub trait ChildOccurrenceShape {
1752    /// Representation of the empty [`Never`] node.
1753    type Empty;
1754}
1755
1756/// Shape-owned eligibility and representation of one exact child occurrence.
1757///
1758/// An interpreter may require the payload contracts its storage actually owns.
1759/// Those requirements govern this projection, not pure actor declarations.
1760///
1761/// Eligibility is required independently at each inhabited occurrence. A shape
1762/// admitting only the tail cannot supply the head:
1763///
1764/// ```compile_fail,E0277
1765/// struct NoChildren;
1766/// struct OccurrenceSlot<Position, Child, Tail> {
1767///     child: Child,
1768///     tail: Tail,
1769///     position: std::marker::PhantomData<fn() -> Position>,
1770/// }
1771/// struct Worker { payload: u32 }
1772/// impl behavior::Protocol for Worker {
1773///     type Addr = behavior::MailAddr;
1774///     type Msg = behavior::Never;
1775/// }
1776/// impl behavior::Behavior for Worker {
1777///     type Protocol = Self;
1778///     type Event = behavior::User<behavior::MailAddr, behavior::Never>;
1779///     type Sends = behavior::NoSends;
1780///     type Birth = behavior::NoBirths;
1781///     type Ph = behavior::Never;
1782///     type Error = behavior::Never;
1783///     fn transition(&mut self, _: behavior::ActiveTurn, event: Self::Event)
1784///         -> behavior::BehaviorActed<Self> {
1785///         match event.message {}
1786///     }
1787/// }
1788/// type Workers = behavior::ChildChoice<Worker, behavior::ChildChoice<Worker, behavior::Never>>;
1789/// struct MissingHead;
1790/// impl behavior::ChildOccurrenceShape for MissingHead {
1791///     type Empty = NoChildren;
1792/// }
1793/// impl<Child: behavior::Behavior, Tail> behavior::ChildOccurrenceMember<behavior::ChildTail<behavior::ChildHead>, Child, Tail> for MissingHead {
1794///     type Member = OccurrenceSlot<behavior::ChildTail<behavior::ChildHead>, Child, Tail>;
1795/// }
1796/// let _: std::marker::PhantomData<behavior::ChildOccurrences<Workers, MissingHead>> = std::marker::PhantomData;
1797/// ```
1798///
1799/// A shape admitting only the head cannot supply the tail:
1800///
1801/// ```compile_fail,E0277
1802/// struct NoChildren;
1803/// struct OccurrenceSlot<Position, Child, Tail> {
1804///     child: Child,
1805///     tail: Tail,
1806///     position: std::marker::PhantomData<fn() -> Position>,
1807/// }
1808/// struct Worker { payload: u32 }
1809/// impl behavior::Protocol for Worker {
1810///     type Addr = behavior::MailAddr;
1811///     type Msg = behavior::Never;
1812/// }
1813/// impl behavior::Behavior for Worker {
1814///     type Protocol = Self;
1815///     type Event = behavior::User<behavior::MailAddr, behavior::Never>;
1816///     type Sends = behavior::NoSends;
1817///     type Birth = behavior::NoBirths;
1818///     type Ph = behavior::Never;
1819///     type Error = behavior::Never;
1820///     fn transition(&mut self, _: behavior::ActiveTurn, event: Self::Event)
1821///         -> behavior::BehaviorActed<Self> {
1822///         match event.message {}
1823///     }
1824/// }
1825/// type Workers = behavior::ChildChoice<Worker, behavior::ChildChoice<Worker, behavior::Never>>;
1826/// struct MissingTail;
1827/// impl behavior::ChildOccurrenceShape for MissingTail {
1828///     type Empty = NoChildren;
1829/// }
1830/// impl<Child: behavior::Behavior, Tail> behavior::ChildOccurrenceMember<behavior::ChildHead, Child, Tail> for MissingTail {
1831///     type Member = OccurrenceSlot<behavior::ChildHead, Child, Tail>;
1832/// }
1833/// let _: std::marker::PhantomData<behavior::ChildOccurrences<Workers, MissingTail>> = std::marker::PhantomData;
1834/// ```
1835pub trait ChildOccurrenceMember<Occurrence, Child: Behavior, Tail>: ChildOccurrenceShape {
1836    /// Storage for this child, its static occurrence, and the remaining product.
1837    type Member;
1838}
1839
1840/// Sealed occurrence product of a closed direct-child birth node.
1841///
1842/// The product starts at [`ChildHead`] and advances through
1843/// [`ChildTail<Position>`] in exactly the same way as [`DispatchBirth`] and
1844/// [`ChildPosition`]. A downstream runtime selects only the result shape
1845/// through [`ChildOccurrenceShape`]; it cannot reclassify a foreign type as a
1846/// birth node or replace the recursion.
1847///
1848/// This product is intentionally direct rather than transitive. Each installed
1849/// actor owns the bindings for its own `Behavior::Birth`; when a concrete child
1850/// is installed, the same product law applies to that child's birth algebra.
1851///
1852/// Foreign types cannot extend the closed node algebra:
1853///
1854/// ```compile_fail,E0277
1855/// struct RuntimeShape;
1856/// impl behavior::ChildOccurrenceShape for RuntimeShape {
1857///     type Empty = ();
1858/// }
1859/// impl<Occurrence, Child: behavior::Behavior, Tail>
1860///     behavior::ChildOccurrenceMember<Occurrence, Child, Tail> for RuntimeShape
1861/// {
1862///     type Member = ();
1863/// }
1864///
1865/// struct ForeignNode;
1866/// impl behavior::ChildOccurrenceProduct<RuntimeShape> for ForeignNode {
1867///     type Product = ();
1868/// }
1869/// ```
1870pub trait ChildOccurrenceProduct<Shape>: sealed::BirthNode
1871where
1872    Shape: ChildOccurrenceShape,
1873{
1874    /// Complete shape-owned representation of this closed birth node.
1875    type Product;
1876}
1877
1878/// Occurrence-carrying recursion for [`ChildOccurrenceProduct`]. Consumers
1879/// should name [`ChildOccurrenceProduct`] or [`ChildOccurrences`] instead.
1880#[doc(hidden)]
1881pub trait ChildOccurrenceProductAt<Occurrence, Shape>: sealed::BirthNode
1882where
1883    Shape: ChildOccurrenceShape,
1884{
1885    type Product;
1886}
1887
1888impl<Node, Shape> ChildOccurrenceProduct<Shape> for Node
1889where
1890    Node: ChildOccurrenceProductAt<ChildHead, Shape>,
1891    Shape: ChildOccurrenceShape,
1892{
1893    type Product = <Node as ChildOccurrenceProductAt<ChildHead, Shape>>::Product;
1894}
1895
1896impl<Occurrence, Shape, Child> ChildOccurrenceProductAt<Occurrence, Shape> for Child
1897where
1898    Shape: ChildOccurrenceShape
1899        + ChildOccurrenceMember<Occurrence, Child, <Shape as ChildOccurrenceShape>::Empty>,
1900    Child: Behavior,
1901{
1902    type Product = <Shape as ChildOccurrenceMember<
1903        Occurrence,
1904        Child,
1905        <Shape as ChildOccurrenceShape>::Empty,
1906    >>::Member;
1907}
1908
1909impl<Occurrence, Shape, Head, Tail> ChildOccurrenceProductAt<Occurrence, Shape>
1910    for ChildChoice<Head, Tail>
1911where
1912    Shape: ChildOccurrenceShape
1913        + ChildOccurrenceMember<
1914            Occurrence,
1915            Head,
1916            <Tail as ChildOccurrenceProductAt<ChildTail<Occurrence>, Shape>>::Product,
1917        >,
1918    Head: Behavior,
1919    Tail: ChildOccurrenceProductAt<ChildTail<Occurrence>, Shape>,
1920{
1921    type Product = <Shape as ChildOccurrenceMember<
1922        Occurrence,
1923        Head,
1924        <Tail as ChildOccurrenceProductAt<ChildTail<Occurrence>, Shape>>::Product,
1925    >>::Member;
1926}
1927
1928impl<Occurrence, Shape> ChildOccurrenceProductAt<Occurrence, Shape> for Never
1929where
1930    Shape: ChildOccurrenceShape,
1931{
1932    type Product = Shape::Empty;
1933}
1934
1935/// Occurrence-preserving representation selected by one downstream shape.
1936pub type ChildOccurrences<Node, Shape> = <Node as ChildOccurrenceProduct<Shape>>::Product;
1937
1938mod sealed {
1939    use super::{
1940        Behavior, BehaviorBase, BirthMode, BirthNodeAt, ChildChoice, ChildHead, ChildOccurrence,
1941        ChildRole, ChildTail, DeclaredChildOccurrence, Never, ResolveChildOccurrenceDescriptor,
1942        StructuralChildOccurrence,
1943    };
1944
1945    pub trait BirthNode {}
1946
1947    pub trait NonEmptyBirthNode: BirthNode {}
1948
1949    impl<Child: Behavior> BirthNode for Child {}
1950    impl<Child: Behavior> NonEmptyBirthNode for Child {}
1951
1952    impl<Head, Tail> BirthNode for ChildChoice<Head, Tail>
1953    where
1954        Head: Behavior,
1955        Tail: BirthNode,
1956    {
1957    }
1958
1959    impl<Head, Tail> NonEmptyBirthNode for ChildChoice<Head, Tail>
1960    where
1961        Head: Behavior,
1962        Tail: BirthNode,
1963    {
1964    }
1965
1966    impl BirthNode for Never {}
1967
1968    pub trait ChildPosition {}
1969    pub trait ChildProduct {}
1970
1971    pub trait ChildOccurrenceDescriptor {}
1972
1973    impl ChildOccurrenceDescriptor for DeclaredChildOccurrence {}
1974
1975    impl<Position> ChildOccurrenceDescriptor for StructuralChildOccurrence<Position> {}
1976
1977    pub trait OccurrenceResolution<Parent: Behavior, Occurrence> {}
1978
1979    impl<Parent, Occurrence> OccurrenceResolution<Parent, Occurrence> for DeclaredChildOccurrence
1980    where
1981        Parent: Behavior,
1982        Occurrence: ChildRole<Parent>,
1983    {
1984    }
1985
1986    impl<Parent: Behavior> OccurrenceResolution<Parent, ChildHead>
1987        for StructuralChildOccurrence<ChildHead>
1988    {
1989    }
1990
1991    impl<Parent: Behavior, Position> OccurrenceResolution<Parent, ChildTail<Position>>
1992        for StructuralChildOccurrence<ChildTail<Position>>
1993    {
1994    }
1995
1996    pub trait ResolveDescriptor<Emitter: Behavior, Occurrence> {}
1997
1998    impl<Emitter, Occurrence, Position> ResolveDescriptor<Emitter, Occurrence>
1999        for StructuralChildOccurrence<Position>
2000    where
2001        Emitter: Behavior,
2002        <Emitter::Birth as BirthMode>::Child: BirthNodeAt<Position>,
2003    {
2004    }
2005
2006    impl<Emitter, Occurrence> ResolveDescriptor<Emitter, Occurrence> for DeclaredChildOccurrence
2007    where
2008        Emitter: Behavior<Protocol = <<Emitter as BehaviorBase>::Base as Behavior>::Protocol>
2009            + BehaviorBase,
2010        Emitter::Base: Behavior,
2011        Occurrence: ChildRole<Emitter::Base>,
2012        <Emitter::Birth as BirthMode>::Child:
2013            BirthNodeAt<Occurrence::Position, Child = Occurrence::Child>,
2014        Occurrence::Position:
2015            super::ChildPosition<<Emitter::Birth as BirthMode>::Child, Occurrence::Child>,
2016    {
2017    }
2018
2019    pub trait ResolveChildOccurrence<Occurrence> {}
2020
2021    impl<Emitter, Occurrence> ResolveChildOccurrence<Occurrence> for Emitter
2022    where
2023        Emitter: Behavior + BehaviorBase,
2024        Emitter::Base: Behavior,
2025        Occurrence: ChildOccurrence<Emitter::Base>,
2026        Occurrence::Resolution: ResolveChildOccurrenceDescriptor<Emitter, Occurrence>,
2027    {
2028    }
2029}
2030
2031/// The empty heterogeneous creation product.
2032#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
2033pub struct NoChildren;
2034
2035impl sealed::ChildProduct for NoChildren {}
2036
2037/// One creation appended to an ordered heterogeneous child product.
2038pub struct ChildCons<A: Address, C, Earlier> {
2039    creation: CreateChild<A, C>,
2040    earlier: Earlier,
2041}
2042
2043impl<A: Address, C, Earlier> sealed::ChildProduct for ChildCons<A, C, Earlier> {}
2044
2045/// A pure, ordered heterogeneous product of staged direct-child creations.
2046///
2047/// This value owns no mailbox, address, runtime actor, or lifecycle. Every
2048/// product position is a distinct static child occurrence, so equal numeric IDs
2049/// in different positions remain distinct correlations.
2050pub struct Children<A: Address, Product = NoChildren> {
2051    product: Product,
2052    address: PhantomData<fn() -> A>,
2053}
2054
2055/// Closed recursive conversion implemented only by Bombay child products.
2056pub trait ChildProduct<A: Address>: sealed::ChildProduct + Sized {
2057    /// Closed sum containing exactly the concrete child behavior types.
2058    type Choice: BirthNodeAppend<Never>;
2059
2060    #[doc(hidden)]
2061    fn stage(self) -> Vec<CreateChild<A, Self::Choice>>;
2062}
2063
2064impl<A: Address> ChildProduct<A> for NoChildren {
2065    type Choice = Never;
2066
2067    fn stage(self) -> Vec<CreateChild<A, Self::Choice>> {
2068        Vec::new()
2069    }
2070}
2071
2072impl<A, C, Earlier> ChildProduct<A> for ChildCons<A, C, Earlier>
2073where
2074    A: Address,
2075    C: Behavior,
2076    C::Protocol: Protocol<Addr = A>,
2077    Earlier: ChildProduct<A>,
2078{
2079    type Choice = ChildChoice<C, Earlier::Choice>;
2080
2081    fn stage(self) -> Vec<CreateChild<A, Self::Choice>> {
2082        let earlier = self.earlier.stage();
2083        let mut creates = earlier
2084            .into_iter()
2085            .map(|creation| {
2086                let (id, child, kind) = creation.into_parts();
2087                CreateChild::from_parts(id, ChildChoice::Tail(child), kind)
2088            })
2089            .collect::<Vec<_>>();
2090        let (id, child, kind) = self.creation.into_parts();
2091        creates.push(CreateChild::from_parts(id, ChildChoice::Head(child), kind));
2092        creates
2093    }
2094}
2095
2096impl<A: Address> Children<A, NoChildren> {
2097    /// Start an empty heterogeneous creation product.
2098    #[must_use]
2099    pub const fn new() -> Self {
2100        Self {
2101            product: NoChildren,
2102            address: PhantomData,
2103        }
2104    }
2105}
2106
2107impl<A: Address> Default for Children<A, NoChildren> {
2108    fn default() -> Self {
2109        Self::new()
2110    }
2111}
2112
2113impl<A: Address, Product> Children<A, Product> {
2114    /// Append one complete staged creation, preserving its provenance.
2115    #[must_use]
2116    pub fn create<C>(self, creation: CreateChild<A, C>) -> Children<A, ChildCons<A, C, Product>>
2117    where
2118        C: Behavior,
2119        C::Protocol: Protocol<Addr = A>,
2120    {
2121        Children {
2122            product: ChildCons {
2123                creation,
2124                earlier: self.product,
2125            },
2126            address: PhantomData,
2127        }
2128    }
2129
2130    /// Append one ordinary fresh-birth request.
2131    #[must_use]
2132    pub fn child<C>(self, id: CreationId, child: C) -> Children<A, ChildCons<A, C, Product>>
2133    where
2134        C: Behavior,
2135        C::Protocol: Protocol<Addr = A>,
2136    {
2137        self.create(CreateChild::birth(id, child))
2138    }
2139}
2140
2141impl<A, Product> Children<A, Product>
2142where
2143    A: Address,
2144    Product: ChildProduct<A>,
2145{
2146    /// Produce one ordered creation batch.
2147    #[must_use]
2148    pub fn into_creates(self) -> Creations<CreateChild<A, Product::Choice>> {
2149        Creations::from_items(self.product.stage())
2150    }
2151}
2152
2153impl<A, Occurrence, Head, Tail> ChildCreationProduct<A, Occurrence> for ChildChoice<Head, Tail>
2154where
2155    A: EndpointAddress,
2156    Head: Behavior,
2157    Head::Protocol: Protocol<Addr = A>,
2158    Tail: ChildCreationProduct<A, ChildTail<Occurrence>>,
2159{
2160    type Result = ChildChoice<
2161        ChildCreationOutcome<Head, Occurrence>,
2162        <Tail as ChildCreationProduct<A, ChildTail<Occurrence>>>::Result,
2163    >;
2164}
2165
2166impl<A, Occurrence, Head, Tail, Host> CreateSelectedChild<A, Occurrence, Host>
2167    for ChildChoice<Head, Tail>
2168where
2169    A: EndpointAddress,
2170    A::Nonce: Send,
2171    Head: Behavior + Send,
2172    Head::Protocol: Protocol<Addr = A>,
2173    Tail: CreateSelectedChild<A, ChildTail<Occurrence>, Host> + Send,
2174    Host: EstablishChild<Occurrence, Head> + Send,
2175{
2176    async fn dispatch_birth_at(
2177        self,
2178        id: CreationId,
2179        route: A::Nonce,
2180        kind: CreationKind,
2181        host: &mut Host,
2182    ) -> ItemSettlement<
2183        RoutedCreation<A, Self>,
2184        <Self as ChildCreationProduct<A, Occurrence>>::Result,
2185        CreationRejection,
2186        Never,
2187    > {
2188        match self {
2189            Self::Head(child) => {
2190                let creation = RoutedCreation::new(CreateChild::from_parts(id, child, kind), route);
2191                match host.establish_child(creation).await {
2192                    ItemSettlement::Accepted(receipt) => {
2193                        ItemSettlement::Accepted(ChildChoice::Head(receipt))
2194                    }
2195                    ItemSettlement::Rejected { item, reason } => {
2196                        let (creation, route) = item.into_parts();
2197                        let (id, child, kind) = creation.into_parts();
2198                        ItemSettlement::Rejected {
2199                            item: RoutedCreation::new(
2200                                CreateChild::from_parts(id, Self::Head(child), kind),
2201                                route,
2202                            ),
2203                            reason,
2204                        }
2205                    }
2206                    ItemSettlement::Blocked { prerequisite, .. } => match prerequisite {},
2207                    ItemSettlement::Corrupt { item, fault } => {
2208                        let (creation, route) = item.into_parts();
2209                        let (id, child, kind) = creation.into_parts();
2210                        ItemSettlement::Corrupt {
2211                            item: RoutedCreation::new(
2212                                CreateChild::from_parts(id, Self::Head(child), kind),
2213                                route,
2214                            ),
2215                            fault,
2216                        }
2217                    }
2218                }
2219            }
2220            Self::Tail(tail) => match tail.dispatch_birth_at(id, route, kind, host).await {
2221                ItemSettlement::Accepted(receipt) => {
2222                    ItemSettlement::Accepted(ChildChoice::Tail(receipt))
2223                }
2224                ItemSettlement::Rejected { item, reason } => {
2225                    let (creation, route) = item.into_parts();
2226                    let (id, child, kind) = creation.into_parts();
2227                    ItemSettlement::Rejected {
2228                        item: RoutedCreation::new(
2229                            CreateChild::from_parts(id, Self::Tail(child), kind),
2230                            route,
2231                        ),
2232                        reason,
2233                    }
2234                }
2235                ItemSettlement::Blocked { prerequisite, .. } => match prerequisite {},
2236                ItemSettlement::Corrupt { item, fault } => {
2237                    let (creation, route) = item.into_parts();
2238                    let (id, child, kind) = creation.into_parts();
2239                    ItemSettlement::Corrupt {
2240                        item: RoutedCreation::new(
2241                            CreateChild::from_parts(id, Self::Tail(child), kind),
2242                            route,
2243                        ),
2244                        fault,
2245                    }
2246                }
2247            },
2248        }
2249    }
2250}
2251
2252impl<A, Occurrence> ChildCreationProduct<A, Occurrence> for Never
2253where
2254    A: Address,
2255{
2256    type Result = Never;
2257}
2258
2259impl<A, Occurrence, Host> CreateSelectedChild<A, Occurrence, Host> for Never
2260where
2261    A: Address,
2262{
2263    fn dispatch_birth_at(
2264        self,
2265        _id: CreationId,
2266        _route: A::Nonce,
2267        _kind: CreationKind,
2268        _host: &mut Host,
2269    ) -> impl Future<
2270        Output = ItemSettlement<
2271            RoutedCreation<A, Self>,
2272            <Self as ChildCreationProduct<A, Occurrence>>::Result,
2273            CreationRejection,
2274            Never,
2275        >,
2276    > + Send {
2277        async move { match self {} }
2278    }
2279}
2280
2281impl<A, Occurrence, C> ChildCreationProduct<A, Occurrence> for C
2282where
2283    A: EndpointAddress,
2284    C: Behavior,
2285    C::Protocol: Protocol<Addr = A>,
2286{
2287    type Result = ChildCreationOutcome<C, Occurrence>;
2288}
2289
2290impl<A, Occurrence, C, Host> CreateSelectedChild<A, Occurrence, Host> for C
2291where
2292    A: EndpointAddress,
2293    C: Behavior,
2294    C::Protocol: Protocol<Addr = A>,
2295    Host: EstablishChild<Occurrence, C>,
2296{
2297    fn dispatch_birth_at(
2298        self,
2299        id: CreationId,
2300        route: A::Nonce,
2301        kind: CreationKind,
2302        host: &mut Host,
2303    ) -> impl Future<
2304        Output = ItemSettlement<
2305            RoutedCreation<A, Self>,
2306            <Self as ChildCreationProduct<A, Occurrence>>::Result,
2307            CreationRejection,
2308            Never,
2309        >,
2310    > + Send {
2311        host.establish_child(RoutedCreation::new(
2312            CreateChild::from_parts(id, self, kind),
2313            route,
2314        ))
2315    }
2316}
2317
2318/// A type-level description of a behavior's creation capability.
2319pub trait BirthMode {
2320    type Child;
2321}
2322
2323/// Empty protocol projection of a closed behavior-birth algebra.
2324pub struct NoBirthProtocols;
2325
2326/// One behavior protocol followed by the remaining closed birth projection.
2327pub struct BirthProtocol<P: Protocol, Tail> {
2328    protocol: PhantomData<fn() -> P>,
2329    tail: PhantomData<fn() -> Tail>,
2330}
2331
2332/// Structural position selecting the current projected birth protocol.
2333pub struct BirthProtocolHead;
2334
2335/// Structural position selecting inside the remaining protocol projection.
2336pub struct BirthProtocolTail<Position>(PhantomData<fn() -> Position>);
2337
2338/// Static membership evidence for one occurrence in a birth-protocol product.
2339pub trait BirthProtocolAt<P: Protocol, Position> {}
2340
2341impl<P: Protocol, Tail> BirthProtocolAt<P, BirthProtocolHead> for BirthProtocol<P, Tail> {}
2342
2343impl<Head, Tail, P, Position> BirthProtocolAt<P, BirthProtocolTail<Position>>
2344    for BirthProtocol<Head, Tail>
2345where
2346    Head: Protocol,
2347    P: Protocol,
2348    Tail: BirthProtocolAt<P, Position>,
2349{
2350}
2351
2352/// Closed product operation used by the structural birth projection.
2353pub trait BirthProtocolProduct {
2354    type Append<Tail: BirthProtocolProduct>: BirthProtocolProduct;
2355}
2356
2357impl BirthProtocolProduct for NoBirthProtocols {
2358    type Append<Tail: BirthProtocolProduct> = Tail;
2359}
2360
2361impl<P, Rest> BirthProtocolProduct for BirthProtocol<P, Rest>
2362where
2363    P: Protocol,
2364    Rest: BirthProtocolProduct,
2365{
2366    type Append<Tail: BirthProtocolProduct> = BirthProtocol<P, Rest::Append<Tail>>;
2367}
2368
2369/// Closed static projection of a behavior's own protocol and every protocol
2370/// reachable through its transitive staged-birth algebra.
2371///
2372/// This is structural information derived from [`Behavior::Birth`]. It makes
2373/// no hosting or allocation decision and does not inspect send destinations.
2374pub trait BirthProtocols: Behavior {
2375    type Protocols: BirthProtocolProduct;
2376}
2377
2378impl<B> BirthProtocols for B
2379where
2380    B: Behavior,
2381    B::Birth: BirthModeProtocols,
2382{
2383    type Protocols = BirthProtocol<B::Protocol, <B::Birth as BirthModeProtocols>::Protocols>;
2384}
2385
2386#[doc(hidden)]
2387pub trait BirthModeProtocols {
2388    type Protocols: BirthProtocolProduct;
2389}
2390
2391impl<M> BirthModeProtocols for M
2392where
2393    M: BirthMode,
2394    M::Child: BirthNodeProtocols,
2395{
2396    type Protocols = <M::Child as BirthNodeProtocols>::Protocols;
2397}
2398
2399#[doc(hidden)]
2400pub trait BirthNodeProtocols {
2401    type Protocols: BirthProtocolProduct;
2402}
2403
2404impl<B> BirthNodeProtocols for B
2405where
2406    B: BirthProtocols,
2407{
2408    type Protocols = B::Protocols;
2409}
2410
2411impl<Head, Tail> BirthNodeProtocols for ChildChoice<Head, Tail>
2412where
2413    Head: BirthNodeProtocols,
2414    Tail: BirthNodeProtocols,
2415{
2416    type Protocols = <Head::Protocols as BirthProtocolProduct>::Append<Tail::Protocols>;
2417}
2418
2419impl BirthNodeProtocols for Never {
2420    type Protocols = NoBirthProtocols;
2421}
2422
2423/// Structural logical-destination projection for one closed birth node.
2424///
2425/// This implementation detail is public only because its associated product
2426/// participates in the blanket [`crate::LogicalHostRequirements`] interface.
2427#[doc(hidden)]
2428pub trait BirthNodeLogicalHosts {
2429    type LogicalHosts: BirthProtocolProduct;
2430}
2431
2432impl<B> BirthNodeLogicalHosts for B
2433where
2434    B: crate::LogicalHostRequirements,
2435{
2436    type LogicalHosts = B::LogicalHosts;
2437}
2438
2439impl<Head, Tail> BirthNodeLogicalHosts for ChildChoice<Head, Tail>
2440where
2441    Head: BirthNodeLogicalHosts,
2442    Tail: BirthNodeLogicalHosts,
2443{
2444    type LogicalHosts = <Head::LogicalHosts as BirthProtocolProduct>::Append<Tail::LogicalHosts>;
2445}
2446
2447impl BirthNodeLogicalHosts for Never {
2448    type LogicalHosts = NoBirthProtocols;
2449}
2450
2451/// This behavior cannot emit child births.
2452#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
2453pub struct NoBirths;
2454
2455impl BirthMode for NoBirths {
2456    type Child = Never;
2457}
2458
2459/// This behavior may emit births of `C`.
2460#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
2461pub struct Births<C>(PhantomData<fn() -> C>);
2462
2463impl<C> BirthMode for Births<C> {
2464    type Child = C;
2465}
2466
2467/// This behavior may emit births of `C` whose exact settlements remain in
2468/// runtime custody until actor retirement.
2469///
2470/// Unlike [`Births`], this mode does not return a creation settlement as a
2471/// later input to the live creator. It is the deliberate policy for actors
2472/// whose terminal owner, rather than another behavior transition, must retain
2473/// every authoritative creation result.
2474#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
2475pub struct RetirementBirths<C>(PhantomData<fn() -> C>);
2476
2477impl<C> BirthMode for RetirementBirths<C> {
2478    type Child = C;
2479}
2480
2481#[cfg(test)]
2482mod tests {
2483    use super::*;
2484    use crate::{
2485        Actions, BehaviorActed, ChildInputIngress, EventLayer, Interpretation, NoBirths, User,
2486    };
2487
2488    #[derive(Clone, Copy, Debug, Eq, PartialEq)]
2489    struct TestAddr(u64);
2490
2491    impl Address for TestAddr {
2492        type Nonce = u64;
2493    }
2494
2495    struct TestEndpoint<P>(PhantomData<fn() -> P>);
2496
2497    impl<P> Clone for TestEndpoint<P> {
2498        fn clone(&self) -> Self {
2499            *self
2500        }
2501    }
2502
2503    impl<P> Copy for TestEndpoint<P> {}
2504
2505    struct TestInstalled<B: Behavior> {
2506        endpoint: TestEndpoint<B::Protocol>,
2507        control: std::sync::mpsc::Sender<B::Event>,
2508    }
2509
2510    impl<B: Behavior> Clone for TestInstalled<B> {
2511        fn clone(&self) -> Self {
2512            Self {
2513                endpoint: self.endpoint,
2514                control: self.control.clone(),
2515            }
2516        }
2517    }
2518
2519    impl EndpointAddress for TestAddr {
2520        type Established<P>
2521            = TestEndpoint<P>
2522        where
2523            P: Protocol<Addr = Self>;
2524
2525        type Installed<B>
2526            = TestInstalled<B>
2527        where
2528            B: Behavior<Protocol: Protocol<Addr = Self>>;
2529
2530        fn recipient<B>(installed: &Self::Installed<B>) -> Self::Established<B::Protocol>
2531        where
2532            B: Behavior<Protocol: Protocol<Addr = Self>>,
2533        {
2534            installed.endpoint
2535        }
2536    }
2537
2538    #[derive(Debug, Clone, Copy, PartialEq, Eq)]
2539    struct Child;
2540
2541    struct SharedProtocol;
2542
2543    impl behavior::Protocol for SharedProtocol {
2544        type Addr = TestAddr;
2545        type Msg = u8;
2546    }
2547
2548    struct Primary;
2549    struct Fallback;
2550
2551    macro_rules! shared_protocol_behavior {
2552        ($behavior:ty, $birth:ty) => {
2553            impl Behavior for $behavior {
2554                type Protocol = SharedProtocol;
2555                type Event = User<TestAddr, u8>;
2556                type Sends = Vec<Never>;
2557                type Ph = Never;
2558                type Error = Never;
2559                type Birth = $birth;
2560
2561                fn transition(
2562                    &mut self,
2563                    _: crate::ActiveTurn,
2564                    _: Self::Event,
2565                ) -> BehaviorActed<Self> {
2566                    Ok(Actions::cont())
2567                }
2568            }
2569        };
2570    }
2571
2572    shared_protocol_behavior!(Primary, Births<Child>);
2573    shared_protocol_behavior!(Fallback, NoBirths);
2574
2575    impl behavior::Protocol for Child {
2576        type Addr = TestAddr;
2577        type Msg = u8;
2578    }
2579
2580    impl Behavior for Child {
2581        type Protocol = Self;
2582        type Event = User<TestAddr, u8>;
2583        type Sends = Vec<Never>;
2584        type Ph = Never;
2585        type Error = Never;
2586        type Birth = NoBirths;
2587
2588        fn transition(&mut self, _: crate::ActiveTurn, _: Self::Event) -> BehaviorActed<Self> {
2589            Ok(Actions::cont())
2590        }
2591    }
2592
2593    #[derive(Debug, Clone, Copy, PartialEq, Eq)]
2594    enum ChildPlan {
2595        CreateChild,
2596        RejectBeforeTransfer,
2597    }
2598
2599    struct RecordingHost {
2600        calls: usize,
2601        observed: Vec<(CreationId, u64, CreationKind)>,
2602        plan: ChildPlan,
2603        control_receivers: Vec<std::sync::mpsc::Receiver<User<TestAddr, u8>>>,
2604    }
2605
2606    #[derive(Debug, PartialEq, Eq)]
2607    enum SharedCreation {
2608        Primary(CreationId, u64),
2609        Fallback(CreationId, u64),
2610    }
2611
2612    #[derive(Default)]
2613    struct SharedProtocolHost(
2614        Vec<SharedCreation>,
2615        Vec<std::sync::mpsc::Receiver<User<TestAddr, u8>>>,
2616    );
2617
2618    impl EstablishChild<ChildHead, Primary> for SharedProtocolHost {
2619        async fn establish_child(
2620            &mut self,
2621            creation: RoutedCreation<TestAddr, Primary>,
2622        ) -> ItemSettlement<
2623            RoutedCreation<TestAddr, Primary>,
2624            ChildCreationOutcome<Primary, ChildHead>,
2625            CreationRejection,
2626            Never,
2627        > {
2628            let id = creation.id();
2629            let kind = creation.kind();
2630            let route = creation.route();
2631            let (creation, _) = creation.into_parts();
2632            let (_, _child, _) = creation.into_parts();
2633            self.0.push(SharedCreation::Primary(id, route));
2634            let (control, receiver) = std::sync::mpsc::channel();
2635            self.1.push(receiver);
2636            ItemSettlement::Accepted(ChildCreationOutcome::Established(CommittedChild::new(
2637                id,
2638                kind,
2639                EstablishedActor::issued(TestInstalled {
2640                    endpoint: TestEndpoint(PhantomData),
2641                    control,
2642                }),
2643            )))
2644        }
2645    }
2646
2647    impl EstablishChild<ChildTail<ChildHead>, Fallback> for SharedProtocolHost {
2648        async fn establish_child(
2649            &mut self,
2650            creation: RoutedCreation<TestAddr, Fallback>,
2651        ) -> ItemSettlement<
2652            RoutedCreation<TestAddr, Fallback>,
2653            ChildCreationOutcome<Fallback, ChildTail<ChildHead>>,
2654            CreationRejection,
2655            Never,
2656        > {
2657            let id = creation.id();
2658            let kind = creation.kind();
2659            let route = creation.route();
2660            let (creation, _) = creation.into_parts();
2661            let (_, _child, _) = creation.into_parts();
2662            self.0.push(SharedCreation::Fallback(id, route));
2663            let (control, receiver) = std::sync::mpsc::channel();
2664            self.1.push(receiver);
2665            ItemSettlement::Accepted(ChildCreationOutcome::Established(CommittedChild::new(
2666                id,
2667                kind,
2668                EstablishedActor::issued(TestInstalled {
2669                    endpoint: TestEndpoint(PhantomData),
2670                    control,
2671                }),
2672            )))
2673        }
2674    }
2675
2676    impl EstablishChild<ChildHead, Child> for RecordingHost {
2677        async fn establish_child(
2678            &mut self,
2679            creation: RoutedCreation<TestAddr, Child>,
2680        ) -> ItemSettlement<
2681            RoutedCreation<TestAddr, Child>,
2682            ChildCreationOutcome<Child, ChildHead>,
2683            CreationRejection,
2684            Never,
2685        > {
2686            self.calls += 1;
2687            self.observed
2688                .push((creation.id(), creation.route(), creation.kind()));
2689            match self.plan {
2690                ChildPlan::CreateChild => {
2691                    let id = creation.id();
2692                    let kind = creation.kind();
2693                    let (creation, _) = creation.into_parts();
2694                    let (_, _child, _) = creation.into_parts();
2695                    let (control, receiver) = std::sync::mpsc::channel();
2696                    self.control_receivers.push(receiver);
2697                    ItemSettlement::Accepted(ChildCreationOutcome::Established(
2698                        CommittedChild::new(
2699                            id,
2700                            kind,
2701                            EstablishedActor::issued(TestInstalled {
2702                                endpoint: TestEndpoint(PhantomData),
2703                                control,
2704                            }),
2705                        ),
2706                    ))
2707                }
2708                ChildPlan::RejectBeforeTransfer => ItemSettlement::Rejected {
2709                    item: creation,
2710                    reason: CreationRejection::EnvironmentFailed,
2711                },
2712            }
2713        }
2714    }
2715
2716    fn host(plan: ChildPlan) -> RecordingHost {
2717        RecordingHost {
2718            calls: 0,
2719            observed: Vec::new(),
2720            plan,
2721            control_receivers: Vec::new(),
2722        }
2723    }
2724
2725    fn assert_send<T: Send>(_: &T) {}
2726
2727    #[test]
2728    fn empty_child_product_stages_no_creations() {
2729        let creations = <NoChildren as ChildProduct<TestAddr>>::stage(NoChildren);
2730        assert!(creations.is_empty());
2731    }
2732
2733    #[test]
2734    fn creation_values_preserve_ids_order_and_debug_identity() {
2735        let mut sequence = CreationSequence::new();
2736        let first = sequence.issue().expect("the first creation ID exists");
2737        let second = sequence.issue().expect("the second creation ID exists");
2738        assert_eq!(first.get(), 1);
2739        assert_eq!(second.get(), 2);
2740
2741        let first_correlation = CreationCorrelation::<SharedProtocol, ChildHead>::new(first);
2742        let same_correlation = CreationCorrelation::<SharedProtocol, ChildHead>::new(first);
2743        let second_correlation = CreationCorrelation::<SharedProtocol, ChildHead>::new(second);
2744        assert_eq!(first_correlation, same_correlation);
2745        assert_ne!(first_correlation, second_correlation);
2746        assert_eq!(
2747            format!("{first_correlation:?}"),
2748            "CreationCorrelation(CreationId(1))"
2749        );
2750
2751        let mut creations = Creations::one(1_u8);
2752        creations.extend([2, 3]);
2753        assert_eq!(creations.len(), 3);
2754        assert!(!creations.is_empty());
2755        assert_eq!(creations.iter().copied().collect::<Vec<_>>(), [1, 2, 3]);
2756        let borrowed = (&creations).into_iter().copied().collect::<Vec<_>>();
2757        assert_eq!(borrowed, [1, 2, 3]);
2758
2759        let collected: Creations<_> = [4_u8, 5].into_iter().collect();
2760        assert_eq!(collected.len(), 2);
2761        let collected_values = collected.into_iter().collect::<Vec<_>>();
2762        assert_eq!(collected_values, [4, 5]);
2763
2764        let returned = ChildCreationSettled::<Child, ChildHead>::new(SettledItem::Unattempted(
2765            RoutedCreation::new(CreateChild::birth(first, Child), 17),
2766        ));
2767        assert_eq!(format!("{returned:?}"), "ChildCreationSettled { .. }");
2768    }
2769
2770    #[tokio::test]
2771    async fn concrete_child_dispatches_once_with_exact_creation_and_route() {
2772        let mut sequence = CreationSequence::new();
2773        let previous = sequence.issue().expect("the previous ID exists");
2774        let id = sequence.issue().expect("the replacement ID exists");
2775        let mut host = host(ChildPlan::CreateChild);
2776        let kind = CreationKind::replacement(previous);
2777        let future = Child.dispatch_birth(id, 17, kind, &mut host);
2778        assert_send(&future);
2779        let result = future.await;
2780
2781        let ItemSettlement::Accepted(ChildCreationOutcome::Established(established)) = result
2782        else {
2783            panic!("expected the child to be created");
2784        };
2785        assert_eq!(established.id(), id);
2786        assert_eq!(host.calls, 1);
2787        assert_eq!(host.observed, [(id, 17, kind)]);
2788    }
2789
2790    #[tokio::test]
2791    async fn concrete_child_returns_the_exact_rejected_creation_without_retry() {
2792        let mut sequence = CreationSequence::new();
2793        let previous = sequence.issue().expect("the previous ID exists");
2794        let id = sequence.issue().expect("the replacement ID exists");
2795        let mut host = host(ChildPlan::RejectBeforeTransfer);
2796        let kind = CreationKind::replacement(previous);
2797        let future = Child.dispatch_birth(id, 23, kind, &mut host);
2798        assert_send(&future);
2799        let result = future.await;
2800
2801        let ItemSettlement::Rejected { item, reason } = result else {
2802            panic!("expected refusal before child ownership transfer");
2803        };
2804        assert_eq!(
2805            item,
2806            RoutedCreation::new(CreateChild::replacement(id, previous, Child), 23)
2807        );
2808        assert_eq!(reason, CreationRejection::EnvironmentFailed);
2809        assert_eq!(host.calls, 1);
2810        assert_eq!(host.observed, [(id, 23, kind)]);
2811    }
2812
2813    #[tokio::test]
2814    async fn distinct_child_alternatives_preserve_one_canonical_protocol_identity() {
2815        type Alternatives = ChildChoice<Primary, ChildChoice<Fallback, Never>>;
2816
2817        fn requires_shared_protocol<C: Behavior<Protocol = SharedProtocol>>() {}
2818        requires_shared_protocol::<Primary>();
2819        requires_shared_protocol::<Fallback>();
2820
2821        let mut sequence = CreationSequence::new();
2822        let primary_id = sequence.issue().expect("the primary ID exists");
2823        let fallback_id = sequence.issue().expect("the fallback ID exists");
2824        let mut host = SharedProtocolHost::default();
2825        let primary = Alternatives::Head(Primary)
2826            .dispatch_birth(primary_id, 11, CreationKind::Birth, &mut host)
2827            .await;
2828        let fallback = Alternatives::Tail(ChildChoice::Head(Fallback))
2829            .dispatch_birth(fallback_id, 17, CreationKind::Birth, &mut host)
2830            .await;
2831
2832        let ItemSettlement::Accepted(ChildChoice::Head(ChildCreationOutcome::Established(primary))) =
2833            primary
2834        else {
2835            panic!("expected the primary child result");
2836        };
2837        assert_eq!(primary.id(), primary_id);
2838        let ItemSettlement::Accepted(ChildChoice::Tail(ChildChoice::Head(
2839            ChildCreationOutcome::Established(fallback),
2840        ))) = fallback
2841        else {
2842            panic!("expected the fallback child result");
2843        };
2844        assert_eq!(fallback.id(), fallback_id);
2845
2846        assert_eq!(
2847            host.0,
2848            [
2849                SharedCreation::Primary(primary_id, 11),
2850                SharedCreation::Fallback(fallback_id, 17),
2851            ]
2852        );
2853    }
2854
2855    #[test]
2856    fn birth_protocol_projection_recurses_without_inspecting_send_lanes() {
2857        type Protocols = <Primary as BirthProtocols>::Protocols;
2858        type Expected = BirthProtocol<SharedProtocol, BirthProtocol<Child, NoBirthProtocols>>;
2859
2860        trait Same<T> {}
2861        impl<T> Same<T> for T {}
2862        fn exact<T: Same<Expected>>() {}
2863        exact::<Protocols>();
2864    }
2865    fn child_request_loan_is_affine<Item, Observation>(
2866        request: Item,
2867        duplicate: Item,
2868        reason: Item::Rejection,
2869        observe: impl Fn(&Item) -> Observation,
2870    ) where
2871        Item: ActionItem<
2872                Custody = (Option<Item>, Option<<Item as ActionItem>::Reply>),
2873                Reply = ItemSettlement<
2874                    Item,
2875                    <Item as ActionItem>::Accepted,
2876                    <Item as ActionItem>::Rejection,
2877                    <Item as ActionItem>::Prerequisite,
2878                >,
2879            > + 'static,
2880        for<'a> Item: ActionItem<Input<'a> = &'a mut Option<Item>>,
2881        Item::Rejection: Copy + PartialEq + core::fmt::Debug,
2882        Observation: PartialEq + core::fmt::Debug,
2883    {
2884        let expected = observe(&request);
2885        let mut progress = Some(InterpretationProgress::Original(request));
2886        Item::prepare_interpretation(&mut progress);
2887        Item::prepare_interpretation(&mut progress);
2888        let Some(InterpretationProgress::Interpreting(custody)) = &mut progress else {
2889            panic!("preparation must preserve the real request in outside custody");
2890        };
2891        let (input, reply) = Item::interpretation_input(custody)
2892            .expect("one unreplied request must loan its complete input");
2893        let request = input.take().expect("the loan owns the complete request");
2894        let observed = observe(&request);
2895        assert_eq!(
2896            observed, expected,
2897            "the host loan must preserve the complete request"
2898        );
2899        *reply = Some(ItemSettlement::Rejected {
2900            item: request,
2901            reason,
2902        });
2903        let replied = Item::interpretation_input(custody);
2904        assert!(
2905            replied.is_none(),
2906            "a replied request must not be loaned again"
2907        );
2908        custody.0 = Some(duplicate);
2909        let duplicate_loan = Item::interpretation_input(custody);
2910        assert!(
2911            duplicate_loan.is_none(),
2912            "a reply denies reentry even if input is retained"
2913        );
2914        let duplicate = custody
2915            .0
2916            .take()
2917            .expect("the duplicate remains outside-owned");
2918        drop(duplicate);
2919        Item::finish_interpretation(&mut progress);
2920        Item::prepare_interpretation(&mut progress);
2921        Item::finish_interpretation(&mut progress);
2922        match progress {
2923            Some(InterpretationProgress::Completed(Interpretation::Complete(
2924                ItemSettlement::Rejected {
2925                    item,
2926                    reason: returned_reason,
2927                },
2928            ))) => {
2929                let observed = observe(&item);
2930                assert_eq!(
2931                    (observed, returned_reason),
2932                    (expected, reason),
2933                    "replay must preserve the complete rejected request and reason"
2934                );
2935            }
2936            _ => panic!("completed ownership must survive preparation and finalization replay"),
2937        }
2938        let mut empty = (None, None);
2939        let missing = Item::interpretation_input(&mut empty);
2940        assert!(
2941            missing.is_none(),
2942            "missing input must never expose a host loan"
2943        );
2944    }
2945
2946    impl ChildInputIngress<ChildHead, u8> for User<TestAddr, u8> {
2947        fn child_input(input: u8) -> Self {
2948            User::new(TestAddr(7), input)
2949        }
2950        fn recover_child_input(event: Self) -> Result<u8, Self> {
2951            Ok(event.message)
2952        }
2953    }
2954
2955    type ParentInputWithOuterNotice = EventLayer<Box<str>, EventLayer<u64, User<TestAddr, u8>>>;
2956    type ParentInputWithInnerNotice = EventLayer<u64, EventLayer<Box<str>, User<TestAddr, u8>>>;
2957
2958    #[test]
2959    fn private_input_lifting_preserves_control_in_both_layer_orders() {
2960        let event =
2961            <ParentInputWithOuterNotice as ChildInputIngress<ChildHead, u8>>::child_input(43);
2962        let EventLayer::Inner(EventLayer::Inner(original)) = &event else {
2963            panic!("private input must reach its exact inner user lane");
2964        };
2965        assert_eq!(original, &User::new(TestAddr(7), 43));
2966        let returned =
2967            <ParentInputWithOuterNotice as ChildInputIngress<ChildHead, u8>>::recover_child_input(
2968                event,
2969            );
2970        assert_eq!(returned, Ok(43));
2971
2972        let event =
2973            <ParentInputWithInnerNotice as ChildInputIngress<ChildHead, u8>>::child_input(47);
2974        let EventLayer::Inner(EventLayer::Inner(original)) = &event else {
2975            panic!("private input must reach the same lane after reordering");
2976        };
2977        assert_eq!(original, &User::new(TestAddr(7), 47));
2978        let returned =
2979            <ParentInputWithInnerNotice as ChildInputIngress<ChildHead, u8>>::recover_child_input(
2980                event,
2981            );
2982        assert_eq!(returned, Ok(47));
2983    }
2984
2985    #[test]
2986    fn private_input_recovery_returns_each_foreign_owned_lane() {
2987        let notice = Box::<str>::from("outer notice");
2988        let allocation = notice.as_ptr();
2989        let event = ParentInputWithOuterNotice::Owned(notice);
2990        let returned =
2991            <ParentInputWithOuterNotice as ChildInputIngress<ChildHead, u8>>::recover_child_input(
2992                event,
2993            );
2994        let Err(EventLayer::Owned(returned)) = returned else {
2995            panic!("the outer notice must return in its original lane");
2996        };
2997        assert_eq!(returned.as_ptr(), allocation);
2998        assert_eq!(&*returned, "outer notice");
2999
3000        let event = ParentInputWithOuterNotice::Inner(EventLayer::Owned(37));
3001        let returned =
3002            <ParentInputWithOuterNotice as ChildInputIngress<ChildHead, u8>>::recover_child_input(
3003                event,
3004            );
3005        assert_eq!(returned, Err(EventLayer::Inner(EventLayer::Owned(37))));
3006
3007        let event = ParentInputWithInnerNotice::Owned(41);
3008        let returned =
3009            <ParentInputWithInnerNotice as ChildInputIngress<ChildHead, u8>>::recover_child_input(
3010                event,
3011            );
3012        assert_eq!(returned, Err(EventLayer::Owned(41)));
3013
3014        let notice = Box::<str>::from("inner notice");
3015        let allocation = notice.as_ptr();
3016        let event = ParentInputWithInnerNotice::Inner(EventLayer::Owned(notice));
3017        let returned =
3018            <ParentInputWithInnerNotice as ChildInputIngress<ChildHead, u8>>::recover_child_input(
3019                event,
3020            );
3021        let Err(EventLayer::Inner(EventLayer::Owned(returned))) = returned else {
3022            panic!("the reordered inner notice must return in its original lane");
3023        };
3024        assert_eq!(returned.as_ptr(), allocation);
3025        assert_eq!(&*returned, "inner notice");
3026    }
3027
3028    #[test]
3029    fn child_delivery_custody_allows_one_complete_request_and_denies_replay() {
3030        let id = CreationSequence::new()
3031            .issue()
3032            .expect("the creation ID exists");
3033        let request = ChildDelivery::<SharedProtocol, ChildHead>::after(id, 41);
3034        child_request_loan_is_affine(
3035            request,
3036            ChildDelivery::<SharedProtocol, ChildHead>::after(id, 47),
3037            ChildDeliveryReason::ClosedRecipient,
3038            |request| (request.creation, request.message),
3039        );
3040    }
3041
3042    #[test]
3043    fn private_child_input_custody_allows_one_complete_request_and_denies_replay() {
3044        let id = CreationSequence::new()
3045            .issue()
3046            .expect("the creation ID exists");
3047        let request = ChildInput::<Child, ChildHead, u8, ChildHead>::after(id, 43);
3048        child_request_loan_is_affine(
3049            request,
3050            ChildInput::<Child, ChildHead, u8, ChildHead>::after(id, 47),
3051            ChildInputReason::ClosedControlLane,
3052            |request| (request.creation, request.input),
3053        );
3054    }
3055
3056    #[test]
3057    fn creation_route_custody_allows_one_complete_batch_and_denies_replay() {
3058        let id = CreationSequence::new()
3059            .issue()
3060            .expect("the creation ID exists");
3061        let request = Creations::one(CreateChild::<TestAddr, Child>::birth(id, Child));
3062        child_request_loan_is_affine(
3063            request,
3064            Creations::one(CreateChild::<TestAddr, Child>::birth(id, Child)),
3065            ChildNamespaceExhausted,
3066            |request| {
3067                request
3068                    .iter()
3069                    .map(|creation| (creation.id(), creation.kind(), *creation.child()))
3070                    .collect::<Vec<_>>()
3071            },
3072        );
3073    }
3074}