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