Skip to main content

behavior/actor/
creation.rs

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